]> Pileus Git - ~andy/linux/blob - tools/perf/ui/hist.c
Merge branch 'for-3.7/core' of git://git.kernel.dk/linux-block
[~andy/linux] / 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         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 }