4 #include <linux/string.h>
5 #include <linux/time64.h>
7 #include <perf/cpumap.h>
14 #include "thread_map.h"
17 #include <linux/ctype.h>
19 #include <api/fs/fs.h>
25 #define CNTR_NOT_SUPPORTED "<not supported>"
26 #define CNTR_NOT_COUNTED "<not counted>"
32 #define INTERVAL_LEN 16
38 static int aggr_header_lens[] = {
50 static const char *aggr_header_csv[] = {
51 [AGGR_CORE] = "core,cpus,",
52 [AGGR_CACHE] = "cache,cpus,",
53 [AGGR_CLUSTER] = "cluster,cpus,",
54 [AGGR_DIE] = "die,cpus,",
55 [AGGR_SOCKET] = "socket,cpus,",
57 [AGGR_THREAD] = "comm-pid,",
58 [AGGR_NODE] = "node,",
62 static const char *aggr_header_std[] = {
64 [AGGR_CACHE] = "cache",
65 [AGGR_CLUSTER] = "cluster",
67 [AGGR_SOCKET] = "socket",
69 [AGGR_THREAD] = "comm-pid",
74 static void print_running_std(struct perf_stat_config *config, u64 run, u64 ena)
77 fprintf(config->output, " (%.2f%%)", 100.0 * run / ena);
80 static void print_running_csv(struct perf_stat_config *config, u64 run, u64 ena)
82 double enabled_percent = 100;
85 enabled_percent = 100 * run / ena;
86 fprintf(config->output, "%s%" PRIu64 "%s%.2f",
87 config->csv_sep, run, config->csv_sep, enabled_percent);
90 static void print_running_json(struct perf_stat_config *config, u64 run, u64 ena)
92 double enabled_percent = 100;
95 enabled_percent = 100 * run / ena;
96 fprintf(config->output, "\"event-runtime\" : %" PRIu64 ", \"pcnt-running\" : %.2f, ",
97 run, enabled_percent);
100 static void print_running(struct perf_stat_config *config,
101 u64 run, u64 ena, bool before_metric)
103 if (config->json_output) {
105 print_running_json(config, run, ena);
106 } else if (config->csv_output) {
108 print_running_csv(config, run, ena);
111 print_running_std(config, run, ena);
115 static void print_noise_pct_std(struct perf_stat_config *config,
119 fprintf(config->output, " ( +-%6.2f%% )", pct);
122 static void print_noise_pct_csv(struct perf_stat_config *config,
125 fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
128 static void print_noise_pct_json(struct perf_stat_config *config,
131 fprintf(config->output, "\"variance\" : %.2f, ", pct);
134 static void print_noise_pct(struct perf_stat_config *config,
135 double total, double avg, bool before_metric)
137 double pct = rel_stddev_stats(total, avg);
139 if (config->json_output) {
141 print_noise_pct_json(config, pct);
142 } else if (config->csv_output) {
144 print_noise_pct_csv(config, pct);
147 print_noise_pct_std(config, pct);
151 static void print_noise(struct perf_stat_config *config,
152 struct evsel *evsel, double avg, bool before_metric)
154 struct perf_stat_evsel *ps;
156 if (config->run_count == 1)
160 print_noise_pct(config, stddev_stats(&ps->res_stats), avg, before_metric);
163 static void print_cgroup_std(struct perf_stat_config *config, const char *cgrp_name)
165 fprintf(config->output, " %-*s", CGROUP_LEN, cgrp_name);
168 static void print_cgroup_csv(struct perf_stat_config *config, const char *cgrp_name)
170 fprintf(config->output, "%s%s", config->csv_sep, cgrp_name);
173 static void print_cgroup_json(struct perf_stat_config *config, const char *cgrp_name)
175 fprintf(config->output, "\"cgroup\" : \"%s\", ", cgrp_name);
178 static void print_cgroup(struct perf_stat_config *config, struct cgroup *cgrp)
180 if (nr_cgroups || config->cgroup_list) {
181 const char *cgrp_name = cgrp ? cgrp->name : "";
183 if (config->json_output)
184 print_cgroup_json(config, cgrp_name);
185 else if (config->csv_output)
186 print_cgroup_csv(config, cgrp_name);
188 print_cgroup_std(config, cgrp_name);
192 static void print_aggr_id_std(struct perf_stat_config *config,
193 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
195 FILE *output = config->output;
196 int idx = config->aggr_mode;
199 switch (config->aggr_mode) {
201 snprintf(buf, sizeof(buf), "S%d-D%d-C%d", id.socket, id.die, id.core);
204 snprintf(buf, sizeof(buf), "S%d-D%d-L%d-ID%d",
205 id.socket, id.die, id.cache_lvl, id.cache);
208 snprintf(buf, sizeof(buf), "S%d-D%d-CLS%d", id.socket, id.die, id.cluster);
211 snprintf(buf, sizeof(buf), "S%d-D%d", id.socket, id.die);
214 snprintf(buf, sizeof(buf), "S%d", id.socket);
217 snprintf(buf, sizeof(buf), "N%d", id.node);
220 if (evsel->percore && !config->percore_show_thread) {
221 snprintf(buf, sizeof(buf), "S%d-D%d-C%d ",
222 id.socket, id.die, id.core);
223 fprintf(output, "%-*s ",
224 aggr_header_lens[AGGR_CORE], buf);
225 } else if (id.cpu.cpu > -1) {
226 fprintf(output, "CPU%-*d ",
227 aggr_header_lens[AGGR_NONE] - 3, id.cpu.cpu);
231 fprintf(output, "%*s-%-*d ",
232 COMM_LEN, perf_thread_map__comm(evsel->core.threads, id.thread_idx),
233 PID_LEN, perf_thread_map__pid(evsel->core.threads, id.thread_idx));
242 fprintf(output, "%-*s %*d ", aggr_header_lens[idx], buf, 4, aggr_nr);
245 static void print_aggr_id_csv(struct perf_stat_config *config,
246 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
248 FILE *output = config->output;
249 const char *sep = config->csv_sep;
251 switch (config->aggr_mode) {
253 fprintf(output, "S%d-D%d-C%d%s%d%s",
254 id.socket, id.die, id.core, sep, aggr_nr, sep);
257 fprintf(config->output, "S%d-D%d-L%d-ID%d%s%d%s",
258 id.socket, id.die, id.cache_lvl, id.cache, sep, aggr_nr, sep);
261 fprintf(config->output, "S%d-D%d-CLS%d%s%d%s",
262 id.socket, id.die, id.cluster, sep, aggr_nr, sep);
265 fprintf(output, "S%d-D%d%s%d%s",
266 id.socket, id.die, sep, aggr_nr, sep);
269 fprintf(output, "S%d%s%d%s",
270 id.socket, sep, aggr_nr, sep);
273 fprintf(output, "N%d%s%d%s",
274 id.node, sep, aggr_nr, sep);
277 if (evsel->percore && !config->percore_show_thread) {
278 fprintf(output, "S%d-D%d-C%d%s",
279 id.socket, id.die, id.core, sep);
280 } else if (id.cpu.cpu > -1) {
281 fprintf(output, "CPU%d%s",
286 fprintf(output, "%s-%d%s",
287 perf_thread_map__comm(evsel->core.threads, id.thread_idx),
288 perf_thread_map__pid(evsel->core.threads, id.thread_idx),
299 static void print_aggr_id_json(struct perf_stat_config *config,
300 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
302 FILE *output = config->output;
304 switch (config->aggr_mode) {
306 fprintf(output, "\"core\" : \"S%d-D%d-C%d\", \"aggregate-number\" : %d, ",
307 id.socket, id.die, id.core, aggr_nr);
310 fprintf(output, "\"cache\" : \"S%d-D%d-L%d-ID%d\", \"aggregate-number\" : %d, ",
311 id.socket, id.die, id.cache_lvl, id.cache, aggr_nr);
314 fprintf(output, "\"cluster\" : \"S%d-D%d-CLS%d\", \"aggregate-number\" : %d, ",
315 id.socket, id.die, id.cluster, aggr_nr);
318 fprintf(output, "\"die\" : \"S%d-D%d\", \"aggregate-number\" : %d, ",
319 id.socket, id.die, aggr_nr);
322 fprintf(output, "\"socket\" : \"S%d\", \"aggregate-number\" : %d, ",
326 fprintf(output, "\"node\" : \"N%d\", \"aggregate-number\" : %d, ",
330 if (evsel->percore && !config->percore_show_thread) {
331 fprintf(output, "\"core\" : \"S%d-D%d-C%d\"",
332 id.socket, id.die, id.core);
333 } else if (id.cpu.cpu > -1) {
334 fprintf(output, "\"cpu\" : \"%d\", ",
339 fprintf(output, "\"thread\" : \"%s-%d\", ",
340 perf_thread_map__comm(evsel->core.threads, id.thread_idx),
341 perf_thread_map__pid(evsel->core.threads, id.thread_idx));
351 static void aggr_printout(struct perf_stat_config *config,
352 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
354 if (config->json_output)
355 print_aggr_id_json(config, evsel, id, aggr_nr);
356 else if (config->csv_output)
357 print_aggr_id_csv(config, evsel, id, aggr_nr);
359 print_aggr_id_std(config, evsel, id, aggr_nr);
369 struct aggr_cpu_id id;
374 static void new_line_std(struct perf_stat_config *config __maybe_unused,
377 struct outstate *os = ctx;
382 static inline void __new_line_std_csv(struct perf_stat_config *config,
387 fputs(os->prefix, os->fh);
388 aggr_printout(config, os->evsel, os->id, os->aggr_nr);
391 static inline void __new_line_std(struct outstate *os)
393 fprintf(os->fh, " ");
396 static void do_new_line_std(struct perf_stat_config *config,
399 __new_line_std_csv(config, os);
400 if (config->aggr_mode == AGGR_NONE)
401 fprintf(os->fh, " ");
405 static void print_metric_std(struct perf_stat_config *config,
406 void *ctx, const char *color, const char *fmt,
407 const char *unit, double val)
409 struct outstate *os = ctx;
412 bool newline = os->newline;
416 if (unit == NULL || fmt == NULL) {
417 fprintf(out, "%-*s", METRIC_LEN, "");
422 do_new_line_std(config, os);
424 n = fprintf(out, " # ");
426 n += color_fprintf(out, color, fmt, val);
428 n += fprintf(out, fmt, val);
429 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
432 static void new_line_csv(struct perf_stat_config *config, void *ctx)
434 struct outstate *os = ctx;
437 __new_line_std_csv(config, os);
438 for (i = 0; i < os->nfields; i++)
439 fputs(config->csv_sep, os->fh);
442 static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
444 const char *color __maybe_unused,
445 const char *fmt, const char *unit, double val)
447 struct outstate *os = ctx;
449 char buf[64], *vals, *ends;
451 if (unit == NULL || fmt == NULL) {
452 fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
455 snprintf(buf, sizeof(buf), fmt, val);
456 ends = vals = skip_spaces(buf);
457 while (isdigit(*ends) || *ends == '.')
460 fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
463 static void print_metric_json(struct perf_stat_config *config __maybe_unused,
465 const char *color __maybe_unused,
466 const char *fmt __maybe_unused,
467 const char *unit, double val)
469 struct outstate *os = ctx;
472 fprintf(out, "\"metric-value\" : \"%f\", ", val);
473 fprintf(out, "\"metric-unit\" : \"%s\"", unit);
474 if (!config->metric_only)
478 static void new_line_json(struct perf_stat_config *config, void *ctx)
480 struct outstate *os = ctx;
482 fputs("\n{", os->fh);
484 fprintf(os->fh, "%s", os->prefix);
485 aggr_printout(config, os->evsel, os->id, os->aggr_nr);
488 static void print_metricgroup_header_json(struct perf_stat_config *config,
490 const char *metricgroup_name)
492 if (!metricgroup_name)
495 fprintf(config->output, "\"metricgroup\" : \"%s\"}", metricgroup_name);
496 new_line_json(config, ctx);
499 static void print_metricgroup_header_csv(struct perf_stat_config *config,
501 const char *metricgroup_name)
503 struct outstate *os = ctx;
506 if (!metricgroup_name) {
507 /* Leave space for running and enabling */
508 for (i = 0; i < os->nfields - 2; i++)
509 fputs(config->csv_sep, os->fh);
513 for (i = 0; i < os->nfields; i++)
514 fputs(config->csv_sep, os->fh);
515 fprintf(config->output, "%s", metricgroup_name);
516 new_line_csv(config, ctx);
519 static void print_metricgroup_header_std(struct perf_stat_config *config,
521 const char *metricgroup_name)
523 struct outstate *os = ctx;
526 if (!metricgroup_name) {
531 n = fprintf(config->output, " %*s", EVNAME_LEN, metricgroup_name);
533 fprintf(config->output, "%*s", MGROUP_LEN - n - 1, "");
536 /* Filter out some columns that don't work well in metrics only mode */
538 static bool valid_only_metric(const char *unit)
542 if (strstr(unit, "/sec") ||
543 strstr(unit, "CPUs utilized"))
548 static const char *fixunit(char *buf, struct evsel *evsel,
551 if (!strncmp(unit, "of all", 6)) {
552 snprintf(buf, 1024, "%s %s", evsel__name(evsel),
559 static void print_metric_only(struct perf_stat_config *config,
560 void *ctx, const char *color, const char *fmt,
561 const char *unit, double val)
563 struct outstate *os = ctx;
565 char buf[1024], str[1024];
566 unsigned mlen = config->metric_only_len;
568 if (!valid_only_metric(unit))
570 unit = fixunit(buf, os->evsel, unit);
571 if (mlen < strlen(unit))
572 mlen = strlen(unit) + 1;
575 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
577 color_snprintf(str, sizeof(str), color ?: "", fmt ?: "", val);
578 fprintf(out, "%*s ", mlen, str);
582 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
583 void *ctx, const char *color __maybe_unused,
585 const char *unit, double val)
587 struct outstate *os = ctx;
589 char buf[64], *vals, *ends;
592 if (!valid_only_metric(unit))
594 unit = fixunit(tbuf, os->evsel, unit);
595 snprintf(buf, sizeof(buf), fmt ?: "", val);
596 ends = vals = skip_spaces(buf);
597 while (isdigit(*ends) || *ends == '.')
600 fprintf(out, "%s%s", vals, config->csv_sep);
604 static void print_metric_only_json(struct perf_stat_config *config __maybe_unused,
605 void *ctx, const char *color __maybe_unused,
607 const char *unit, double val)
609 struct outstate *os = ctx;
611 char buf[64], *vals, *ends;
614 if (!valid_only_metric(unit))
616 unit = fixunit(tbuf, os->evsel, unit);
617 snprintf(buf, sizeof(buf), fmt ?: "", val);
618 ends = vals = skip_spaces(buf);
619 while (isdigit(*ends) || *ends == '.')
622 if (!unit[0] || !vals[0])
624 fprintf(out, "%s\"%s\" : \"%s\"", os->first ? "" : ", ", unit, vals);
628 static void new_line_metric(struct perf_stat_config *config __maybe_unused,
629 void *ctx __maybe_unused)
633 static void print_metric_header(struct perf_stat_config *config,
634 void *ctx, const char *color __maybe_unused,
635 const char *fmt __maybe_unused,
636 const char *unit, double val __maybe_unused)
638 struct outstate *os = ctx;
641 /* In case of iostat, print metric header for first root port only */
642 if (config->iostat_run &&
643 os->evsel->priv != os->evsel->evlist->selected->priv)
646 if (os->evsel->cgrp != os->cgrp)
649 if (!valid_only_metric(unit))
651 unit = fixunit(tbuf, os->evsel, unit);
653 if (config->json_output)
655 else if (config->csv_output)
656 fprintf(os->fh, "%s%s", unit, config->csv_sep);
658 fprintf(os->fh, "%*s ", config->metric_only_len, unit);
661 static void print_counter_value_std(struct perf_stat_config *config,
662 struct evsel *evsel, double avg, bool ok)
664 FILE *output = config->output;
665 double sc = evsel->scale;
667 const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
670 fmt = floor(sc) != sc ? "%'*.2f " : "%'*.0f ";
672 fmt = floor(sc) != sc ? "%*.2f " : "%*.0f ";
675 fprintf(output, fmt, COUNTS_LEN, avg);
677 fprintf(output, "%*s ", COUNTS_LEN, bad_count);
680 fprintf(output, "%-*s ", config->unit_width, evsel->unit);
682 fprintf(output, "%-*s", EVNAME_LEN, evsel__name(evsel));
685 static void print_counter_value_csv(struct perf_stat_config *config,
686 struct evsel *evsel, double avg, bool ok)
688 FILE *output = config->output;
689 double sc = evsel->scale;
690 const char *sep = config->csv_sep;
691 const char *fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
692 const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
695 fprintf(output, fmt, avg, sep);
697 fprintf(output, "%s%s", bad_count, sep);
700 fprintf(output, "%s%s", evsel->unit, sep);
702 fprintf(output, "%s", evsel__name(evsel));
705 static void print_counter_value_json(struct perf_stat_config *config,
706 struct evsel *evsel, double avg, bool ok)
708 FILE *output = config->output;
709 const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
712 fprintf(output, "\"counter-value\" : \"%f\", ", avg);
714 fprintf(output, "\"counter-value\" : \"%s\", ", bad_count);
717 fprintf(output, "\"unit\" : \"%s\", ", evsel->unit);
719 fprintf(output, "\"event\" : \"%s\", ", evsel__name(evsel));
722 static void print_counter_value(struct perf_stat_config *config,
723 struct evsel *evsel, double avg, bool ok)
725 if (config->json_output)
726 print_counter_value_json(config, evsel, avg, ok);
727 else if (config->csv_output)
728 print_counter_value_csv(config, evsel, avg, ok);
730 print_counter_value_std(config, evsel, avg, ok);
733 static void abs_printout(struct perf_stat_config *config,
734 struct aggr_cpu_id id, int aggr_nr,
735 struct evsel *evsel, double avg, bool ok)
737 aggr_printout(config, evsel, id, aggr_nr);
738 print_counter_value(config, evsel, avg, ok);
739 print_cgroup(config, evsel->cgrp);
742 static bool is_mixed_hw_group(struct evsel *counter)
744 struct evlist *evlist = counter->evlist;
745 u32 pmu_type = counter->core.attr.type;
748 if (counter->core.nr_members < 2)
751 evlist__for_each_entry(evlist, pos) {
752 /* software events can be part of any hardware group */
753 if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
755 if (pmu_type == PERF_TYPE_SOFTWARE) {
756 pmu_type = pos->core.attr.type;
759 if (pmu_type != pos->core.attr.type)
766 static bool evlist__has_hybrid(struct evlist *evlist)
770 if (perf_pmus__num_core_pmus() == 1)
773 evlist__for_each_entry(evlist, evsel) {
774 if (evsel->core.is_pmu_core)
781 static void printout(struct perf_stat_config *config, struct outstate *os,
782 double uval, u64 run, u64 ena, double noise, int aggr_idx)
784 struct perf_stat_output_ctx out;
787 print_metricgroup_header_t pmh;
789 struct evsel *counter = os->evsel;
791 if (config->csv_output) {
792 pm = config->metric_only ? print_metric_only_csv : print_metric_csv;
793 nl = config->metric_only ? new_line_metric : new_line_csv;
794 pmh = print_metricgroup_header_csv;
795 os->nfields = 4 + (counter->cgrp ? 1 : 0);
796 } else if (config->json_output) {
797 pm = config->metric_only ? print_metric_only_json : print_metric_json;
798 nl = config->metric_only ? new_line_metric : new_line_json;
799 pmh = print_metricgroup_header_json;
801 pm = config->metric_only ? print_metric_only : print_metric_std;
802 nl = config->metric_only ? new_line_metric : new_line_std;
803 pmh = print_metricgroup_header_std;
806 if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
807 if (config->metric_only) {
808 pm(config, os, NULL, "", "", 0);
814 if (counter->supported) {
815 if (!evlist__has_hybrid(counter->evlist)) {
816 config->print_free_counters_hint = 1;
817 if (is_mixed_hw_group(counter))
818 config->print_mixed_hw_group_error = 1;
823 out.print_metric = pm;
825 out.print_metricgroup_header = pmh;
827 out.force_header = false;
829 if (!config->metric_only && !counter->default_metricgroup) {
830 abs_printout(config, os->id, os->aggr_nr, counter, uval, ok);
832 print_noise(config, counter, noise, /*before_metric=*/true);
833 print_running(config, run, ena, /*before_metric=*/true);
837 if (!config->metric_only && counter->default_metricgroup) {
840 aggr_printout(config, os->evsel, os->id, os->aggr_nr);
841 /* Print out all the metricgroup with the same metric event. */
845 /* Print out the new line for the next new metricgroup. */
847 if (config->json_output)
848 new_line_json(config, (void *)os);
850 __new_line_std_csv(config, os);
853 print_noise(config, counter, noise, /*before_metric=*/true);
854 print_running(config, run, ena, /*before_metric=*/true);
855 from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx,
857 &config->metric_events);
858 } while (from != NULL);
860 perf_stat__print_shadow_stats(config, counter, uval, aggr_idx,
861 &out, &config->metric_events);
863 pm(config, os, /*color=*/NULL, /*format=*/NULL, /*unit=*/"", /*val=*/0);
866 if (!config->metric_only) {
867 print_noise(config, counter, noise, /*before_metric=*/false);
868 print_running(config, run, ena, /*before_metric=*/false);
872 static void uniquify_event_name(struct evsel *counter)
878 if (counter->uniquified_name || counter->use_config_name ||
879 !counter->pmu_name || !strncmp(evsel__name(counter), counter->pmu_name,
880 strlen(counter->pmu_name)))
883 config = strchr(counter->name, '/');
885 if (asprintf(&new_name,
886 "%s%s", counter->pmu_name, config) > 0) {
888 counter->name = new_name;
891 if (evsel__is_hybrid(counter)) {
892 ret = asprintf(&new_name, "%s/%s/",
893 counter->pmu_name, counter->name);
895 ret = asprintf(&new_name, "%s [%s]",
896 counter->name, counter->pmu_name);
901 counter->name = new_name;
905 counter->uniquified_name = true;
908 static bool hybrid_uniquify(struct evsel *evsel, struct perf_stat_config *config)
910 return evsel__is_hybrid(evsel) && !config->hybrid_merge;
913 static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter)
915 if (config->aggr_mode == AGGR_NONE || hybrid_uniquify(counter, config))
916 uniquify_event_name(counter);
920 * should_skip_zero_count() - Check if the event should print 0 values.
921 * @config: The perf stat configuration (including aggregation mode).
922 * @counter: The evsel with its associated cpumap.
923 * @id: The aggregation id that is being queried.
925 * Due to mismatch between the event cpumap or thread-map and the
926 * aggregation mode, sometimes it'd iterate the counter with the map
927 * which does not contain any values.
929 * For example, uncore events have dedicated CPUs to manage them,
930 * result for other CPUs should be zero and skipped.
932 * Return: %true if the value should NOT be printed, %false if the value
933 * needs to be printed like "<not counted>" or "<not supported>".
935 static bool should_skip_zero_counter(struct perf_stat_config *config,
936 struct evsel *counter,
937 const struct aggr_cpu_id *id)
943 * Skip value 0 when enabling --per-thread globally,
944 * otherwise it will have too many 0 output.
946 if (config->aggr_mode == AGGR_THREAD && config->system_wide)
949 /* Tool events have the software PMU but are only gathered on 1. */
950 if (evsel__is_tool(counter))
954 * Skip value 0 when it's an uncore event and the given aggr id
955 * does not belong to the PMU cpumask.
957 if (!counter->pmu || !counter->pmu->is_uncore)
960 perf_cpu_map__for_each_cpu(cpu, idx, counter->pmu->cpus) {
961 struct aggr_cpu_id own_id = config->aggr_get_id(config, cpu);
963 if (aggr_cpu_id__equal(id, &own_id))
969 static void print_counter_aggrdata(struct perf_stat_config *config,
970 struct evsel *counter, int aggr_idx,
973 FILE *output = config->output;
976 struct perf_stat_evsel *ps = counter->stats;
977 struct perf_stat_aggr *aggr = &ps->aggr[aggr_idx];
978 struct aggr_cpu_id id = config->aggr_map->map[aggr_idx];
979 double avg = aggr->counts.val;
980 bool metric_only = config->metric_only;
983 os->aggr_nr = aggr->nr;
986 /* Skip already merged uncore/hybrid events */
987 if (counter->merged_stat)
990 uniquify_counter(config, counter);
992 val = aggr->counts.val;
993 ena = aggr->counts.ena;
994 run = aggr->counts.run;
996 if (perf_stat__skip_metric_event(counter, &config->metric_events, ena, run))
999 if (val == 0 && should_skip_zero_counter(config, counter, &id))
1003 if (config->json_output)
1006 fprintf(output, "%s", os->prefix);
1007 else if (config->summary && config->csv_output &&
1008 !config->no_csv_summary && !config->interval)
1009 fprintf(output, "%s%s", "summary", config->csv_sep);
1012 uval = val * counter->scale;
1014 printout(config, os, uval, run, ena, avg, aggr_idx);
1017 fputc('\n', output);
1020 static void print_metric_begin(struct perf_stat_config *config,
1021 struct evlist *evlist,
1022 struct outstate *os, int aggr_idx)
1024 struct perf_stat_aggr *aggr;
1025 struct aggr_cpu_id id;
1026 struct evsel *evsel;
1029 if (!config->metric_only)
1032 if (config->json_output)
1033 fputc('{', config->output);
1035 fprintf(config->output, "%s", os->prefix);
1037 evsel = evlist__first(evlist);
1038 id = config->aggr_map->map[aggr_idx];
1039 aggr = &evsel->stats->aggr[aggr_idx];
1040 aggr_printout(config, evsel, id, aggr->nr);
1042 print_cgroup(config, os->cgrp ? : evsel->cgrp);
1045 static void print_metric_end(struct perf_stat_config *config, struct outstate *os)
1047 FILE *output = config->output;
1049 if (!config->metric_only)
1052 if (config->json_output) {
1054 fputs("\"metric-value\" : \"none\"", output);
1057 fputc('\n', output);
1060 static void print_aggr(struct perf_stat_config *config,
1061 struct evlist *evlist,
1062 struct outstate *os)
1064 struct evsel *counter;
1067 if (!config->aggr_map || !config->aggr_get_id)
1071 * With metric_only everything is on a single line.
1072 * Without each counter has its own line.
1074 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1075 print_metric_begin(config, evlist, os, aggr_idx);
1077 evlist__for_each_entry(evlist, counter) {
1078 print_counter_aggrdata(config, counter, aggr_idx, os);
1080 print_metric_end(config, os);
1084 static void print_aggr_cgroup(struct perf_stat_config *config,
1085 struct evlist *evlist,
1086 struct outstate *os)
1088 struct evsel *counter, *evsel;
1091 if (!config->aggr_map || !config->aggr_get_id)
1094 evlist__for_each_entry(evlist, evsel) {
1095 if (os->cgrp == evsel->cgrp)
1098 os->cgrp = evsel->cgrp;
1100 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1101 print_metric_begin(config, evlist, os, aggr_idx);
1103 evlist__for_each_entry(evlist, counter) {
1104 if (counter->cgrp != os->cgrp)
1107 print_counter_aggrdata(config, counter, aggr_idx, os);
1109 print_metric_end(config, os);
1114 static void print_counter(struct perf_stat_config *config,
1115 struct evsel *counter, struct outstate *os)
1119 /* AGGR_THREAD doesn't have config->aggr_get_id */
1120 if (!config->aggr_map)
1123 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1124 print_counter_aggrdata(config, counter, aggr_idx, os);
1128 static void print_no_aggr_metric(struct perf_stat_config *config,
1129 struct evlist *evlist,
1130 struct outstate *os)
1133 struct perf_cpu cpu;
1135 perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.user_requested_cpus) {
1136 struct evsel *counter;
1139 evlist__for_each_entry(evlist, counter) {
1142 struct perf_stat_evsel *ps = counter->stats;
1145 if (!perf_cpu_map__has(evsel__cpus(counter), cpu))
1148 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1149 if (config->aggr_map->map[aggr_idx].cpu.cpu == cpu.cpu)
1153 os->evsel = counter;
1154 os->id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
1156 print_metric_begin(config, evlist, os, aggr_idx);
1159 val = ps->aggr[aggr_idx].counts.val;
1160 ena = ps->aggr[aggr_idx].counts.ena;
1161 run = ps->aggr[aggr_idx].counts.run;
1163 uval = val * counter->scale;
1164 printout(config, os, uval, run, ena, 1.0, aggr_idx);
1167 print_metric_end(config, os);
1171 static void print_metric_headers_std(struct perf_stat_config *config,
1174 fputc(' ', config->output);
1177 int len = aggr_header_lens[config->aggr_mode];
1179 if (nr_cgroups || config->cgroup_list)
1180 len += CGROUP_LEN + 1;
1182 fprintf(config->output, "%*s", len, "");
1186 static void print_metric_headers_csv(struct perf_stat_config *config,
1187 bool no_indent __maybe_unused)
1191 if (config->interval)
1192 fprintf(config->output, "time%s", config->csv_sep);
1193 if (config->iostat_run)
1196 p = aggr_header_csv[config->aggr_mode];
1199 fputs(config->csv_sep, config->output);
1201 fputc(*p, config->output);
1206 static void print_metric_headers_json(struct perf_stat_config *config __maybe_unused,
1207 bool no_indent __maybe_unused)
1211 static void print_metric_headers(struct perf_stat_config *config,
1212 struct evlist *evlist, bool no_indent)
1214 struct evsel *counter;
1215 struct outstate os = {
1216 .fh = config->output
1218 struct perf_stat_output_ctx out = {
1220 .print_metric = print_metric_header,
1221 .new_line = new_line_metric,
1222 .force_header = true,
1225 if (config->json_output)
1226 print_metric_headers_json(config, no_indent);
1227 else if (config->csv_output)
1228 print_metric_headers_csv(config, no_indent);
1230 print_metric_headers_std(config, no_indent);
1232 if (config->iostat_run)
1233 iostat_print_header_prefix(config);
1235 if (config->cgroup_list)
1236 os.cgrp = evlist__first(evlist)->cgrp;
1238 /* Print metrics headers only */
1239 evlist__for_each_entry(evlist, counter) {
1240 if (config->aggr_mode != AGGR_NONE && counter->metric_leader != counter)
1245 perf_stat__print_shadow_stats(config, counter, 0,
1248 &config->metric_events);
1251 if (!config->json_output)
1252 fputc('\n', config->output);
1255 static void prepare_interval(struct perf_stat_config *config,
1256 char *prefix, size_t len, struct timespec *ts)
1258 if (config->iostat_run)
1261 if (config->json_output)
1262 scnprintf(prefix, len, "\"interval\" : %lu.%09lu, ",
1263 (unsigned long) ts->tv_sec, ts->tv_nsec);
1264 else if (config->csv_output)
1265 scnprintf(prefix, len, "%lu.%09lu%s",
1266 (unsigned long) ts->tv_sec, ts->tv_nsec, config->csv_sep);
1268 scnprintf(prefix, len, "%6lu.%09lu ",
1269 (unsigned long) ts->tv_sec, ts->tv_nsec);
1272 static void print_header_interval_std(struct perf_stat_config *config,
1273 struct target *_target __maybe_unused,
1274 struct evlist *evlist,
1275 int argc __maybe_unused,
1276 const char **argv __maybe_unused)
1278 FILE *output = config->output;
1280 switch (config->aggr_mode) {
1287 fprintf(output, "#%*s %-*s cpus",
1288 INTERVAL_LEN - 1, "time",
1289 aggr_header_lens[config->aggr_mode],
1290 aggr_header_std[config->aggr_mode]);
1293 fprintf(output, "#%*s %-*s",
1294 INTERVAL_LEN - 1, "time",
1295 aggr_header_lens[config->aggr_mode],
1296 aggr_header_std[config->aggr_mode]);
1299 fprintf(output, "#%*s %*s-%-*s",
1300 INTERVAL_LEN - 1, "time",
1301 COMM_LEN, "comm", PID_LEN, "pid");
1305 if (!config->iostat_run)
1306 fprintf(output, "#%*s",
1307 INTERVAL_LEN - 1, "time");
1313 if (config->metric_only)
1314 print_metric_headers(config, evlist, true);
1316 fprintf(output, " %*s %*s events\n",
1317 COUNTS_LEN, "counts", config->unit_width, "unit");
1320 static void print_header_std(struct perf_stat_config *config,
1321 struct target *_target, struct evlist *evlist,
1322 int argc, const char **argv)
1324 FILE *output = config->output;
1327 fprintf(output, "\n");
1328 fprintf(output, " Performance counter stats for ");
1329 if (_target->bpf_str)
1330 fprintf(output, "\'BPF program(s) %s", _target->bpf_str);
1331 else if (_target->system_wide)
1332 fprintf(output, "\'system wide");
1333 else if (_target->cpu_list)
1334 fprintf(output, "\'CPU(s) %s", _target->cpu_list);
1335 else if (!target__has_task(_target)) {
1336 fprintf(output, "\'%s", argv ? argv[0] : "pipe");
1337 for (i = 1; argv && (i < argc); i++)
1338 fprintf(output, " %s", argv[i]);
1339 } else if (_target->pid)
1340 fprintf(output, "process id \'%s", _target->pid);
1342 fprintf(output, "thread id \'%s", _target->tid);
1344 fprintf(output, "\'");
1345 if (config->run_count > 1)
1346 fprintf(output, " (%d runs)", config->run_count);
1347 fprintf(output, ":\n\n");
1349 if (config->metric_only)
1350 print_metric_headers(config, evlist, false);
1353 static void print_header_csv(struct perf_stat_config *config,
1354 struct target *_target __maybe_unused,
1355 struct evlist *evlist,
1356 int argc __maybe_unused,
1357 const char **argv __maybe_unused)
1359 if (config->metric_only)
1360 print_metric_headers(config, evlist, true);
1362 static void print_header_json(struct perf_stat_config *config,
1363 struct target *_target __maybe_unused,
1364 struct evlist *evlist,
1365 int argc __maybe_unused,
1366 const char **argv __maybe_unused)
1368 if (config->metric_only)
1369 print_metric_headers(config, evlist, true);
1372 static void print_header(struct perf_stat_config *config,
1373 struct target *_target,
1374 struct evlist *evlist,
1375 int argc, const char **argv)
1377 static int num_print_iv;
1381 if (config->interval_clear)
1382 puts(CONSOLE_CLEAR);
1384 if (num_print_iv == 0 || config->interval_clear) {
1385 if (config->json_output)
1386 print_header_json(config, _target, evlist, argc, argv);
1387 else if (config->csv_output)
1388 print_header_csv(config, _target, evlist, argc, argv);
1389 else if (config->interval)
1390 print_header_interval_std(config, _target, evlist, argc, argv);
1392 print_header_std(config, _target, evlist, argc, argv);
1395 if (num_print_iv++ == 25)
1399 static int get_precision(double num)
1404 return lround(ceil(-log10(num)));
1407 static void print_table(struct perf_stat_config *config,
1408 FILE *output, int precision, double avg)
1411 int idx, indent = 0;
1413 scnprintf(tmp, 64, " %17.*f", precision, avg);
1414 while (tmp[indent] == ' ')
1417 fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1419 for (idx = 0; idx < config->run_count; idx++) {
1420 double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
1421 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1423 fprintf(output, " %17.*f (%+.*f) ",
1424 precision, run, precision, run - avg);
1426 for (h = 0; h < n; h++)
1427 fprintf(output, "#");
1429 fprintf(output, "\n");
1432 fprintf(output, "\n%*s# Final result:\n", indent, "");
1435 static double timeval2double(struct timeval *t)
1437 return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1440 static void print_footer(struct perf_stat_config *config)
1442 double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1443 FILE *output = config->output;
1445 if (config->interval || config->csv_output || config->json_output)
1448 if (!config->null_run)
1449 fprintf(output, "\n");
1451 if (config->run_count == 1) {
1452 fprintf(output, " %17.9f seconds time elapsed", avg);
1454 if (config->ru_display) {
1455 double ru_utime = timeval2double(&config->ru_data.ru_utime);
1456 double ru_stime = timeval2double(&config->ru_data.ru_stime);
1458 fprintf(output, "\n\n");
1459 fprintf(output, " %17.9f seconds user\n", ru_utime);
1460 fprintf(output, " %17.9f seconds sys\n", ru_stime);
1463 double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1465 * Display at most 2 more significant
1466 * digits than the stddev inaccuracy.
1468 int precision = get_precision(sd) + 2;
1470 if (config->walltime_run_table)
1471 print_table(config, output, precision, avg);
1473 fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1474 precision, avg, precision, sd);
1476 print_noise_pct(config, sd, avg, /*before_metric=*/false);
1478 fprintf(output, "\n\n");
1480 if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled())
1482 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1483 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1485 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1487 if (config->print_mixed_hw_group_error)
1489 "The events in group usually have to be from "
1490 "the same PMU. Try reorganizing the group.\n");
1493 static void print_percore(struct perf_stat_config *config,
1494 struct evsel *counter, struct outstate *os)
1496 bool metric_only = config->metric_only;
1497 FILE *output = config->output;
1498 struct cpu_aggr_map *core_map;
1499 int aggr_idx, core_map_len = 0;
1501 if (!config->aggr_map || !config->aggr_get_id)
1504 if (config->percore_show_thread)
1505 return print_counter(config, counter, os);
1508 * core_map will hold the aggr_cpu_id for the cores that have been
1509 * printed so that each core is printed just once.
1511 core_map = cpu_aggr_map__empty_new(config->aggr_map->nr);
1512 if (core_map == NULL) {
1513 fprintf(output, "Cannot allocate per-core aggr map for display\n");
1517 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1518 struct perf_cpu curr_cpu = config->aggr_map->map[aggr_idx].cpu;
1519 struct aggr_cpu_id core_id = aggr_cpu_id__core(curr_cpu, NULL);
1522 for (int i = 0; i < core_map_len; i++) {
1523 if (aggr_cpu_id__equal(&core_map->map[i], &core_id)) {
1531 print_counter_aggrdata(config, counter, aggr_idx, os);
1533 core_map->map[core_map_len++] = core_id;
1538 fputc('\n', output);
1541 static void print_cgroup_counter(struct perf_stat_config *config, struct evlist *evlist,
1542 struct outstate *os)
1544 struct evsel *counter;
1546 evlist__for_each_entry(evlist, counter) {
1547 if (os->cgrp != counter->cgrp) {
1548 if (os->cgrp != NULL)
1549 print_metric_end(config, os);
1551 os->cgrp = counter->cgrp;
1552 print_metric_begin(config, evlist, os, /*aggr_idx=*/0);
1555 print_counter(config, counter, os);
1558 print_metric_end(config, os);
1561 void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
1562 struct target *_target, struct timespec *ts,
1563 int argc, const char **argv)
1565 bool metric_only = config->metric_only;
1566 int interval = config->interval;
1567 struct evsel *counter;
1569 struct outstate os = {
1570 .fh = config->output,
1574 if (config->iostat_run)
1575 evlist->selected = evlist__first(evlist);
1579 prepare_interval(config, buf, sizeof(buf), ts);
1582 print_header(config, _target, evlist, argc, argv);
1584 switch (config->aggr_mode) {
1591 if (config->cgroup_list)
1592 print_aggr_cgroup(config, evlist, &os);
1594 print_aggr(config, evlist, &os);
1598 if (config->iostat_run) {
1599 iostat_print_counters(evlist, config, ts, buf,
1600 (iostat_print_counter_t)print_counter, &os);
1601 } else if (config->cgroup_list) {
1602 print_cgroup_counter(config, evlist, &os);
1604 print_metric_begin(config, evlist, &os, /*aggr_idx=*/0);
1605 evlist__for_each_entry(evlist, counter) {
1606 print_counter(config, counter, &os);
1608 print_metric_end(config, &os);
1613 print_no_aggr_metric(config, evlist, &os);
1615 evlist__for_each_entry(evlist, counter) {
1616 if (counter->percore)
1617 print_percore(config, counter, &os);
1619 print_counter(config, counter, &os);
1629 print_footer(config);
1631 fflush(config->output);