4 #include <linux/string.h>
5 #include <linux/time64.h>
7 #include <perf/cpumap.h>
15 #include "thread_map.h"
18 #include <linux/ctype.h>
20 #include <api/fs/fs.h>
27 #define CNTR_NOT_SUPPORTED "<not supported>"
28 #define CNTR_NOT_COUNTED "<not counted>"
34 #define INTERVAL_LEN 16
40 static int aggr_header_lens
[] = {
52 static const char *aggr_header_csv
[] = {
53 [AGGR_CORE
] = "core,cpus,",
54 [AGGR_CACHE
] = "cache,cpus,",
55 [AGGR_CLUSTER
] = "cluster,cpus,",
56 [AGGR_DIE
] = "die,cpus,",
57 [AGGR_SOCKET
] = "socket,cpus,",
59 [AGGR_THREAD
] = "comm-pid,",
60 [AGGR_NODE
] = "node,",
64 static const char *aggr_header_std
[] = {
66 [AGGR_CACHE
] = "cache",
67 [AGGR_CLUSTER
] = "cluster",
69 [AGGR_SOCKET
] = "socket",
71 [AGGR_THREAD
] = "comm-pid",
76 const char *metric_threshold_classify__color(enum metric_threshold_classify thresh
)
78 const char * const colors
[] = {
80 PERF_COLOR_RED
, /* bad */
81 PERF_COLOR_MAGENTA
, /* nearly bad */
82 PERF_COLOR_YELLOW
, /* less good */
83 PERF_COLOR_GREEN
, /* good */
85 static_assert(ARRAY_SIZE(colors
) - 1 == METRIC_THRESHOLD_GOOD
, "missing enum value");
86 return colors
[thresh
];
89 static const char *metric_threshold_classify__str(enum metric_threshold_classify thresh
)
91 const char * const strs
[] = {
98 static_assert(ARRAY_SIZE(strs
) - 1 == METRIC_THRESHOLD_GOOD
, "missing enum value");
102 static void print_running_std(struct perf_stat_config
*config
, u64 run
, u64 ena
)
105 fprintf(config
->output
, " (%.2f%%)", 100.0 * run
/ ena
);
108 static void print_running_csv(struct perf_stat_config
*config
, u64 run
, u64 ena
)
110 double enabled_percent
= 100;
113 enabled_percent
= 100 * run
/ ena
;
114 fprintf(config
->output
, "%s%" PRIu64
"%s%.2f",
115 config
->csv_sep
, run
, config
->csv_sep
, enabled_percent
);
118 static void print_running_json(struct perf_stat_config
*config
, u64 run
, u64 ena
)
120 double enabled_percent
= 100;
123 enabled_percent
= 100 * run
/ ena
;
124 fprintf(config
->output
, "\"event-runtime\" : %" PRIu64
", \"pcnt-running\" : %.2f, ",
125 run
, enabled_percent
);
128 static void print_running(struct perf_stat_config
*config
,
129 u64 run
, u64 ena
, bool before_metric
)
131 if (config
->json_output
) {
133 print_running_json(config
, run
, ena
);
134 } else if (config
->csv_output
) {
136 print_running_csv(config
, run
, ena
);
139 print_running_std(config
, run
, ena
);
143 static void print_noise_pct_std(struct perf_stat_config
*config
,
147 fprintf(config
->output
, " ( +-%6.2f%% )", pct
);
150 static void print_noise_pct_csv(struct perf_stat_config
*config
,
153 fprintf(config
->output
, "%s%.2f%%", config
->csv_sep
, pct
);
156 static void print_noise_pct_json(struct perf_stat_config
*config
,
159 fprintf(config
->output
, "\"variance\" : %.2f, ", pct
);
162 static void print_noise_pct(struct perf_stat_config
*config
,
163 double total
, double avg
, bool before_metric
)
165 double pct
= rel_stddev_stats(total
, avg
);
167 if (config
->json_output
) {
169 print_noise_pct_json(config
, pct
);
170 } else if (config
->csv_output
) {
172 print_noise_pct_csv(config
, pct
);
175 print_noise_pct_std(config
, pct
);
179 static void print_noise(struct perf_stat_config
*config
,
180 struct evsel
*evsel
, double avg
, bool before_metric
)
182 struct perf_stat_evsel
*ps
;
184 if (config
->run_count
== 1)
188 print_noise_pct(config
, stddev_stats(&ps
->res_stats
), avg
, before_metric
);
191 static void print_cgroup_std(struct perf_stat_config
*config
, const char *cgrp_name
)
193 fprintf(config
->output
, " %-*s", CGROUP_LEN
, cgrp_name
);
196 static void print_cgroup_csv(struct perf_stat_config
*config
, const char *cgrp_name
)
198 fprintf(config
->output
, "%s%s", config
->csv_sep
, cgrp_name
);
201 static void print_cgroup_json(struct perf_stat_config
*config
, const char *cgrp_name
)
203 fprintf(config
->output
, "\"cgroup\" : \"%s\", ", cgrp_name
);
206 static void print_cgroup(struct perf_stat_config
*config
, struct cgroup
*cgrp
)
208 if (nr_cgroups
|| config
->cgroup_list
) {
209 const char *cgrp_name
= cgrp
? cgrp
->name
: "";
211 if (config
->json_output
)
212 print_cgroup_json(config
, cgrp_name
);
213 else if (config
->csv_output
)
214 print_cgroup_csv(config
, cgrp_name
);
216 print_cgroup_std(config
, cgrp_name
);
220 static void print_aggr_id_std(struct perf_stat_config
*config
,
221 struct evsel
*evsel
, struct aggr_cpu_id id
, int aggr_nr
)
223 FILE *output
= config
->output
;
224 int idx
= config
->aggr_mode
;
227 switch (config
->aggr_mode
) {
229 snprintf(buf
, sizeof(buf
), "S%d-D%d-C%d", id
.socket
, id
.die
, id
.core
);
232 snprintf(buf
, sizeof(buf
), "S%d-D%d-L%d-ID%d",
233 id
.socket
, id
.die
, id
.cache_lvl
, id
.cache
);
236 snprintf(buf
, sizeof(buf
), "S%d-D%d-CLS%d", id
.socket
, id
.die
, id
.cluster
);
239 snprintf(buf
, sizeof(buf
), "S%d-D%d", id
.socket
, id
.die
);
242 snprintf(buf
, sizeof(buf
), "S%d", id
.socket
);
245 snprintf(buf
, sizeof(buf
), "N%d", id
.node
);
248 if (evsel
->percore
&& !config
->percore_show_thread
) {
249 snprintf(buf
, sizeof(buf
), "S%d-D%d-C%d ",
250 id
.socket
, id
.die
, id
.core
);
251 fprintf(output
, "%-*s ",
252 aggr_header_lens
[AGGR_CORE
], buf
);
253 } else if (id
.cpu
.cpu
> -1) {
254 fprintf(output
, "CPU%-*d ",
255 aggr_header_lens
[AGGR_NONE
] - 3, id
.cpu
.cpu
);
259 fprintf(output
, "%*s-%-*d ",
260 COMM_LEN
, perf_thread_map__comm(evsel
->core
.threads
, id
.thread_idx
),
261 PID_LEN
, perf_thread_map__pid(evsel
->core
.threads
, id
.thread_idx
));
270 fprintf(output
, "%-*s %*d ", aggr_header_lens
[idx
], buf
, 4, aggr_nr
);
273 static void print_aggr_id_csv(struct perf_stat_config
*config
,
274 struct evsel
*evsel
, struct aggr_cpu_id id
, int aggr_nr
)
276 FILE *output
= config
->output
;
277 const char *sep
= config
->csv_sep
;
279 switch (config
->aggr_mode
) {
281 fprintf(output
, "S%d-D%d-C%d%s%d%s",
282 id
.socket
, id
.die
, id
.core
, sep
, aggr_nr
, sep
);
285 fprintf(config
->output
, "S%d-D%d-L%d-ID%d%s%d%s",
286 id
.socket
, id
.die
, id
.cache_lvl
, id
.cache
, sep
, aggr_nr
, sep
);
289 fprintf(config
->output
, "S%d-D%d-CLS%d%s%d%s",
290 id
.socket
, id
.die
, id
.cluster
, sep
, aggr_nr
, sep
);
293 fprintf(output
, "S%d-D%d%s%d%s",
294 id
.socket
, id
.die
, sep
, aggr_nr
, sep
);
297 fprintf(output
, "S%d%s%d%s",
298 id
.socket
, sep
, aggr_nr
, sep
);
301 fprintf(output
, "N%d%s%d%s",
302 id
.node
, sep
, aggr_nr
, sep
);
305 if (evsel
->percore
&& !config
->percore_show_thread
) {
306 fprintf(output
, "S%d-D%d-C%d%s",
307 id
.socket
, id
.die
, id
.core
, sep
);
308 } else if (id
.cpu
.cpu
> -1) {
309 fprintf(output
, "CPU%d%s",
314 fprintf(output
, "%s-%d%s",
315 perf_thread_map__comm(evsel
->core
.threads
, id
.thread_idx
),
316 perf_thread_map__pid(evsel
->core
.threads
, id
.thread_idx
),
327 static void print_aggr_id_json(struct perf_stat_config
*config
,
328 struct evsel
*evsel
, struct aggr_cpu_id id
, int aggr_nr
)
330 FILE *output
= config
->output
;
332 switch (config
->aggr_mode
) {
334 fprintf(output
, "\"core\" : \"S%d-D%d-C%d\", \"aggregate-number\" : %d, ",
335 id
.socket
, id
.die
, id
.core
, aggr_nr
);
338 fprintf(output
, "\"cache\" : \"S%d-D%d-L%d-ID%d\", \"aggregate-number\" : %d, ",
339 id
.socket
, id
.die
, id
.cache_lvl
, id
.cache
, aggr_nr
);
342 fprintf(output
, "\"cluster\" : \"S%d-D%d-CLS%d\", \"aggregate-number\" : %d, ",
343 id
.socket
, id
.die
, id
.cluster
, aggr_nr
);
346 fprintf(output
, "\"die\" : \"S%d-D%d\", \"aggregate-number\" : %d, ",
347 id
.socket
, id
.die
, aggr_nr
);
350 fprintf(output
, "\"socket\" : \"S%d\", \"aggregate-number\" : %d, ",
354 fprintf(output
, "\"node\" : \"N%d\", \"aggregate-number\" : %d, ",
358 if (evsel
->percore
&& !config
->percore_show_thread
) {
359 fprintf(output
, "\"core\" : \"S%d-D%d-C%d\"",
360 id
.socket
, id
.die
, id
.core
);
361 } else if (id
.cpu
.cpu
> -1) {
362 fprintf(output
, "\"cpu\" : \"%d\", ",
367 fprintf(output
, "\"thread\" : \"%s-%d\", ",
368 perf_thread_map__comm(evsel
->core
.threads
, id
.thread_idx
),
369 perf_thread_map__pid(evsel
->core
.threads
, id
.thread_idx
));
379 static void aggr_printout(struct perf_stat_config
*config
,
380 struct evsel
*evsel
, struct aggr_cpu_id id
, int aggr_nr
)
382 if (config
->json_output
)
383 print_aggr_id_json(config
, evsel
, id
, aggr_nr
);
384 else if (config
->csv_output
)
385 print_aggr_id_csv(config
, evsel
, id
, aggr_nr
);
387 print_aggr_id_std(config
, evsel
, id
, aggr_nr
);
397 struct aggr_cpu_id id
;
402 static void new_line_std(struct perf_stat_config
*config __maybe_unused
,
405 struct outstate
*os
= ctx
;
410 static inline void __new_line_std_csv(struct perf_stat_config
*config
,
415 fputs(os
->prefix
, os
->fh
);
416 aggr_printout(config
, os
->evsel
, os
->id
, os
->aggr_nr
);
419 static inline void __new_line_std(struct outstate
*os
)
421 fprintf(os
->fh
, " ");
424 static void do_new_line_std(struct perf_stat_config
*config
,
427 __new_line_std_csv(config
, os
);
428 if (config
->aggr_mode
== AGGR_NONE
)
429 fprintf(os
->fh
, " ");
433 static void print_metric_std(struct perf_stat_config
*config
,
434 void *ctx
, enum metric_threshold_classify thresh
,
435 const char *fmt
, const char *unit
, double val
)
437 struct outstate
*os
= ctx
;
440 bool newline
= os
->newline
;
441 const char *color
= metric_threshold_classify__color(thresh
);
445 if (unit
== NULL
|| fmt
== NULL
) {
446 fprintf(out
, "%-*s", METRIC_LEN
, "");
451 do_new_line_std(config
, os
);
453 n
= fprintf(out
, " # ");
455 n
+= color_fprintf(out
, color
, fmt
, val
);
457 n
+= fprintf(out
, fmt
, val
);
458 fprintf(out
, " %-*s", METRIC_LEN
- n
- 1, unit
);
461 static void new_line_csv(struct perf_stat_config
*config
, void *ctx
)
463 struct outstate
*os
= ctx
;
466 __new_line_std_csv(config
, os
);
467 for (i
= 0; i
< os
->nfields
; i
++)
468 fputs(config
->csv_sep
, os
->fh
);
471 static void print_metric_csv(struct perf_stat_config
*config __maybe_unused
,
473 enum metric_threshold_classify thresh __maybe_unused
,
474 const char *fmt
, const char *unit
, double val
)
476 struct outstate
*os
= ctx
;
478 char buf
[64], *vals
, *ends
;
480 if (unit
== NULL
|| fmt
== NULL
) {
481 fprintf(out
, "%s%s", config
->csv_sep
, config
->csv_sep
);
484 snprintf(buf
, sizeof(buf
), fmt
, val
);
485 ends
= vals
= skip_spaces(buf
);
486 while (isdigit(*ends
) || *ends
== '.')
489 fprintf(out
, "%s%s%s%s", config
->csv_sep
, vals
, config
->csv_sep
, skip_spaces(unit
));
492 static void print_metric_json(struct perf_stat_config
*config __maybe_unused
,
494 enum metric_threshold_classify thresh
,
495 const char *fmt __maybe_unused
,
496 const char *unit
, double val
)
498 struct outstate
*os
= ctx
;
502 fprintf(out
, "\"metric-value\" : \"%f\", \"metric-unit\" : \"%s\"", val
, unit
);
503 if (thresh
!= METRIC_THRESHOLD_UNKNOWN
) {
504 fprintf(out
, ", \"metric-threshold\" : \"%s\"",
505 metric_threshold_classify__str(thresh
));
508 if (!config
->metric_only
)
512 static void new_line_json(struct perf_stat_config
*config
, void *ctx
)
514 struct outstate
*os
= ctx
;
516 fputs("\n{", os
->fh
);
518 fprintf(os
->fh
, "%s", os
->prefix
);
519 aggr_printout(config
, os
->evsel
, os
->id
, os
->aggr_nr
);
522 static void print_metricgroup_header_json(struct perf_stat_config
*config
,
524 const char *metricgroup_name
)
526 if (!metricgroup_name
)
529 fprintf(config
->output
, "\"metricgroup\" : \"%s\"}", metricgroup_name
);
530 new_line_json(config
, ctx
);
533 static void print_metricgroup_header_csv(struct perf_stat_config
*config
,
535 const char *metricgroup_name
)
537 struct outstate
*os
= ctx
;
540 if (!metricgroup_name
) {
541 /* Leave space for running and enabling */
542 for (i
= 0; i
< os
->nfields
- 2; i
++)
543 fputs(config
->csv_sep
, os
->fh
);
547 for (i
= 0; i
< os
->nfields
; i
++)
548 fputs(config
->csv_sep
, os
->fh
);
549 fprintf(config
->output
, "%s", metricgroup_name
);
550 new_line_csv(config
, ctx
);
553 static void print_metricgroup_header_std(struct perf_stat_config
*config
,
555 const char *metricgroup_name
)
557 struct outstate
*os
= ctx
;
560 if (!metricgroup_name
) {
565 n
= fprintf(config
->output
, " %*s", EVNAME_LEN
, metricgroup_name
);
567 fprintf(config
->output
, "%*s", MGROUP_LEN
- n
- 1, "");
570 /* Filter out some columns that don't work well in metrics only mode */
572 static bool valid_only_metric(const char *unit
)
576 if (strstr(unit
, "/sec") ||
577 strstr(unit
, "CPUs utilized"))
582 static const char *fixunit(char *buf
, struct evsel
*evsel
,
585 if (!strncmp(unit
, "of all", 6)) {
586 snprintf(buf
, 1024, "%s %s", evsel__name(evsel
),
593 static void print_metric_only(struct perf_stat_config
*config
,
594 void *ctx
, enum metric_threshold_classify thresh
,
595 const char *fmt
, const char *unit
, double val
)
597 struct outstate
*os
= ctx
;
599 char buf
[1024], str
[1024];
600 unsigned mlen
= config
->metric_only_len
;
601 const char *color
= metric_threshold_classify__color(thresh
);
603 if (!valid_only_metric(unit
))
605 unit
= fixunit(buf
, os
->evsel
, unit
);
606 if (mlen
< strlen(unit
))
607 mlen
= strlen(unit
) + 1;
610 mlen
+= strlen(color
) + sizeof(PERF_COLOR_RESET
) - 1;
612 color_snprintf(str
, sizeof(str
), color
?: "", fmt
?: "", val
);
613 fprintf(out
, "%*s ", mlen
, str
);
617 static void print_metric_only_csv(struct perf_stat_config
*config __maybe_unused
,
619 enum metric_threshold_classify thresh __maybe_unused
,
621 const char *unit
, double val
)
623 struct outstate
*os
= ctx
;
625 char buf
[64], *vals
, *ends
;
628 if (!valid_only_metric(unit
))
630 unit
= fixunit(tbuf
, os
->evsel
, unit
);
631 snprintf(buf
, sizeof(buf
), fmt
?: "", val
);
632 ends
= vals
= skip_spaces(buf
);
633 while (isdigit(*ends
) || *ends
== '.')
636 fprintf(out
, "%s%s", vals
, config
->csv_sep
);
640 static void print_metric_only_json(struct perf_stat_config
*config __maybe_unused
,
642 enum metric_threshold_classify thresh __maybe_unused
,
644 const char *unit
, double val
)
646 struct outstate
*os
= ctx
;
652 if (!valid_only_metric(unit
))
654 unit
= fixunit(tbuf
, os
->evsel
, unit
);
657 snprintf(buf
, sizeof(buf
), fmt
?: "", val
);
658 vals
= ends
= skip_spaces(buf
);
659 while (isdigit(*ends
) || *ends
== '.')
664 fprintf(out
, "%s\"%s\" : \"%s\"", os
->first
? "" : ", ", unit
, vals
);
668 static void new_line_metric(struct perf_stat_config
*config __maybe_unused
,
669 void *ctx __maybe_unused
)
673 static void print_metric_header(struct perf_stat_config
*config
,
675 enum metric_threshold_classify thresh __maybe_unused
,
676 const char *fmt __maybe_unused
,
677 const char *unit
, double val __maybe_unused
)
679 struct outstate
*os
= ctx
;
682 /* In case of iostat, print metric header for first root port only */
683 if (config
->iostat_run
&&
684 os
->evsel
->priv
!= os
->evsel
->evlist
->selected
->priv
)
687 if (os
->evsel
->cgrp
!= os
->cgrp
)
690 if (!valid_only_metric(unit
))
692 unit
= fixunit(tbuf
, os
->evsel
, unit
);
694 if (config
->json_output
)
696 else if (config
->csv_output
)
697 fprintf(os
->fh
, "%s%s", unit
, config
->csv_sep
);
699 fprintf(os
->fh
, "%*s ", config
->metric_only_len
, unit
);
702 static void print_counter_value_std(struct perf_stat_config
*config
,
703 struct evsel
*evsel
, double avg
, bool ok
)
705 FILE *output
= config
->output
;
706 double sc
= evsel
->scale
;
708 const char *bad_count
= evsel
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
;
711 fmt
= floor(sc
) != sc
? "%'*.2f " : "%'*.0f ";
713 fmt
= floor(sc
) != sc
? "%*.2f " : "%*.0f ";
716 fprintf(output
, fmt
, COUNTS_LEN
, avg
);
718 fprintf(output
, "%*s ", COUNTS_LEN
, bad_count
);
721 fprintf(output
, "%-*s ", config
->unit_width
, evsel
->unit
);
723 fprintf(output
, "%-*s", EVNAME_LEN
, evsel__name(evsel
));
726 static void print_counter_value_csv(struct perf_stat_config
*config
,
727 struct evsel
*evsel
, double avg
, bool ok
)
729 FILE *output
= config
->output
;
730 double sc
= evsel
->scale
;
731 const char *sep
= config
->csv_sep
;
732 const char *fmt
= floor(sc
) != sc
? "%.2f%s" : "%.0f%s";
733 const char *bad_count
= evsel
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
;
736 fprintf(output
, fmt
, avg
, sep
);
738 fprintf(output
, "%s%s", bad_count
, sep
);
741 fprintf(output
, "%s%s", evsel
->unit
, sep
);
743 fprintf(output
, "%s", evsel__name(evsel
));
746 static void print_counter_value_json(struct perf_stat_config
*config
,
747 struct evsel
*evsel
, double avg
, bool ok
)
749 FILE *output
= config
->output
;
750 const char *bad_count
= evsel
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
;
753 fprintf(output
, "\"counter-value\" : \"%f\", ", avg
);
755 fprintf(output
, "\"counter-value\" : \"%s\", ", bad_count
);
758 fprintf(output
, "\"unit\" : \"%s\", ", evsel
->unit
);
760 fprintf(output
, "\"event\" : \"%s\", ", evsel__name(evsel
));
763 static void print_counter_value(struct perf_stat_config
*config
,
764 struct evsel
*evsel
, double avg
, bool ok
)
766 if (config
->json_output
)
767 print_counter_value_json(config
, evsel
, avg
, ok
);
768 else if (config
->csv_output
)
769 print_counter_value_csv(config
, evsel
, avg
, ok
);
771 print_counter_value_std(config
, evsel
, avg
, ok
);
774 static void abs_printout(struct perf_stat_config
*config
,
775 struct aggr_cpu_id id
, int aggr_nr
,
776 struct evsel
*evsel
, double avg
, bool ok
)
778 aggr_printout(config
, evsel
, id
, aggr_nr
);
779 print_counter_value(config
, evsel
, avg
, ok
);
780 print_cgroup(config
, evsel
->cgrp
);
783 static bool is_mixed_hw_group(struct evsel
*counter
)
785 struct evlist
*evlist
= counter
->evlist
;
786 u32 pmu_type
= counter
->core
.attr
.type
;
789 if (counter
->core
.nr_members
< 2)
792 evlist__for_each_entry(evlist
, pos
) {
793 /* software events can be part of any hardware group */
794 if (pos
->core
.attr
.type
== PERF_TYPE_SOFTWARE
)
796 if (pmu_type
== PERF_TYPE_SOFTWARE
) {
797 pmu_type
= pos
->core
.attr
.type
;
800 if (pmu_type
!= pos
->core
.attr
.type
)
807 static bool evlist__has_hybrid(struct evlist
*evlist
)
811 if (perf_pmus__num_core_pmus() == 1)
814 evlist__for_each_entry(evlist
, evsel
) {
815 if (evsel
->core
.is_pmu_core
)
822 static void printout(struct perf_stat_config
*config
, struct outstate
*os
,
823 double uval
, u64 run
, u64 ena
, double noise
, int aggr_idx
)
825 struct perf_stat_output_ctx out
;
828 print_metricgroup_header_t pmh
;
830 struct evsel
*counter
= os
->evsel
;
832 if (config
->csv_output
) {
833 pm
= config
->metric_only
? print_metric_only_csv
: print_metric_csv
;
834 nl
= config
->metric_only
? new_line_metric
: new_line_csv
;
835 pmh
= print_metricgroup_header_csv
;
836 os
->nfields
= 4 + (counter
->cgrp
? 1 : 0);
837 } else if (config
->json_output
) {
838 pm
= config
->metric_only
? print_metric_only_json
: print_metric_json
;
839 nl
= config
->metric_only
? new_line_metric
: new_line_json
;
840 pmh
= print_metricgroup_header_json
;
842 pm
= config
->metric_only
? print_metric_only
: print_metric_std
;
843 nl
= config
->metric_only
? new_line_metric
: new_line_std
;
844 pmh
= print_metricgroup_header_std
;
847 if (run
== 0 || ena
== 0 || counter
->counts
->scaled
== -1) {
848 if (config
->metric_only
) {
849 pm(config
, os
, METRIC_THRESHOLD_UNKNOWN
, "", "", 0);
855 if (counter
->supported
) {
856 if (!evlist__has_hybrid(counter
->evlist
)) {
857 config
->print_free_counters_hint
= 1;
858 if (is_mixed_hw_group(counter
))
859 config
->print_mixed_hw_group_error
= 1;
864 out
.print_metric
= pm
;
866 out
.print_metricgroup_header
= pmh
;
868 out
.force_header
= false;
870 if (!config
->metric_only
&& !counter
->default_metricgroup
) {
871 abs_printout(config
, os
->id
, os
->aggr_nr
, counter
, uval
, ok
);
873 print_noise(config
, counter
, noise
, /*before_metric=*/true);
874 print_running(config
, run
, ena
, /*before_metric=*/true);
878 if (!config
->metric_only
&& counter
->default_metricgroup
) {
881 aggr_printout(config
, os
->evsel
, os
->id
, os
->aggr_nr
);
882 /* Print out all the metricgroup with the same metric event. */
886 /* Print out the new line for the next new metricgroup. */
888 if (config
->json_output
)
889 new_line_json(config
, (void *)os
);
891 __new_line_std_csv(config
, os
);
894 print_noise(config
, counter
, noise
, /*before_metric=*/true);
895 print_running(config
, run
, ena
, /*before_metric=*/true);
896 from
= perf_stat__print_shadow_stats_metricgroup(config
, counter
, aggr_idx
,
898 &config
->metric_events
);
899 } while (from
!= NULL
);
901 perf_stat__print_shadow_stats(config
, counter
, uval
, aggr_idx
,
902 &out
, &config
->metric_events
);
904 pm(config
, os
, METRIC_THRESHOLD_UNKNOWN
, /*format=*/NULL
, /*unit=*/"", /*val=*/0);
907 if (!config
->metric_only
) {
908 print_noise(config
, counter
, noise
, /*before_metric=*/false);
909 print_running(config
, run
, ena
, /*before_metric=*/false);
913 static void uniquify_event_name(struct evsel
*counter
)
915 const char *name
, *pmu_name
;
916 char *new_name
, *config
;
919 /* The evsel was already uniquified. */
920 if (counter
->uniquified_name
)
923 /* Avoid checking to uniquify twice. */
924 counter
->uniquified_name
= true;
926 /* The evsel has a "name=" config term or is from libpfm. */
927 if (counter
->use_config_name
|| counter
->is_libpfm_event
)
930 /* Legacy no PMU event, don't uniquify. */
932 (counter
->pmu
->type
< PERF_TYPE_MAX
&& counter
->pmu
->type
!= PERF_TYPE_RAW
))
935 /* A sysfs or json event replacing a legacy event, don't uniquify. */
936 if (counter
->pmu
->is_core
&& counter
->alternate_hw_config
!= PERF_COUNT_HW_MAX
)
939 name
= evsel__name(counter
);
940 pmu_name
= counter
->pmu
->name
;
941 /* Already prefixed by the PMU name. */
942 if (!strncmp(name
, pmu_name
, strlen(pmu_name
)))
945 config
= strchr(name
, '/');
947 int len
= config
- name
;
949 if (config
[1] == '/') {
951 ret
= asprintf(&new_name
, "%s/%.*s/%s", pmu_name
, len
, name
, config
+ 2);
953 /* case: event/.../ */
954 ret
= asprintf(&new_name
, "%s/%.*s,%s", pmu_name
, len
, name
, config
+ 1);
957 config
= strchr(name
, ':');
960 int len
= config
- name
;
962 ret
= asprintf(&new_name
, "%s/%.*s/%s", pmu_name
, len
, name
, config
+ 1);
965 ret
= asprintf(&new_name
, "%s/%s/", pmu_name
, name
);
970 counter
->name
= new_name
;
972 /* ENOMEM from asprintf. */
973 counter
->uniquified_name
= false;
977 static bool hybrid_uniquify(struct evsel
*evsel
, struct perf_stat_config
*config
)
979 return evsel__is_hybrid(evsel
) && !config
->hybrid_merge
;
982 static void uniquify_counter(struct perf_stat_config
*config
, struct evsel
*counter
)
984 if (config
->aggr_mode
== AGGR_NONE
|| hybrid_uniquify(counter
, config
))
985 uniquify_event_name(counter
);
989 * should_skip_zero_count() - Check if the event should print 0 values.
990 * @config: The perf stat configuration (including aggregation mode).
991 * @counter: The evsel with its associated cpumap.
992 * @id: The aggregation id that is being queried.
994 * Due to mismatch between the event cpumap or thread-map and the
995 * aggregation mode, sometimes it'd iterate the counter with the map
996 * which does not contain any values.
998 * For example, uncore events have dedicated CPUs to manage them,
999 * result for other CPUs should be zero and skipped.
1001 * Return: %true if the value should NOT be printed, %false if the value
1002 * needs to be printed like "<not counted>" or "<not supported>".
1004 static bool should_skip_zero_counter(struct perf_stat_config
*config
,
1005 struct evsel
*counter
,
1006 const struct aggr_cpu_id
*id
)
1008 struct perf_cpu cpu
;
1012 * Skip unsupported default events when not verbose. (default events
1013 * are all marked 'skippable').
1015 if (verbose
== 0 && counter
->skippable
&& !counter
->supported
)
1019 * Skip value 0 when enabling --per-thread globally,
1020 * otherwise it will have too many 0 output.
1022 if (config
->aggr_mode
== AGGR_THREAD
&& config
->system_wide
)
1026 * Many tool events are only gathered on the first index, skip other
1029 if (evsel__is_tool(counter
)) {
1030 struct aggr_cpu_id own_id
=
1031 config
->aggr_get_id(config
, (struct perf_cpu
){ .cpu
= 0 });
1033 return !aggr_cpu_id__equal(id
, &own_id
);
1037 * Skip value 0 when it's an uncore event and the given aggr id
1038 * does not belong to the PMU cpumask.
1040 if (!counter
->pmu
|| !counter
->pmu
->is_uncore
)
1043 perf_cpu_map__for_each_cpu(cpu
, idx
, counter
->pmu
->cpus
) {
1044 struct aggr_cpu_id own_id
= config
->aggr_get_id(config
, cpu
);
1046 if (aggr_cpu_id__equal(id
, &own_id
))
1052 static void print_counter_aggrdata(struct perf_stat_config
*config
,
1053 struct evsel
*counter
, int aggr_idx
,
1054 struct outstate
*os
)
1056 FILE *output
= config
->output
;
1059 struct perf_stat_evsel
*ps
= counter
->stats
;
1060 struct perf_stat_aggr
*aggr
= &ps
->aggr
[aggr_idx
];
1061 struct aggr_cpu_id id
= config
->aggr_map
->map
[aggr_idx
];
1062 double avg
= aggr
->counts
.val
;
1063 bool metric_only
= config
->metric_only
;
1066 os
->aggr_nr
= aggr
->nr
;
1067 os
->evsel
= counter
;
1069 /* Skip already merged uncore/hybrid events */
1070 if (counter
->merged_stat
)
1073 uniquify_counter(config
, counter
);
1075 val
= aggr
->counts
.val
;
1076 ena
= aggr
->counts
.ena
;
1077 run
= aggr
->counts
.run
;
1079 if (perf_stat__skip_metric_event(counter
, &config
->metric_events
, ena
, run
))
1082 if (val
== 0 && should_skip_zero_counter(config
, counter
, &id
))
1086 if (config
->json_output
)
1089 fprintf(output
, "%s", os
->prefix
);
1090 else if (config
->summary
&& config
->csv_output
&&
1091 !config
->no_csv_summary
&& !config
->interval
)
1092 fprintf(output
, "%s%s", "summary", config
->csv_sep
);
1095 uval
= val
* counter
->scale
;
1097 printout(config
, os
, uval
, run
, ena
, avg
, aggr_idx
);
1100 fputc('\n', output
);
1103 static void print_metric_begin(struct perf_stat_config
*config
,
1104 struct evlist
*evlist
,
1105 struct outstate
*os
, int aggr_idx
)
1107 struct perf_stat_aggr
*aggr
;
1108 struct aggr_cpu_id id
;
1109 struct evsel
*evsel
;
1112 if (!config
->metric_only
)
1115 if (config
->json_output
)
1116 fputc('{', config
->output
);
1118 fprintf(config
->output
, "%s", os
->prefix
);
1120 evsel
= evlist__first(evlist
);
1121 id
= config
->aggr_map
->map
[aggr_idx
];
1122 aggr
= &evsel
->stats
->aggr
[aggr_idx
];
1123 aggr_printout(config
, evsel
, id
, aggr
->nr
);
1125 print_cgroup(config
, os
->cgrp
? : evsel
->cgrp
);
1128 static void print_metric_end(struct perf_stat_config
*config
, struct outstate
*os
)
1130 FILE *output
= config
->output
;
1132 if (!config
->metric_only
)
1135 if (config
->json_output
) {
1137 fputs("\"metric-value\" : \"none\"", output
);
1140 fputc('\n', output
);
1143 static void print_aggr(struct perf_stat_config
*config
,
1144 struct evlist
*evlist
,
1145 struct outstate
*os
)
1147 struct evsel
*counter
;
1150 if (!config
->aggr_map
|| !config
->aggr_get_id
)
1154 * With metric_only everything is on a single line.
1155 * Without each counter has its own line.
1157 cpu_aggr_map__for_each_idx(aggr_idx
, config
->aggr_map
) {
1158 print_metric_begin(config
, evlist
, os
, aggr_idx
);
1160 evlist__for_each_entry(evlist
, counter
) {
1161 print_counter_aggrdata(config
, counter
, aggr_idx
, os
);
1163 print_metric_end(config
, os
);
1167 static void print_aggr_cgroup(struct perf_stat_config
*config
,
1168 struct evlist
*evlist
,
1169 struct outstate
*os
)
1171 struct evsel
*counter
, *evsel
;
1174 if (!config
->aggr_map
|| !config
->aggr_get_id
)
1177 evlist__for_each_entry(evlist
, evsel
) {
1178 if (os
->cgrp
== evsel
->cgrp
)
1181 os
->cgrp
= evsel
->cgrp
;
1183 cpu_aggr_map__for_each_idx(aggr_idx
, config
->aggr_map
) {
1184 print_metric_begin(config
, evlist
, os
, aggr_idx
);
1186 evlist__for_each_entry(evlist
, counter
) {
1187 if (counter
->cgrp
!= os
->cgrp
)
1190 print_counter_aggrdata(config
, counter
, aggr_idx
, os
);
1192 print_metric_end(config
, os
);
1197 static void print_counter(struct perf_stat_config
*config
,
1198 struct evsel
*counter
, struct outstate
*os
)
1202 /* AGGR_THREAD doesn't have config->aggr_get_id */
1203 if (!config
->aggr_map
)
1206 cpu_aggr_map__for_each_idx(aggr_idx
, config
->aggr_map
) {
1207 print_counter_aggrdata(config
, counter
, aggr_idx
, os
);
1211 static void print_no_aggr_metric(struct perf_stat_config
*config
,
1212 struct evlist
*evlist
,
1213 struct outstate
*os
)
1216 struct perf_cpu cpu
;
1218 perf_cpu_map__for_each_cpu(cpu
, all_idx
, evlist
->core
.user_requested_cpus
) {
1219 struct evsel
*counter
;
1222 evlist__for_each_entry(evlist
, counter
) {
1225 struct perf_stat_evsel
*ps
= counter
->stats
;
1228 if (!perf_cpu_map__has(evsel__cpus(counter
), cpu
))
1231 cpu_aggr_map__for_each_idx(aggr_idx
, config
->aggr_map
) {
1232 if (config
->aggr_map
->map
[aggr_idx
].cpu
.cpu
== cpu
.cpu
)
1236 os
->evsel
= counter
;
1237 os
->id
= aggr_cpu_id__cpu(cpu
, /*data=*/NULL
);
1239 print_metric_begin(config
, evlist
, os
, aggr_idx
);
1242 val
= ps
->aggr
[aggr_idx
].counts
.val
;
1243 ena
= ps
->aggr
[aggr_idx
].counts
.ena
;
1244 run
= ps
->aggr
[aggr_idx
].counts
.run
;
1246 uval
= val
* counter
->scale
;
1247 printout(config
, os
, uval
, run
, ena
, 1.0, aggr_idx
);
1250 print_metric_end(config
, os
);
1254 static void print_metric_headers_std(struct perf_stat_config
*config
,
1257 fputc(' ', config
->output
);
1260 int len
= aggr_header_lens
[config
->aggr_mode
];
1262 if (nr_cgroups
|| config
->cgroup_list
)
1263 len
+= CGROUP_LEN
+ 1;
1265 fprintf(config
->output
, "%*s", len
, "");
1269 static void print_metric_headers_csv(struct perf_stat_config
*config
,
1270 bool no_indent __maybe_unused
)
1274 if (config
->interval
)
1275 fprintf(config
->output
, "time%s", config
->csv_sep
);
1276 if (config
->iostat_run
)
1279 p
= aggr_header_csv
[config
->aggr_mode
];
1282 fputs(config
->csv_sep
, config
->output
);
1284 fputc(*p
, config
->output
);
1289 static void print_metric_headers_json(struct perf_stat_config
*config __maybe_unused
,
1290 bool no_indent __maybe_unused
)
1294 static void print_metric_headers(struct perf_stat_config
*config
,
1295 struct evlist
*evlist
, bool no_indent
)
1297 struct evsel
*counter
;
1298 struct outstate os
= {
1299 .fh
= config
->output
1301 struct perf_stat_output_ctx out
= {
1303 .print_metric
= print_metric_header
,
1304 .new_line
= new_line_metric
,
1305 .force_header
= true,
1308 if (config
->json_output
)
1309 print_metric_headers_json(config
, no_indent
);
1310 else if (config
->csv_output
)
1311 print_metric_headers_csv(config
, no_indent
);
1313 print_metric_headers_std(config
, no_indent
);
1315 if (config
->iostat_run
)
1316 iostat_print_header_prefix(config
);
1318 if (config
->cgroup_list
)
1319 os
.cgrp
= evlist__first(evlist
)->cgrp
;
1321 /* Print metrics headers only */
1322 evlist__for_each_entry(evlist
, counter
) {
1323 if (!config
->iostat_run
&&
1324 config
->aggr_mode
!= AGGR_NONE
&& counter
->metric_leader
!= counter
)
1329 perf_stat__print_shadow_stats(config
, counter
, 0,
1332 &config
->metric_events
);
1335 if (!config
->json_output
)
1336 fputc('\n', config
->output
);
1339 static void prepare_interval(struct perf_stat_config
*config
,
1340 char *prefix
, size_t len
, struct timespec
*ts
)
1342 if (config
->iostat_run
)
1345 if (config
->json_output
)
1346 scnprintf(prefix
, len
, "\"interval\" : %lu.%09lu, ",
1347 (unsigned long) ts
->tv_sec
, ts
->tv_nsec
);
1348 else if (config
->csv_output
)
1349 scnprintf(prefix
, len
, "%lu.%09lu%s",
1350 (unsigned long) ts
->tv_sec
, ts
->tv_nsec
, config
->csv_sep
);
1352 scnprintf(prefix
, len
, "%6lu.%09lu ",
1353 (unsigned long) ts
->tv_sec
, ts
->tv_nsec
);
1356 static void print_header_interval_std(struct perf_stat_config
*config
,
1357 struct target
*_target __maybe_unused
,
1358 struct evlist
*evlist
,
1359 int argc __maybe_unused
,
1360 const char **argv __maybe_unused
)
1362 FILE *output
= config
->output
;
1364 switch (config
->aggr_mode
) {
1371 fprintf(output
, "#%*s %-*s cpus",
1372 INTERVAL_LEN
- 1, "time",
1373 aggr_header_lens
[config
->aggr_mode
],
1374 aggr_header_std
[config
->aggr_mode
]);
1377 fprintf(output
, "#%*s %-*s",
1378 INTERVAL_LEN
- 1, "time",
1379 aggr_header_lens
[config
->aggr_mode
],
1380 aggr_header_std
[config
->aggr_mode
]);
1383 fprintf(output
, "#%*s %*s-%-*s",
1384 INTERVAL_LEN
- 1, "time",
1385 COMM_LEN
, "comm", PID_LEN
, "pid");
1389 if (!config
->iostat_run
)
1390 fprintf(output
, "#%*s",
1391 INTERVAL_LEN
- 1, "time");
1397 if (config
->metric_only
)
1398 print_metric_headers(config
, evlist
, true);
1400 fprintf(output
, " %*s %*s events\n",
1401 COUNTS_LEN
, "counts", config
->unit_width
, "unit");
1404 static void print_header_std(struct perf_stat_config
*config
,
1405 struct target
*_target
, struct evlist
*evlist
,
1406 int argc
, const char **argv
)
1408 FILE *output
= config
->output
;
1411 fprintf(output
, "\n");
1412 fprintf(output
, " Performance counter stats for ");
1413 if (_target
->bpf_str
)
1414 fprintf(output
, "\'BPF program(s) %s", _target
->bpf_str
);
1415 else if (_target
->system_wide
)
1416 fprintf(output
, "\'system wide");
1417 else if (_target
->cpu_list
)
1418 fprintf(output
, "\'CPU(s) %s", _target
->cpu_list
);
1419 else if (!target__has_task(_target
)) {
1420 fprintf(output
, "\'%s", argv
? argv
[0] : "pipe");
1421 for (i
= 1; argv
&& (i
< argc
); i
++)
1422 fprintf(output
, " %s", argv
[i
]);
1423 } else if (_target
->pid
)
1424 fprintf(output
, "process id \'%s", _target
->pid
);
1426 fprintf(output
, "thread id \'%s", _target
->tid
);
1428 fprintf(output
, "\'");
1429 if (config
->run_count
> 1)
1430 fprintf(output
, " (%d runs)", config
->run_count
);
1431 fprintf(output
, ":\n\n");
1433 if (config
->metric_only
)
1434 print_metric_headers(config
, evlist
, false);
1437 static void print_header_csv(struct perf_stat_config
*config
,
1438 struct target
*_target __maybe_unused
,
1439 struct evlist
*evlist
,
1440 int argc __maybe_unused
,
1441 const char **argv __maybe_unused
)
1443 if (config
->metric_only
)
1444 print_metric_headers(config
, evlist
, true);
1446 static void print_header_json(struct perf_stat_config
*config
,
1447 struct target
*_target __maybe_unused
,
1448 struct evlist
*evlist
,
1449 int argc __maybe_unused
,
1450 const char **argv __maybe_unused
)
1452 if (config
->metric_only
)
1453 print_metric_headers(config
, evlist
, true);
1456 static void print_header(struct perf_stat_config
*config
,
1457 struct target
*_target
,
1458 struct evlist
*evlist
,
1459 int argc
, const char **argv
)
1461 static int num_print_iv
;
1465 if (config
->interval_clear
)
1466 puts(CONSOLE_CLEAR
);
1468 if (num_print_iv
== 0 || config
->interval_clear
) {
1469 if (config
->json_output
)
1470 print_header_json(config
, _target
, evlist
, argc
, argv
);
1471 else if (config
->csv_output
)
1472 print_header_csv(config
, _target
, evlist
, argc
, argv
);
1473 else if (config
->interval
)
1474 print_header_interval_std(config
, _target
, evlist
, argc
, argv
);
1476 print_header_std(config
, _target
, evlist
, argc
, argv
);
1479 if (num_print_iv
++ == 25)
1483 static int get_precision(double num
)
1488 return lround(ceil(-log10(num
)));
1491 static void print_table(struct perf_stat_config
*config
,
1492 FILE *output
, int precision
, double avg
)
1495 int idx
, indent
= 0;
1497 scnprintf(tmp
, 64, " %17.*f", precision
, avg
);
1498 while (tmp
[indent
] == ' ')
1501 fprintf(output
, "%*s# Table of individual measurements:\n", indent
, "");
1503 for (idx
= 0; idx
< config
->run_count
; idx
++) {
1504 double run
= (double) config
->walltime_run
[idx
] / NSEC_PER_SEC
;
1505 int h
, n
= 1 + abs((int) (100.0 * (run
- avg
)/run
) / 5);
1507 fprintf(output
, " %17.*f (%+.*f) ",
1508 precision
, run
, precision
, run
- avg
);
1510 for (h
= 0; h
< n
; h
++)
1511 fprintf(output
, "#");
1513 fprintf(output
, "\n");
1516 fprintf(output
, "\n%*s# Final result:\n", indent
, "");
1519 static double timeval2double(struct timeval
*t
)
1521 return t
->tv_sec
+ (double) t
->tv_usec
/USEC_PER_SEC
;
1524 static void print_footer(struct perf_stat_config
*config
)
1526 double avg
= avg_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1527 FILE *output
= config
->output
;
1529 if (config
->interval
|| config
->csv_output
|| config
->json_output
)
1532 if (!config
->null_run
)
1533 fprintf(output
, "\n");
1535 if (config
->run_count
== 1) {
1536 fprintf(output
, " %17.9f seconds time elapsed", avg
);
1538 if (config
->ru_display
) {
1539 double ru_utime
= timeval2double(&config
->ru_data
.ru_utime
);
1540 double ru_stime
= timeval2double(&config
->ru_data
.ru_stime
);
1542 fprintf(output
, "\n\n");
1543 fprintf(output
, " %17.9f seconds user\n", ru_utime
);
1544 fprintf(output
, " %17.9f seconds sys\n", ru_stime
);
1547 double sd
= stddev_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1549 * Display at most 2 more significant
1550 * digits than the stddev inaccuracy.
1552 int precision
= get_precision(sd
) + 2;
1554 if (config
->walltime_run_table
)
1555 print_table(config
, output
, precision
, avg
);
1557 fprintf(output
, " %17.*f +- %.*f seconds time elapsed",
1558 precision
, avg
, precision
, sd
);
1560 print_noise_pct(config
, sd
, avg
, /*before_metric=*/false);
1562 fprintf(output
, "\n\n");
1564 if (config
->print_free_counters_hint
&& sysctl__nmi_watchdog_enabled())
1566 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1567 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1569 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1571 if (config
->print_mixed_hw_group_error
)
1573 "The events in group usually have to be from "
1574 "the same PMU. Try reorganizing the group.\n");
1577 static void print_percore(struct perf_stat_config
*config
,
1578 struct evsel
*counter
, struct outstate
*os
)
1580 bool metric_only
= config
->metric_only
;
1581 FILE *output
= config
->output
;
1582 struct cpu_aggr_map
*core_map
;
1583 int aggr_idx
, core_map_len
= 0;
1585 if (!config
->aggr_map
|| !config
->aggr_get_id
)
1588 if (config
->percore_show_thread
)
1589 return print_counter(config
, counter
, os
);
1592 * core_map will hold the aggr_cpu_id for the cores that have been
1593 * printed so that each core is printed just once.
1595 core_map
= cpu_aggr_map__empty_new(config
->aggr_map
->nr
);
1596 if (core_map
== NULL
) {
1597 fprintf(output
, "Cannot allocate per-core aggr map for display\n");
1601 cpu_aggr_map__for_each_idx(aggr_idx
, config
->aggr_map
) {
1602 struct perf_cpu curr_cpu
= config
->aggr_map
->map
[aggr_idx
].cpu
;
1603 struct aggr_cpu_id core_id
= aggr_cpu_id__core(curr_cpu
, NULL
);
1606 for (int i
= 0; i
< core_map_len
; i
++) {
1607 if (aggr_cpu_id__equal(&core_map
->map
[i
], &core_id
)) {
1615 print_counter_aggrdata(config
, counter
, aggr_idx
, os
);
1617 core_map
->map
[core_map_len
++] = core_id
;
1622 fputc('\n', output
);
1625 static void print_cgroup_counter(struct perf_stat_config
*config
, struct evlist
*evlist
,
1626 struct outstate
*os
)
1628 struct evsel
*counter
;
1630 evlist__for_each_entry(evlist
, counter
) {
1631 if (os
->cgrp
!= counter
->cgrp
) {
1632 if (os
->cgrp
!= NULL
)
1633 print_metric_end(config
, os
);
1635 os
->cgrp
= counter
->cgrp
;
1636 print_metric_begin(config
, evlist
, os
, /*aggr_idx=*/0);
1639 print_counter(config
, counter
, os
);
1642 print_metric_end(config
, os
);
1645 static void disable_uniquify(struct evlist
*evlist
)
1647 struct evsel
*counter
;
1648 struct perf_pmu
*last_pmu
= NULL
;
1651 evlist__for_each_entry(evlist
, counter
) {
1652 /* If PMUs vary then uniquify can be useful. */
1653 if (!first
&& counter
->pmu
!= last_pmu
)
1657 /* Allow uniquify for uncore PMUs. */
1658 if (!counter
->pmu
->is_core
)
1660 /* Keep hybrid event names uniquified for clarity. */
1661 if (perf_pmus__num_core_pmus() > 1)
1665 evlist__for_each_entry_continue(evlist
, counter
) {
1666 counter
->uniquified_name
= true;
1670 void evlist__print_counters(struct evlist
*evlist
, struct perf_stat_config
*config
,
1671 struct target
*_target
, struct timespec
*ts
,
1672 int argc
, const char **argv
)
1674 bool metric_only
= config
->metric_only
;
1675 int interval
= config
->interval
;
1676 struct evsel
*counter
;
1678 struct outstate os
= {
1679 .fh
= config
->output
,
1683 disable_uniquify(evlist
);
1685 if (config
->iostat_run
)
1686 evlist
->selected
= evlist__first(evlist
);
1690 prepare_interval(config
, buf
, sizeof(buf
), ts
);
1693 print_header(config
, _target
, evlist
, argc
, argv
);
1695 switch (config
->aggr_mode
) {
1702 if (config
->cgroup_list
)
1703 print_aggr_cgroup(config
, evlist
, &os
);
1705 print_aggr(config
, evlist
, &os
);
1709 if (config
->iostat_run
) {
1710 iostat_print_counters(evlist
, config
, ts
, buf
,
1711 (iostat_print_counter_t
)print_counter
, &os
);
1712 } else if (config
->cgroup_list
) {
1713 print_cgroup_counter(config
, evlist
, &os
);
1715 print_metric_begin(config
, evlist
, &os
, /*aggr_idx=*/0);
1716 evlist__for_each_entry(evlist
, counter
) {
1717 print_counter(config
, counter
, &os
);
1719 print_metric_end(config
, &os
);
1724 print_no_aggr_metric(config
, evlist
, &os
);
1726 evlist__for_each_entry(evlist
, counter
) {
1727 if (counter
->percore
)
1728 print_percore(config
, counter
, &os
);
1730 print_counter(config
, counter
, &os
);
1740 print_footer(config
);
1742 fflush(config
->output
);