Commit | Line | Data |
---|---|---|
ea251d51 | 1 | #include <math.h> |
2c5d4b4a | 2 | #include <linux/compiler.h> |
ea251d51 NK |
3 | |
4 | #include "../util/hist.h" | |
5 | #include "../util/util.h" | |
6 | #include "../util/sort.h" | |
4fb71074 | 7 | #include "../util/evsel.h" |
ea251d51 NK |
8 | |
9 | /* hist period print (hpp) functions */ | |
ea251d51 | 10 | |
a0088adc NK |
11 | #define hpp__call_print_fn(hpp, fn, fmt, ...) \ |
12 | ({ \ | |
13 | int __ret = fn(hpp, fmt, ##__VA_ARGS__); \ | |
14 | advance_hpp(hpp, __ret); \ | |
15 | __ret; \ | |
16 | }) | |
17 | ||
4a62109f | 18 | int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, |
2f6d9009 | 19 | hpp_field_fn get_field, hpp_callback_fn callback, |
4a62109f | 20 | const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent) |
ea251d51 | 21 | { |
2f6d9009 | 22 | int ret = 0; |
b5ff71c3 | 23 | struct hists *hists = he->hists; |
759ff497 | 24 | struct perf_evsel *evsel = hists_to_evsel(hists); |
a0088adc NK |
25 | char *buf = hpp->buf; |
26 | size_t size = hpp->size; | |
ea251d51 | 27 | |
2f6d9009 NK |
28 | if (callback) { |
29 | ret = callback(hpp, true); | |
30 | advance_hpp(hpp, ret); | |
31 | } | |
32 | ||
0c5268bf JO |
33 | if (fmt_percent) { |
34 | double percent = 0.0; | |
9ffad987 | 35 | |
0c5268bf JO |
36 | if (hists->stats.total_period) |
37 | percent = 100.0 * get_field(he) / | |
38 | hists->stats.total_period; | |
39 | ||
2f6d9009 | 40 | ret += hpp__call_print_fn(hpp, print_fn, fmt, percent); |
0c5268bf | 41 | } else |
2f6d9009 | 42 | ret += hpp__call_print_fn(hpp, print_fn, fmt, get_field(he)); |
5b9e2146 | 43 | |
759ff497 | 44 | if (perf_evsel__is_group_event(evsel)) { |
5b9e2146 | 45 | int prev_idx, idx_delta; |
5b9e2146 NK |
46 | struct hist_entry *pair; |
47 | int nr_members = evsel->nr_members; | |
48 | ||
5b9e2146 NK |
49 | prev_idx = perf_evsel__group_idx(evsel); |
50 | ||
51 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | |
52 | u64 period = get_field(pair); | |
53 | u64 total = pair->hists->stats.total_period; | |
54 | ||
55 | if (!total) | |
56 | continue; | |
57 | ||
58 | evsel = hists_to_evsel(pair->hists); | |
59 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | |
60 | ||
61 | while (idx_delta--) { | |
62 | /* | |
63 | * zero-fill group members in the middle which | |
64 | * have no sample | |
65 | */ | |
9b0d2fb8 | 66 | if (fmt_percent) { |
a0088adc NK |
67 | ret += hpp__call_print_fn(hpp, print_fn, |
68 | fmt, 0.0); | |
9b0d2fb8 | 69 | } else { |
a0088adc NK |
70 | ret += hpp__call_print_fn(hpp, print_fn, |
71 | fmt, 0ULL); | |
9b0d2fb8 | 72 | } |
5b9e2146 NK |
73 | } |
74 | ||
a0088adc NK |
75 | if (fmt_percent) { |
76 | ret += hpp__call_print_fn(hpp, print_fn, fmt, | |
77 | 100.0 * period / total); | |
78 | } else { | |
79 | ret += hpp__call_print_fn(hpp, print_fn, fmt, | |
80 | period); | |
81 | } | |
5b9e2146 NK |
82 | |
83 | prev_idx = perf_evsel__group_idx(evsel); | |
84 | } | |
85 | ||
86 | idx_delta = nr_members - prev_idx - 1; | |
87 | ||
88 | while (idx_delta--) { | |
89 | /* | |
90 | * zero-fill group members at last which have no sample | |
91 | */ | |
9b0d2fb8 | 92 | if (fmt_percent) { |
a0088adc NK |
93 | ret += hpp__call_print_fn(hpp, print_fn, |
94 | fmt, 0.0); | |
9b0d2fb8 | 95 | } else { |
a0088adc NK |
96 | ret += hpp__call_print_fn(hpp, print_fn, |
97 | fmt, 0ULL); | |
9b0d2fb8 | 98 | } |
5b9e2146 NK |
99 | } |
100 | } | |
a0088adc | 101 | |
2f6d9009 NK |
102 | if (callback) { |
103 | int __ret = callback(hpp, false); | |
104 | ||
105 | advance_hpp(hpp, __ret); | |
106 | ret += __ret; | |
107 | } | |
108 | ||
a0088adc NK |
109 | /* |
110 | * Restore original buf and size as it's where caller expects | |
111 | * the result will be saved. | |
112 | */ | |
113 | hpp->buf = buf; | |
114 | hpp->size = size; | |
115 | ||
4fb71074 | 116 | return ret; |
ea251d51 NK |
117 | } |
118 | ||
4fb71074 | 119 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
2c5d4b4a JO |
120 | static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
121 | struct perf_hpp *hpp) \ | |
4fb71074 NK |
122 | { \ |
123 | int len = _min_width; \ | |
124 | \ | |
5b9e2146 NK |
125 | if (symbol_conf.event_group) { \ |
126 | struct perf_evsel *evsel = hpp->ptr; \ | |
127 | \ | |
128 | len = max(len, evsel->nr_members * _unit_width); \ | |
129 | } \ | |
4fb71074 | 130 | return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ |
ea251d51 NK |
131 | } |
132 | ||
4fb71074 | 133 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ |
2c5d4b4a JO |
134 | static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
135 | struct perf_hpp *hpp __maybe_unused) \ | |
4fb71074 NK |
136 | { \ |
137 | int len = _min_width; \ | |
138 | \ | |
5b9e2146 NK |
139 | if (symbol_conf.event_group) { \ |
140 | struct perf_evsel *evsel = hpp->ptr; \ | |
141 | \ | |
142 | len = max(len, evsel->nr_members * _unit_width); \ | |
143 | } \ | |
4fb71074 | 144 | return len; \ |
ea251d51 NK |
145 | } |
146 | ||
a0088adc NK |
147 | static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) |
148 | { | |
149 | va_list args; | |
150 | ssize_t ssize = hpp->size; | |
151 | double percent; | |
152 | int ret; | |
153 | ||
154 | va_start(args, fmt); | |
155 | percent = va_arg(args, double); | |
156 | ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent); | |
157 | va_end(args); | |
158 | ||
159 | return (ret >= ssize) ? (ssize - 1) : ret; | |
160 | } | |
161 | ||
162 | static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) | |
163 | { | |
164 | va_list args; | |
165 | ssize_t ssize = hpp->size; | |
166 | int ret; | |
167 | ||
168 | va_start(args, fmt); | |
169 | ret = vsnprintf(hpp->buf, hpp->size, fmt, args); | |
170 | va_end(args); | |
171 | ||
172 | return (ret >= ssize) ? (ssize - 1) : ret; | |
173 | } | |
174 | ||
4fb71074 NK |
175 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ |
176 | static u64 he_get_##_field(struct hist_entry *he) \ | |
177 | { \ | |
178 | return he->stat._field; \ | |
179 | } \ | |
180 | \ | |
2c5d4b4a JO |
181 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
182 | struct perf_hpp *hpp, struct hist_entry *he) \ | |
4fb71074 | 183 | { \ |
2f6d9009 | 184 | return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \ |
a0088adc | 185 | hpp_color_scnprintf, true); \ |
ea251d51 NK |
186 | } |
187 | ||
4fb71074 | 188 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
2c5d4b4a JO |
189 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
190 | struct perf_hpp *hpp, struct hist_entry *he) \ | |
4fb71074 NK |
191 | { \ |
192 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | |
2f6d9009 | 193 | return __hpp__fmt(hpp, he, he_get_##_field, NULL, fmt, \ |
a0088adc | 194 | hpp_entry_scnprintf, true); \ |
ea251d51 NK |
195 | } |
196 | ||
4fb71074 NK |
197 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ |
198 | static u64 he_get_raw_##_field(struct hist_entry *he) \ | |
199 | { \ | |
200 | return he->stat._field; \ | |
201 | } \ | |
202 | \ | |
2c5d4b4a JO |
203 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
204 | struct perf_hpp *hpp, struct hist_entry *he) \ | |
4fb71074 NK |
205 | { \ |
206 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | |
2f6d9009 | 207 | return __hpp__fmt(hpp, he, he_get_raw_##_field, NULL, fmt, \ |
a0088adc | 208 | hpp_entry_scnprintf, false); \ |
ea251d51 NK |
209 | } |
210 | ||
4fb71074 NK |
211 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ |
212 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | |
213 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | |
214 | __HPP_COLOR_PERCENT_FN(_type, _field) \ | |
215 | __HPP_ENTRY_PERCENT_FN(_type, _field) | |
ea251d51 | 216 | |
4fb71074 NK |
217 | #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ |
218 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | |
219 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | |
220 | __HPP_ENTRY_RAW_FN(_type, _field) | |
ea251d51 | 221 | |
b5ff71c3 | 222 | |
4fb71074 NK |
223 | HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) |
224 | HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) | |
225 | HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) | |
226 | HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) | |
227 | HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | |
ea251d51 | 228 | |
4fb71074 NK |
229 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) |
230 | HPP_RAW_FNS(period, "Period", period, 12, 12) | |
9ffad987 | 231 | |
1240005e JO |
232 | #define HPP__COLOR_PRINT_FNS(_name) \ |
233 | { \ | |
234 | .header = hpp__header_ ## _name, \ | |
235 | .width = hpp__width_ ## _name, \ | |
236 | .color = hpp__color_ ## _name, \ | |
237 | .entry = hpp__entry_ ## _name \ | |
238 | } | |
ea251d51 | 239 | |
1240005e JO |
240 | #define HPP__PRINT_FNS(_name) \ |
241 | { \ | |
242 | .header = hpp__header_ ## _name, \ | |
243 | .width = hpp__width_ ## _name, \ | |
244 | .entry = hpp__entry_ ## _name \ | |
245 | } | |
ea251d51 NK |
246 | |
247 | struct perf_hpp_fmt perf_hpp__format[] = { | |
1240005e JO |
248 | HPP__COLOR_PRINT_FNS(overhead), |
249 | HPP__COLOR_PRINT_FNS(overhead_sys), | |
250 | HPP__COLOR_PRINT_FNS(overhead_us), | |
251 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), | |
252 | HPP__COLOR_PRINT_FNS(overhead_guest_us), | |
253 | HPP__PRINT_FNS(samples), | |
345dc0b4 | 254 | HPP__PRINT_FNS(period) |
ea251d51 NK |
255 | }; |
256 | ||
1240005e JO |
257 | LIST_HEAD(perf_hpp__list); |
258 | ||
4fb71074 | 259 | |
ea251d51 NK |
260 | #undef HPP__COLOR_PRINT_FNS |
261 | #undef HPP__PRINT_FNS | |
262 | ||
4fb71074 NK |
263 | #undef HPP_PERCENT_FNS |
264 | #undef HPP_RAW_FNS | |
265 | ||
266 | #undef __HPP_HEADER_FN | |
267 | #undef __HPP_WIDTH_FN | |
268 | #undef __HPP_COLOR_PERCENT_FN | |
269 | #undef __HPP_ENTRY_PERCENT_FN | |
270 | #undef __HPP_ENTRY_RAW_FN | |
271 | ||
272 | ||
1d77822e | 273 | void perf_hpp__init(void) |
ea251d51 | 274 | { |
2b8bfa6b JO |
275 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); |
276 | ||
ea251d51 | 277 | if (symbol_conf.show_cpu_utilization) { |
1240005e JO |
278 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
279 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); | |
ea251d51 NK |
280 | |
281 | if (perf_guest) { | |
1240005e JO |
282 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); |
283 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); | |
ea251d51 NK |
284 | } |
285 | } | |
286 | ||
287 | if (symbol_conf.show_nr_samples) | |
1240005e | 288 | perf_hpp__column_enable(PERF_HPP__SAMPLES); |
ea251d51 NK |
289 | |
290 | if (symbol_conf.show_total_period) | |
1240005e | 291 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
1d77822e | 292 | } |
ea251d51 | 293 | |
1240005e JO |
294 | void perf_hpp__column_register(struct perf_hpp_fmt *format) |
295 | { | |
296 | list_add_tail(&format->list, &perf_hpp__list); | |
297 | } | |
298 | ||
299 | void perf_hpp__column_enable(unsigned col) | |
1d77822e JO |
300 | { |
301 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | |
1240005e | 302 | perf_hpp__column_register(&perf_hpp__format[col]); |
ea251d51 NK |
303 | } |
304 | ||
ea251d51 NK |
305 | int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, |
306 | struct hists *hists) | |
307 | { | |
308 | const char *sep = symbol_conf.field_sep; | |
309 | struct sort_entry *se; | |
310 | int ret = 0; | |
311 | ||
312 | list_for_each_entry(se, &hist_entry__sort_list, list) { | |
313 | if (se->elide) | |
314 | continue; | |
315 | ||
316 | ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); | |
317 | ret += se->se_snprintf(he, s + ret, size - ret, | |
318 | hists__col_len(hists, se->se_width_idx)); | |
319 | } | |
320 | ||
321 | return ret; | |
322 | } | |
7e62ef44 NK |
323 | |
324 | /* | |
325 | * See hists__fprintf to match the column widths | |
326 | */ | |
327 | unsigned int hists__sort_list_width(struct hists *hists) | |
328 | { | |
1240005e | 329 | struct perf_hpp_fmt *fmt; |
7e62ef44 | 330 | struct sort_entry *se; |
1240005e | 331 | int i = 0, ret = 0; |
5b9e2146 NK |
332 | struct perf_hpp dummy_hpp = { |
333 | .ptr = hists_to_evsel(hists), | |
334 | }; | |
7e62ef44 | 335 | |
1240005e | 336 | perf_hpp__for_each_format(fmt) { |
7e62ef44 NK |
337 | if (i) |
338 | ret += 2; | |
339 | ||
2c5d4b4a | 340 | ret += fmt->width(fmt, &dummy_hpp); |
7e62ef44 NK |
341 | } |
342 | ||
343 | list_for_each_entry(se, &hist_entry__sort_list, list) | |
344 | if (!se->elide) | |
345 | ret += 2 + hists__col_len(hists, se->se_width_idx); | |
346 | ||
347 | if (verbose) /* Addr + origin */ | |
348 | ret += 3 + BITS_PER_LONG / 4; | |
349 | ||
350 | return ret; | |
351 | } |