Linux Audio

Check our new training course

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