]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - tools/perf/ui/hist.c
perf hists: Separate overhead and baseline columns
[~shefty/rdma-dev.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
7
8 /* hist period print (hpp) functions */
9 static int hpp__header_overhead(struct perf_hpp *hpp)
10 {
11         return scnprintf(hpp->buf, hpp->size, "Overhead");
12 }
13
14 static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
15 {
16         return 8;
17 }
18
19 static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
20 {
21         double percent = 100.0 * he->period / hpp->total_period;
22
23         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
24 }
25
26 static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
27 {
28         double percent = 100.0 * he->period / hpp->total_period;
29         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
30
31         return scnprintf(hpp->buf, hpp->size, fmt, percent);
32 }
33
34 static int hpp__header_overhead_sys(struct perf_hpp *hpp)
35 {
36         const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
37
38         return scnprintf(hpp->buf, hpp->size, fmt, "sys");
39 }
40
41 static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
42 {
43         return 7;
44 }
45
46 static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
47 {
48         double percent = 100.0 * he->period_sys / hpp->total_period;
49         return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
50 }
51
52 static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
53 {
54         double percent = 100.0 * he->period_sys / hpp->total_period;
55         const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
56
57         return scnprintf(hpp->buf, hpp->size, fmt, percent);
58 }
59
60 static int hpp__header_overhead_us(struct perf_hpp *hpp)
61 {
62         const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
63
64         return scnprintf(hpp->buf, hpp->size, fmt, "user");
65 }
66
67 static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
68 {
69         return 7;
70 }
71
72 static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
73 {
74         double percent = 100.0 * he->period_us / hpp->total_period;
75         return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
76 }
77
78 static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
79 {
80         double percent = 100.0 * he->period_us / hpp->total_period;
81         const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
82
83         return scnprintf(hpp->buf, hpp->size, fmt, percent);
84 }
85
86 static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
87 {
88         return scnprintf(hpp->buf, hpp->size, "guest sys");
89 }
90
91 static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
92 {
93         return 9;
94 }
95
96 static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
97                                          struct hist_entry *he)
98 {
99         double percent = 100.0 * he->period_guest_sys / hpp->total_period;
100         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
101 }
102
103 static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
104                                          struct hist_entry *he)
105 {
106         double percent = 100.0 * he->period_guest_sys / hpp->total_period;
107         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
108
109         return scnprintf(hpp->buf, hpp->size, fmt, percent);
110 }
111
112 static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
113 {
114         return scnprintf(hpp->buf, hpp->size, "guest usr");
115 }
116
117 static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
118 {
119         return 9;
120 }
121
122 static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
123                                         struct hist_entry *he)
124 {
125         double percent = 100.0 * he->period_guest_us / hpp->total_period;
126         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
127 }
128
129 static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
130                                         struct hist_entry *he)
131 {
132         double percent = 100.0 * he->period_guest_us / hpp->total_period;
133         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
134
135         return scnprintf(hpp->buf, hpp->size, fmt, percent);
136 }
137
138 static int hpp__header_baseline(struct perf_hpp *hpp)
139 {
140         return scnprintf(hpp->buf, hpp->size, "Baseline");
141 }
142
143 static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
144 {
145         return 8;
146 }
147
148 static double baseline_percent(struct hist_entry *he)
149 {
150         struct hist_entry *pair = he->pair;
151         struct hists *pair_hists = pair ? pair->hists : NULL;
152         double percent = 0.0;
153
154         if (pair) {
155                 u64 total_period = pair_hists->stats.total_period;
156                 u64 base_period  = pair->period;
157
158                 percent = 100.0 * base_period / total_period;
159         }
160
161         return percent;
162 }
163
164 static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
165 {
166         double percent = baseline_percent(he);
167
168         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
169 }
170
171 static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
172 {
173         double percent = baseline_percent(he);
174         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
175
176         return scnprintf(hpp->buf, hpp->size, fmt, percent);
177 }
178
179 static int hpp__header_samples(struct perf_hpp *hpp)
180 {
181         const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
182
183         return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
184 }
185
186 static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
187 {
188         return 11;
189 }
190
191 static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
192 {
193         const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
194
195         return scnprintf(hpp->buf, hpp->size, fmt, he->nr_events);
196 }
197
198 static int hpp__header_period(struct perf_hpp *hpp)
199 {
200         const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
201
202         return scnprintf(hpp->buf, hpp->size, fmt, "Period");
203 }
204
205 static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
206 {
207         return 12;
208 }
209
210 static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
211 {
212         const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
213
214         return scnprintf(hpp->buf, hpp->size, fmt, he->period);
215 }
216
217 static int hpp__header_delta(struct perf_hpp *hpp)
218 {
219         const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
220
221         return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
222 }
223
224 static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
225 {
226         return 7;
227 }
228
229 static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
230 {
231         struct hists *pair_hists = hpp->ptr;
232         u64 old_total, new_total;
233         double old_percent = 0, new_percent = 0;
234         double diff;
235         const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
236         char buf[32] = " ";
237
238         old_total = pair_hists->stats.total_period;
239         if (old_total > 0 && he->pair)
240                 old_percent = 100.0 * he->pair->period / old_total;
241
242         new_total = hpp->total_period;
243         if (new_total > 0)
244                 new_percent = 100.0 * he->period / new_total;
245
246         diff = new_percent - old_percent;
247         if (fabs(diff) >= 0.01)
248                 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
249
250         return scnprintf(hpp->buf, hpp->size, fmt, buf);
251 }
252
253 static int hpp__header_displ(struct perf_hpp *hpp)
254 {
255         return scnprintf(hpp->buf, hpp->size, "Displ.");
256 }
257
258 static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
259 {
260         return 6;
261 }
262
263 static int hpp__entry_displ(struct perf_hpp *hpp,
264                             struct hist_entry *he)
265 {
266         struct hist_entry *pair = he->pair;
267         long displacement = pair ? pair->position - he->position : 0;
268         const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
269         char buf[32] = " ";
270
271         if (displacement)
272                 scnprintf(buf, sizeof(buf), "%+4ld", displacement);
273
274         return scnprintf(hpp->buf, hpp->size, fmt, buf);
275 }
276
277 #define HPP__COLOR_PRINT_FNS(_name)             \
278         .header = hpp__header_ ## _name,                \
279         .width  = hpp__width_ ## _name,         \
280         .color  = hpp__color_ ## _name,         \
281         .entry  = hpp__entry_ ## _name
282
283 #define HPP__PRINT_FNS(_name)                   \
284         .header = hpp__header_ ## _name,                \
285         .width  = hpp__width_ ## _name,         \
286         .entry  = hpp__entry_ ## _name
287
288 struct perf_hpp_fmt perf_hpp__format[] = {
289         { .cond = false, HPP__COLOR_PRINT_FNS(baseline) },
290         { .cond = true,  HPP__COLOR_PRINT_FNS(overhead) },
291         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
292         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
293         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
294         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
295         { .cond = false, HPP__PRINT_FNS(samples) },
296         { .cond = false, HPP__PRINT_FNS(period) },
297         { .cond = false, HPP__PRINT_FNS(delta) },
298         { .cond = false, HPP__PRINT_FNS(displ) }
299 };
300
301 #undef HPP__COLOR_PRINT_FNS
302 #undef HPP__PRINT_FNS
303
304 void perf_hpp__init(bool need_pair, bool show_displacement)
305 {
306         if (symbol_conf.show_cpu_utilization) {
307                 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
308                 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
309
310                 if (perf_guest) {
311                         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
312                         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
313                 }
314         }
315
316         if (symbol_conf.show_nr_samples)
317                 perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
318
319         if (symbol_conf.show_total_period)
320                 perf_hpp__format[PERF_HPP__PERIOD].cond = true;
321
322         if (need_pair) {
323                 perf_hpp__format[PERF_HPP__OVERHEAD].cond = false;
324                 perf_hpp__format[PERF_HPP__BASELINE].cond = true;
325                 perf_hpp__format[PERF_HPP__DELTA].cond = true;
326
327                 if (show_displacement)
328                         perf_hpp__format[PERF_HPP__DISPL].cond = true;
329         }
330 }
331
332 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
333 {
334         hpp->buf  += inc;
335         hpp->size -= inc;
336 }
337
338 int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
339                                 bool color)
340 {
341         const char *sep = symbol_conf.field_sep;
342         char *start = hpp->buf;
343         int i, ret;
344         bool first = true;
345
346         if (symbol_conf.exclude_other && !he->parent)
347                 return 0;
348
349         for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
350                 if (!perf_hpp__format[i].cond)
351                         continue;
352
353                 if (!sep || !first) {
354                         ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
355                         advance_hpp(hpp, ret);
356                         first = false;
357                 }
358
359                 if (color && perf_hpp__format[i].color)
360                         ret = perf_hpp__format[i].color(hpp, he);
361                 else
362                         ret = perf_hpp__format[i].entry(hpp, he);
363
364                 advance_hpp(hpp, ret);
365         }
366
367         return hpp->buf - start;
368 }
369
370 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
371                               struct hists *hists)
372 {
373         const char *sep = symbol_conf.field_sep;
374         struct sort_entry *se;
375         int ret = 0;
376
377         list_for_each_entry(se, &hist_entry__sort_list, list) {
378                 if (se->elide)
379                         continue;
380
381                 ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
382                 ret += se->se_snprintf(he, s + ret, size - ret,
383                                        hists__col_len(hists, se->se_width_idx));
384         }
385
386         return ret;
387 }
388
389 /*
390  * See hists__fprintf to match the column widths
391  */
392 unsigned int hists__sort_list_width(struct hists *hists)
393 {
394         struct sort_entry *se;
395         int i, ret = 0;
396
397         for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
398                 if (!perf_hpp__format[i].cond)
399                         continue;
400                 if (i)
401                         ret += 2;
402
403                 ret += perf_hpp__format[i].width(NULL);
404         }
405
406         list_for_each_entry(se, &hist_entry__sort_list, list)
407                 if (!se->elide)
408                         ret += 2 + hists__col_len(hists, se->se_width_idx);
409
410         if (verbose) /* Addr + origin */
411                 ret += 3 + BITS_PER_LONG / 4;
412
413         return ret;
414 }