Linux Audio

Check our new training course

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