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