ipv6: fix race condition regarding dst->expires and dst->from.
[pandora-kernel.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         struct hists *hists = he->hists;
22         double percent = 100.0 * he->stat.period / hists->stats.total_period;
23
24         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
25 }
26
27 static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
28 {
29         struct hists *hists = he->hists;
30         double percent = 100.0 * he->stat.period / hists->stats.total_period;
31         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
32
33         return scnprintf(hpp->buf, hpp->size, fmt, percent);
34 }
35
36 static int hpp__header_overhead_sys(struct perf_hpp *hpp)
37 {
38         const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
39
40         return scnprintf(hpp->buf, hpp->size, fmt, "sys");
41 }
42
43 static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
44 {
45         return 7;
46 }
47
48 static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
49 {
50         struct hists *hists = he->hists;
51         double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
52
53         return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
54 }
55
56 static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
57 {
58         struct hists *hists = he->hists;
59         double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
60         const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
61
62         return scnprintf(hpp->buf, hpp->size, fmt, percent);
63 }
64
65 static int hpp__header_overhead_us(struct perf_hpp *hpp)
66 {
67         const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
68
69         return scnprintf(hpp->buf, hpp->size, fmt, "user");
70 }
71
72 static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
73 {
74         return 7;
75 }
76
77 static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
78 {
79         struct hists *hists = he->hists;
80         double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
81
82         return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
83 }
84
85 static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
86 {
87         struct hists *hists = he->hists;
88         double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
89         const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
90
91         return scnprintf(hpp->buf, hpp->size, fmt, percent);
92 }
93
94 static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
95 {
96         return scnprintf(hpp->buf, hpp->size, "guest sys");
97 }
98
99 static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
100 {
101         return 9;
102 }
103
104 static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
105                                          struct hist_entry *he)
106 {
107         struct hists *hists = he->hists;
108         double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
109
110         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
111 }
112
113 static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
114                                          struct hist_entry *he)
115 {
116         struct hists *hists = he->hists;
117         double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
118         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
119
120         return scnprintf(hpp->buf, hpp->size, fmt, percent);
121 }
122
123 static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
124 {
125         return scnprintf(hpp->buf, hpp->size, "guest usr");
126 }
127
128 static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
129 {
130         return 9;
131 }
132
133 static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
134                                         struct hist_entry *he)
135 {
136         struct hists *hists = he->hists;
137         double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
138
139         return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
140 }
141
142 static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
143                                         struct hist_entry *he)
144 {
145         struct hists *hists = he->hists;
146         double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
147         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
148
149         return scnprintf(hpp->buf, hpp->size, fmt, percent);
150 }
151
152 static int hpp__header_baseline(struct perf_hpp *hpp)
153 {
154         return scnprintf(hpp->buf, hpp->size, "Baseline");
155 }
156
157 static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
158 {
159         return 8;
160 }
161
162 static double baseline_percent(struct hist_entry *he)
163 {
164         struct hist_entry *pair = hist_entry__next_pair(he);
165         struct hists *pair_hists = pair ? pair->hists : NULL;
166         double percent = 0.0;
167
168         if (pair) {
169                 u64 total_period = pair_hists->stats.total_period;
170                 u64 base_period  = pair->stat.period;
171
172                 percent = 100.0 * base_period / total_period;
173         }
174
175         return percent;
176 }
177
178 static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
179 {
180         double percent = baseline_percent(he);
181
182         if (hist_entry__has_pairs(he))
183                 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
184         else
185                 return scnprintf(hpp->buf, hpp->size, "        ");
186 }
187
188 static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
189 {
190         double percent = baseline_percent(he);
191         const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
192
193         if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
194                 return scnprintf(hpp->buf, hpp->size, fmt, percent);
195         else
196                 return scnprintf(hpp->buf, hpp->size, "            ");
197 }
198
199 static int hpp__header_samples(struct perf_hpp *hpp)
200 {
201         const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
202
203         return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
204 }
205
206 static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
207 {
208         return 11;
209 }
210
211 static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
212 {
213         const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
214
215         return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
216 }
217
218 static int hpp__header_period(struct perf_hpp *hpp)
219 {
220         const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
221
222         return scnprintf(hpp->buf, hpp->size, fmt, "Period");
223 }
224
225 static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
226 {
227         return 12;
228 }
229
230 static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
231 {
232         const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
233
234         return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
235 }
236
237 static int hpp__header_period_baseline(struct perf_hpp *hpp)
238 {
239         const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
240
241         return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
242 }
243
244 static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
245 {
246         return 12;
247 }
248
249 static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
250 {
251         struct hist_entry *pair = hist_entry__next_pair(he);
252         u64 period = pair ? pair->stat.period : 0;
253         const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
254
255         return scnprintf(hpp->buf, hpp->size, fmt, period);
256 }
257 static int hpp__header_delta(struct perf_hpp *hpp)
258 {
259         const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
260
261         return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
262 }
263
264 static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
265 {
266         return 7;
267 }
268
269 static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
270 {
271         const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
272         char buf[32] = " ";
273         double diff;
274
275         if (he->diff.computed)
276                 diff = he->diff.period_ratio_delta;
277         else
278                 diff = perf_diff__compute_delta(he);
279
280         if (fabs(diff) >= 0.01)
281                 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
282
283         return scnprintf(hpp->buf, hpp->size, fmt, buf);
284 }
285
286 static int hpp__header_ratio(struct perf_hpp *hpp)
287 {
288         const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
289
290         return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
291 }
292
293 static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
294 {
295         return 14;
296 }
297
298 static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
299 {
300         const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
301         char buf[32] = " ";
302         double ratio;
303
304         if (he->diff.computed)
305                 ratio = he->diff.period_ratio;
306         else
307                 ratio = perf_diff__compute_ratio(he);
308
309         if (ratio > 0.0)
310                 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
311
312         return scnprintf(hpp->buf, hpp->size, fmt, buf);
313 }
314
315 static int hpp__header_wdiff(struct perf_hpp *hpp)
316 {
317         const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
318
319         return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
320 }
321
322 static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
323 {
324         return 14;
325 }
326
327 static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
328 {
329         const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
330         char buf[32] = " ";
331         s64 wdiff;
332
333         if (he->diff.computed)
334                 wdiff = he->diff.wdiff;
335         else
336                 wdiff = perf_diff__compute_wdiff(he);
337
338         if (wdiff != 0)
339                 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
340
341         return scnprintf(hpp->buf, hpp->size, fmt, buf);
342 }
343
344 static int hpp__header_displ(struct perf_hpp *hpp)
345 {
346         return scnprintf(hpp->buf, hpp->size, "Displ.");
347 }
348
349 static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
350 {
351         return 6;
352 }
353
354 static int hpp__entry_displ(struct perf_hpp *hpp,
355                             struct hist_entry *he)
356 {
357         struct hist_entry *pair = hist_entry__next_pair(he);
358         long displacement = pair ? pair->position - he->position : 0;
359         const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
360         char buf[32] = " ";
361
362         if (displacement)
363                 scnprintf(buf, sizeof(buf), "%+4ld", displacement);
364
365         return scnprintf(hpp->buf, hpp->size, fmt, buf);
366 }
367
368 static int hpp__header_formula(struct perf_hpp *hpp)
369 {
370         const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
371
372         return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
373 }
374
375 static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
376 {
377         return 70;
378 }
379
380 static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
381 {
382         const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
383         char buf[96] = " ";
384
385         perf_diff__formula(buf, sizeof(buf), he);
386         return scnprintf(hpp->buf, hpp->size, fmt, buf);
387 }
388
389 #define HPP__COLOR_PRINT_FNS(_name)             \
390         .header = hpp__header_ ## _name,                \
391         .width  = hpp__width_ ## _name,         \
392         .color  = hpp__color_ ## _name,         \
393         .entry  = hpp__entry_ ## _name
394
395 #define HPP__PRINT_FNS(_name)                   \
396         .header = hpp__header_ ## _name,                \
397         .width  = hpp__width_ ## _name,         \
398         .entry  = hpp__entry_ ## _name
399
400 struct perf_hpp_fmt perf_hpp__format[] = {
401         { .cond = false, HPP__COLOR_PRINT_FNS(baseline) },
402         { .cond = true,  HPP__COLOR_PRINT_FNS(overhead) },
403         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
404         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
405         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
406         { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
407         { .cond = false, HPP__PRINT_FNS(samples) },
408         { .cond = false, HPP__PRINT_FNS(period) },
409         { .cond = false, HPP__PRINT_FNS(period_baseline) },
410         { .cond = false, HPP__PRINT_FNS(delta) },
411         { .cond = false, HPP__PRINT_FNS(ratio) },
412         { .cond = false, HPP__PRINT_FNS(wdiff) },
413         { .cond = false, HPP__PRINT_FNS(displ) },
414         { .cond = false, HPP__PRINT_FNS(formula) }
415 };
416
417 #undef HPP__COLOR_PRINT_FNS
418 #undef HPP__PRINT_FNS
419
420 void perf_hpp__init(void)
421 {
422         if (symbol_conf.show_cpu_utilization) {
423                 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
424                 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
425
426                 if (perf_guest) {
427                         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
428                         perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
429                 }
430         }
431
432         if (symbol_conf.show_nr_samples)
433                 perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
434
435         if (symbol_conf.show_total_period)
436                 perf_hpp__format[PERF_HPP__PERIOD].cond = true;
437 }
438
439 void perf_hpp__column_enable(unsigned col, bool enable)
440 {
441         BUG_ON(col >= PERF_HPP__MAX_INDEX);
442         perf_hpp__format[col].cond = enable;
443 }
444
445 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
446 {
447         hpp->buf  += inc;
448         hpp->size -= inc;
449 }
450
451 int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
452                                 bool color)
453 {
454         const char *sep = symbol_conf.field_sep;
455         char *start = hpp->buf;
456         int i, ret;
457         bool first = true;
458
459         if (symbol_conf.exclude_other && !he->parent)
460                 return 0;
461
462         for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
463                 if (!perf_hpp__format[i].cond)
464                         continue;
465
466                 if (!sep || !first) {
467                         ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
468                         advance_hpp(hpp, ret);
469                         first = false;
470                 }
471
472                 if (color && perf_hpp__format[i].color)
473                         ret = perf_hpp__format[i].color(hpp, he);
474                 else
475                         ret = perf_hpp__format[i].entry(hpp, he);
476
477                 advance_hpp(hpp, ret);
478         }
479
480         return hpp->buf - start;
481 }
482
483 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
484                               struct hists *hists)
485 {
486         const char *sep = symbol_conf.field_sep;
487         struct sort_entry *se;
488         int ret = 0;
489
490         list_for_each_entry(se, &hist_entry__sort_list, list) {
491                 if (se->elide)
492                         continue;
493
494                 ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
495                 ret += se->se_snprintf(he, s + ret, size - ret,
496                                        hists__col_len(hists, se->se_width_idx));
497         }
498
499         return ret;
500 }
501
502 /*
503  * See hists__fprintf to match the column widths
504  */
505 unsigned int hists__sort_list_width(struct hists *hists)
506 {
507         struct sort_entry *se;
508         int i, ret = 0;
509
510         for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
511                 if (!perf_hpp__format[i].cond)
512                         continue;
513                 if (i)
514                         ret += 2;
515
516                 ret += perf_hpp__format[i].width(NULL);
517         }
518
519         list_for_each_entry(se, &hist_entry__sort_list, list)
520                 if (!se->elide)
521                         ret += 2 + hists__col_len(hists, se->se_width_idx);
522
523         if (verbose) /* Addr + origin */
524                 ret += 3 + BITS_PER_LONG / 4;
525
526         return ret;
527 }