Linux Audio

Check our new training course

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