xref: /linux/tools/perf/ui/hist.c (revision 08ec212c0f92cbf30e3ecc7349f18151714041d6)
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 = he->pair;
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 	return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
183 }
184 
185 static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
186 {
187 	double percent = baseline_percent(he);
188 	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
189 
190 	return scnprintf(hpp->buf, hpp->size, fmt, percent);
191 }
192 
193 static int hpp__header_samples(struct perf_hpp *hpp)
194 {
195 	const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
196 
197 	return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
198 }
199 
200 static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
201 {
202 	return 11;
203 }
204 
205 static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
206 {
207 	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
208 
209 	return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
210 }
211 
212 static int hpp__header_period(struct perf_hpp *hpp)
213 {
214 	const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
215 
216 	return scnprintf(hpp->buf, hpp->size, fmt, "Period");
217 }
218 
219 static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
220 {
221 	return 12;
222 }
223 
224 static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
225 {
226 	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
227 
228 	return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
229 }
230 
231 static int hpp__header_delta(struct perf_hpp *hpp)
232 {
233 	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
234 
235 	return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
236 }
237 
238 static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
239 {
240 	return 7;
241 }
242 
243 static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
244 {
245 	struct hist_entry *pair = he->pair;
246 	struct hists *pair_hists = pair ? pair->hists : NULL;
247 	struct hists *hists = he->hists;
248 	u64 old_total, new_total;
249 	double old_percent = 0, new_percent = 0;
250 	double diff;
251 	const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
252 	char buf[32] = " ";
253 
254 	old_total = pair_hists ? pair_hists->stats.total_period : 0;
255 	if (old_total > 0 && pair)
256 		old_percent = 100.0 * pair->stat.period / old_total;
257 
258 	new_total = hists->stats.total_period;
259 	if (new_total > 0)
260 		new_percent = 100.0 * he->stat.period / new_total;
261 
262 	diff = new_percent - old_percent;
263 	if (fabs(diff) >= 0.01)
264 		scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
265 
266 	return scnprintf(hpp->buf, hpp->size, fmt, buf);
267 }
268 
269 static int hpp__header_displ(struct perf_hpp *hpp)
270 {
271 	return scnprintf(hpp->buf, hpp->size, "Displ.");
272 }
273 
274 static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
275 {
276 	return 6;
277 }
278 
279 static int hpp__entry_displ(struct perf_hpp *hpp,
280 			    struct hist_entry *he)
281 {
282 	struct hist_entry *pair = he->pair;
283 	long displacement = pair ? pair->position - he->position : 0;
284 	const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
285 	char buf[32] = " ";
286 
287 	if (displacement)
288 		scnprintf(buf, sizeof(buf), "%+4ld", displacement);
289 
290 	return scnprintf(hpp->buf, hpp->size, fmt, buf);
291 }
292 
293 #define HPP__COLOR_PRINT_FNS(_name)		\
294 	.header	= hpp__header_ ## _name,		\
295 	.width	= hpp__width_ ## _name,		\
296 	.color	= hpp__color_ ## _name,		\
297 	.entry	= hpp__entry_ ## _name
298 
299 #define HPP__PRINT_FNS(_name)			\
300 	.header	= hpp__header_ ## _name,		\
301 	.width	= hpp__width_ ## _name,		\
302 	.entry	= hpp__entry_ ## _name
303 
304 struct perf_hpp_fmt perf_hpp__format[] = {
305 	{ .cond = false, HPP__COLOR_PRINT_FNS(baseline) },
306 	{ .cond = true,  HPP__COLOR_PRINT_FNS(overhead) },
307 	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
308 	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
309 	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
310 	{ .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
311 	{ .cond = false, HPP__PRINT_FNS(samples) },
312 	{ .cond = false, HPP__PRINT_FNS(period) },
313 	{ .cond = false, HPP__PRINT_FNS(delta) },
314 	{ .cond = false, HPP__PRINT_FNS(displ) }
315 };
316 
317 #undef HPP__COLOR_PRINT_FNS
318 #undef HPP__PRINT_FNS
319 
320 void perf_hpp__init(void)
321 {
322 	if (symbol_conf.show_cpu_utilization) {
323 		perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
324 		perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
325 
326 		if (perf_guest) {
327 			perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
328 			perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
329 		}
330 	}
331 
332 	if (symbol_conf.show_nr_samples)
333 		perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
334 
335 	if (symbol_conf.show_total_period)
336 		perf_hpp__format[PERF_HPP__PERIOD].cond = true;
337 }
338 
339 void perf_hpp__column_enable(unsigned col, bool enable)
340 {
341 	BUG_ON(col >= PERF_HPP__MAX_INDEX);
342 	perf_hpp__format[col].cond = enable;
343 }
344 
345 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
346 {
347 	hpp->buf  += inc;
348 	hpp->size -= inc;
349 }
350 
351 int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
352 				bool color)
353 {
354 	const char *sep = symbol_conf.field_sep;
355 	char *start = hpp->buf;
356 	int i, ret;
357 	bool first = true;
358 
359 	if (symbol_conf.exclude_other && !he->parent)
360 		return 0;
361 
362 	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
363 		if (!perf_hpp__format[i].cond)
364 			continue;
365 
366 		if (!sep || !first) {
367 			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
368 			advance_hpp(hpp, ret);
369 			first = false;
370 		}
371 
372 		if (color && perf_hpp__format[i].color)
373 			ret = perf_hpp__format[i].color(hpp, he);
374 		else
375 			ret = perf_hpp__format[i].entry(hpp, he);
376 
377 		advance_hpp(hpp, ret);
378 	}
379 
380 	return hpp->buf - start;
381 }
382 
383 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
384 			      struct hists *hists)
385 {
386 	const char *sep = symbol_conf.field_sep;
387 	struct sort_entry *se;
388 	int ret = 0;
389 
390 	list_for_each_entry(se, &hist_entry__sort_list, list) {
391 		if (se->elide)
392 			continue;
393 
394 		ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
395 		ret += se->se_snprintf(he, s + ret, size - ret,
396 				       hists__col_len(hists, se->se_width_idx));
397 	}
398 
399 	return ret;
400 }
401 
402 /*
403  * See hists__fprintf to match the column widths
404  */
405 unsigned int hists__sort_list_width(struct hists *hists)
406 {
407 	struct sort_entry *se;
408 	int i, ret = 0;
409 
410 	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
411 		if (!perf_hpp__format[i].cond)
412 			continue;
413 		if (i)
414 			ret += 2;
415 
416 		ret += perf_hpp__format[i].width(NULL);
417 	}
418 
419 	list_for_each_entry(se, &hist_entry__sort_list, list)
420 		if (!se->elide)
421 			ret += 2 + hists__col_len(hists, se->se_width_idx);
422 
423 	if (verbose) /* Addr + origin */
424 		ret += 3 + BITS_PER_LONG / 4;
425 
426 	return ret;
427 }
428