18c2ecf20Sopenharmony_ci#include <stdlib.h>
28c2ecf20Sopenharmony_ci#include <stdio.h>
38c2ecf20Sopenharmony_ci#include <inttypes.h>
48c2ecf20Sopenharmony_ci#include <linux/string.h>
58c2ecf20Sopenharmony_ci#include <linux/time64.h>
68c2ecf20Sopenharmony_ci#include <math.h>
78c2ecf20Sopenharmony_ci#include "color.h"
88c2ecf20Sopenharmony_ci#include "counts.h"
98c2ecf20Sopenharmony_ci#include "evlist.h"
108c2ecf20Sopenharmony_ci#include "evsel.h"
118c2ecf20Sopenharmony_ci#include "stat.h"
128c2ecf20Sopenharmony_ci#include "top.h"
138c2ecf20Sopenharmony_ci#include "thread_map.h"
148c2ecf20Sopenharmony_ci#include "cpumap.h"
158c2ecf20Sopenharmony_ci#include "string2.h"
168c2ecf20Sopenharmony_ci#include <linux/ctype.h>
178c2ecf20Sopenharmony_ci#include "cgroup.h"
188c2ecf20Sopenharmony_ci#include <api/fs/fs.h>
198c2ecf20Sopenharmony_ci#include "util.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define CNTR_NOT_SUPPORTED	"<not supported>"
228c2ecf20Sopenharmony_ci#define CNTR_NOT_COUNTED	"<not counted>"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic void print_running(struct perf_stat_config *config,
258c2ecf20Sopenharmony_ci			  u64 run, u64 ena)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	if (config->csv_output) {
288c2ecf20Sopenharmony_ci		fprintf(config->output, "%s%" PRIu64 "%s%.2f",
298c2ecf20Sopenharmony_ci					config->csv_sep,
308c2ecf20Sopenharmony_ci					run,
318c2ecf20Sopenharmony_ci					config->csv_sep,
328c2ecf20Sopenharmony_ci					ena ? 100.0 * run / ena : 100.0);
338c2ecf20Sopenharmony_ci	} else if (run != ena) {
348c2ecf20Sopenharmony_ci		fprintf(config->output, "  (%.2f%%)", 100.0 * run / ena);
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic void print_noise_pct(struct perf_stat_config *config,
398c2ecf20Sopenharmony_ci			    double total, double avg)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	double pct = rel_stddev_stats(total, avg);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (config->csv_output)
448c2ecf20Sopenharmony_ci		fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
458c2ecf20Sopenharmony_ci	else if (pct)
468c2ecf20Sopenharmony_ci		fprintf(config->output, "  ( +-%6.2f%% )", pct);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void print_noise(struct perf_stat_config *config,
508c2ecf20Sopenharmony_ci			struct evsel *evsel, double avg)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct perf_stat_evsel *ps;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (config->run_count == 1)
558c2ecf20Sopenharmony_ci		return;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	ps = evsel->stats;
588c2ecf20Sopenharmony_ci	print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void print_cgroup(struct perf_stat_config *config, struct evsel *evsel)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	if (nr_cgroups) {
648c2ecf20Sopenharmony_ci		const char *cgrp_name = evsel->cgrp ? evsel->cgrp->name  : "";
658c2ecf20Sopenharmony_ci		fprintf(config->output, "%s%s", config->csv_sep, cgrp_name);
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void aggr_printout(struct perf_stat_config *config,
718c2ecf20Sopenharmony_ci			  struct evsel *evsel, int id, int nr)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	switch (config->aggr_mode) {
748c2ecf20Sopenharmony_ci	case AGGR_CORE:
758c2ecf20Sopenharmony_ci		fprintf(config->output, "S%d-D%d-C%*d%s%*d%s",
768c2ecf20Sopenharmony_ci			cpu_map__id_to_socket(id),
778c2ecf20Sopenharmony_ci			cpu_map__id_to_die(id),
788c2ecf20Sopenharmony_ci			config->csv_output ? 0 : -8,
798c2ecf20Sopenharmony_ci			cpu_map__id_to_cpu(id),
808c2ecf20Sopenharmony_ci			config->csv_sep,
818c2ecf20Sopenharmony_ci			config->csv_output ? 0 : 4,
828c2ecf20Sopenharmony_ci			nr,
838c2ecf20Sopenharmony_ci			config->csv_sep);
848c2ecf20Sopenharmony_ci		break;
858c2ecf20Sopenharmony_ci	case AGGR_DIE:
868c2ecf20Sopenharmony_ci		fprintf(config->output, "S%d-D%*d%s%*d%s",
878c2ecf20Sopenharmony_ci			cpu_map__id_to_socket(id << 16),
888c2ecf20Sopenharmony_ci			config->csv_output ? 0 : -8,
898c2ecf20Sopenharmony_ci			cpu_map__id_to_die(id << 16),
908c2ecf20Sopenharmony_ci			config->csv_sep,
918c2ecf20Sopenharmony_ci			config->csv_output ? 0 : 4,
928c2ecf20Sopenharmony_ci			nr,
938c2ecf20Sopenharmony_ci			config->csv_sep);
948c2ecf20Sopenharmony_ci		break;
958c2ecf20Sopenharmony_ci	case AGGR_SOCKET:
968c2ecf20Sopenharmony_ci		fprintf(config->output, "S%*d%s%*d%s",
978c2ecf20Sopenharmony_ci			config->csv_output ? 0 : -5,
988c2ecf20Sopenharmony_ci			id,
998c2ecf20Sopenharmony_ci			config->csv_sep,
1008c2ecf20Sopenharmony_ci			config->csv_output ? 0 : 4,
1018c2ecf20Sopenharmony_ci			nr,
1028c2ecf20Sopenharmony_ci			config->csv_sep);
1038c2ecf20Sopenharmony_ci			break;
1048c2ecf20Sopenharmony_ci	case AGGR_NODE:
1058c2ecf20Sopenharmony_ci		fprintf(config->output, "N%*d%s%*d%s",
1068c2ecf20Sopenharmony_ci			config->csv_output ? 0 : -5,
1078c2ecf20Sopenharmony_ci			id,
1088c2ecf20Sopenharmony_ci			config->csv_sep,
1098c2ecf20Sopenharmony_ci			config->csv_output ? 0 : 4,
1108c2ecf20Sopenharmony_ci			nr,
1118c2ecf20Sopenharmony_ci			config->csv_sep);
1128c2ecf20Sopenharmony_ci			break;
1138c2ecf20Sopenharmony_ci	case AGGR_NONE:
1148c2ecf20Sopenharmony_ci		if (evsel->percore && !config->percore_show_thread) {
1158c2ecf20Sopenharmony_ci			fprintf(config->output, "S%d-D%d-C%*d%s",
1168c2ecf20Sopenharmony_ci				cpu_map__id_to_socket(id),
1178c2ecf20Sopenharmony_ci				cpu_map__id_to_die(id),
1188c2ecf20Sopenharmony_ci				config->csv_output ? 0 : -3,
1198c2ecf20Sopenharmony_ci				cpu_map__id_to_cpu(id), config->csv_sep);
1208c2ecf20Sopenharmony_ci		} else if (id > -1) {
1218c2ecf20Sopenharmony_ci			fprintf(config->output, "CPU%*d%s",
1228c2ecf20Sopenharmony_ci				config->csv_output ? 0 : -7,
1238c2ecf20Sopenharmony_ci				evsel__cpus(evsel)->map[id],
1248c2ecf20Sopenharmony_ci				config->csv_sep);
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	case AGGR_THREAD:
1288c2ecf20Sopenharmony_ci		fprintf(config->output, "%*s-%*d%s",
1298c2ecf20Sopenharmony_ci			config->csv_output ? 0 : 16,
1308c2ecf20Sopenharmony_ci			perf_thread_map__comm(evsel->core.threads, id),
1318c2ecf20Sopenharmony_ci			config->csv_output ? 0 : -8,
1328c2ecf20Sopenharmony_ci			perf_thread_map__pid(evsel->core.threads, id),
1338c2ecf20Sopenharmony_ci			config->csv_sep);
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	case AGGR_GLOBAL:
1368c2ecf20Sopenharmony_ci	case AGGR_UNSET:
1378c2ecf20Sopenharmony_ci	default:
1388c2ecf20Sopenharmony_ci		break;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistruct outstate {
1438c2ecf20Sopenharmony_ci	FILE *fh;
1448c2ecf20Sopenharmony_ci	bool newline;
1458c2ecf20Sopenharmony_ci	const char *prefix;
1468c2ecf20Sopenharmony_ci	int  nfields;
1478c2ecf20Sopenharmony_ci	int  id, nr;
1488c2ecf20Sopenharmony_ci	struct evsel *evsel;
1498c2ecf20Sopenharmony_ci};
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define METRIC_LEN  35
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic void new_line_std(struct perf_stat_config *config __maybe_unused,
1548c2ecf20Sopenharmony_ci			 void *ctx)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	os->newline = true;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void do_new_line_std(struct perf_stat_config *config,
1628c2ecf20Sopenharmony_ci			    struct outstate *os)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	fputc('\n', os->fh);
1658c2ecf20Sopenharmony_ci	fputs(os->prefix, os->fh);
1668c2ecf20Sopenharmony_ci	aggr_printout(config, os->evsel, os->id, os->nr);
1678c2ecf20Sopenharmony_ci	if (config->aggr_mode == AGGR_NONE)
1688c2ecf20Sopenharmony_ci		fprintf(os->fh, "        ");
1698c2ecf20Sopenharmony_ci	fprintf(os->fh, "                                                 ");
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic void print_metric_std(struct perf_stat_config *config,
1738c2ecf20Sopenharmony_ci			     void *ctx, const char *color, const char *fmt,
1748c2ecf20Sopenharmony_ci			     const char *unit, double val)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
1778c2ecf20Sopenharmony_ci	FILE *out = os->fh;
1788c2ecf20Sopenharmony_ci	int n;
1798c2ecf20Sopenharmony_ci	bool newline = os->newline;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	os->newline = false;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (unit == NULL || fmt == NULL) {
1848c2ecf20Sopenharmony_ci		fprintf(out, "%-*s", METRIC_LEN, "");
1858c2ecf20Sopenharmony_ci		return;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (newline)
1898c2ecf20Sopenharmony_ci		do_new_line_std(config, os);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	n = fprintf(out, " # ");
1928c2ecf20Sopenharmony_ci	if (color)
1938c2ecf20Sopenharmony_ci		n += color_fprintf(out, color, fmt, val);
1948c2ecf20Sopenharmony_ci	else
1958c2ecf20Sopenharmony_ci		n += fprintf(out, fmt, val);
1968c2ecf20Sopenharmony_ci	fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void new_line_csv(struct perf_stat_config *config, void *ctx)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
2028c2ecf20Sopenharmony_ci	int i;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	fputc('\n', os->fh);
2058c2ecf20Sopenharmony_ci	if (os->prefix)
2068c2ecf20Sopenharmony_ci		fprintf(os->fh, "%s", os->prefix);
2078c2ecf20Sopenharmony_ci	aggr_printout(config, os->evsel, os->id, os->nr);
2088c2ecf20Sopenharmony_ci	for (i = 0; i < os->nfields; i++)
2098c2ecf20Sopenharmony_ci		fputs(config->csv_sep, os->fh);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void print_metric_csv(struct perf_stat_config *config __maybe_unused,
2138c2ecf20Sopenharmony_ci			     void *ctx,
2148c2ecf20Sopenharmony_ci			     const char *color __maybe_unused,
2158c2ecf20Sopenharmony_ci			     const char *fmt, const char *unit, double val)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
2188c2ecf20Sopenharmony_ci	FILE *out = os->fh;
2198c2ecf20Sopenharmony_ci	char buf[64], *vals, *ends;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (unit == NULL || fmt == NULL) {
2228c2ecf20Sopenharmony_ci		fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
2238c2ecf20Sopenharmony_ci		return;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf), fmt, val);
2268c2ecf20Sopenharmony_ci	ends = vals = skip_spaces(buf);
2278c2ecf20Sopenharmony_ci	while (isdigit(*ends) || *ends == '.')
2288c2ecf20Sopenharmony_ci		ends++;
2298c2ecf20Sopenharmony_ci	*ends = 0;
2308c2ecf20Sopenharmony_ci	fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/* Filter out some columns that don't work well in metrics only mode */
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic bool valid_only_metric(const char *unit)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	if (!unit)
2388c2ecf20Sopenharmony_ci		return false;
2398c2ecf20Sopenharmony_ci	if (strstr(unit, "/sec") ||
2408c2ecf20Sopenharmony_ci	    strstr(unit, "CPUs utilized"))
2418c2ecf20Sopenharmony_ci		return false;
2428c2ecf20Sopenharmony_ci	return true;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic const char *fixunit(char *buf, struct evsel *evsel,
2468c2ecf20Sopenharmony_ci			   const char *unit)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	if (!strncmp(unit, "of all", 6)) {
2498c2ecf20Sopenharmony_ci		snprintf(buf, 1024, "%s %s", evsel__name(evsel),
2508c2ecf20Sopenharmony_ci			 unit);
2518c2ecf20Sopenharmony_ci		return buf;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci	return unit;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic void print_metric_only(struct perf_stat_config *config,
2578c2ecf20Sopenharmony_ci			      void *ctx, const char *color, const char *fmt,
2588c2ecf20Sopenharmony_ci			      const char *unit, double val)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
2618c2ecf20Sopenharmony_ci	FILE *out = os->fh;
2628c2ecf20Sopenharmony_ci	char buf[1024], str[1024];
2638c2ecf20Sopenharmony_ci	unsigned mlen = config->metric_only_len;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (!valid_only_metric(unit))
2668c2ecf20Sopenharmony_ci		return;
2678c2ecf20Sopenharmony_ci	unit = fixunit(buf, os->evsel, unit);
2688c2ecf20Sopenharmony_ci	if (mlen < strlen(unit))
2698c2ecf20Sopenharmony_ci		mlen = strlen(unit) + 1;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (color)
2728c2ecf20Sopenharmony_ci		mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	color_snprintf(str, sizeof(str), color ?: "", fmt, val);
2758c2ecf20Sopenharmony_ci	fprintf(out, "%*s ", mlen, str);
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
2798c2ecf20Sopenharmony_ci				  void *ctx, const char *color __maybe_unused,
2808c2ecf20Sopenharmony_ci				  const char *fmt,
2818c2ecf20Sopenharmony_ci				  const char *unit, double val)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
2848c2ecf20Sopenharmony_ci	FILE *out = os->fh;
2858c2ecf20Sopenharmony_ci	char buf[64], *vals, *ends;
2868c2ecf20Sopenharmony_ci	char tbuf[1024];
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!valid_only_metric(unit))
2898c2ecf20Sopenharmony_ci		return;
2908c2ecf20Sopenharmony_ci	unit = fixunit(tbuf, os->evsel, unit);
2918c2ecf20Sopenharmony_ci	snprintf(buf, sizeof buf, fmt, val);
2928c2ecf20Sopenharmony_ci	ends = vals = skip_spaces(buf);
2938c2ecf20Sopenharmony_ci	while (isdigit(*ends) || *ends == '.')
2948c2ecf20Sopenharmony_ci		ends++;
2958c2ecf20Sopenharmony_ci	*ends = 0;
2968c2ecf20Sopenharmony_ci	fprintf(out, "%s%s", vals, config->csv_sep);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void new_line_metric(struct perf_stat_config *config __maybe_unused,
3008c2ecf20Sopenharmony_ci			    void *ctx __maybe_unused)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void print_metric_header(struct perf_stat_config *config,
3058c2ecf20Sopenharmony_ci				void *ctx, const char *color __maybe_unused,
3068c2ecf20Sopenharmony_ci				const char *fmt __maybe_unused,
3078c2ecf20Sopenharmony_ci				const char *unit, double val __maybe_unused)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct outstate *os = ctx;
3108c2ecf20Sopenharmony_ci	char tbuf[1024];
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (!valid_only_metric(unit))
3138c2ecf20Sopenharmony_ci		return;
3148c2ecf20Sopenharmony_ci	unit = fixunit(tbuf, os->evsel, unit);
3158c2ecf20Sopenharmony_ci	if (config->csv_output)
3168c2ecf20Sopenharmony_ci		fprintf(os->fh, "%s%s", unit, config->csv_sep);
3178c2ecf20Sopenharmony_ci	else
3188c2ecf20Sopenharmony_ci		fprintf(os->fh, "%*s ", config->metric_only_len, unit);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int first_shadow_cpu(struct perf_stat_config *config,
3228c2ecf20Sopenharmony_ci			    struct evsel *evsel, int id)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct evlist *evlist = evsel->evlist;
3258c2ecf20Sopenharmony_ci	int i;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (config->aggr_mode == AGGR_NONE)
3288c2ecf20Sopenharmony_ci		return id;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (!config->aggr_get_id)
3318c2ecf20Sopenharmony_ci		return 0;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	for (i = 0; i < evsel__nr_cpus(evsel); i++) {
3348c2ecf20Sopenharmony_ci		int cpu2 = evsel__cpus(evsel)->map[i];
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		if (config->aggr_get_id(config, evlist->core.cpus, cpu2) == id)
3378c2ecf20Sopenharmony_ci			return cpu2;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic void abs_printout(struct perf_stat_config *config,
3438c2ecf20Sopenharmony_ci			 int id, int nr, struct evsel *evsel, double avg)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	FILE *output = config->output;
3468c2ecf20Sopenharmony_ci	double sc =  evsel->scale;
3478c2ecf20Sopenharmony_ci	const char *fmt;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (config->csv_output) {
3508c2ecf20Sopenharmony_ci		fmt = floor(sc) != sc ?  "%.2f%s" : "%.0f%s";
3518c2ecf20Sopenharmony_ci	} else {
3528c2ecf20Sopenharmony_ci		if (config->big_num)
3538c2ecf20Sopenharmony_ci			fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s";
3548c2ecf20Sopenharmony_ci		else
3558c2ecf20Sopenharmony_ci			fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s";
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	aggr_printout(config, evsel, id, nr);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	fprintf(output, fmt, avg, config->csv_sep);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (evsel->unit)
3638c2ecf20Sopenharmony_ci		fprintf(output, "%-*s%s",
3648c2ecf20Sopenharmony_ci			config->csv_output ? 0 : config->unit_width,
3658c2ecf20Sopenharmony_ci			evsel->unit, config->csv_sep);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	fprintf(output, "%-*s", config->csv_output ? 0 : 25, evsel__name(evsel));
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	print_cgroup(config, evsel);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic bool is_mixed_hw_group(struct evsel *counter)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct evlist *evlist = counter->evlist;
3758c2ecf20Sopenharmony_ci	u32 pmu_type = counter->core.attr.type;
3768c2ecf20Sopenharmony_ci	struct evsel *pos;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (counter->core.nr_members < 2)
3798c2ecf20Sopenharmony_ci		return false;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
3828c2ecf20Sopenharmony_ci		/* software events can be part of any hardware group */
3838c2ecf20Sopenharmony_ci		if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
3848c2ecf20Sopenharmony_ci			continue;
3858c2ecf20Sopenharmony_ci		if (pmu_type == PERF_TYPE_SOFTWARE) {
3868c2ecf20Sopenharmony_ci			pmu_type = pos->core.attr.type;
3878c2ecf20Sopenharmony_ci			continue;
3888c2ecf20Sopenharmony_ci		}
3898c2ecf20Sopenharmony_ci		if (pmu_type != pos->core.attr.type)
3908c2ecf20Sopenharmony_ci			return true;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return false;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic void printout(struct perf_stat_config *config, int id, int nr,
3978c2ecf20Sopenharmony_ci		     struct evsel *counter, double uval,
3988c2ecf20Sopenharmony_ci		     char *prefix, u64 run, u64 ena, double noise,
3998c2ecf20Sopenharmony_ci		     struct runtime_stat *st)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct perf_stat_output_ctx out;
4028c2ecf20Sopenharmony_ci	struct outstate os = {
4038c2ecf20Sopenharmony_ci		.fh = config->output,
4048c2ecf20Sopenharmony_ci		.prefix = prefix ? prefix : "",
4058c2ecf20Sopenharmony_ci		.id = id,
4068c2ecf20Sopenharmony_ci		.nr = nr,
4078c2ecf20Sopenharmony_ci		.evsel = counter,
4088c2ecf20Sopenharmony_ci	};
4098c2ecf20Sopenharmony_ci	print_metric_t pm = print_metric_std;
4108c2ecf20Sopenharmony_ci	new_line_t nl;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (config->metric_only) {
4138c2ecf20Sopenharmony_ci		nl = new_line_metric;
4148c2ecf20Sopenharmony_ci		if (config->csv_output)
4158c2ecf20Sopenharmony_ci			pm = print_metric_only_csv;
4168c2ecf20Sopenharmony_ci		else
4178c2ecf20Sopenharmony_ci			pm = print_metric_only;
4188c2ecf20Sopenharmony_ci	} else
4198c2ecf20Sopenharmony_ci		nl = new_line_std;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (config->csv_output && !config->metric_only) {
4228c2ecf20Sopenharmony_ci		static int aggr_fields[] = {
4238c2ecf20Sopenharmony_ci			[AGGR_GLOBAL] = 0,
4248c2ecf20Sopenharmony_ci			[AGGR_THREAD] = 1,
4258c2ecf20Sopenharmony_ci			[AGGR_NONE] = 1,
4268c2ecf20Sopenharmony_ci			[AGGR_SOCKET] = 2,
4278c2ecf20Sopenharmony_ci			[AGGR_DIE] = 2,
4288c2ecf20Sopenharmony_ci			[AGGR_CORE] = 2,
4298c2ecf20Sopenharmony_ci		};
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		pm = print_metric_csv;
4328c2ecf20Sopenharmony_ci		nl = new_line_csv;
4338c2ecf20Sopenharmony_ci		os.nfields = 3;
4348c2ecf20Sopenharmony_ci		os.nfields += aggr_fields[config->aggr_mode];
4358c2ecf20Sopenharmony_ci		if (counter->cgrp)
4368c2ecf20Sopenharmony_ci			os.nfields++;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci	if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
4398c2ecf20Sopenharmony_ci		if (config->metric_only) {
4408c2ecf20Sopenharmony_ci			pm(config, &os, NULL, "", "", 0);
4418c2ecf20Sopenharmony_ci			return;
4428c2ecf20Sopenharmony_ci		}
4438c2ecf20Sopenharmony_ci		aggr_printout(config, counter, id, nr);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		fprintf(config->output, "%*s%s",
4468c2ecf20Sopenharmony_ci			config->csv_output ? 0 : 18,
4478c2ecf20Sopenharmony_ci			counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
4488c2ecf20Sopenharmony_ci			config->csv_sep);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		if (counter->supported) {
4518c2ecf20Sopenharmony_ci			config->print_free_counters_hint = 1;
4528c2ecf20Sopenharmony_ci			if (is_mixed_hw_group(counter))
4538c2ecf20Sopenharmony_ci				config->print_mixed_hw_group_error = 1;
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		fprintf(config->output, "%-*s%s",
4578c2ecf20Sopenharmony_ci			config->csv_output ? 0 : config->unit_width,
4588c2ecf20Sopenharmony_ci			counter->unit, config->csv_sep);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		fprintf(config->output, "%*s",
4618c2ecf20Sopenharmony_ci			config->csv_output ? 0 : -25, evsel__name(counter));
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		print_cgroup(config, counter);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (!config->csv_output)
4668c2ecf20Sopenharmony_ci			pm(config, &os, NULL, NULL, "", 0);
4678c2ecf20Sopenharmony_ci		print_noise(config, counter, noise);
4688c2ecf20Sopenharmony_ci		print_running(config, run, ena);
4698c2ecf20Sopenharmony_ci		if (config->csv_output)
4708c2ecf20Sopenharmony_ci			pm(config, &os, NULL, NULL, "", 0);
4718c2ecf20Sopenharmony_ci		return;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (!config->metric_only)
4758c2ecf20Sopenharmony_ci		abs_printout(config, id, nr, counter, uval);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	out.print_metric = pm;
4788c2ecf20Sopenharmony_ci	out.new_line = nl;
4798c2ecf20Sopenharmony_ci	out.ctx = &os;
4808c2ecf20Sopenharmony_ci	out.force_header = false;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	if (config->csv_output && !config->metric_only) {
4838c2ecf20Sopenharmony_ci		print_noise(config, counter, noise);
4848c2ecf20Sopenharmony_ci		print_running(config, run, ena);
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	perf_stat__print_shadow_stats(config, counter, uval,
4888c2ecf20Sopenharmony_ci				first_shadow_cpu(config, counter, id),
4898c2ecf20Sopenharmony_ci				&out, &config->metric_events, st);
4908c2ecf20Sopenharmony_ci	if (!config->csv_output && !config->metric_only) {
4918c2ecf20Sopenharmony_ci		print_noise(config, counter, noise);
4928c2ecf20Sopenharmony_ci		print_running(config, run, ena);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic void aggr_update_shadow(struct perf_stat_config *config,
4978c2ecf20Sopenharmony_ci			       struct evlist *evlist)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	int cpu, s2, id, s;
5008c2ecf20Sopenharmony_ci	u64 val;
5018c2ecf20Sopenharmony_ci	struct evsel *counter;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	for (s = 0; s < config->aggr_map->nr; s++) {
5048c2ecf20Sopenharmony_ci		id = config->aggr_map->map[s];
5058c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, counter) {
5068c2ecf20Sopenharmony_ci			val = 0;
5078c2ecf20Sopenharmony_ci			for (cpu = 0; cpu < evsel__nr_cpus(counter); cpu++) {
5088c2ecf20Sopenharmony_ci				s2 = config->aggr_get_id(config, evlist->core.cpus, cpu);
5098c2ecf20Sopenharmony_ci				if (s2 != id)
5108c2ecf20Sopenharmony_ci					continue;
5118c2ecf20Sopenharmony_ci				val += perf_counts(counter->counts, cpu, 0)->val;
5128c2ecf20Sopenharmony_ci			}
5138c2ecf20Sopenharmony_ci			perf_stat__update_shadow_stats(counter, val,
5148c2ecf20Sopenharmony_ci					first_shadow_cpu(config, counter, id),
5158c2ecf20Sopenharmony_ci					&rt_stat);
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic void uniquify_event_name(struct evsel *counter)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	char *new_name;
5238c2ecf20Sopenharmony_ci	char *config;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (counter->uniquified_name ||
5268c2ecf20Sopenharmony_ci	    !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
5278c2ecf20Sopenharmony_ci					   strlen(counter->pmu_name)))
5288c2ecf20Sopenharmony_ci		return;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	config = strchr(counter->name, '/');
5318c2ecf20Sopenharmony_ci	if (config) {
5328c2ecf20Sopenharmony_ci		if (asprintf(&new_name,
5338c2ecf20Sopenharmony_ci			     "%s%s", counter->pmu_name, config) > 0) {
5348c2ecf20Sopenharmony_ci			free(counter->name);
5358c2ecf20Sopenharmony_ci			counter->name = new_name;
5368c2ecf20Sopenharmony_ci		}
5378c2ecf20Sopenharmony_ci	} else {
5388c2ecf20Sopenharmony_ci		if (asprintf(&new_name,
5398c2ecf20Sopenharmony_ci			     "%s [%s]", counter->name, counter->pmu_name) > 0) {
5408c2ecf20Sopenharmony_ci			free(counter->name);
5418c2ecf20Sopenharmony_ci			counter->name = new_name;
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	counter->uniquified_name = true;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic void collect_all_aliases(struct perf_stat_config *config, struct evsel *counter,
5498c2ecf20Sopenharmony_ci			    void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
5508c2ecf20Sopenharmony_ci				       bool first),
5518c2ecf20Sopenharmony_ci			    void *data)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct evlist *evlist = counter->evlist;
5548c2ecf20Sopenharmony_ci	struct evsel *alias;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	alias = list_prepare_entry(counter, &(evlist->core.entries), core.node);
5578c2ecf20Sopenharmony_ci	list_for_each_entry_continue (alias, &evlist->core.entries, core.node) {
5588c2ecf20Sopenharmony_ci		/* Merge events with the same name, etc. but on different PMUs. */
5598c2ecf20Sopenharmony_ci		if (!strcmp(evsel__name(alias), evsel__name(counter)) &&
5608c2ecf20Sopenharmony_ci			alias->scale == counter->scale &&
5618c2ecf20Sopenharmony_ci			alias->cgrp == counter->cgrp &&
5628c2ecf20Sopenharmony_ci			!strcmp(alias->unit, counter->unit) &&
5638c2ecf20Sopenharmony_ci			evsel__is_clock(alias) == evsel__is_clock(counter) &&
5648c2ecf20Sopenharmony_ci			strcmp(alias->pmu_name, counter->pmu_name)) {
5658c2ecf20Sopenharmony_ci			alias->merged_stat = true;
5668c2ecf20Sopenharmony_ci			cb(config, alias, data, false);
5678c2ecf20Sopenharmony_ci		}
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic bool collect_data(struct perf_stat_config *config, struct evsel *counter,
5728c2ecf20Sopenharmony_ci			    void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
5738c2ecf20Sopenharmony_ci				       bool first),
5748c2ecf20Sopenharmony_ci			    void *data)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	if (counter->merged_stat)
5778c2ecf20Sopenharmony_ci		return false;
5788c2ecf20Sopenharmony_ci	cb(config, counter, data, true);
5798c2ecf20Sopenharmony_ci	if (config->no_merge)
5808c2ecf20Sopenharmony_ci		uniquify_event_name(counter);
5818c2ecf20Sopenharmony_ci	else if (counter->auto_merge_stats)
5828c2ecf20Sopenharmony_ci		collect_all_aliases(config, counter, cb, data);
5838c2ecf20Sopenharmony_ci	return true;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistruct aggr_data {
5878c2ecf20Sopenharmony_ci	u64 ena, run, val;
5888c2ecf20Sopenharmony_ci	int id;
5898c2ecf20Sopenharmony_ci	int nr;
5908c2ecf20Sopenharmony_ci	int cpu;
5918c2ecf20Sopenharmony_ci};
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic void aggr_cb(struct perf_stat_config *config,
5948c2ecf20Sopenharmony_ci		    struct evsel *counter, void *data, bool first)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct aggr_data *ad = data;
5978c2ecf20Sopenharmony_ci	int cpu, s2;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	for (cpu = 0; cpu < evsel__nr_cpus(counter); cpu++) {
6008c2ecf20Sopenharmony_ci		struct perf_counts_values *counts;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		s2 = config->aggr_get_id(config, evsel__cpus(counter), cpu);
6038c2ecf20Sopenharmony_ci		if (s2 != ad->id)
6048c2ecf20Sopenharmony_ci			continue;
6058c2ecf20Sopenharmony_ci		if (first)
6068c2ecf20Sopenharmony_ci			ad->nr++;
6078c2ecf20Sopenharmony_ci		counts = perf_counts(counter->counts, cpu, 0);
6088c2ecf20Sopenharmony_ci		/*
6098c2ecf20Sopenharmony_ci		 * When any result is bad, make them all to give
6108c2ecf20Sopenharmony_ci		 * consistent output in interval mode.
6118c2ecf20Sopenharmony_ci		 */
6128c2ecf20Sopenharmony_ci		if (counts->ena == 0 || counts->run == 0 ||
6138c2ecf20Sopenharmony_ci		    counter->counts->scaled == -1) {
6148c2ecf20Sopenharmony_ci			ad->ena = 0;
6158c2ecf20Sopenharmony_ci			ad->run = 0;
6168c2ecf20Sopenharmony_ci			break;
6178c2ecf20Sopenharmony_ci		}
6188c2ecf20Sopenharmony_ci		ad->val += counts->val;
6198c2ecf20Sopenharmony_ci		ad->ena += counts->ena;
6208c2ecf20Sopenharmony_ci		ad->run += counts->run;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic void print_counter_aggrdata(struct perf_stat_config *config,
6258c2ecf20Sopenharmony_ci				   struct evsel *counter, int s,
6268c2ecf20Sopenharmony_ci				   char *prefix, bool metric_only,
6278c2ecf20Sopenharmony_ci				   bool *first, int cpu)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	struct aggr_data ad;
6308c2ecf20Sopenharmony_ci	FILE *output = config->output;
6318c2ecf20Sopenharmony_ci	u64 ena, run, val;
6328c2ecf20Sopenharmony_ci	int id, nr;
6338c2ecf20Sopenharmony_ci	double uval;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	ad.id = id = config->aggr_map->map[s];
6368c2ecf20Sopenharmony_ci	ad.val = ad.ena = ad.run = 0;
6378c2ecf20Sopenharmony_ci	ad.nr = 0;
6388c2ecf20Sopenharmony_ci	if (!collect_data(config, counter, aggr_cb, &ad))
6398c2ecf20Sopenharmony_ci		return;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	nr = ad.nr;
6428c2ecf20Sopenharmony_ci	ena = ad.ena;
6438c2ecf20Sopenharmony_ci	run = ad.run;
6448c2ecf20Sopenharmony_ci	val = ad.val;
6458c2ecf20Sopenharmony_ci	if (*first && metric_only) {
6468c2ecf20Sopenharmony_ci		*first = false;
6478c2ecf20Sopenharmony_ci		aggr_printout(config, counter, id, nr);
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci	if (prefix && !metric_only)
6508c2ecf20Sopenharmony_ci		fprintf(output, "%s", prefix);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	uval = val * counter->scale;
6538c2ecf20Sopenharmony_ci	printout(config, cpu != -1 ? cpu : id, nr, counter, uval, prefix,
6548c2ecf20Sopenharmony_ci		 run, ena, 1.0, &rt_stat);
6558c2ecf20Sopenharmony_ci	if (!metric_only)
6568c2ecf20Sopenharmony_ci		fputc('\n', output);
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic void print_aggr(struct perf_stat_config *config,
6608c2ecf20Sopenharmony_ci		       struct evlist *evlist,
6618c2ecf20Sopenharmony_ci		       char *prefix)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	bool metric_only = config->metric_only;
6648c2ecf20Sopenharmony_ci	FILE *output = config->output;
6658c2ecf20Sopenharmony_ci	struct evsel *counter;
6668c2ecf20Sopenharmony_ci	int s;
6678c2ecf20Sopenharmony_ci	bool first;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (!config->aggr_map || !config->aggr_get_id)
6708c2ecf20Sopenharmony_ci		return;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	aggr_update_shadow(config, evlist);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	/*
6758c2ecf20Sopenharmony_ci	 * With metric_only everything is on a single line.
6768c2ecf20Sopenharmony_ci	 * Without each counter has its own line.
6778c2ecf20Sopenharmony_ci	 */
6788c2ecf20Sopenharmony_ci	for (s = 0; s < config->aggr_map->nr; s++) {
6798c2ecf20Sopenharmony_ci		if (prefix && metric_only)
6808c2ecf20Sopenharmony_ci			fprintf(output, "%s", prefix);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci		first = true;
6838c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, counter) {
6848c2ecf20Sopenharmony_ci			print_counter_aggrdata(config, counter, s,
6858c2ecf20Sopenharmony_ci					       prefix, metric_only,
6868c2ecf20Sopenharmony_ci					       &first, -1);
6878c2ecf20Sopenharmony_ci		}
6888c2ecf20Sopenharmony_ci		if (metric_only)
6898c2ecf20Sopenharmony_ci			fputc('\n', output);
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cistatic int cmp_val(const void *a, const void *b)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	return ((struct perf_aggr_thread_value *)b)->val -
6968c2ecf20Sopenharmony_ci		((struct perf_aggr_thread_value *)a)->val;
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic struct perf_aggr_thread_value *sort_aggr_thread(
7008c2ecf20Sopenharmony_ci					struct evsel *counter,
7018c2ecf20Sopenharmony_ci					int nthreads, int ncpus,
7028c2ecf20Sopenharmony_ci					int *ret,
7038c2ecf20Sopenharmony_ci					struct target *_target)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	int cpu, thread, i = 0;
7068c2ecf20Sopenharmony_ci	double uval;
7078c2ecf20Sopenharmony_ci	struct perf_aggr_thread_value *buf;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
7108c2ecf20Sopenharmony_ci	if (!buf)
7118c2ecf20Sopenharmony_ci		return NULL;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	for (thread = 0; thread < nthreads; thread++) {
7148c2ecf20Sopenharmony_ci		u64 ena = 0, run = 0, val = 0;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		for (cpu = 0; cpu < ncpus; cpu++) {
7178c2ecf20Sopenharmony_ci			val += perf_counts(counter->counts, cpu, thread)->val;
7188c2ecf20Sopenharmony_ci			ena += perf_counts(counter->counts, cpu, thread)->ena;
7198c2ecf20Sopenharmony_ci			run += perf_counts(counter->counts, cpu, thread)->run;
7208c2ecf20Sopenharmony_ci		}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci		uval = val * counter->scale;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		/*
7258c2ecf20Sopenharmony_ci		 * Skip value 0 when enabling --per-thread globally,
7268c2ecf20Sopenharmony_ci		 * otherwise too many 0 output.
7278c2ecf20Sopenharmony_ci		 */
7288c2ecf20Sopenharmony_ci		if (uval == 0.0 && target__has_per_thread(_target))
7298c2ecf20Sopenharmony_ci			continue;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		buf[i].counter = counter;
7328c2ecf20Sopenharmony_ci		buf[i].id = thread;
7338c2ecf20Sopenharmony_ci		buf[i].uval = uval;
7348c2ecf20Sopenharmony_ci		buf[i].val = val;
7358c2ecf20Sopenharmony_ci		buf[i].run = run;
7368c2ecf20Sopenharmony_ci		buf[i].ena = ena;
7378c2ecf20Sopenharmony_ci		i++;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (ret)
7438c2ecf20Sopenharmony_ci		*ret = i;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	return buf;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic void print_aggr_thread(struct perf_stat_config *config,
7498c2ecf20Sopenharmony_ci			      struct target *_target,
7508c2ecf20Sopenharmony_ci			      struct evsel *counter, char *prefix)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	FILE *output = config->output;
7538c2ecf20Sopenharmony_ci	int nthreads = perf_thread_map__nr(counter->core.threads);
7548c2ecf20Sopenharmony_ci	int ncpus = perf_cpu_map__nr(counter->core.cpus);
7558c2ecf20Sopenharmony_ci	int thread, sorted_threads, id;
7568c2ecf20Sopenharmony_ci	struct perf_aggr_thread_value *buf;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	buf = sort_aggr_thread(counter, nthreads, ncpus, &sorted_threads, _target);
7598c2ecf20Sopenharmony_ci	if (!buf) {
7608c2ecf20Sopenharmony_ci		perror("cannot sort aggr thread");
7618c2ecf20Sopenharmony_ci		return;
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	for (thread = 0; thread < sorted_threads; thread++) {
7658c2ecf20Sopenharmony_ci		if (prefix)
7668c2ecf20Sopenharmony_ci			fprintf(output, "%s", prefix);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		id = buf[thread].id;
7698c2ecf20Sopenharmony_ci		if (config->stats)
7708c2ecf20Sopenharmony_ci			printout(config, id, 0, buf[thread].counter, buf[thread].uval,
7718c2ecf20Sopenharmony_ci				 prefix, buf[thread].run, buf[thread].ena, 1.0,
7728c2ecf20Sopenharmony_ci				 &config->stats[id]);
7738c2ecf20Sopenharmony_ci		else
7748c2ecf20Sopenharmony_ci			printout(config, id, 0, buf[thread].counter, buf[thread].uval,
7758c2ecf20Sopenharmony_ci				 prefix, buf[thread].run, buf[thread].ena, 1.0,
7768c2ecf20Sopenharmony_ci				 &rt_stat);
7778c2ecf20Sopenharmony_ci		fputc('\n', output);
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	free(buf);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistruct caggr_data {
7848c2ecf20Sopenharmony_ci	double avg, avg_enabled, avg_running;
7858c2ecf20Sopenharmony_ci};
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic void counter_aggr_cb(struct perf_stat_config *config __maybe_unused,
7888c2ecf20Sopenharmony_ci			    struct evsel *counter, void *data,
7898c2ecf20Sopenharmony_ci			    bool first __maybe_unused)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	struct caggr_data *cd = data;
7928c2ecf20Sopenharmony_ci	struct perf_stat_evsel *ps = counter->stats;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	cd->avg += avg_stats(&ps->res_stats[0]);
7958c2ecf20Sopenharmony_ci	cd->avg_enabled += avg_stats(&ps->res_stats[1]);
7968c2ecf20Sopenharmony_ci	cd->avg_running += avg_stats(&ps->res_stats[2]);
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci/*
8008c2ecf20Sopenharmony_ci * Print out the results of a single counter:
8018c2ecf20Sopenharmony_ci * aggregated counts in system-wide mode
8028c2ecf20Sopenharmony_ci */
8038c2ecf20Sopenharmony_cistatic void print_counter_aggr(struct perf_stat_config *config,
8048c2ecf20Sopenharmony_ci			       struct evsel *counter, char *prefix)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	bool metric_only = config->metric_only;
8078c2ecf20Sopenharmony_ci	FILE *output = config->output;
8088c2ecf20Sopenharmony_ci	double uval;
8098c2ecf20Sopenharmony_ci	struct caggr_data cd = { .avg = 0.0 };
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (!collect_data(config, counter, counter_aggr_cb, &cd))
8128c2ecf20Sopenharmony_ci		return;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (prefix && !metric_only)
8158c2ecf20Sopenharmony_ci		fprintf(output, "%s", prefix);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	uval = cd.avg * counter->scale;
8188c2ecf20Sopenharmony_ci	printout(config, -1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled,
8198c2ecf20Sopenharmony_ci		 cd.avg, &rt_stat);
8208c2ecf20Sopenharmony_ci	if (!metric_only)
8218c2ecf20Sopenharmony_ci		fprintf(output, "\n");
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_cistatic void counter_cb(struct perf_stat_config *config __maybe_unused,
8258c2ecf20Sopenharmony_ci		       struct evsel *counter, void *data,
8268c2ecf20Sopenharmony_ci		       bool first __maybe_unused)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	struct aggr_data *ad = data;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
8318c2ecf20Sopenharmony_ci	ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
8328c2ecf20Sopenharmony_ci	ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci/*
8368c2ecf20Sopenharmony_ci * Print out the results of a single counter:
8378c2ecf20Sopenharmony_ci * does not use aggregated count in system-wide
8388c2ecf20Sopenharmony_ci */
8398c2ecf20Sopenharmony_cistatic void print_counter(struct perf_stat_config *config,
8408c2ecf20Sopenharmony_ci			  struct evsel *counter, char *prefix)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	FILE *output = config->output;
8438c2ecf20Sopenharmony_ci	u64 ena, run, val;
8448c2ecf20Sopenharmony_ci	double uval;
8458c2ecf20Sopenharmony_ci	int cpu;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	for (cpu = 0; cpu < evsel__nr_cpus(counter); cpu++) {
8488c2ecf20Sopenharmony_ci		struct aggr_data ad = { .cpu = cpu };
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci		if (!collect_data(config, counter, counter_cb, &ad))
8518c2ecf20Sopenharmony_ci			return;
8528c2ecf20Sopenharmony_ci		val = ad.val;
8538c2ecf20Sopenharmony_ci		ena = ad.ena;
8548c2ecf20Sopenharmony_ci		run = ad.run;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		if (prefix)
8578c2ecf20Sopenharmony_ci			fprintf(output, "%s", prefix);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci		uval = val * counter->scale;
8608c2ecf20Sopenharmony_ci		printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
8618c2ecf20Sopenharmony_ci			 &rt_stat);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		fputc('\n', output);
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic void print_no_aggr_metric(struct perf_stat_config *config,
8688c2ecf20Sopenharmony_ci				 struct evlist *evlist,
8698c2ecf20Sopenharmony_ci				 char *prefix)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	int cpu;
8728c2ecf20Sopenharmony_ci	int nrcpus = 0;
8738c2ecf20Sopenharmony_ci	struct evsel *counter;
8748c2ecf20Sopenharmony_ci	u64 ena, run, val;
8758c2ecf20Sopenharmony_ci	double uval;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	nrcpus = evlist->core.cpus->nr;
8788c2ecf20Sopenharmony_ci	for (cpu = 0; cpu < nrcpus; cpu++) {
8798c2ecf20Sopenharmony_ci		bool first = true;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci		if (prefix)
8828c2ecf20Sopenharmony_ci			fputs(prefix, config->output);
8838c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, counter) {
8848c2ecf20Sopenharmony_ci			if (first) {
8858c2ecf20Sopenharmony_ci				aggr_printout(config, counter, cpu, 0);
8868c2ecf20Sopenharmony_ci				first = false;
8878c2ecf20Sopenharmony_ci			}
8888c2ecf20Sopenharmony_ci			val = perf_counts(counter->counts, cpu, 0)->val;
8898c2ecf20Sopenharmony_ci			ena = perf_counts(counter->counts, cpu, 0)->ena;
8908c2ecf20Sopenharmony_ci			run = perf_counts(counter->counts, cpu, 0)->run;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci			uval = val * counter->scale;
8938c2ecf20Sopenharmony_ci			printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
8948c2ecf20Sopenharmony_ci				 &rt_stat);
8958c2ecf20Sopenharmony_ci		}
8968c2ecf20Sopenharmony_ci		fputc('\n', config->output);
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_cistatic int aggr_header_lens[] = {
9018c2ecf20Sopenharmony_ci	[AGGR_CORE] = 24,
9028c2ecf20Sopenharmony_ci	[AGGR_DIE] = 18,
9038c2ecf20Sopenharmony_ci	[AGGR_SOCKET] = 12,
9048c2ecf20Sopenharmony_ci	[AGGR_NONE] = 6,
9058c2ecf20Sopenharmony_ci	[AGGR_THREAD] = 24,
9068c2ecf20Sopenharmony_ci	[AGGR_GLOBAL] = 0,
9078c2ecf20Sopenharmony_ci};
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic const char *aggr_header_csv[] = {
9108c2ecf20Sopenharmony_ci	[AGGR_CORE] 	= 	"core,cpus,",
9118c2ecf20Sopenharmony_ci	[AGGR_DIE] 	= 	"die,cpus",
9128c2ecf20Sopenharmony_ci	[AGGR_SOCKET] 	= 	"socket,cpus",
9138c2ecf20Sopenharmony_ci	[AGGR_NONE] 	= 	"cpu,",
9148c2ecf20Sopenharmony_ci	[AGGR_THREAD] 	= 	"comm-pid,",
9158c2ecf20Sopenharmony_ci	[AGGR_GLOBAL] 	=	""
9168c2ecf20Sopenharmony_ci};
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cistatic void print_metric_headers(struct perf_stat_config *config,
9198c2ecf20Sopenharmony_ci				 struct evlist *evlist,
9208c2ecf20Sopenharmony_ci				 const char *prefix, bool no_indent)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	struct perf_stat_output_ctx out;
9238c2ecf20Sopenharmony_ci	struct evsel *counter;
9248c2ecf20Sopenharmony_ci	struct outstate os = {
9258c2ecf20Sopenharmony_ci		.fh = config->output
9268c2ecf20Sopenharmony_ci	};
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	if (prefix)
9298c2ecf20Sopenharmony_ci		fprintf(config->output, "%s", prefix);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	if (!config->csv_output && !no_indent)
9328c2ecf20Sopenharmony_ci		fprintf(config->output, "%*s",
9338c2ecf20Sopenharmony_ci			aggr_header_lens[config->aggr_mode], "");
9348c2ecf20Sopenharmony_ci	if (config->csv_output) {
9358c2ecf20Sopenharmony_ci		if (config->interval)
9368c2ecf20Sopenharmony_ci			fputs("time,", config->output);
9378c2ecf20Sopenharmony_ci		fputs(aggr_header_csv[config->aggr_mode], config->output);
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	/* Print metrics headers only */
9418c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, counter) {
9428c2ecf20Sopenharmony_ci		os.evsel = counter;
9438c2ecf20Sopenharmony_ci		out.ctx = &os;
9448c2ecf20Sopenharmony_ci		out.print_metric = print_metric_header;
9458c2ecf20Sopenharmony_ci		out.new_line = new_line_metric;
9468c2ecf20Sopenharmony_ci		out.force_header = true;
9478c2ecf20Sopenharmony_ci		perf_stat__print_shadow_stats(config, counter, 0,
9488c2ecf20Sopenharmony_ci					      0,
9498c2ecf20Sopenharmony_ci					      &out,
9508c2ecf20Sopenharmony_ci					      &config->metric_events,
9518c2ecf20Sopenharmony_ci					      &rt_stat);
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci	fputc('\n', config->output);
9548c2ecf20Sopenharmony_ci}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_cistatic void print_interval(struct perf_stat_config *config,
9578c2ecf20Sopenharmony_ci			   struct evlist *evlist,
9588c2ecf20Sopenharmony_ci			   char *prefix, struct timespec *ts)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	bool metric_only = config->metric_only;
9618c2ecf20Sopenharmony_ci	unsigned int unit_width = config->unit_width;
9628c2ecf20Sopenharmony_ci	FILE *output = config->output;
9638c2ecf20Sopenharmony_ci	static int num_print_interval;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (config->interval_clear)
9668c2ecf20Sopenharmony_ci		puts(CONSOLE_CLEAR);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, config->csv_sep);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	if ((num_print_interval == 0 && !config->csv_output) || config->interval_clear) {
9718c2ecf20Sopenharmony_ci		switch (config->aggr_mode) {
9728c2ecf20Sopenharmony_ci		case AGGR_NODE:
9738c2ecf20Sopenharmony_ci			fprintf(output, "#           time node   cpus");
9748c2ecf20Sopenharmony_ci			if (!metric_only)
9758c2ecf20Sopenharmony_ci				fprintf(output, "             counts %*s events\n", unit_width, "unit");
9768c2ecf20Sopenharmony_ci			break;
9778c2ecf20Sopenharmony_ci		case AGGR_SOCKET:
9788c2ecf20Sopenharmony_ci			fprintf(output, "#           time socket cpus");
9798c2ecf20Sopenharmony_ci			if (!metric_only)
9808c2ecf20Sopenharmony_ci				fprintf(output, "             counts %*s events\n", unit_width, "unit");
9818c2ecf20Sopenharmony_ci			break;
9828c2ecf20Sopenharmony_ci		case AGGR_DIE:
9838c2ecf20Sopenharmony_ci			fprintf(output, "#           time die          cpus");
9848c2ecf20Sopenharmony_ci			if (!metric_only)
9858c2ecf20Sopenharmony_ci				fprintf(output, "             counts %*s events\n", unit_width, "unit");
9868c2ecf20Sopenharmony_ci			break;
9878c2ecf20Sopenharmony_ci		case AGGR_CORE:
9888c2ecf20Sopenharmony_ci			fprintf(output, "#           time core            cpus");
9898c2ecf20Sopenharmony_ci			if (!metric_only)
9908c2ecf20Sopenharmony_ci				fprintf(output, "             counts %*s events\n", unit_width, "unit");
9918c2ecf20Sopenharmony_ci			break;
9928c2ecf20Sopenharmony_ci		case AGGR_NONE:
9938c2ecf20Sopenharmony_ci			fprintf(output, "#           time CPU    ");
9948c2ecf20Sopenharmony_ci			if (!metric_only)
9958c2ecf20Sopenharmony_ci				fprintf(output, "                counts %*s events\n", unit_width, "unit");
9968c2ecf20Sopenharmony_ci			break;
9978c2ecf20Sopenharmony_ci		case AGGR_THREAD:
9988c2ecf20Sopenharmony_ci			fprintf(output, "#           time             comm-pid");
9998c2ecf20Sopenharmony_ci			if (!metric_only)
10008c2ecf20Sopenharmony_ci				fprintf(output, "                  counts %*s events\n", unit_width, "unit");
10018c2ecf20Sopenharmony_ci			break;
10028c2ecf20Sopenharmony_ci		case AGGR_GLOBAL:
10038c2ecf20Sopenharmony_ci		default:
10048c2ecf20Sopenharmony_ci			fprintf(output, "#           time");
10058c2ecf20Sopenharmony_ci			if (!metric_only)
10068c2ecf20Sopenharmony_ci				fprintf(output, "             counts %*s events\n", unit_width, "unit");
10078c2ecf20Sopenharmony_ci		case AGGR_UNSET:
10088c2ecf20Sopenharmony_ci			break;
10098c2ecf20Sopenharmony_ci		}
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	if ((num_print_interval == 0 || config->interval_clear) && metric_only)
10138c2ecf20Sopenharmony_ci		print_metric_headers(config, evlist, " ", true);
10148c2ecf20Sopenharmony_ci	if (++num_print_interval == 25)
10158c2ecf20Sopenharmony_ci		num_print_interval = 0;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic void print_header(struct perf_stat_config *config,
10198c2ecf20Sopenharmony_ci			 struct target *_target,
10208c2ecf20Sopenharmony_ci			 int argc, const char **argv)
10218c2ecf20Sopenharmony_ci{
10228c2ecf20Sopenharmony_ci	FILE *output = config->output;
10238c2ecf20Sopenharmony_ci	int i;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	fflush(stdout);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (!config->csv_output) {
10288c2ecf20Sopenharmony_ci		fprintf(output, "\n");
10298c2ecf20Sopenharmony_ci		fprintf(output, " Performance counter stats for ");
10308c2ecf20Sopenharmony_ci		if (_target->system_wide)
10318c2ecf20Sopenharmony_ci			fprintf(output, "\'system wide");
10328c2ecf20Sopenharmony_ci		else if (_target->cpu_list)
10338c2ecf20Sopenharmony_ci			fprintf(output, "\'CPU(s) %s", _target->cpu_list);
10348c2ecf20Sopenharmony_ci		else if (!target__has_task(_target)) {
10358c2ecf20Sopenharmony_ci			fprintf(output, "\'%s", argv ? argv[0] : "pipe");
10368c2ecf20Sopenharmony_ci			for (i = 1; argv && (i < argc); i++)
10378c2ecf20Sopenharmony_ci				fprintf(output, " %s", argv[i]);
10388c2ecf20Sopenharmony_ci		} else if (_target->pid)
10398c2ecf20Sopenharmony_ci			fprintf(output, "process id \'%s", _target->pid);
10408c2ecf20Sopenharmony_ci		else
10418c2ecf20Sopenharmony_ci			fprintf(output, "thread id \'%s", _target->tid);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci		fprintf(output, "\'");
10448c2ecf20Sopenharmony_ci		if (config->run_count > 1)
10458c2ecf20Sopenharmony_ci			fprintf(output, " (%d runs)", config->run_count);
10468c2ecf20Sopenharmony_ci		fprintf(output, ":\n\n");
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic int get_precision(double num)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	if (num > 1)
10538c2ecf20Sopenharmony_ci		return 0;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	return lround(ceil(-log10(num)));
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_cistatic void print_table(struct perf_stat_config *config,
10598c2ecf20Sopenharmony_ci			FILE *output, int precision, double avg)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	char tmp[64];
10628c2ecf20Sopenharmony_ci	int idx, indent = 0;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	scnprintf(tmp, 64, " %17.*f", precision, avg);
10658c2ecf20Sopenharmony_ci	while (tmp[indent] == ' ')
10668c2ecf20Sopenharmony_ci		indent++;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	for (idx = 0; idx < config->run_count; idx++) {
10718c2ecf20Sopenharmony_ci		double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
10728c2ecf20Sopenharmony_ci		int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci		fprintf(output, " %17.*f (%+.*f) ",
10758c2ecf20Sopenharmony_ci			precision, run, precision, run - avg);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		for (h = 0; h < n; h++)
10788c2ecf20Sopenharmony_ci			fprintf(output, "#");
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci		fprintf(output, "\n");
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	fprintf(output, "\n%*s# Final result:\n", indent, "");
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_cistatic double timeval2double(struct timeval *t)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
10898c2ecf20Sopenharmony_ci}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_cistatic void print_footer(struct perf_stat_config *config)
10928c2ecf20Sopenharmony_ci{
10938c2ecf20Sopenharmony_ci	double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
10948c2ecf20Sopenharmony_ci	FILE *output = config->output;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	if (!config->null_run)
10978c2ecf20Sopenharmony_ci		fprintf(output, "\n");
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (config->run_count == 1) {
11008c2ecf20Sopenharmony_ci		fprintf(output, " %17.9f seconds time elapsed", avg);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci		if (config->ru_display) {
11038c2ecf20Sopenharmony_ci			double ru_utime = timeval2double(&config->ru_data.ru_utime);
11048c2ecf20Sopenharmony_ci			double ru_stime = timeval2double(&config->ru_data.ru_stime);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci			fprintf(output, "\n\n");
11078c2ecf20Sopenharmony_ci			fprintf(output, " %17.9f seconds user\n", ru_utime);
11088c2ecf20Sopenharmony_ci			fprintf(output, " %17.9f seconds sys\n", ru_stime);
11098c2ecf20Sopenharmony_ci		}
11108c2ecf20Sopenharmony_ci	} else {
11118c2ecf20Sopenharmony_ci		double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
11128c2ecf20Sopenharmony_ci		/*
11138c2ecf20Sopenharmony_ci		 * Display at most 2 more significant
11148c2ecf20Sopenharmony_ci		 * digits than the stddev inaccuracy.
11158c2ecf20Sopenharmony_ci		 */
11168c2ecf20Sopenharmony_ci		int precision = get_precision(sd) + 2;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		if (config->walltime_run_table)
11198c2ecf20Sopenharmony_ci			print_table(config, output, precision, avg);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci		fprintf(output, " %17.*f +- %.*f seconds time elapsed",
11228c2ecf20Sopenharmony_ci			precision, avg, precision, sd);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci		print_noise_pct(config, sd, avg);
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci	fprintf(output, "\n\n");
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled())
11298c2ecf20Sopenharmony_ci		fprintf(output,
11308c2ecf20Sopenharmony_ci"Some events weren't counted. Try disabling the NMI watchdog:\n"
11318c2ecf20Sopenharmony_ci"	echo 0 > /proc/sys/kernel/nmi_watchdog\n"
11328c2ecf20Sopenharmony_ci"	perf stat ...\n"
11338c2ecf20Sopenharmony_ci"	echo 1 > /proc/sys/kernel/nmi_watchdog\n");
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (config->print_mixed_hw_group_error)
11368c2ecf20Sopenharmony_ci		fprintf(output,
11378c2ecf20Sopenharmony_ci			"The events in group usually have to be from "
11388c2ecf20Sopenharmony_ci			"the same PMU. Try reorganizing the group.\n");
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_cistatic void print_percore_thread(struct perf_stat_config *config,
11428c2ecf20Sopenharmony_ci				 struct evsel *counter, char *prefix)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	int s, s2, id;
11458c2ecf20Sopenharmony_ci	bool first = true;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	for (int i = 0; i < evsel__nr_cpus(counter); i++) {
11488c2ecf20Sopenharmony_ci		s2 = config->aggr_get_id(config, evsel__cpus(counter), i);
11498c2ecf20Sopenharmony_ci		for (s = 0; s < config->aggr_map->nr; s++) {
11508c2ecf20Sopenharmony_ci			id = config->aggr_map->map[s];
11518c2ecf20Sopenharmony_ci			if (s2 == id)
11528c2ecf20Sopenharmony_ci				break;
11538c2ecf20Sopenharmony_ci		}
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		print_counter_aggrdata(config, counter, s,
11568c2ecf20Sopenharmony_ci				       prefix, false,
11578c2ecf20Sopenharmony_ci				       &first, i);
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_cistatic void print_percore(struct perf_stat_config *config,
11628c2ecf20Sopenharmony_ci			  struct evsel *counter, char *prefix)
11638c2ecf20Sopenharmony_ci{
11648c2ecf20Sopenharmony_ci	bool metric_only = config->metric_only;
11658c2ecf20Sopenharmony_ci	FILE *output = config->output;
11668c2ecf20Sopenharmony_ci	int s;
11678c2ecf20Sopenharmony_ci	bool first = true;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (!config->aggr_map || !config->aggr_get_id)
11708c2ecf20Sopenharmony_ci		return;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	if (config->percore_show_thread)
11738c2ecf20Sopenharmony_ci		return print_percore_thread(config, counter, prefix);
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	for (s = 0; s < config->aggr_map->nr; s++) {
11768c2ecf20Sopenharmony_ci		if (prefix && metric_only)
11778c2ecf20Sopenharmony_ci			fprintf(output, "%s", prefix);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci		print_counter_aggrdata(config, counter, s,
11808c2ecf20Sopenharmony_ci				       prefix, metric_only,
11818c2ecf20Sopenharmony_ci				       &first, -1);
11828c2ecf20Sopenharmony_ci	}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (metric_only)
11858c2ecf20Sopenharmony_ci		fputc('\n', output);
11868c2ecf20Sopenharmony_ci}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_civoid
11898c2ecf20Sopenharmony_ciperf_evlist__print_counters(struct evlist *evlist,
11908c2ecf20Sopenharmony_ci			    struct perf_stat_config *config,
11918c2ecf20Sopenharmony_ci			    struct target *_target,
11928c2ecf20Sopenharmony_ci			    struct timespec *ts,
11938c2ecf20Sopenharmony_ci			    int argc, const char **argv)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	bool metric_only = config->metric_only;
11968c2ecf20Sopenharmony_ci	int interval = config->interval;
11978c2ecf20Sopenharmony_ci	struct evsel *counter;
11988c2ecf20Sopenharmony_ci	char buf[64], *prefix = NULL;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (interval)
12018c2ecf20Sopenharmony_ci		print_interval(config, evlist, prefix = buf, ts);
12028c2ecf20Sopenharmony_ci	else
12038c2ecf20Sopenharmony_ci		print_header(config, _target, argc, argv);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (metric_only) {
12068c2ecf20Sopenharmony_ci		static int num_print_iv;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci		if (num_print_iv == 0 && !interval)
12098c2ecf20Sopenharmony_ci			print_metric_headers(config, evlist, prefix, false);
12108c2ecf20Sopenharmony_ci		if (num_print_iv++ == 25)
12118c2ecf20Sopenharmony_ci			num_print_iv = 0;
12128c2ecf20Sopenharmony_ci		if (config->aggr_mode == AGGR_GLOBAL && prefix)
12138c2ecf20Sopenharmony_ci			fprintf(config->output, "%s", prefix);
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	switch (config->aggr_mode) {
12178c2ecf20Sopenharmony_ci	case AGGR_CORE:
12188c2ecf20Sopenharmony_ci	case AGGR_DIE:
12198c2ecf20Sopenharmony_ci	case AGGR_SOCKET:
12208c2ecf20Sopenharmony_ci	case AGGR_NODE:
12218c2ecf20Sopenharmony_ci		print_aggr(config, evlist, prefix);
12228c2ecf20Sopenharmony_ci		break;
12238c2ecf20Sopenharmony_ci	case AGGR_THREAD:
12248c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, counter) {
12258c2ecf20Sopenharmony_ci			print_aggr_thread(config, _target, counter, prefix);
12268c2ecf20Sopenharmony_ci		}
12278c2ecf20Sopenharmony_ci		break;
12288c2ecf20Sopenharmony_ci	case AGGR_GLOBAL:
12298c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, counter) {
12308c2ecf20Sopenharmony_ci			print_counter_aggr(config, counter, prefix);
12318c2ecf20Sopenharmony_ci		}
12328c2ecf20Sopenharmony_ci		if (metric_only)
12338c2ecf20Sopenharmony_ci			fputc('\n', config->output);
12348c2ecf20Sopenharmony_ci		break;
12358c2ecf20Sopenharmony_ci	case AGGR_NONE:
12368c2ecf20Sopenharmony_ci		if (metric_only)
12378c2ecf20Sopenharmony_ci			print_no_aggr_metric(config, evlist, prefix);
12388c2ecf20Sopenharmony_ci		else {
12398c2ecf20Sopenharmony_ci			evlist__for_each_entry(evlist, counter) {
12408c2ecf20Sopenharmony_ci				if (counter->percore)
12418c2ecf20Sopenharmony_ci					print_percore(config, counter, prefix);
12428c2ecf20Sopenharmony_ci				else
12438c2ecf20Sopenharmony_ci					print_counter(config, counter, prefix);
12448c2ecf20Sopenharmony_ci			}
12458c2ecf20Sopenharmony_ci		}
12468c2ecf20Sopenharmony_ci		break;
12478c2ecf20Sopenharmony_ci	case AGGR_UNSET:
12488c2ecf20Sopenharmony_ci	default:
12498c2ecf20Sopenharmony_ci		break;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	if (!interval && !config->csv_output)
12538c2ecf20Sopenharmony_ci		print_footer(config);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	fflush(config->output);
12568c2ecf20Sopenharmony_ci}
1257