diff options
Diffstat (limited to 'tools/perf/ui/hist.c')
-rw-r--r-- | tools/perf/ui/hist.c | 481 |
1 files changed, 235 insertions, 246 deletions
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index aa84130024d5..d671e63aa351 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -3,151 +3,163 @@ | |||
3 | #include "../util/hist.h" | 3 | #include "../util/hist.h" |
4 | #include "../util/util.h" | 4 | #include "../util/util.h" |
5 | #include "../util/sort.h" | 5 | #include "../util/sort.h" |
6 | 6 | #include "../util/evsel.h" | |
7 | 7 | ||
8 | /* hist period print (hpp) functions */ | 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 | 9 | ||
24 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 10 | typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); |
25 | } | ||
26 | 11 | ||
27 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 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) | ||
28 | { | 16 | { |
17 | int ret; | ||
29 | struct hists *hists = he->hists; | 18 | 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 | 19 | ||
36 | static int hpp__header_overhead_sys(struct perf_hpp *hpp) | 20 | if (fmt_percent) { |
37 | { | 21 | double percent = 0.0; |
38 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | ||
39 | |||
40 | return scnprintf(hpp->buf, hpp->size, fmt, "sys"); | ||
41 | } | ||
42 | 22 | ||
43 | static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) | 23 | if (hists->stats.total_period) |
44 | { | 24 | percent = 100.0 * get_field(he) / |
45 | return 7; | 25 | hists->stats.total_period; |
46 | } | ||
47 | 26 | ||
48 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 27 | ret = print_fn(hpp->buf, hpp->size, fmt, percent); |
49 | { | 28 | } else |
50 | struct hists *hists = he->hists; | 29 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); |
51 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
52 | 30 | ||
53 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 31 | if (symbol_conf.event_group) { |
54 | } | 32 | int prev_idx, idx_delta; |
33 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
34 | struct hist_entry *pair; | ||
35 | int nr_members = evsel->nr_members; | ||
55 | 36 | ||
56 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 37 | if (nr_members <= 1) |
57 | { | 38 | return ret; |
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 | 39 | ||
62 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 40 | prev_idx = perf_evsel__group_idx(evsel); |
63 | } | ||
64 | 41 | ||
65 | static int hpp__header_overhead_us(struct perf_hpp *hpp) | 42 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { |
66 | { | 43 | u64 period = get_field(pair); |
67 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | 44 | u64 total = pair->hists->stats.total_period; |
68 | 45 | ||
69 | return scnprintf(hpp->buf, hpp->size, fmt, "user"); | 46 | if (!total) |
70 | } | 47 | continue; |
71 | 48 | ||
72 | static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) | 49 | evsel = hists_to_evsel(pair->hists); |
73 | { | 50 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; |
74 | return 7; | ||
75 | } | ||
76 | 51 | ||
77 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 52 | while (idx_delta--) { |
78 | { | 53 | /* |
79 | struct hists *hists = he->hists; | 54 | * zero-fill group members in the middle which |
80 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | 55 | * have no sample |
56 | */ | ||
57 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
58 | fmt, 0); | ||
59 | } | ||
81 | 60 | ||
82 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 61 | if (fmt_percent) |
83 | } | 62 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
63 | fmt, 100.0 * period / total); | ||
64 | else | ||
65 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
66 | fmt, period); | ||
84 | 67 | ||
85 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 68 | prev_idx = perf_evsel__group_idx(evsel); |
86 | { | 69 | } |
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 | 70 | ||
128 | static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) | 71 | idx_delta = nr_members - prev_idx - 1; |
129 | { | ||
130 | return 9; | ||
131 | } | ||
132 | 72 | ||
133 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, | 73 | while (idx_delta--) { |
134 | struct hist_entry *he) | 74 | /* |
135 | { | 75 | * zero-fill group members at last which have no sample |
136 | struct hists *hists = he->hists; | 76 | */ |
137 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | 77 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
138 | 78 | fmt, 0); | |
139 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 79 | } |
80 | } | ||
81 | return ret; | ||
140 | } | 82 | } |
141 | 83 | ||
142 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, | 84 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
143 | struct hist_entry *he) | 85 | static int hpp__header_##_type(struct perf_hpp *hpp) \ |
144 | { | 86 | { \ |
145 | struct hists *hists = he->hists; | 87 | int len = _min_width; \ |
146 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | 88 | \ |
147 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 89 | if (symbol_conf.event_group) { \ |
90 | struct perf_evsel *evsel = hpp->ptr; \ | ||
91 | \ | ||
92 | len = max(len, evsel->nr_members * _unit_width); \ | ||
93 | } \ | ||
94 | return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ | ||
95 | } | ||
96 | |||
97 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
98 | static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ | ||
99 | { \ | ||
100 | int len = _min_width; \ | ||
101 | \ | ||
102 | if (symbol_conf.event_group) { \ | ||
103 | struct perf_evsel *evsel = hpp->ptr; \ | ||
104 | \ | ||
105 | len = max(len, evsel->nr_members * _unit_width); \ | ||
106 | } \ | ||
107 | return len; \ | ||
108 | } | ||
109 | |||
110 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
111 | static u64 he_get_##_field(struct hist_entry *he) \ | ||
112 | { \ | ||
113 | return he->stat._field; \ | ||
114 | } \ | ||
115 | \ | ||
116 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
117 | { \ | ||
118 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | ||
119 | (hpp_snprint_fn)percent_color_snprintf, true); \ | ||
120 | } | ||
121 | |||
122 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | ||
123 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
124 | { \ | ||
125 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | ||
126 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ | ||
127 | scnprintf, true); \ | ||
128 | } | ||
129 | |||
130 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ | ||
131 | static u64 he_get_raw_##_field(struct hist_entry *he) \ | ||
132 | { \ | ||
133 | return he->stat._field; \ | ||
134 | } \ | ||
135 | \ | ||
136 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
137 | { \ | ||
138 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | ||
139 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ | ||
140 | } | ||
141 | |||
142 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ | ||
143 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
144 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
145 | __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
146 | __HPP_ENTRY_PERCENT_FN(_type, _field) | ||
147 | |||
148 | #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ | ||
149 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
150 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
151 | __HPP_ENTRY_RAW_FN(_type, _field) | ||
152 | |||
153 | |||
154 | HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) | ||
155 | HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) | ||
156 | HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) | ||
157 | HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) | ||
158 | HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | ||
159 | |||
160 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) | ||
161 | HPP_RAW_FNS(period, "Period", period, 12, 12) | ||
148 | 162 | ||
149 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
150 | } | ||
151 | 163 | ||
152 | static int hpp__header_baseline(struct perf_hpp *hpp) | 164 | static int hpp__header_baseline(struct perf_hpp *hpp) |
153 | { | 165 | { |
@@ -179,7 +191,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | |||
179 | { | 191 | { |
180 | double percent = baseline_percent(he); | 192 | double percent = baseline_percent(he); |
181 | 193 | ||
182 | if (hist_entry__has_pairs(he)) | 194 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) |
183 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 195 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); |
184 | else | 196 | else |
185 | return scnprintf(hpp->buf, hpp->size, " "); | 197 | return scnprintf(hpp->buf, hpp->size, " "); |
@@ -196,44 +208,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | |||
196 | return scnprintf(hpp->buf, hpp->size, " "); | 208 | return scnprintf(hpp->buf, hpp->size, " "); |
197 | } | 209 | } |
198 | 210 | ||
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) | 211 | static int hpp__header_period_baseline(struct perf_hpp *hpp) |
238 | { | 212 | { |
239 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | 213 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; |
@@ -254,6 +228,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h | |||
254 | 228 | ||
255 | return scnprintf(hpp->buf, hpp->size, fmt, period); | 229 | return scnprintf(hpp->buf, hpp->size, fmt, period); |
256 | } | 230 | } |
231 | |||
257 | static int hpp__header_delta(struct perf_hpp *hpp) | 232 | static int hpp__header_delta(struct perf_hpp *hpp) |
258 | { | 233 | { |
259 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | 234 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; |
@@ -268,14 +243,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | |||
268 | 243 | ||
269 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | 244 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) |
270 | { | 245 | { |
246 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
271 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | 247 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; |
272 | char buf[32] = " "; | 248 | char buf[32] = " "; |
273 | double diff; | 249 | double diff = 0.0; |
274 | 250 | ||
275 | if (he->diff.computed) | 251 | if (pair) { |
276 | diff = he->diff.period_ratio_delta; | 252 | if (he->diff.computed) |
277 | else | 253 | diff = he->diff.period_ratio_delta; |
278 | diff = perf_diff__compute_delta(he); | 254 | else |
255 | diff = perf_diff__compute_delta(he, pair); | ||
256 | } else | ||
257 | diff = perf_diff__period_percent(he, he->stat.period); | ||
279 | 258 | ||
280 | if (fabs(diff) >= 0.01) | 259 | if (fabs(diff) >= 0.01) |
281 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); | 260 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); |
@@ -297,14 +276,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) | |||
297 | 276 | ||
298 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) | 277 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) |
299 | { | 278 | { |
279 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
300 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 280 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
301 | char buf[32] = " "; | 281 | char buf[32] = " "; |
302 | double ratio; | 282 | double ratio = 0.0; |
303 | 283 | ||
304 | if (he->diff.computed) | 284 | if (pair) { |
305 | ratio = he->diff.period_ratio; | 285 | if (he->diff.computed) |
306 | else | 286 | ratio = he->diff.period_ratio; |
307 | ratio = perf_diff__compute_ratio(he); | 287 | else |
288 | ratio = perf_diff__compute_ratio(he, pair); | ||
289 | } | ||
308 | 290 | ||
309 | if (ratio > 0.0) | 291 | if (ratio > 0.0) |
310 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); | 292 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); |
@@ -326,14 +308,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) | |||
326 | 308 | ||
327 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | 309 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) |
328 | { | 310 | { |
311 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
329 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 312 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
330 | char buf[32] = " "; | 313 | char buf[32] = " "; |
331 | s64 wdiff; | 314 | s64 wdiff = 0; |
332 | 315 | ||
333 | if (he->diff.computed) | 316 | if (pair) { |
334 | wdiff = he->diff.wdiff; | 317 | if (he->diff.computed) |
335 | else | 318 | wdiff = he->diff.wdiff; |
336 | wdiff = perf_diff__compute_wdiff(he); | 319 | else |
320 | wdiff = perf_diff__compute_wdiff(he, pair); | ||
321 | } | ||
337 | 322 | ||
338 | if (wdiff != 0) | 323 | if (wdiff != 0) |
339 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); | 324 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); |
@@ -341,30 +326,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | |||
341 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 326 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
342 | } | 327 | } |
343 | 328 | ||
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) | 329 | static int hpp__header_formula(struct perf_hpp *hpp) |
369 | { | 330 | { |
370 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; | 331 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; |
@@ -379,67 +340,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) | |||
379 | 340 | ||
380 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | 341 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) |
381 | { | 342 | { |
343 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
382 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; | 344 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; |
383 | char buf[96] = " "; | 345 | char buf[96] = " "; |
384 | 346 | ||
385 | perf_diff__formula(buf, sizeof(buf), he); | 347 | if (pair) |
348 | perf_diff__formula(he, pair, buf, sizeof(buf)); | ||
349 | |||
386 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 350 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
387 | } | 351 | } |
388 | 352 | ||
389 | #define HPP__COLOR_PRINT_FNS(_name) \ | 353 | #define HPP__COLOR_PRINT_FNS(_name) \ |
390 | .header = hpp__header_ ## _name, \ | 354 | { \ |
391 | .width = hpp__width_ ## _name, \ | 355 | .header = hpp__header_ ## _name, \ |
392 | .color = hpp__color_ ## _name, \ | 356 | .width = hpp__width_ ## _name, \ |
393 | .entry = hpp__entry_ ## _name | 357 | .color = hpp__color_ ## _name, \ |
358 | .entry = hpp__entry_ ## _name \ | ||
359 | } | ||
394 | 360 | ||
395 | #define HPP__PRINT_FNS(_name) \ | 361 | #define HPP__PRINT_FNS(_name) \ |
396 | .header = hpp__header_ ## _name, \ | 362 | { \ |
397 | .width = hpp__width_ ## _name, \ | 363 | .header = hpp__header_ ## _name, \ |
398 | .entry = hpp__entry_ ## _name | 364 | .width = hpp__width_ ## _name, \ |
365 | .entry = hpp__entry_ ## _name \ | ||
366 | } | ||
399 | 367 | ||
400 | struct perf_hpp_fmt perf_hpp__format[] = { | 368 | struct perf_hpp_fmt perf_hpp__format[] = { |
401 | { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, | 369 | HPP__COLOR_PRINT_FNS(baseline), |
402 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, | 370 | HPP__COLOR_PRINT_FNS(overhead), |
403 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, | 371 | HPP__COLOR_PRINT_FNS(overhead_sys), |
404 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, | 372 | HPP__COLOR_PRINT_FNS(overhead_us), |
405 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, | 373 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), |
406 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, | 374 | HPP__COLOR_PRINT_FNS(overhead_guest_us), |
407 | { .cond = false, HPP__PRINT_FNS(samples) }, | 375 | HPP__PRINT_FNS(samples), |
408 | { .cond = false, HPP__PRINT_FNS(period) }, | 376 | HPP__PRINT_FNS(period), |
409 | { .cond = false, HPP__PRINT_FNS(period_baseline) }, | 377 | HPP__PRINT_FNS(period_baseline), |
410 | { .cond = false, HPP__PRINT_FNS(delta) }, | 378 | HPP__PRINT_FNS(delta), |
411 | { .cond = false, HPP__PRINT_FNS(ratio) }, | 379 | HPP__PRINT_FNS(ratio), |
412 | { .cond = false, HPP__PRINT_FNS(wdiff) }, | 380 | HPP__PRINT_FNS(wdiff), |
413 | { .cond = false, HPP__PRINT_FNS(displ) }, | 381 | HPP__PRINT_FNS(formula) |
414 | { .cond = false, HPP__PRINT_FNS(formula) } | ||
415 | }; | 382 | }; |
416 | 383 | ||
384 | LIST_HEAD(perf_hpp__list); | ||
385 | |||
386 | |||
417 | #undef HPP__COLOR_PRINT_FNS | 387 | #undef HPP__COLOR_PRINT_FNS |
418 | #undef HPP__PRINT_FNS | 388 | #undef HPP__PRINT_FNS |
419 | 389 | ||
390 | #undef HPP_PERCENT_FNS | ||
391 | #undef HPP_RAW_FNS | ||
392 | |||
393 | #undef __HPP_HEADER_FN | ||
394 | #undef __HPP_WIDTH_FN | ||
395 | #undef __HPP_COLOR_PERCENT_FN | ||
396 | #undef __HPP_ENTRY_PERCENT_FN | ||
397 | #undef __HPP_ENTRY_RAW_FN | ||
398 | |||
399 | |||
420 | void perf_hpp__init(void) | 400 | void perf_hpp__init(void) |
421 | { | 401 | { |
422 | if (symbol_conf.show_cpu_utilization) { | 402 | if (symbol_conf.show_cpu_utilization) { |
423 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; | 403 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
424 | perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; | 404 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); |
425 | 405 | ||
426 | if (perf_guest) { | 406 | if (perf_guest) { |
427 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; | 407 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); |
428 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; | 408 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); |
429 | } | 409 | } |
430 | } | 410 | } |
431 | 411 | ||
432 | if (symbol_conf.show_nr_samples) | 412 | if (symbol_conf.show_nr_samples) |
433 | perf_hpp__format[PERF_HPP__SAMPLES].cond = true; | 413 | perf_hpp__column_enable(PERF_HPP__SAMPLES); |
434 | 414 | ||
435 | if (symbol_conf.show_total_period) | 415 | if (symbol_conf.show_total_period) |
436 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; | 416 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
417 | } | ||
418 | |||
419 | void perf_hpp__column_register(struct perf_hpp_fmt *format) | ||
420 | { | ||
421 | list_add_tail(&format->list, &perf_hpp__list); | ||
437 | } | 422 | } |
438 | 423 | ||
439 | void perf_hpp__column_enable(unsigned col, bool enable) | 424 | void perf_hpp__column_enable(unsigned col) |
440 | { | 425 | { |
441 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | 426 | BUG_ON(col >= PERF_HPP__MAX_INDEX); |
442 | perf_hpp__format[col].cond = enable; | 427 | perf_hpp__column_register(&perf_hpp__format[col]); |
443 | } | 428 | } |
444 | 429 | ||
445 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 430 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
@@ -452,27 +437,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
452 | bool color) | 437 | bool color) |
453 | { | 438 | { |
454 | const char *sep = symbol_conf.field_sep; | 439 | const char *sep = symbol_conf.field_sep; |
440 | struct perf_hpp_fmt *fmt; | ||
455 | char *start = hpp->buf; | 441 | char *start = hpp->buf; |
456 | int i, ret; | 442 | int ret; |
457 | bool first = true; | 443 | bool first = true; |
458 | 444 | ||
459 | if (symbol_conf.exclude_other && !he->parent) | 445 | if (symbol_conf.exclude_other && !he->parent) |
460 | return 0; | 446 | return 0; |
461 | 447 | ||
462 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 448 | perf_hpp__for_each_format(fmt) { |
463 | if (!perf_hpp__format[i].cond) | 449 | /* |
464 | continue; | 450 | * If there's no field_sep, we still need |
465 | 451 | * to display initial ' '. | |
452 | */ | ||
466 | if (!sep || !first) { | 453 | if (!sep || !first) { |
467 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | 454 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); |
468 | advance_hpp(hpp, ret); | 455 | advance_hpp(hpp, ret); |
456 | } else | ||
469 | first = false; | 457 | first = false; |
470 | } | ||
471 | 458 | ||
472 | if (color && perf_hpp__format[i].color) | 459 | if (color && fmt->color) |
473 | ret = perf_hpp__format[i].color(hpp, he); | 460 | ret = fmt->color(hpp, he); |
474 | else | 461 | else |
475 | ret = perf_hpp__format[i].entry(hpp, he); | 462 | ret = fmt->entry(hpp, he); |
476 | 463 | ||
477 | advance_hpp(hpp, ret); | 464 | advance_hpp(hpp, ret); |
478 | } | 465 | } |
@@ -504,16 +491,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, | |||
504 | */ | 491 | */ |
505 | unsigned int hists__sort_list_width(struct hists *hists) | 492 | unsigned int hists__sort_list_width(struct hists *hists) |
506 | { | 493 | { |
494 | struct perf_hpp_fmt *fmt; | ||
507 | struct sort_entry *se; | 495 | struct sort_entry *se; |
508 | int i, ret = 0; | 496 | int i = 0, ret = 0; |
497 | struct perf_hpp dummy_hpp = { | ||
498 | .ptr = hists_to_evsel(hists), | ||
499 | }; | ||
509 | 500 | ||
510 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 501 | perf_hpp__for_each_format(fmt) { |
511 | if (!perf_hpp__format[i].cond) | ||
512 | continue; | ||
513 | if (i) | 502 | if (i) |
514 | ret += 2; | 503 | ret += 2; |
515 | 504 | ||
516 | ret += perf_hpp__format[i].width(NULL); | 505 | ret += fmt->width(&dummy_hpp); |
517 | } | 506 | } |
518 | 507 | ||
519 | list_for_each_entry(se, &hist_entry__sort_list, list) | 508 | list_for_each_entry(se, &hist_entry__sort_list, list) |