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