Merge remote-tracking branch 'lsk/v3.10/topic/gator' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / tools / perf / ui / hist.c
1 #include <math.h>
2
3 #include "../util/hist.h"
4 #include "../util/util.h"
5 #include "../util/sort.h"
6 #include "../util/evsel.h"
7
8 /* hist period print (hpp) functions */
9
10 typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
11
12 static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
13                       u64 (*get_field)(struct hist_entry *),
14                       const char *fmt, hpp_snprint_fn print_fn,
15                       bool fmt_percent)
16 {
17         int ret;
18         struct hists *hists = he->hists;
19         struct perf_evsel *evsel = hists_to_evsel(hists);
20
21         if (fmt_percent) {
22                 double percent = 0.0;
23
24                 if (hists->stats.total_period)
25                         percent = 100.0 * get_field(he) /
26                                   hists->stats.total_period;
27
28                 ret = print_fn(hpp->buf, hpp->size, fmt, percent);
29         } else
30                 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
31
32         if (perf_evsel__is_group_event(evsel)) {
33                 int prev_idx, idx_delta;
34                 struct hist_entry *pair;
35                 int nr_members = evsel->nr_members;
36
37                 prev_idx = perf_evsel__group_idx(evsel);
38
39                 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
40                         u64 period = get_field(pair);
41                         u64 total = pair->hists->stats.total_period;
42
43                         if (!total)
44                                 continue;
45
46                         evsel = hists_to_evsel(pair->hists);
47                         idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
48
49                         while (idx_delta--) {
50                                 /*
51                                  * zero-fill group members in the middle which
52                                  * have no sample
53                                  */
54                                 ret += print_fn(hpp->buf + ret, hpp->size - ret,
55                                                 fmt, 0);
56                         }
57
58                         if (fmt_percent)
59                                 ret += print_fn(hpp->buf + ret, hpp->size - ret,
60                                                 fmt, 100.0 * period / total);
61                         else
62                                 ret += print_fn(hpp->buf + ret, hpp->size - ret,
63                                                 fmt, period);
64
65                         prev_idx = perf_evsel__group_idx(evsel);
66                 }
67
68                 idx_delta = nr_members - prev_idx - 1;
69
70                 while (idx_delta--) {
71                         /*
72                          * zero-fill group members at last which have no sample
73                          */
74                         ret += print_fn(hpp->buf + ret, hpp->size - ret,
75                                         fmt, 0);
76                 }
77         }
78         return ret;
79 }
80
81 #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)           \
82 static int hpp__header_##_type(struct perf_hpp *hpp)                    \
83 {                                                                       \
84         int len = _min_width;                                           \
85                                                                         \
86         if (symbol_conf.event_group) {                                  \
87                 struct perf_evsel *evsel = hpp->ptr;                    \
88                                                                         \
89                 len = max(len, evsel->nr_members * _unit_width);        \
90         }                                                               \
91         return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);        \
92 }
93
94 #define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                  \
95 static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused)      \
96 {                                                                       \
97         int len = _min_width;                                           \
98                                                                         \
99         if (symbol_conf.event_group) {                                  \
100                 struct perf_evsel *evsel = hpp->ptr;                    \
101                                                                         \
102                 len = max(len, evsel->nr_members * _unit_width);        \
103         }                                                               \
104         return len;                                                     \
105 }
106
107 #define __HPP_COLOR_PERCENT_FN(_type, _field)                                   \
108 static u64 he_get_##_field(struct hist_entry *he)                               \
109 {                                                                               \
110         return he->stat._field;                                                 \
111 }                                                                               \
112                                                                                 \
113 static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he)      \
114 {                                                                               \
115         return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
116                           percent_color_snprintf, true);                        \
117 }
118
119 #define __HPP_ENTRY_PERCENT_FN(_type, _field)                                   \
120 static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he)      \
121 {                                                                               \
122         const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
123         return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
124                           scnprintf, true);                                     \
125 }
126
127 #define __HPP_ENTRY_RAW_FN(_type, _field)                                       \
128 static u64 he_get_raw_##_field(struct hist_entry *he)                           \
129 {                                                                               \
130         return he->stat._field;                                                 \
131 }                                                                               \
132                                                                                 \
133 static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he)      \
134 {                                                                               \
135         const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
136         return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
137 }
138
139 #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)   \
140 __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                   \
141 __HPP_WIDTH_FN(_type, _min_width, _unit_width)                          \
142 __HPP_COLOR_PERCENT_FN(_type, _field)                                   \
143 __HPP_ENTRY_PERCENT_FN(_type, _field)
144
145 #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width)       \
146 __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                   \
147 __HPP_WIDTH_FN(_type, _min_width, _unit_width)                          \
148 __HPP_ENTRY_RAW_FN(_type, _field)
149
150
151 HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
152 HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
153 HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
154 HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
155 HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
156
157 HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
158 HPP_RAW_FNS(period, "Period", period, 12, 12)
159
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)                     \
351         {                                               \
352                 .header = hpp__header_ ## _name,        \
353                 .width  = hpp__width_ ## _name,         \
354                 .color  = hpp__color_ ## _name,         \
355                 .entry  = hpp__entry_ ## _name          \
356         }
357
358 #define HPP__PRINT_FNS(_name)                           \
359         {                                               \
360                 .header = hpp__header_ ## _name,        \
361                 .width  = hpp__width_ ## _name,         \
362                 .entry  = hpp__entry_ ## _name          \
363         }
364
365 struct perf_hpp_fmt perf_hpp__format[] = {
366         HPP__COLOR_PRINT_FNS(baseline),
367         HPP__COLOR_PRINT_FNS(overhead),
368         HPP__COLOR_PRINT_FNS(overhead_sys),
369         HPP__COLOR_PRINT_FNS(overhead_us),
370         HPP__COLOR_PRINT_FNS(overhead_guest_sys),
371         HPP__COLOR_PRINT_FNS(overhead_guest_us),
372         HPP__PRINT_FNS(samples),
373         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 };
380
381 LIST_HEAD(perf_hpp__list);
382
383
384 #undef HPP__COLOR_PRINT_FNS
385 #undef HPP__PRINT_FNS
386
387 #undef HPP_PERCENT_FNS
388 #undef HPP_RAW_FNS
389
390 #undef __HPP_HEADER_FN
391 #undef __HPP_WIDTH_FN
392 #undef __HPP_COLOR_PERCENT_FN
393 #undef __HPP_ENTRY_PERCENT_FN
394 #undef __HPP_ENTRY_RAW_FN
395
396
397 void perf_hpp__init(void)
398 {
399         if (symbol_conf.show_cpu_utilization) {
400                 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
401                 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
402
403                 if (perf_guest) {
404                         perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
405                         perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
406                 }
407         }
408
409         if (symbol_conf.show_nr_samples)
410                 perf_hpp__column_enable(PERF_HPP__SAMPLES);
411
412         if (symbol_conf.show_total_period)
413                 perf_hpp__column_enable(PERF_HPP__PERIOD);
414 }
415
416 void perf_hpp__column_register(struct perf_hpp_fmt *format)
417 {
418         list_add_tail(&format->list, &perf_hpp__list);
419 }
420
421 void perf_hpp__column_enable(unsigned col)
422 {
423         BUG_ON(col >= PERF_HPP__MAX_INDEX);
424         perf_hpp__column_register(&perf_hpp__format[col]);
425 }
426
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,
468                               struct hists *hists)
469 {
470         const char *sep = symbol_conf.field_sep;
471         struct sort_entry *se;
472         int ret = 0;
473
474         list_for_each_entry(se, &hist_entry__sort_list, list) {
475                 if (se->elide)
476                         continue;
477
478                 ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
479                 ret += se->se_snprintf(he, s + ret, size - ret,
480                                        hists__col_len(hists, se->se_width_idx));
481         }
482
483         return ret;
484 }
485
486 /*
487  * See hists__fprintf to match the column widths
488  */
489 unsigned int hists__sort_list_width(struct hists *hists)
490 {
491         struct perf_hpp_fmt *fmt;
492         struct sort_entry *se;
493         int i = 0, ret = 0;
494         struct perf_hpp dummy_hpp = {
495                 .ptr    = hists_to_evsel(hists),
496         };
497
498         perf_hpp__for_each_format(fmt) {
499                 if (i)
500                         ret += 2;
501
502                 ret += fmt->width(&dummy_hpp);
503         }
504
505         list_for_each_entry(se, &hist_entry__sort_list, list)
506                 if (!se->elide)
507                         ret += 2 + hists__col_len(hists, se->se_width_idx);
508
509         if (verbose) /* Addr + origin */
510                 ret += 3 + BITS_PER_LONG / 4;
511
512         return ret;
513 }