xref: /openbmc/linux/tools/perf/util/stat-display.c (revision 4c12f41a)
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <inttypes.h>
4 #include <linux/string.h>
5 #include <linux/time64.h>
6 #include <math.h>
7 #include <perf/cpumap.h>
8 #include "color.h"
9 #include "counts.h"
10 #include "evlist.h"
11 #include "evsel.h"
12 #include "stat.h"
13 #include "top.h"
14 #include "thread_map.h"
15 #include "cpumap.h"
16 #include "string2.h"
17 #include <linux/ctype.h>
18 #include "cgroup.h"
19 #include <api/fs/fs.h>
20 #include "util.h"
21 #include "iostat.h"
22 #include "pmu-hybrid.h"
23 #include "evlist-hybrid.h"
24 
25 #define CNTR_NOT_SUPPORTED	"<not supported>"
26 #define CNTR_NOT_COUNTED	"<not counted>"
27 
28 #define METRIC_LEN   38
29 #define EVNAME_LEN   32
30 #define COUNTS_LEN   18
31 #define INTERVAL_LEN 16
32 #define CGROUP_LEN   16
33 #define COMM_LEN     16
34 #define PID_LEN       7
35 #define CPUS_LEN      4
36 
37 static int aggr_header_lens[] = {
38 	[AGGR_CORE] 	= 18,
39 	[AGGR_DIE] 	= 12,
40 	[AGGR_SOCKET] 	= 6,
41 	[AGGR_NODE] 	= 6,
42 	[AGGR_NONE] 	= 6,
43 	[AGGR_THREAD] 	= 16,
44 	[AGGR_GLOBAL] 	= 0,
45 };
46 
47 static const char *aggr_header_csv[] = {
48 	[AGGR_CORE] 	= 	"core,cpus,",
49 	[AGGR_DIE] 	= 	"die,cpus,",
50 	[AGGR_SOCKET] 	= 	"socket,cpus,",
51 	[AGGR_NONE] 	= 	"cpu,",
52 	[AGGR_THREAD] 	= 	"comm-pid,",
53 	[AGGR_NODE] 	= 	"node,",
54 	[AGGR_GLOBAL] 	=	""
55 };
56 
57 static const char *aggr_header_std[] = {
58 	[AGGR_CORE] 	= 	"core",
59 	[AGGR_DIE] 	= 	"die",
60 	[AGGR_SOCKET] 	= 	"socket",
61 	[AGGR_NONE] 	= 	"cpu",
62 	[AGGR_THREAD] 	= 	"comm-pid",
63 	[AGGR_NODE] 	= 	"node",
64 	[AGGR_GLOBAL] 	=	""
65 };
66 
67 static void print_running_std(struct perf_stat_config *config, u64 run, u64 ena)
68 {
69 	if (run != ena)
70 		fprintf(config->output, "  (%.2f%%)", 100.0 * run / ena);
71 }
72 
73 static void print_running_csv(struct perf_stat_config *config, u64 run, u64 ena)
74 {
75 	double enabled_percent = 100;
76 
77 	if (run != ena)
78 		enabled_percent = 100 * run / ena;
79 	fprintf(config->output, "%s%" PRIu64 "%s%.2f",
80 		config->csv_sep, run, config->csv_sep, enabled_percent);
81 }
82 
83 static void print_running_json(struct perf_stat_config *config, u64 run, u64 ena)
84 {
85 	double enabled_percent = 100;
86 
87 	if (run != ena)
88 		enabled_percent = 100 * run / ena;
89 	fprintf(config->output, "\"event-runtime\" : %" PRIu64 ", \"pcnt-running\" : %.2f, ",
90 		run, enabled_percent);
91 }
92 
93 static void print_running(struct perf_stat_config *config,
94 			  u64 run, u64 ena, bool before_metric)
95 {
96 	if (config->json_output) {
97 		if (before_metric)
98 			print_running_json(config, run, ena);
99 	} else if (config->csv_output) {
100 		if (before_metric)
101 			print_running_csv(config, run, ena);
102 	} else {
103 		if (!before_metric)
104 			print_running_std(config, run, ena);
105 	}
106 }
107 
108 static void print_noise_pct_std(struct perf_stat_config *config,
109 				double pct)
110 {
111 	if (pct)
112 		fprintf(config->output, "  ( +-%6.2f%% )", pct);
113 }
114 
115 static void print_noise_pct_csv(struct perf_stat_config *config,
116 				double pct)
117 {
118 	fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
119 }
120 
121 static void print_noise_pct_json(struct perf_stat_config *config,
122 				 double pct)
123 {
124 	fprintf(config->output, "\"variance\" : %.2f, ", pct);
125 }
126 
127 static void print_noise_pct(struct perf_stat_config *config,
128 			    double total, double avg, bool before_metric)
129 {
130 	double pct = rel_stddev_stats(total, avg);
131 
132 	if (config->json_output) {
133 		if (before_metric)
134 			print_noise_pct_json(config, pct);
135 	} else if (config->csv_output) {
136 		if (before_metric)
137 			print_noise_pct_csv(config, pct);
138 	} else {
139 		if (!before_metric)
140 			print_noise_pct_std(config, pct);
141 	}
142 }
143 
144 static void print_noise(struct perf_stat_config *config,
145 			struct evsel *evsel, double avg, bool before_metric)
146 {
147 	struct perf_stat_evsel *ps;
148 
149 	if (config->run_count == 1)
150 		return;
151 
152 	ps = evsel->stats;
153 	print_noise_pct(config, stddev_stats(&ps->res_stats), avg, before_metric);
154 }
155 
156 static void print_cgroup_std(struct perf_stat_config *config, const char *cgrp_name)
157 {
158 	fprintf(config->output, " %-*s", CGROUP_LEN, cgrp_name);
159 }
160 
161 static void print_cgroup_csv(struct perf_stat_config *config, const char *cgrp_name)
162 {
163 	fprintf(config->output, "%s%s", config->csv_sep, cgrp_name);
164 }
165 
166 static void print_cgroup_json(struct perf_stat_config *config, const char *cgrp_name)
167 {
168 	fprintf(config->output, "\"cgroup\" : \"%s\", ", cgrp_name);
169 }
170 
171 static void print_cgroup(struct perf_stat_config *config, struct cgroup *cgrp)
172 {
173 	if (nr_cgroups || config->cgroup_list) {
174 		const char *cgrp_name = cgrp ? cgrp->name  : "";
175 
176 		if (config->json_output)
177 			print_cgroup_json(config, cgrp_name);
178 		else if (config->csv_output)
179 			print_cgroup_csv(config, cgrp_name);
180 		else
181 			print_cgroup_std(config, cgrp_name);
182 	}
183 }
184 
185 static void print_aggr_id_std(struct perf_stat_config *config,
186 			      struct evsel *evsel, struct aggr_cpu_id id, int nr)
187 {
188 	FILE *output = config->output;
189 	int idx = config->aggr_mode;
190 	char buf[128];
191 
192 	switch (config->aggr_mode) {
193 	case AGGR_CORE:
194 		snprintf(buf, sizeof(buf), "S%d-D%d-C%d", id.socket, id.die, id.core);
195 		break;
196 	case AGGR_DIE:
197 		snprintf(buf, sizeof(buf), "S%d-D%d", id.socket, id.die);
198 		break;
199 	case AGGR_SOCKET:
200 		snprintf(buf, sizeof(buf), "S%d", id.socket);
201 		break;
202 	case AGGR_NODE:
203 		snprintf(buf, sizeof(buf), "N%d", id.node);
204 		break;
205 	case AGGR_NONE:
206 		if (evsel->percore && !config->percore_show_thread) {
207 			snprintf(buf, sizeof(buf), "S%d-D%d-C%d ",
208 				id.socket, id.die, id.core);
209 			fprintf(output, "%-*s ",
210 				aggr_header_lens[AGGR_CORE], buf);
211 		} else if (id.cpu.cpu > -1) {
212 			fprintf(output, "CPU%-*d ",
213 				aggr_header_lens[AGGR_NONE] - 3, id.cpu.cpu);
214 		}
215 		return;
216 	case AGGR_THREAD:
217 		fprintf(output, "%*s-%-*d ",
218 			COMM_LEN, perf_thread_map__comm(evsel->core.threads, id.thread_idx),
219 			PID_LEN, perf_thread_map__pid(evsel->core.threads, id.thread_idx));
220 		return;
221 	case AGGR_GLOBAL:
222 	case AGGR_UNSET:
223 	case AGGR_MAX:
224 	default:
225 		return;
226 	}
227 
228 	fprintf(output, "%-*s %*d ", aggr_header_lens[idx], buf, 4, nr);
229 }
230 
231 static void print_aggr_id_csv(struct perf_stat_config *config,
232 			      struct evsel *evsel, struct aggr_cpu_id id, int nr)
233 {
234 	FILE *output = config->output;
235 	const char *sep = config->csv_sep;
236 
237 	switch (config->aggr_mode) {
238 	case AGGR_CORE:
239 		fprintf(output, "S%d-D%d-C%d%s%d%s",
240 			id.socket, id.die, id.core, sep, nr, sep);
241 		break;
242 	case AGGR_DIE:
243 		fprintf(output, "S%d-D%d%s%d%s",
244 			id.socket, id.die, sep, nr, sep);
245 		break;
246 	case AGGR_SOCKET:
247 		fprintf(output, "S%d%s%d%s",
248 			id.socket, sep, nr, sep);
249 		break;
250 	case AGGR_NODE:
251 		fprintf(output, "N%d%s%d%s",
252 			id.node, sep, nr, sep);
253 		break;
254 	case AGGR_NONE:
255 		if (evsel->percore && !config->percore_show_thread) {
256 			fprintf(output, "S%d-D%d-C%d%s",
257 				id.socket, id.die, id.core, sep);
258 		} else if (id.cpu.cpu > -1) {
259 			fprintf(output, "CPU%d%s",
260 				id.cpu.cpu, sep);
261 		}
262 		break;
263 	case AGGR_THREAD:
264 		fprintf(output, "%s-%d%s",
265 			perf_thread_map__comm(evsel->core.threads, id.thread_idx),
266 			perf_thread_map__pid(evsel->core.threads, id.thread_idx),
267 			sep);
268 		break;
269 	case AGGR_GLOBAL:
270 	case AGGR_UNSET:
271 	case AGGR_MAX:
272 	default:
273 		break;
274 	}
275 }
276 
277 static void print_aggr_id_json(struct perf_stat_config *config,
278 			       struct evsel *evsel, struct aggr_cpu_id id, int nr)
279 {
280 	FILE *output = config->output;
281 
282 	switch (config->aggr_mode) {
283 	case AGGR_CORE:
284 		fprintf(output, "\"core\" : \"S%d-D%d-C%d\", \"cpu-count\" : %d, ",
285 			id.socket, id.die, id.core, nr);
286 		break;
287 	case AGGR_DIE:
288 		fprintf(output, "\"die\" : \"S%d-D%d\", \"cpu-count\" : %d, ",
289 			id.socket, id.die, nr);
290 		break;
291 	case AGGR_SOCKET:
292 		fprintf(output, "\"socket\" : \"S%d\", \"cpu-count\" : %d, ",
293 			id.socket, nr);
294 		break;
295 	case AGGR_NODE:
296 		fprintf(output, "\"node\" : \"N%d\", \"cpu-count\" : %d, ",
297 			id.node, nr);
298 		break;
299 	case AGGR_NONE:
300 		if (evsel->percore && !config->percore_show_thread) {
301 			fprintf(output, "\"core\" : \"S%d-D%d-C%d\"",
302 				id.socket, id.die, id.core);
303 		} else if (id.cpu.cpu > -1) {
304 			fprintf(output, "\"cpu\" : \"%d\", ",
305 				id.cpu.cpu);
306 		}
307 		break;
308 	case AGGR_THREAD:
309 		fprintf(output, "\"thread\" : \"%s-%d\", ",
310 			perf_thread_map__comm(evsel->core.threads, id.thread_idx),
311 			perf_thread_map__pid(evsel->core.threads, id.thread_idx));
312 		break;
313 	case AGGR_GLOBAL:
314 	case AGGR_UNSET:
315 	case AGGR_MAX:
316 	default:
317 		break;
318 	}
319 }
320 
321 static void aggr_printout(struct perf_stat_config *config,
322 			  struct evsel *evsel, struct aggr_cpu_id id, int nr)
323 {
324 	if (config->json_output)
325 		print_aggr_id_json(config, evsel, id, nr);
326 	else if (config->csv_output)
327 		print_aggr_id_csv(config, evsel, id, nr);
328 	else
329 		print_aggr_id_std(config, evsel, id, nr);
330 }
331 
332 struct outstate {
333 	FILE *fh;
334 	bool newline;
335 	bool first;
336 	const char *prefix;
337 	int  nfields;
338 	int  nr;
339 	struct aggr_cpu_id id;
340 	struct evsel *evsel;
341 	struct cgroup *cgrp;
342 };
343 
344 static void new_line_std(struct perf_stat_config *config __maybe_unused,
345 			 void *ctx)
346 {
347 	struct outstate *os = ctx;
348 
349 	os->newline = true;
350 }
351 
352 static void do_new_line_std(struct perf_stat_config *config,
353 			    struct outstate *os)
354 {
355 	fputc('\n', os->fh);
356 	fputs(os->prefix, os->fh);
357 	aggr_printout(config, os->evsel, os->id, os->nr);
358 	if (config->aggr_mode == AGGR_NONE)
359 		fprintf(os->fh, "        ");
360 	fprintf(os->fh, "                                                 ");
361 }
362 
363 static void print_metric_std(struct perf_stat_config *config,
364 			     void *ctx, const char *color, const char *fmt,
365 			     const char *unit, double val)
366 {
367 	struct outstate *os = ctx;
368 	FILE *out = os->fh;
369 	int n;
370 	bool newline = os->newline;
371 
372 	os->newline = false;
373 
374 	if (unit == NULL || fmt == NULL) {
375 		fprintf(out, "%-*s", METRIC_LEN, "");
376 		return;
377 	}
378 
379 	if (newline)
380 		do_new_line_std(config, os);
381 
382 	n = fprintf(out, " # ");
383 	if (color)
384 		n += color_fprintf(out, color, fmt, val);
385 	else
386 		n += fprintf(out, fmt, val);
387 	fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
388 }
389 
390 static void new_line_csv(struct perf_stat_config *config, void *ctx)
391 {
392 	struct outstate *os = ctx;
393 	int i;
394 
395 	fputc('\n', os->fh);
396 	if (os->prefix)
397 		fprintf(os->fh, "%s", os->prefix);
398 	aggr_printout(config, os->evsel, os->id, os->nr);
399 	for (i = 0; i < os->nfields; i++)
400 		fputs(config->csv_sep, os->fh);
401 }
402 
403 static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
404 			     void *ctx,
405 			     const char *color __maybe_unused,
406 			     const char *fmt, const char *unit, double val)
407 {
408 	struct outstate *os = ctx;
409 	FILE *out = os->fh;
410 	char buf[64], *vals, *ends;
411 
412 	if (unit == NULL || fmt == NULL) {
413 		fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
414 		return;
415 	}
416 	snprintf(buf, sizeof(buf), fmt, val);
417 	ends = vals = skip_spaces(buf);
418 	while (isdigit(*ends) || *ends == '.')
419 		ends++;
420 	*ends = 0;
421 	fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
422 }
423 
424 static void print_metric_json(struct perf_stat_config *config __maybe_unused,
425 			     void *ctx,
426 			     const char *color __maybe_unused,
427 			     const char *fmt __maybe_unused,
428 			     const char *unit, double val)
429 {
430 	struct outstate *os = ctx;
431 	FILE *out = os->fh;
432 
433 	fprintf(out, "\"metric-value\" : %f, ", val);
434 	fprintf(out, "\"metric-unit\" : \"%s\"", unit);
435 	if (!config->metric_only)
436 		fprintf(out, "}");
437 }
438 
439 static void new_line_json(struct perf_stat_config *config, void *ctx)
440 {
441 	struct outstate *os = ctx;
442 
443 	fputc('\n', os->fh);
444 	if (os->prefix)
445 		fprintf(os->fh, "%s", os->prefix);
446 	aggr_printout(config, os->evsel, os->id, os->nr);
447 }
448 
449 /* Filter out some columns that don't work well in metrics only mode */
450 
451 static bool valid_only_metric(const char *unit)
452 {
453 	if (!unit)
454 		return false;
455 	if (strstr(unit, "/sec") ||
456 	    strstr(unit, "CPUs utilized"))
457 		return false;
458 	return true;
459 }
460 
461 static const char *fixunit(char *buf, struct evsel *evsel,
462 			   const char *unit)
463 {
464 	if (!strncmp(unit, "of all", 6)) {
465 		snprintf(buf, 1024, "%s %s", evsel__name(evsel),
466 			 unit);
467 		return buf;
468 	}
469 	return unit;
470 }
471 
472 static void print_metric_only(struct perf_stat_config *config,
473 			      void *ctx, const char *color, const char *fmt,
474 			      const char *unit, double val)
475 {
476 	struct outstate *os = ctx;
477 	FILE *out = os->fh;
478 	char buf[1024], str[1024];
479 	unsigned mlen = config->metric_only_len;
480 
481 	if (!valid_only_metric(unit))
482 		return;
483 	unit = fixunit(buf, os->evsel, unit);
484 	if (mlen < strlen(unit))
485 		mlen = strlen(unit) + 1;
486 
487 	if (color)
488 		mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
489 
490 	color_snprintf(str, sizeof(str), color ?: "", fmt, val);
491 	fprintf(out, "%*s ", mlen, str);
492 	os->first = false;
493 }
494 
495 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
496 				  void *ctx, const char *color __maybe_unused,
497 				  const char *fmt,
498 				  const char *unit, double val)
499 {
500 	struct outstate *os = ctx;
501 	FILE *out = os->fh;
502 	char buf[64], *vals, *ends;
503 	char tbuf[1024];
504 
505 	if (!valid_only_metric(unit))
506 		return;
507 	unit = fixunit(tbuf, os->evsel, unit);
508 	snprintf(buf, sizeof buf, fmt, val);
509 	ends = vals = skip_spaces(buf);
510 	while (isdigit(*ends) || *ends == '.')
511 		ends++;
512 	*ends = 0;
513 	fprintf(out, "%s%s", vals, config->csv_sep);
514 	os->first = false;
515 }
516 
517 static void print_metric_only_json(struct perf_stat_config *config __maybe_unused,
518 				  void *ctx, const char *color __maybe_unused,
519 				  const char *fmt,
520 				  const char *unit, double val)
521 {
522 	struct outstate *os = ctx;
523 	FILE *out = os->fh;
524 	char buf[64], *vals, *ends;
525 	char tbuf[1024];
526 
527 	if (!valid_only_metric(unit))
528 		return;
529 	unit = fixunit(tbuf, os->evsel, unit);
530 	snprintf(buf, sizeof(buf), fmt, val);
531 	ends = vals = skip_spaces(buf);
532 	while (isdigit(*ends) || *ends == '.')
533 		ends++;
534 	*ends = 0;
535 	if (!unit[0] || !vals[0])
536 		return;
537 	fprintf(out, "%s\"%s\" : \"%s\"", os->first ? "" : ", ", unit, vals);
538 	os->first = false;
539 }
540 
541 static void new_line_metric(struct perf_stat_config *config __maybe_unused,
542 			    void *ctx __maybe_unused)
543 {
544 }
545 
546 static void print_metric_header(struct perf_stat_config *config,
547 				void *ctx, const char *color __maybe_unused,
548 				const char *fmt __maybe_unused,
549 				const char *unit, double val __maybe_unused)
550 {
551 	struct outstate *os = ctx;
552 	char tbuf[1024];
553 
554 	/* In case of iostat, print metric header for first root port only */
555 	if (config->iostat_run &&
556 	    os->evsel->priv != os->evsel->evlist->selected->priv)
557 		return;
558 
559 	if (os->evsel->cgrp != os->cgrp)
560 		return;
561 
562 	if (!valid_only_metric(unit))
563 		return;
564 	unit = fixunit(tbuf, os->evsel, unit);
565 
566 	if (config->json_output)
567 		return;
568 	else if (config->csv_output)
569 		fprintf(os->fh, "%s%s", unit, config->csv_sep);
570 	else
571 		fprintf(os->fh, "%*s ", config->metric_only_len, unit);
572 }
573 
574 static void print_counter_value_std(struct perf_stat_config *config,
575 				    struct evsel *evsel, double avg, bool ok)
576 {
577 	FILE *output = config->output;
578 	double sc =  evsel->scale;
579 	const char *fmt;
580 	const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
581 
582 	if (config->big_num)
583 		fmt = floor(sc) != sc ? "%'*.2f " : "%'*.0f ";
584 	else
585 		fmt = floor(sc) != sc ? "%*.2f " : "%*.0f ";
586 
587 	if (ok)
588 		fprintf(output, fmt, COUNTS_LEN, avg);
589 	else
590 		fprintf(output, "%*s ", COUNTS_LEN, bad_count);
591 
592 	if (evsel->unit)
593 		fprintf(output, "%-*s ", config->unit_width, evsel->unit);
594 
595 	fprintf(output, "%-*s", EVNAME_LEN, evsel__name(evsel));
596 }
597 
598 static void print_counter_value_csv(struct perf_stat_config *config,
599 				    struct evsel *evsel, double avg, bool ok)
600 {
601 	FILE *output = config->output;
602 	double sc =  evsel->scale;
603 	const char *sep = config->csv_sep;
604 	const char *fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
605 	const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
606 
607 	if (ok)
608 		fprintf(output, fmt, avg, sep);
609 	else
610 		fprintf(output, "%s%s", bad_count, sep);
611 
612 	if (evsel->unit)
613 		fprintf(output, "%s%s", evsel->unit, sep);
614 
615 	fprintf(output, "%s", evsel__name(evsel));
616 }
617 
618 static void print_counter_value_json(struct perf_stat_config *config,
619 				     struct evsel *evsel, double avg, bool ok)
620 {
621 	FILE *output = config->output;
622 	const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
623 
624 	if (ok)
625 		fprintf(output, "\"counter-value\" : \"%f\", ", avg);
626 	else
627 		fprintf(output, "\"counter-value\" : \"%s\", ", bad_count);
628 
629 	if (evsel->unit)
630 		fprintf(output, "\"unit\" : \"%s\", ", evsel->unit);
631 
632 	fprintf(output, "\"event\" : \"%s\", ", evsel__name(evsel));
633 }
634 
635 static void print_counter_value(struct perf_stat_config *config,
636 				struct evsel *evsel, double avg, bool ok)
637 {
638 	if (config->json_output)
639 		print_counter_value_json(config, evsel, avg, ok);
640 	else if (config->csv_output)
641 		print_counter_value_csv(config, evsel, avg, ok);
642 	else
643 		print_counter_value_std(config, evsel, avg, ok);
644 }
645 
646 static void abs_printout(struct perf_stat_config *config,
647 			 struct aggr_cpu_id id, int nr,
648 			 struct evsel *evsel, double avg, bool ok)
649 {
650 	aggr_printout(config, evsel, id, nr);
651 	print_counter_value(config, evsel, avg, ok);
652 	print_cgroup(config, evsel->cgrp);
653 }
654 
655 static bool is_mixed_hw_group(struct evsel *counter)
656 {
657 	struct evlist *evlist = counter->evlist;
658 	u32 pmu_type = counter->core.attr.type;
659 	struct evsel *pos;
660 
661 	if (counter->core.nr_members < 2)
662 		return false;
663 
664 	evlist__for_each_entry(evlist, pos) {
665 		/* software events can be part of any hardware group */
666 		if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
667 			continue;
668 		if (pmu_type == PERF_TYPE_SOFTWARE) {
669 			pmu_type = pos->core.attr.type;
670 			continue;
671 		}
672 		if (pmu_type != pos->core.attr.type)
673 			return true;
674 	}
675 
676 	return false;
677 }
678 
679 static void printout(struct perf_stat_config *config, struct outstate *os,
680 		     double uval, u64 run, u64 ena, double noise, int map_idx)
681 {
682 	struct perf_stat_output_ctx out;
683 	print_metric_t pm;
684 	new_line_t nl;
685 	bool ok = true;
686 	struct evsel *counter = os->evsel;
687 
688 	if (config->csv_output) {
689 		static const int aggr_fields[AGGR_MAX] = {
690 			[AGGR_NONE] = 1,
691 			[AGGR_GLOBAL] = 0,
692 			[AGGR_SOCKET] = 2,
693 			[AGGR_DIE] = 2,
694 			[AGGR_CORE] = 2,
695 			[AGGR_THREAD] = 1,
696 			[AGGR_UNSET] = 0,
697 			[AGGR_NODE] = 1,
698 		};
699 
700 		pm = config->metric_only ? print_metric_only_csv : print_metric_csv;
701 		nl = config->metric_only ? new_line_metric : new_line_csv;
702 		os->nfields = 3 + aggr_fields[config->aggr_mode] + (counter->cgrp ? 1 : 0);
703 	} else if (config->json_output) {
704 		pm = config->metric_only ? print_metric_only_json : print_metric_json;
705 		nl = config->metric_only ? new_line_metric : new_line_json;
706 	} else {
707 		pm = config->metric_only ? print_metric_only : print_metric_std;
708 		nl = config->metric_only ? new_line_metric : new_line_std;
709 	}
710 
711 	if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
712 		if (config->metric_only) {
713 			pm(config, os, NULL, "", "", 0);
714 			return;
715 		}
716 
717 		ok = false;
718 
719 		if (counter->supported) {
720 			if (!evlist__has_hybrid(counter->evlist)) {
721 				config->print_free_counters_hint = 1;
722 				if (is_mixed_hw_group(counter))
723 					config->print_mixed_hw_group_error = 1;
724 			}
725 		}
726 	}
727 
728 	out.print_metric = pm;
729 	out.new_line = nl;
730 	out.ctx = os;
731 	out.force_header = false;
732 
733 	if (!config->metric_only) {
734 		abs_printout(config, os->id, os->nr, counter, uval, ok);
735 
736 		print_noise(config, counter, noise, /*before_metric=*/true);
737 		print_running(config, run, ena, /*before_metric=*/true);
738 	}
739 
740 	if (ok) {
741 		perf_stat__print_shadow_stats(config, counter, uval, map_idx,
742 					      &out, &config->metric_events, &rt_stat);
743 	} else {
744 		pm(config, &os, /*color=*/NULL, /*format=*/NULL, /*unit=*/"", /*val=*/0);
745 	}
746 
747 	if (!config->metric_only) {
748 		print_noise(config, counter, noise, /*before_metric=*/false);
749 		print_running(config, run, ena, /*before_metric=*/false);
750 	}
751 }
752 
753 static void uniquify_event_name(struct evsel *counter)
754 {
755 	char *new_name;
756 	char *config;
757 	int ret = 0;
758 
759 	if (counter->uniquified_name || counter->use_config_name ||
760 	    !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
761 					   strlen(counter->pmu_name)))
762 		return;
763 
764 	config = strchr(counter->name, '/');
765 	if (config) {
766 		if (asprintf(&new_name,
767 			     "%s%s", counter->pmu_name, config) > 0) {
768 			free(counter->name);
769 			counter->name = new_name;
770 		}
771 	} else {
772 		if (evsel__is_hybrid(counter)) {
773 			ret = asprintf(&new_name, "%s/%s/",
774 				       counter->pmu_name, counter->name);
775 		} else {
776 			ret = asprintf(&new_name, "%s [%s]",
777 				       counter->name, counter->pmu_name);
778 		}
779 
780 		if (ret) {
781 			free(counter->name);
782 			counter->name = new_name;
783 		}
784 	}
785 
786 	counter->uniquified_name = true;
787 }
788 
789 static bool hybrid_uniquify(struct evsel *evsel, struct perf_stat_config *config)
790 {
791 	return evsel__is_hybrid(evsel) && !config->hybrid_merge;
792 }
793 
794 static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter)
795 {
796 	if (config->no_merge || hybrid_uniquify(counter, config))
797 		uniquify_event_name(counter);
798 }
799 
800 static void print_counter_aggrdata(struct perf_stat_config *config,
801 				   struct evsel *counter, int s,
802 				   struct outstate *os)
803 {
804 	FILE *output = config->output;
805 	u64 ena, run, val;
806 	double uval;
807 	struct perf_stat_evsel *ps = counter->stats;
808 	struct perf_stat_aggr *aggr = &ps->aggr[s];
809 	struct aggr_cpu_id id = config->aggr_map->map[s];
810 	double avg = aggr->counts.val;
811 	bool metric_only = config->metric_only;
812 
813 	os->id = id;
814 	os->nr = aggr->nr;
815 	os->evsel = counter;
816 
817 	if (counter->supported && aggr->nr == 0)
818 		return;
819 
820 	uniquify_counter(config, counter);
821 
822 	val = aggr->counts.val;
823 	ena = aggr->counts.ena;
824 	run = aggr->counts.run;
825 
826 	if (!metric_only) {
827 		if (config->json_output)
828 			fputc('{', output);
829 		if (os->prefix)
830 			fprintf(output, "%s", os->prefix);
831 		else if (config->summary && config->csv_output &&
832 			 !config->no_csv_summary && !config->interval)
833 			fprintf(output, "%s%s", "summary", config->csv_sep);
834 	}
835 
836 	uval = val * counter->scale;
837 
838 	printout(config, os, uval, run, ena, avg, s);
839 
840 	if (!metric_only)
841 		fputc('\n', output);
842 }
843 
844 static void print_metric_begin(struct perf_stat_config *config,
845 			       struct evlist *evlist,
846 			       struct outstate *os, int aggr_idx)
847 {
848 	struct perf_stat_aggr *aggr;
849 	struct aggr_cpu_id id;
850 	struct evsel *evsel;
851 
852 	os->first = true;
853 	if (!config->metric_only)
854 		return;
855 
856 	if (config->json_output)
857 		fputc('{', config->output);
858 	if (os->prefix)
859 		fprintf(config->output, "%s", os->prefix);
860 
861 	evsel = evlist__first(evlist);
862 	id = config->aggr_map->map[aggr_idx];
863 	aggr = &evsel->stats->aggr[aggr_idx];
864 	aggr_printout(config, evsel, id, aggr->nr);
865 
866 	print_cgroup(config, os->cgrp ? : evsel->cgrp);
867 }
868 
869 static void print_metric_end(struct perf_stat_config *config, struct outstate *os)
870 {
871 	FILE *output = config->output;
872 
873 	if (!config->metric_only)
874 		return;
875 
876 	if (config->json_output) {
877 		if (os->first)
878 			fputs("\"metric-value\" : \"none\"", output);
879 		fputc('}', output);
880 	}
881 	fputc('\n', output);
882 }
883 
884 static void print_aggr(struct perf_stat_config *config,
885 		       struct evlist *evlist,
886 		       struct outstate *os)
887 {
888 	struct evsel *counter;
889 	int s;
890 
891 	if (!config->aggr_map || !config->aggr_get_id)
892 		return;
893 
894 	/*
895 	 * With metric_only everything is on a single line.
896 	 * Without each counter has its own line.
897 	 */
898 	for (s = 0; s < config->aggr_map->nr; s++) {
899 		print_metric_begin(config, evlist, os, s);
900 
901 		evlist__for_each_entry(evlist, counter) {
902 			if (counter->merged_stat)
903 				continue;
904 
905 			print_counter_aggrdata(config, counter, s, os);
906 		}
907 		print_metric_end(config, os);
908 	}
909 }
910 
911 static void print_aggr_cgroup(struct perf_stat_config *config,
912 			      struct evlist *evlist,
913 			      struct outstate *os)
914 {
915 	struct evsel *counter, *evsel;
916 	int s;
917 
918 	if (!config->aggr_map || !config->aggr_get_id)
919 		return;
920 
921 	evlist__for_each_entry(evlist, evsel) {
922 		if (os->cgrp == evsel->cgrp)
923 			continue;
924 
925 		os->cgrp = evsel->cgrp;
926 
927 		for (s = 0; s < config->aggr_map->nr; s++) {
928 			print_metric_begin(config, evlist, os, s);
929 
930 			evlist__for_each_entry(evlist, counter) {
931 				if (counter->merged_stat)
932 					continue;
933 
934 				if (counter->cgrp != os->cgrp)
935 					continue;
936 
937 				print_counter_aggrdata(config, counter, s, os);
938 			}
939 			print_metric_end(config, os);
940 		}
941 	}
942 }
943 
944 static void print_counter(struct perf_stat_config *config,
945 			  struct evsel *counter, struct outstate *os)
946 {
947 	int s;
948 
949 	/* AGGR_THREAD doesn't have config->aggr_get_id */
950 	if (!config->aggr_map)
951 		return;
952 
953 	if (counter->merged_stat)
954 		return;
955 
956 	for (s = 0; s < config->aggr_map->nr; s++) {
957 		print_counter_aggrdata(config, counter, s, os);
958 	}
959 }
960 
961 static void print_no_aggr_metric(struct perf_stat_config *config,
962 				 struct evlist *evlist,
963 				 struct outstate *os)
964 {
965 	int all_idx;
966 	struct perf_cpu cpu;
967 
968 	perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.user_requested_cpus) {
969 		struct evsel *counter;
970 		bool first = true;
971 
972 		evlist__for_each_entry(evlist, counter) {
973 			u64 ena, run, val;
974 			double uval;
975 			struct perf_stat_evsel *ps = counter->stats;
976 			int counter_idx = perf_cpu_map__idx(evsel__cpus(counter), cpu);
977 
978 			if (counter_idx < 0)
979 				continue;
980 
981 			os->evsel = counter;
982 			os->id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
983 			if (first) {
984 				print_metric_begin(config, evlist, os, counter_idx);
985 				first = false;
986 			}
987 			val = ps->aggr[counter_idx].counts.val;
988 			ena = ps->aggr[counter_idx].counts.ena;
989 			run = ps->aggr[counter_idx].counts.run;
990 
991 			uval = val * counter->scale;
992 			printout(config, os, uval, run, ena, 1.0, counter_idx);
993 		}
994 		if (!first)
995 			print_metric_end(config, os);
996 	}
997 }
998 
999 static void print_metric_headers_std(struct perf_stat_config *config,
1000 				     bool no_indent)
1001 {
1002 	fputc(' ', config->output);
1003 
1004 	if (!no_indent) {
1005 		int len = aggr_header_lens[config->aggr_mode];
1006 
1007 		if (nr_cgroups || config->cgroup_list)
1008 			len += CGROUP_LEN + 1;
1009 
1010 		fprintf(config->output, "%*s", len, "");
1011 	}
1012 }
1013 
1014 static void print_metric_headers_csv(struct perf_stat_config *config,
1015 				     bool no_indent __maybe_unused)
1016 {
1017 	if (config->interval)
1018 		fputs("time,", config->output);
1019 	if (!config->iostat_run)
1020 		fputs(aggr_header_csv[config->aggr_mode], config->output);
1021 }
1022 
1023 static void print_metric_headers_json(struct perf_stat_config *config __maybe_unused,
1024 				      bool no_indent __maybe_unused)
1025 {
1026 }
1027 
1028 static void print_metric_headers(struct perf_stat_config *config,
1029 				 struct evlist *evlist, bool no_indent)
1030 {
1031 	struct evsel *counter;
1032 	struct outstate os = {
1033 		.fh = config->output
1034 	};
1035 	struct perf_stat_output_ctx out = {
1036 		.ctx = &os,
1037 		.print_metric = print_metric_header,
1038 		.new_line = new_line_metric,
1039 		.force_header = true,
1040 	};
1041 
1042 	if (config->json_output)
1043 		print_metric_headers_json(config, no_indent);
1044 	else if (config->csv_output)
1045 		print_metric_headers_csv(config, no_indent);
1046 	else
1047 		print_metric_headers_std(config, no_indent);
1048 
1049 	if (config->iostat_run)
1050 		iostat_print_header_prefix(config);
1051 
1052 	if (config->cgroup_list)
1053 		os.cgrp = evlist__first(evlist)->cgrp;
1054 
1055 	/* Print metrics headers only */
1056 	evlist__for_each_entry(evlist, counter) {
1057 		os.evsel = counter;
1058 
1059 		perf_stat__print_shadow_stats(config, counter, 0,
1060 					      0,
1061 					      &out,
1062 					      &config->metric_events,
1063 					      &rt_stat);
1064 	}
1065 
1066 	if (!config->json_output)
1067 		fputc('\n', config->output);
1068 }
1069 
1070 static void prepare_interval(struct perf_stat_config *config,
1071 			     char *prefix, size_t len, struct timespec *ts)
1072 {
1073 	if (config->iostat_run)
1074 		return;
1075 
1076 	if (config->json_output)
1077 		scnprintf(prefix, len, "\"interval\" : %lu.%09lu, ",
1078 			  (unsigned long) ts->tv_sec, ts->tv_nsec);
1079 	else if (config->csv_output)
1080 		scnprintf(prefix, len, "%lu.%09lu%s",
1081 			  (unsigned long) ts->tv_sec, ts->tv_nsec, config->csv_sep);
1082 	else
1083 		scnprintf(prefix, len, "%6lu.%09lu ",
1084 			  (unsigned long) ts->tv_sec, ts->tv_nsec);
1085 }
1086 
1087 static void print_header_interval_std(struct perf_stat_config *config,
1088 				      struct target *_target __maybe_unused,
1089 				      struct evlist *evlist,
1090 				      int argc __maybe_unused,
1091 				      const char **argv __maybe_unused)
1092 {
1093 	FILE *output = config->output;
1094 
1095 	switch (config->aggr_mode) {
1096 	case AGGR_NODE:
1097 	case AGGR_SOCKET:
1098 	case AGGR_DIE:
1099 	case AGGR_CORE:
1100 		fprintf(output, "#%*s %-*s cpus",
1101 			INTERVAL_LEN - 1, "time",
1102 			aggr_header_lens[config->aggr_mode],
1103 			aggr_header_std[config->aggr_mode]);
1104 		break;
1105 	case AGGR_NONE:
1106 		fprintf(output, "#%*s %-*s",
1107 			INTERVAL_LEN - 1, "time",
1108 			aggr_header_lens[config->aggr_mode],
1109 			aggr_header_std[config->aggr_mode]);
1110 		break;
1111 	case AGGR_THREAD:
1112 		fprintf(output, "#%*s %*s-%-*s",
1113 			INTERVAL_LEN - 1, "time",
1114 			COMM_LEN, "comm", PID_LEN, "pid");
1115 		break;
1116 	case AGGR_GLOBAL:
1117 	default:
1118 		if (!config->iostat_run)
1119 			fprintf(output, "#%*s",
1120 				INTERVAL_LEN - 1, "time");
1121 	case AGGR_UNSET:
1122 	case AGGR_MAX:
1123 		break;
1124 	}
1125 
1126 	if (config->metric_only)
1127 		print_metric_headers(config, evlist, true);
1128 	else
1129 		fprintf(output, " %*s %*s events\n",
1130 			COUNTS_LEN, "counts", config->unit_width, "unit");
1131 }
1132 
1133 static void print_header_std(struct perf_stat_config *config,
1134 			     struct target *_target, struct evlist *evlist,
1135 			     int argc, const char **argv)
1136 {
1137 	FILE *output = config->output;
1138 	int i;
1139 
1140 	fprintf(output, "\n");
1141 	fprintf(output, " Performance counter stats for ");
1142 	if (_target->bpf_str)
1143 		fprintf(output, "\'BPF program(s) %s", _target->bpf_str);
1144 	else if (_target->system_wide)
1145 		fprintf(output, "\'system wide");
1146 	else if (_target->cpu_list)
1147 		fprintf(output, "\'CPU(s) %s", _target->cpu_list);
1148 	else if (!target__has_task(_target)) {
1149 		fprintf(output, "\'%s", argv ? argv[0] : "pipe");
1150 		for (i = 1; argv && (i < argc); i++)
1151 			fprintf(output, " %s", argv[i]);
1152 	} else if (_target->pid)
1153 		fprintf(output, "process id \'%s", _target->pid);
1154 	else
1155 		fprintf(output, "thread id \'%s", _target->tid);
1156 
1157 	fprintf(output, "\'");
1158 	if (config->run_count > 1)
1159 		fprintf(output, " (%d runs)", config->run_count);
1160 	fprintf(output, ":\n\n");
1161 
1162 	if (config->metric_only)
1163 		print_metric_headers(config, evlist, false);
1164 }
1165 
1166 static void print_header_csv(struct perf_stat_config *config,
1167 			     struct target *_target __maybe_unused,
1168 			     struct evlist *evlist,
1169 			     int argc __maybe_unused,
1170 			     const char **argv __maybe_unused)
1171 {
1172 	if (config->metric_only)
1173 		print_metric_headers(config, evlist, true);
1174 }
1175 static void print_header_json(struct perf_stat_config *config,
1176 			      struct target *_target __maybe_unused,
1177 			      struct evlist *evlist,
1178 			      int argc __maybe_unused,
1179 			      const char **argv __maybe_unused)
1180 {
1181 	if (config->metric_only)
1182 		print_metric_headers(config, evlist, true);
1183 }
1184 
1185 static void print_header(struct perf_stat_config *config,
1186 			 struct target *_target,
1187 			 struct evlist *evlist,
1188 			 int argc, const char **argv)
1189 {
1190 	static int num_print_iv;
1191 
1192 	fflush(stdout);
1193 
1194 	if (config->interval_clear)
1195 		puts(CONSOLE_CLEAR);
1196 
1197 	if (num_print_iv == 0 || config->interval_clear) {
1198 		if (config->json_output)
1199 			print_header_json(config, _target, evlist, argc, argv);
1200 		else if (config->csv_output)
1201 			print_header_csv(config, _target, evlist, argc, argv);
1202 		else if (config->interval)
1203 			print_header_interval_std(config, _target, evlist, argc, argv);
1204 		else
1205 			print_header_std(config, _target, evlist, argc, argv);
1206 	}
1207 
1208 	if (num_print_iv++ == 25)
1209 		num_print_iv = 0;
1210 }
1211 
1212 static int get_precision(double num)
1213 {
1214 	if (num > 1)
1215 		return 0;
1216 
1217 	return lround(ceil(-log10(num)));
1218 }
1219 
1220 static void print_table(struct perf_stat_config *config,
1221 			FILE *output, int precision, double avg)
1222 {
1223 	char tmp[64];
1224 	int idx, indent = 0;
1225 
1226 	scnprintf(tmp, 64, " %17.*f", precision, avg);
1227 	while (tmp[indent] == ' ')
1228 		indent++;
1229 
1230 	fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1231 
1232 	for (idx = 0; idx < config->run_count; idx++) {
1233 		double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
1234 		int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1235 
1236 		fprintf(output, " %17.*f (%+.*f) ",
1237 			precision, run, precision, run - avg);
1238 
1239 		for (h = 0; h < n; h++)
1240 			fprintf(output, "#");
1241 
1242 		fprintf(output, "\n");
1243 	}
1244 
1245 	fprintf(output, "\n%*s# Final result:\n", indent, "");
1246 }
1247 
1248 static double timeval2double(struct timeval *t)
1249 {
1250 	return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1251 }
1252 
1253 static void print_footer(struct perf_stat_config *config)
1254 {
1255 	double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1256 	FILE *output = config->output;
1257 
1258 	if (config->interval || config->csv_output || config->json_output)
1259 		return;
1260 
1261 	if (!config->null_run)
1262 		fprintf(output, "\n");
1263 
1264 	if (config->run_count == 1) {
1265 		fprintf(output, " %17.9f seconds time elapsed", avg);
1266 
1267 		if (config->ru_display) {
1268 			double ru_utime = timeval2double(&config->ru_data.ru_utime);
1269 			double ru_stime = timeval2double(&config->ru_data.ru_stime);
1270 
1271 			fprintf(output, "\n\n");
1272 			fprintf(output, " %17.9f seconds user\n", ru_utime);
1273 			fprintf(output, " %17.9f seconds sys\n", ru_stime);
1274 		}
1275 	} else {
1276 		double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1277 		/*
1278 		 * Display at most 2 more significant
1279 		 * digits than the stddev inaccuracy.
1280 		 */
1281 		int precision = get_precision(sd) + 2;
1282 
1283 		if (config->walltime_run_table)
1284 			print_table(config, output, precision, avg);
1285 
1286 		fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1287 			precision, avg, precision, sd);
1288 
1289 		print_noise_pct(config, sd, avg, /*before_metric=*/false);
1290 	}
1291 	fprintf(output, "\n\n");
1292 
1293 	if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled())
1294 		fprintf(output,
1295 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1296 "	echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1297 "	perf stat ...\n"
1298 "	echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1299 
1300 	if (config->print_mixed_hw_group_error)
1301 		fprintf(output,
1302 			"The events in group usually have to be from "
1303 			"the same PMU. Try reorganizing the group.\n");
1304 }
1305 
1306 static void print_percore(struct perf_stat_config *config,
1307 			  struct evsel *counter, struct outstate *os)
1308 {
1309 	bool metric_only = config->metric_only;
1310 	FILE *output = config->output;
1311 	struct cpu_aggr_map *core_map;
1312 	int s, c, i;
1313 
1314 	if (!config->aggr_map || !config->aggr_get_id)
1315 		return;
1316 
1317 	if (config->percore_show_thread)
1318 		return print_counter(config, counter, os);
1319 
1320 	core_map = cpu_aggr_map__empty_new(config->aggr_map->nr);
1321 	if (core_map == NULL) {
1322 		fprintf(output, "Cannot allocate per-core aggr map for display\n");
1323 		return;
1324 	}
1325 
1326 	for (s = 0, c = 0; s < config->aggr_map->nr; s++) {
1327 		struct perf_cpu curr_cpu = config->aggr_map->map[s].cpu;
1328 		struct aggr_cpu_id core_id = aggr_cpu_id__core(curr_cpu, NULL);
1329 		bool found = false;
1330 
1331 		for (i = 0; i < c; i++) {
1332 			if (aggr_cpu_id__equal(&core_map->map[i], &core_id)) {
1333 				found = true;
1334 				break;
1335 			}
1336 		}
1337 		if (found)
1338 			continue;
1339 
1340 		print_counter_aggrdata(config, counter, s, os);
1341 
1342 		core_map->map[c++] = core_id;
1343 	}
1344 	free(core_map);
1345 
1346 	if (metric_only)
1347 		fputc('\n', output);
1348 }
1349 
1350 static void print_cgroup_counter(struct perf_stat_config *config, struct evlist *evlist,
1351 				 struct outstate *os)
1352 {
1353 	struct evsel *counter;
1354 
1355 	evlist__for_each_entry(evlist, counter) {
1356 		if (os->cgrp != counter->cgrp) {
1357 			if (os->cgrp != NULL)
1358 				print_metric_end(config, os);
1359 
1360 			os->cgrp = counter->cgrp;
1361 			print_metric_begin(config, evlist, os, /*aggr_idx=*/0);
1362 		}
1363 
1364 		print_counter(config, counter, os);
1365 	}
1366 	if (os->cgrp)
1367 		print_metric_end(config, os);
1368 }
1369 
1370 void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
1371 			    struct target *_target, struct timespec *ts,
1372 			    int argc, const char **argv)
1373 {
1374 	bool metric_only = config->metric_only;
1375 	int interval = config->interval;
1376 	struct evsel *counter;
1377 	char buf[64];
1378 	struct outstate os = {
1379 		.fh = config->output,
1380 		.first = true,
1381 	};
1382 
1383 	if (config->iostat_run)
1384 		evlist->selected = evlist__first(evlist);
1385 
1386 	if (interval) {
1387 		os.prefix = buf;
1388 		prepare_interval(config, buf, sizeof(buf), ts);
1389 	}
1390 
1391 	print_header(config, _target, evlist, argc, argv);
1392 
1393 	switch (config->aggr_mode) {
1394 	case AGGR_CORE:
1395 	case AGGR_DIE:
1396 	case AGGR_SOCKET:
1397 	case AGGR_NODE:
1398 		if (config->cgroup_list)
1399 			print_aggr_cgroup(config, evlist, &os);
1400 		else
1401 			print_aggr(config, evlist, &os);
1402 		break;
1403 	case AGGR_THREAD:
1404 	case AGGR_GLOBAL:
1405 		if (config->iostat_run) {
1406 			iostat_print_counters(evlist, config, ts, buf,
1407 					      (iostat_print_counter_t)print_counter, &os);
1408 		} else if (config->cgroup_list) {
1409 			print_cgroup_counter(config, evlist, &os);
1410 		} else {
1411 			print_metric_begin(config, evlist, &os, /*aggr_idx=*/0);
1412 			evlist__for_each_entry(evlist, counter) {
1413 				print_counter(config, counter, &os);
1414 			}
1415 			print_metric_end(config, &os);
1416 		}
1417 		break;
1418 	case AGGR_NONE:
1419 		if (metric_only)
1420 			print_no_aggr_metric(config, evlist, &os);
1421 		else {
1422 			evlist__for_each_entry(evlist, counter) {
1423 				if (counter->percore)
1424 					print_percore(config, counter, &os);
1425 				else
1426 					print_counter(config, counter, &os);
1427 			}
1428 		}
1429 		break;
1430 	case AGGR_MAX:
1431 	case AGGR_UNSET:
1432 	default:
1433 		break;
1434 	}
1435 
1436 	print_footer(config);
1437 
1438 	fflush(config->output);
1439 }
1440