diff options
Diffstat (limited to 'tools/perf/ui/hist.c')
-rw-r--r-- | tools/perf/ui/hist.c | 258 |
1 files changed, 15 insertions, 243 deletions
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 4bf91b09d62d..0a193281eba8 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <math.h> | 1 | #include <math.h> |
2 | #include <linux/compiler.h> | ||
2 | 3 | ||
3 | #include "../util/hist.h" | 4 | #include "../util/hist.h" |
4 | #include "../util/util.h" | 5 | #include "../util/util.h" |
@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
79 | } | 80 | } |
80 | 81 | ||
81 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | 82 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
82 | static int hpp__header_##_type(struct perf_hpp *hpp) \ | 83 | static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
84 | struct perf_hpp *hpp) \ | ||
83 | { \ | 85 | { \ |
84 | int len = _min_width; \ | 86 | int len = _min_width; \ |
85 | \ | 87 | \ |
@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \ | |||
92 | } | 94 | } |
93 | 95 | ||
94 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | 96 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ |
95 | static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ | 97 | static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
98 | struct perf_hpp *hpp __maybe_unused) \ | ||
96 | { \ | 99 | { \ |
97 | int len = _min_width; \ | 100 | int len = _min_width; \ |
98 | \ | 101 | \ |
@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ | |||
110 | return he->stat._field; \ | 113 | return he->stat._field; \ |
111 | } \ | 114 | } \ |
112 | \ | 115 | \ |
113 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 116 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
117 | struct perf_hpp *hpp, struct hist_entry *he) \ | ||
114 | { \ | 118 | { \ |
115 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | 119 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ |
116 | (hpp_snprint_fn)percent_color_snprintf, true); \ | 120 | (hpp_snprint_fn)percent_color_snprintf, true); \ |
117 | } | 121 | } |
118 | 122 | ||
119 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | 123 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
120 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 124 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
125 | struct perf_hpp *hpp, struct hist_entry *he) \ | ||
121 | { \ | 126 | { \ |
122 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | 127 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ |
123 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ | 128 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ |
@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ | |||
130 | return he->stat._field; \ | 135 | return he->stat._field; \ |
131 | } \ | 136 | } \ |
132 | \ | 137 | \ |
133 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 138 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
139 | struct perf_hpp *hpp, struct hist_entry *he) \ | ||
134 | { \ | 140 | { \ |
135 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | 141 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ |
136 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ | 142 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ |
@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | |||
157 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) | 163 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) |
158 | HPP_RAW_FNS(period, "Period", period, 12, 12) | 164 | HPP_RAW_FNS(period, "Period", period, 12, 12) |
159 | 165 | ||
160 | |||
161 | static int hpp__header_baseline(struct perf_hpp *hpp) | ||
162 | { | ||
163 | return scnprintf(hpp->buf, hpp->size, "Baseline"); | ||
164 | } | ||
165 | |||
166 | static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) | ||
167 | { | ||
168 | return 8; | ||
169 | } | ||
170 | |||
171 | static double baseline_percent(struct hist_entry *he) | ||
172 | { | ||
173 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
174 | struct hists *pair_hists = pair ? pair->hists : NULL; | ||
175 | double percent = 0.0; | ||
176 | |||
177 | if (pair) { | ||
178 | u64 total_period = pair_hists->stats.total_period; | ||
179 | u64 base_period = pair->stat.period; | ||
180 | |||
181 | percent = 100.0 * base_period / total_period; | ||
182 | } | ||
183 | |||
184 | return percent; | ||
185 | } | ||
186 | |||
187 | static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
188 | { | ||
189 | double percent = baseline_percent(he); | ||
190 | |||
191 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) | ||
192 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | ||
193 | else | ||
194 | return scnprintf(hpp->buf, hpp->size, " "); | ||
195 | } | ||
196 | |||
197 | static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
198 | { | ||
199 | double percent = baseline_percent(he); | ||
200 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | ||
201 | |||
202 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) | ||
203 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
204 | else | ||
205 | return scnprintf(hpp->buf, hpp->size, " "); | ||
206 | } | ||
207 | |||
208 | static int hpp__header_period_baseline(struct perf_hpp *hpp) | ||
209 | { | ||
210 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | ||
211 | |||
212 | return scnprintf(hpp->buf, hpp->size, fmt, "Period Base"); | ||
213 | } | ||
214 | |||
215 | static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused) | ||
216 | { | ||
217 | return 12; | ||
218 | } | ||
219 | |||
220 | static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
221 | { | ||
222 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
223 | u64 period = pair ? pair->stat.period : 0; | ||
224 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; | ||
225 | |||
226 | return scnprintf(hpp->buf, hpp->size, fmt, period); | ||
227 | } | ||
228 | |||
229 | static int hpp__header_delta(struct perf_hpp *hpp) | ||
230 | { | ||
231 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | ||
232 | |||
233 | return scnprintf(hpp->buf, hpp->size, fmt, "Delta"); | ||
234 | } | ||
235 | |||
236 | static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | ||
237 | { | ||
238 | return 7; | ||
239 | } | ||
240 | |||
241 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | ||
242 | { | ||
243 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
244 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | ||
245 | char buf[32] = " "; | ||
246 | double diff = 0.0; | ||
247 | |||
248 | if (pair) { | ||
249 | if (he->diff.computed) | ||
250 | diff = he->diff.period_ratio_delta; | ||
251 | else | ||
252 | diff = perf_diff__compute_delta(he, pair); | ||
253 | } else | ||
254 | diff = perf_diff__period_percent(he, he->stat.period); | ||
255 | |||
256 | if (fabs(diff) >= 0.01) | ||
257 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); | ||
258 | |||
259 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
260 | } | ||
261 | |||
262 | static int hpp__header_ratio(struct perf_hpp *hpp) | ||
263 | { | ||
264 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
265 | |||
266 | return scnprintf(hpp->buf, hpp->size, fmt, "Ratio"); | ||
267 | } | ||
268 | |||
269 | static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) | ||
270 | { | ||
271 | return 14; | ||
272 | } | ||
273 | |||
274 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) | ||
275 | { | ||
276 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
277 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
278 | char buf[32] = " "; | ||
279 | double ratio = 0.0; | ||
280 | |||
281 | if (pair) { | ||
282 | if (he->diff.computed) | ||
283 | ratio = he->diff.period_ratio; | ||
284 | else | ||
285 | ratio = perf_diff__compute_ratio(he, pair); | ||
286 | } | ||
287 | |||
288 | if (ratio > 0.0) | ||
289 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); | ||
290 | |||
291 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
292 | } | ||
293 | |||
294 | static int hpp__header_wdiff(struct perf_hpp *hpp) | ||
295 | { | ||
296 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
297 | |||
298 | return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff"); | ||
299 | } | ||
300 | |||
301 | static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) | ||
302 | { | ||
303 | return 14; | ||
304 | } | ||
305 | |||
306 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | ||
307 | { | ||
308 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
309 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
310 | char buf[32] = " "; | ||
311 | s64 wdiff = 0; | ||
312 | |||
313 | if (pair) { | ||
314 | if (he->diff.computed) | ||
315 | wdiff = he->diff.wdiff; | ||
316 | else | ||
317 | wdiff = perf_diff__compute_wdiff(he, pair); | ||
318 | } | ||
319 | |||
320 | if (wdiff != 0) | ||
321 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); | ||
322 | |||
323 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
324 | } | ||
325 | |||
326 | static int hpp__header_formula(struct perf_hpp *hpp) | ||
327 | { | ||
328 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; | ||
329 | |||
330 | return scnprintf(hpp->buf, hpp->size, fmt, "Formula"); | ||
331 | } | ||
332 | |||
333 | static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) | ||
334 | { | ||
335 | return 70; | ||
336 | } | ||
337 | |||
338 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | ||
339 | { | ||
340 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
341 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; | ||
342 | char buf[96] = " "; | ||
343 | |||
344 | if (pair) | ||
345 | perf_diff__formula(he, pair, buf, sizeof(buf)); | ||
346 | |||
347 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
348 | } | ||
349 | |||
350 | #define HPP__COLOR_PRINT_FNS(_name) \ | 166 | #define HPP__COLOR_PRINT_FNS(_name) \ |
351 | { \ | 167 | { \ |
352 | .header = hpp__header_ ## _name, \ | 168 | .header = hpp__header_ ## _name, \ |
@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | |||
363 | } | 179 | } |
364 | 180 | ||
365 | struct perf_hpp_fmt perf_hpp__format[] = { | 181 | struct perf_hpp_fmt perf_hpp__format[] = { |
366 | HPP__COLOR_PRINT_FNS(baseline), | ||
367 | HPP__COLOR_PRINT_FNS(overhead), | 182 | HPP__COLOR_PRINT_FNS(overhead), |
368 | HPP__COLOR_PRINT_FNS(overhead_sys), | 183 | HPP__COLOR_PRINT_FNS(overhead_sys), |
369 | HPP__COLOR_PRINT_FNS(overhead_us), | 184 | HPP__COLOR_PRINT_FNS(overhead_us), |
370 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), | 185 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), |
371 | HPP__COLOR_PRINT_FNS(overhead_guest_us), | 186 | HPP__COLOR_PRINT_FNS(overhead_guest_us), |
372 | HPP__PRINT_FNS(samples), | 187 | HPP__PRINT_FNS(samples), |
373 | HPP__PRINT_FNS(period), | 188 | HPP__PRINT_FNS(period) |
374 | HPP__PRINT_FNS(period_baseline), | ||
375 | HPP__PRINT_FNS(delta), | ||
376 | HPP__PRINT_FNS(ratio), | ||
377 | HPP__PRINT_FNS(wdiff), | ||
378 | HPP__PRINT_FNS(formula) | ||
379 | }; | 189 | }; |
380 | 190 | ||
381 | LIST_HEAD(perf_hpp__list); | 191 | LIST_HEAD(perf_hpp__list); |
@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list); | |||
396 | 206 | ||
397 | void perf_hpp__init(void) | 207 | void perf_hpp__init(void) |
398 | { | 208 | { |
209 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
210 | |||
399 | if (symbol_conf.show_cpu_utilization) { | 211 | if (symbol_conf.show_cpu_utilization) { |
400 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); | 212 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
401 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); | 213 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); |
@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col) | |||
424 | perf_hpp__column_register(&perf_hpp__format[col]); | 236 | perf_hpp__column_register(&perf_hpp__format[col]); |
425 | } | 237 | } |
426 | 238 | ||
427 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | ||
428 | { | ||
429 | hpp->buf += inc; | ||
430 | hpp->size -= inc; | ||
431 | } | ||
432 | |||
433 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | ||
434 | bool color) | ||
435 | { | ||
436 | const char *sep = symbol_conf.field_sep; | ||
437 | struct perf_hpp_fmt *fmt; | ||
438 | char *start = hpp->buf; | ||
439 | int ret; | ||
440 | bool first = true; | ||
441 | |||
442 | if (symbol_conf.exclude_other && !he->parent) | ||
443 | return 0; | ||
444 | |||
445 | perf_hpp__for_each_format(fmt) { | ||
446 | /* | ||
447 | * If there's no field_sep, we still need | ||
448 | * to display initial ' '. | ||
449 | */ | ||
450 | if (!sep || !first) { | ||
451 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | ||
452 | advance_hpp(hpp, ret); | ||
453 | } else | ||
454 | first = false; | ||
455 | |||
456 | if (color && fmt->color) | ||
457 | ret = fmt->color(hpp, he); | ||
458 | else | ||
459 | ret = fmt->entry(hpp, he); | ||
460 | |||
461 | advance_hpp(hpp, ret); | ||
462 | } | ||
463 | |||
464 | return hpp->buf - start; | ||
465 | } | ||
466 | |||
467 | int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, | 239 | int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, |
468 | struct hists *hists) | 240 | struct hists *hists) |
469 | { | 241 | { |
@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists) | |||
499 | if (i) | 271 | if (i) |
500 | ret += 2; | 272 | ret += 2; |
501 | 273 | ||
502 | ret += fmt->width(&dummy_hpp); | 274 | ret += fmt->width(fmt, &dummy_hpp); |
503 | } | 275 | } |
504 | 276 | ||
505 | list_for_each_entry(se, &hist_entry__sort_list, list) | 277 | list_for_each_entry(se, &hist_entry__sort_list, list) |