4 #include <linux/string.h>
5 #include <linux/time64.h>
13 #include "thread_map.h"
16 #include <linux/ctype.h>
18 #include <api/fs/fs.h>
21 #define CNTR_NOT_SUPPORTED "<not supported>"
22 #define CNTR_NOT_COUNTED "<not counted>"
24 static void print_running(struct perf_stat_config
*config
,
27 if (config
->csv_output
) {
28 fprintf(config
->output
, "%s%" PRIu64
"%s%.2f",
32 ena
? 100.0 * run
/ ena
: 100.0);
33 } else if (run
!= ena
) {
34 fprintf(config
->output
, " (%.2f%%)", 100.0 * run
/ ena
);
38 static void print_noise_pct(struct perf_stat_config
*config
,
39 double total
, double avg
)
41 double pct
= rel_stddev_stats(total
, avg
);
43 if (config
->csv_output
)
44 fprintf(config
->output
, "%s%.2f%%", config
->csv_sep
, pct
);
46 fprintf(config
->output
, " ( +-%6.2f%% )", pct
);
49 static void print_noise(struct perf_stat_config
*config
,
50 struct evsel
*evsel
, double avg
)
52 struct perf_stat_evsel
*ps
;
54 if (config
->run_count
== 1)
58 print_noise_pct(config
, stddev_stats(&ps
->res_stats
[0]), avg
);
61 static void print_cgroup(struct perf_stat_config
*config
, struct evsel
*evsel
)
64 const char *cgrp_name
= evsel
->cgrp
? evsel
->cgrp
->name
: "";
65 fprintf(config
->output
, "%s%s", config
->csv_sep
, cgrp_name
);
70 static void aggr_printout(struct perf_stat_config
*config
,
71 struct evsel
*evsel
, int id
, int nr
)
73 switch (config
->aggr_mode
) {
75 fprintf(config
->output
, "S%d-D%d-C%*d%s%*d%s",
76 cpu_map__id_to_socket(id
),
77 cpu_map__id_to_die(id
),
78 config
->csv_output
? 0 : -8,
79 cpu_map__id_to_cpu(id
),
81 config
->csv_output
? 0 : 4,
86 fprintf(config
->output
, "S%d-D%*d%s%*d%s",
87 cpu_map__id_to_socket(id
<< 16),
88 config
->csv_output
? 0 : -8,
89 cpu_map__id_to_die(id
<< 16),
91 config
->csv_output
? 0 : 4,
96 fprintf(config
->output
, "S%*d%s%*d%s",
97 config
->csv_output
? 0 : -5,
100 config
->csv_output
? 0 : 4,
105 fprintf(config
->output
, "N%*d%s%*d%s",
106 config
->csv_output
? 0 : -5,
109 config
->csv_output
? 0 : 4,
114 if (evsel
->percore
&& !config
->percore_show_thread
) {
115 fprintf(config
->output
, "S%d-D%d-C%*d%s",
116 cpu_map__id_to_socket(id
),
117 cpu_map__id_to_die(id
),
118 config
->csv_output
? 0 : -3,
119 cpu_map__id_to_cpu(id
), config
->csv_sep
);
121 fprintf(config
->output
, "CPU%*d%s",
122 config
->csv_output
? 0 : -7,
123 evsel__cpus(evsel
)->map
[id
],
128 fprintf(config
->output
, "%*s-%*d%s",
129 config
->csv_output
? 0 : 16,
130 perf_thread_map__comm(evsel
->core
.threads
, id
),
131 config
->csv_output
? 0 : -8,
132 perf_thread_map__pid(evsel
->core
.threads
, id
),
151 #define METRIC_LEN 35
153 static void new_line_std(struct perf_stat_config
*config __maybe_unused
,
156 struct outstate
*os
= ctx
;
161 static void do_new_line_std(struct perf_stat_config
*config
,
165 fputs(os
->prefix
, os
->fh
);
166 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
167 if (config
->aggr_mode
== AGGR_NONE
)
168 fprintf(os
->fh
, " ");
169 fprintf(os
->fh
, " ");
172 static void print_metric_std(struct perf_stat_config
*config
,
173 void *ctx
, const char *color
, const char *fmt
,
174 const char *unit
, double val
)
176 struct outstate
*os
= ctx
;
179 bool newline
= os
->newline
;
183 if (unit
== NULL
|| fmt
== NULL
) {
184 fprintf(out
, "%-*s", METRIC_LEN
, "");
189 do_new_line_std(config
, os
);
191 n
= fprintf(out
, " # ");
193 n
+= color_fprintf(out
, color
, fmt
, val
);
195 n
+= fprintf(out
, fmt
, val
);
196 fprintf(out
, " %-*s", METRIC_LEN
- n
- 1, unit
);
199 static void new_line_csv(struct perf_stat_config
*config
, void *ctx
)
201 struct outstate
*os
= ctx
;
206 fprintf(os
->fh
, "%s%s", os
->prefix
, config
->csv_sep
);
207 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
208 for (i
= 0; i
< os
->nfields
; i
++)
209 fputs(config
->csv_sep
, os
->fh
);
212 static void print_metric_csv(struct perf_stat_config
*config __maybe_unused
,
214 const char *color __maybe_unused
,
215 const char *fmt
, const char *unit
, double val
)
217 struct outstate
*os
= ctx
;
219 char buf
[64], *vals
, *ends
;
221 if (unit
== NULL
|| fmt
== NULL
) {
222 fprintf(out
, "%s%s", config
->csv_sep
, config
->csv_sep
);
225 snprintf(buf
, sizeof(buf
), fmt
, val
);
226 ends
= vals
= skip_spaces(buf
);
227 while (isdigit(*ends
) || *ends
== '.')
230 fprintf(out
, "%s%s%s%s", config
->csv_sep
, vals
, config
->csv_sep
, skip_spaces(unit
));
233 /* Filter out some columns that don't work well in metrics only mode */
235 static bool valid_only_metric(const char *unit
)
239 if (strstr(unit
, "/sec") ||
240 strstr(unit
, "CPUs utilized"))
245 static const char *fixunit(char *buf
, struct evsel
*evsel
,
248 if (!strncmp(unit
, "of all", 6)) {
249 snprintf(buf
, 1024, "%s %s", evsel__name(evsel
),
256 static void print_metric_only(struct perf_stat_config
*config
,
257 void *ctx
, const char *color
, const char *fmt
,
258 const char *unit
, double val
)
260 struct outstate
*os
= ctx
;
262 char buf
[1024], str
[1024];
263 unsigned mlen
= config
->metric_only_len
;
265 if (!valid_only_metric(unit
))
267 unit
= fixunit(buf
, os
->evsel
, unit
);
268 if (mlen
< strlen(unit
))
269 mlen
= strlen(unit
) + 1;
272 mlen
+= strlen(color
) + sizeof(PERF_COLOR_RESET
) - 1;
274 color_snprintf(str
, sizeof(str
), color
?: "", fmt
, val
);
275 fprintf(out
, "%*s ", mlen
, str
);
278 static void print_metric_only_csv(struct perf_stat_config
*config __maybe_unused
,
279 void *ctx
, const char *color __maybe_unused
,
281 const char *unit
, double val
)
283 struct outstate
*os
= ctx
;
285 char buf
[64], *vals
, *ends
;
288 if (!valid_only_metric(unit
))
290 unit
= fixunit(tbuf
, os
->evsel
, unit
);
291 snprintf(buf
, sizeof buf
, fmt
, val
);
292 ends
= vals
= skip_spaces(buf
);
293 while (isdigit(*ends
) || *ends
== '.')
296 fprintf(out
, "%s%s", vals
, config
->csv_sep
);
299 static void new_line_metric(struct perf_stat_config
*config __maybe_unused
,
300 void *ctx __maybe_unused
)
304 static void print_metric_header(struct perf_stat_config
*config
,
305 void *ctx
, const char *color __maybe_unused
,
306 const char *fmt __maybe_unused
,
307 const char *unit
, double val __maybe_unused
)
309 struct outstate
*os
= ctx
;
312 if (!valid_only_metric(unit
))
314 unit
= fixunit(tbuf
, os
->evsel
, unit
);
315 if (config
->csv_output
)
316 fprintf(os
->fh
, "%s%s", unit
, config
->csv_sep
);
318 fprintf(os
->fh
, "%*s ", config
->metric_only_len
, unit
);
321 static int first_shadow_cpu(struct perf_stat_config
*config
,
322 struct evsel
*evsel
, int id
)
324 struct evlist
*evlist
= evsel
->evlist
;
327 if (!config
->aggr_get_id
)
330 if (config
->aggr_mode
== AGGR_NONE
)
333 if (config
->aggr_mode
== AGGR_GLOBAL
)
336 for (i
= 0; i
< evsel__nr_cpus(evsel
); i
++) {
337 int cpu2
= evsel__cpus(evsel
)->map
[i
];
339 if (config
->aggr_get_id(config
, evlist
->core
.cpus
, cpu2
) == id
)
345 static void abs_printout(struct perf_stat_config
*config
,
346 int id
, int nr
, struct evsel
*evsel
, double avg
)
348 FILE *output
= config
->output
;
349 double sc
= evsel
->scale
;
352 if (config
->csv_output
) {
353 fmt
= floor(sc
) != sc
? "%.2f%s" : "%.0f%s";
356 fmt
= floor(sc
) != sc
? "%'18.2f%s" : "%'18.0f%s";
358 fmt
= floor(sc
) != sc
? "%18.2f%s" : "%18.0f%s";
361 aggr_printout(config
, evsel
, id
, nr
);
363 fprintf(output
, fmt
, avg
, config
->csv_sep
);
366 fprintf(output
, "%-*s%s",
367 config
->csv_output
? 0 : config
->unit_width
,
368 evsel
->unit
, config
->csv_sep
);
370 fprintf(output
, "%-*s", config
->csv_output
? 0 : 25, evsel__name(evsel
));
372 print_cgroup(config
, evsel
);
375 static bool is_mixed_hw_group(struct evsel
*counter
)
377 struct evlist
*evlist
= counter
->evlist
;
378 u32 pmu_type
= counter
->core
.attr
.type
;
381 if (counter
->core
.nr_members
< 2)
384 evlist__for_each_entry(evlist
, pos
) {
385 /* software events can be part of any hardware group */
386 if (pos
->core
.attr
.type
== PERF_TYPE_SOFTWARE
)
388 if (pmu_type
== PERF_TYPE_SOFTWARE
) {
389 pmu_type
= pos
->core
.attr
.type
;
392 if (pmu_type
!= pos
->core
.attr
.type
)
399 static void printout(struct perf_stat_config
*config
, int id
, int nr
,
400 struct evsel
*counter
, double uval
,
401 char *prefix
, u64 run
, u64 ena
, double noise
,
402 struct runtime_stat
*st
)
404 struct perf_stat_output_ctx out
;
405 struct outstate os
= {
406 .fh
= config
->output
,
407 .prefix
= prefix
? prefix
: "",
412 print_metric_t pm
= print_metric_std
;
415 if (config
->metric_only
) {
416 nl
= new_line_metric
;
417 if (config
->csv_output
)
418 pm
= print_metric_only_csv
;
420 pm
= print_metric_only
;
424 if (config
->csv_output
&& !config
->metric_only
) {
425 static int aggr_fields
[] = {
434 pm
= print_metric_csv
;
437 os
.nfields
+= aggr_fields
[config
->aggr_mode
];
441 if (run
== 0 || ena
== 0 || counter
->counts
->scaled
== -1) {
442 if (config
->metric_only
) {
443 pm(config
, &os
, NULL
, "", "", 0);
446 aggr_printout(config
, counter
, id
, nr
);
448 fprintf(config
->output
, "%*s%s",
449 config
->csv_output
? 0 : 18,
450 counter
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
,
453 if (counter
->supported
) {
454 config
->print_free_counters_hint
= 1;
455 if (is_mixed_hw_group(counter
))
456 config
->print_mixed_hw_group_error
= 1;
459 fprintf(config
->output
, "%-*s%s",
460 config
->csv_output
? 0 : config
->unit_width
,
461 counter
->unit
, config
->csv_sep
);
463 fprintf(config
->output
, "%*s",
464 config
->csv_output
? 0 : -25, evsel__name(counter
));
466 print_cgroup(config
, counter
);
468 if (!config
->csv_output
)
469 pm(config
, &os
, NULL
, NULL
, "", 0);
470 print_noise(config
, counter
, noise
);
471 print_running(config
, run
, ena
);
472 if (config
->csv_output
)
473 pm(config
, &os
, NULL
, NULL
, "", 0);
477 if (!config
->metric_only
)
478 abs_printout(config
, id
, nr
, counter
, uval
);
480 out
.print_metric
= pm
;
483 out
.force_header
= false;
485 if (config
->csv_output
&& !config
->metric_only
) {
486 print_noise(config
, counter
, noise
);
487 print_running(config
, run
, ena
);
490 perf_stat__print_shadow_stats(config
, counter
, uval
,
491 first_shadow_cpu(config
, counter
, id
),
492 &out
, &config
->metric_events
, st
);
493 if (!config
->csv_output
&& !config
->metric_only
) {
494 print_noise(config
, counter
, noise
);
495 print_running(config
, run
, ena
);
499 static void aggr_update_shadow(struct perf_stat_config
*config
,
500 struct evlist
*evlist
)
504 struct evsel
*counter
;
506 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
507 id
= config
->aggr_map
->map
[s
];
508 evlist__for_each_entry(evlist
, counter
) {
510 for (cpu
= 0; cpu
< evsel__nr_cpus(counter
); cpu
++) {
511 s2
= config
->aggr_get_id(config
, evlist
->core
.cpus
, cpu
);
514 val
+= perf_counts(counter
->counts
, cpu
, 0)->val
;
516 perf_stat__update_shadow_stats(counter
, val
,
517 first_shadow_cpu(config
, counter
, id
),
523 static void uniquify_event_name(struct evsel
*counter
)
528 if (counter
->uniquified_name
||
529 !counter
->pmu_name
|| !strncmp(counter
->name
, counter
->pmu_name
,
530 strlen(counter
->pmu_name
)))
533 config
= strchr(counter
->name
, '/');
535 if (asprintf(&new_name
,
536 "%s%s", counter
->pmu_name
, config
) > 0) {
538 counter
->name
= new_name
;
541 if (asprintf(&new_name
,
542 "%s [%s]", counter
->name
, counter
->pmu_name
) > 0) {
544 counter
->name
= new_name
;
548 counter
->uniquified_name
= true;
551 static void collect_all_aliases(struct perf_stat_config
*config
, struct evsel
*counter
,
552 void (*cb
)(struct perf_stat_config
*config
, struct evsel
*counter
, void *data
,
556 struct evlist
*evlist
= counter
->evlist
;
559 alias
= list_prepare_entry(counter
, &(evlist
->core
.entries
), core
.node
);
560 list_for_each_entry_continue (alias
, &evlist
->core
.entries
, core
.node
) {
561 if (strcmp(evsel__name(alias
), evsel__name(counter
)) ||
562 alias
->scale
!= counter
->scale
||
563 alias
->cgrp
!= counter
->cgrp
||
564 strcmp(alias
->unit
, counter
->unit
) ||
565 evsel__is_clock(alias
) != evsel__is_clock(counter
) ||
566 !strcmp(alias
->pmu_name
, counter
->pmu_name
))
568 alias
->merged_stat
= true;
569 cb(config
, alias
, data
, false);
573 static bool collect_data(struct perf_stat_config
*config
, struct evsel
*counter
,
574 void (*cb
)(struct perf_stat_config
*config
, struct evsel
*counter
, void *data
,
578 if (counter
->merged_stat
)
580 cb(config
, counter
, data
, true);
581 if (config
->no_merge
)
582 uniquify_event_name(counter
);
583 else if (counter
->auto_merge_stats
)
584 collect_all_aliases(config
, counter
, cb
, data
);
595 static void aggr_cb(struct perf_stat_config
*config
,
596 struct evsel
*counter
, void *data
, bool first
)
598 struct aggr_data
*ad
= data
;
601 for (cpu
= 0; cpu
< evsel__nr_cpus(counter
); cpu
++) {
602 struct perf_counts_values
*counts
;
604 s2
= config
->aggr_get_id(config
, evsel__cpus(counter
), cpu
);
609 counts
= perf_counts(counter
->counts
, cpu
, 0);
611 * When any result is bad, make them all to give
612 * consistent output in interval mode.
614 if (counts
->ena
== 0 || counts
->run
== 0 ||
615 counter
->counts
->scaled
== -1) {
620 ad
->val
+= counts
->val
;
621 ad
->ena
+= counts
->ena
;
622 ad
->run
+= counts
->run
;
626 static void print_counter_aggrdata(struct perf_stat_config
*config
,
627 struct evsel
*counter
, int s
,
628 char *prefix
, bool metric_only
,
629 bool *first
, int cpu
)
632 FILE *output
= config
->output
;
637 ad
.id
= id
= config
->aggr_map
->map
[s
];
638 ad
.val
= ad
.ena
= ad
.run
= 0;
640 if (!collect_data(config
, counter
, aggr_cb
, &ad
))
647 if (*first
&& metric_only
) {
649 aggr_printout(config
, counter
, id
, nr
);
651 if (prefix
&& !metric_only
)
652 fprintf(output
, "%s", prefix
);
654 uval
= val
* counter
->scale
;
655 printout(config
, cpu
!= -1 ? cpu
: id
, nr
, counter
, uval
, prefix
,
656 run
, ena
, 1.0, &rt_stat
);
661 static void print_aggr(struct perf_stat_config
*config
,
662 struct evlist
*evlist
,
665 bool metric_only
= config
->metric_only
;
666 FILE *output
= config
->output
;
667 struct evsel
*counter
;
671 if (!config
->aggr_map
|| !config
->aggr_get_id
)
674 aggr_update_shadow(config
, evlist
);
677 * With metric_only everything is on a single line.
678 * Without each counter has its own line.
680 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
681 if (prefix
&& metric_only
)
682 fprintf(output
, "%s", prefix
);
685 evlist__for_each_entry(evlist
, counter
) {
686 print_counter_aggrdata(config
, counter
, s
,
695 static int cmp_val(const void *a
, const void *b
)
697 return ((struct perf_aggr_thread_value
*)b
)->val
-
698 ((struct perf_aggr_thread_value
*)a
)->val
;
701 static struct perf_aggr_thread_value
*sort_aggr_thread(
702 struct evsel
*counter
,
703 int nthreads
, int ncpus
,
705 struct target
*_target
)
707 int cpu
, thread
, i
= 0;
709 struct perf_aggr_thread_value
*buf
;
711 buf
= calloc(nthreads
, sizeof(struct perf_aggr_thread_value
));
715 for (thread
= 0; thread
< nthreads
; thread
++) {
716 u64 ena
= 0, run
= 0, val
= 0;
718 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
719 val
+= perf_counts(counter
->counts
, cpu
, thread
)->val
;
720 ena
+= perf_counts(counter
->counts
, cpu
, thread
)->ena
;
721 run
+= perf_counts(counter
->counts
, cpu
, thread
)->run
;
724 uval
= val
* counter
->scale
;
727 * Skip value 0 when enabling --per-thread globally,
728 * otherwise too many 0 output.
730 if (uval
== 0.0 && target__has_per_thread(_target
))
733 buf
[i
].counter
= counter
;
742 qsort(buf
, i
, sizeof(struct perf_aggr_thread_value
), cmp_val
);
750 static void print_aggr_thread(struct perf_stat_config
*config
,
751 struct target
*_target
,
752 struct evsel
*counter
, char *prefix
)
754 FILE *output
= config
->output
;
755 int nthreads
= perf_thread_map__nr(counter
->core
.threads
);
756 int ncpus
= perf_cpu_map__nr(counter
->core
.cpus
);
757 int thread
, sorted_threads
, id
;
758 struct perf_aggr_thread_value
*buf
;
760 buf
= sort_aggr_thread(counter
, nthreads
, ncpus
, &sorted_threads
, _target
);
762 perror("cannot sort aggr thread");
766 for (thread
= 0; thread
< sorted_threads
; thread
++) {
768 fprintf(output
, "%s", prefix
);
772 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
773 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
776 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
777 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
786 double avg
, avg_enabled
, avg_running
;
789 static void counter_aggr_cb(struct perf_stat_config
*config __maybe_unused
,
790 struct evsel
*counter
, void *data
,
791 bool first __maybe_unused
)
793 struct caggr_data
*cd
= data
;
794 struct perf_stat_evsel
*ps
= counter
->stats
;
796 cd
->avg
+= avg_stats(&ps
->res_stats
[0]);
797 cd
->avg_enabled
+= avg_stats(&ps
->res_stats
[1]);
798 cd
->avg_running
+= avg_stats(&ps
->res_stats
[2]);
802 * Print out the results of a single counter:
803 * aggregated counts in system-wide mode
805 static void print_counter_aggr(struct perf_stat_config
*config
,
806 struct evsel
*counter
, char *prefix
)
808 bool metric_only
= config
->metric_only
;
809 FILE *output
= config
->output
;
811 struct caggr_data cd
= { .avg
= 0.0 };
813 if (!collect_data(config
, counter
, counter_aggr_cb
, &cd
))
816 if (prefix
&& !metric_only
)
817 fprintf(output
, "%s", prefix
);
819 uval
= cd
.avg
* counter
->scale
;
820 printout(config
, -1, 0, counter
, uval
, prefix
, cd
.avg_running
, cd
.avg_enabled
,
823 fprintf(output
, "\n");
826 static void counter_cb(struct perf_stat_config
*config __maybe_unused
,
827 struct evsel
*counter
, void *data
,
828 bool first __maybe_unused
)
830 struct aggr_data
*ad
= data
;
832 ad
->val
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->val
;
833 ad
->ena
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->ena
;
834 ad
->run
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->run
;
838 * Print out the results of a single counter:
839 * does not use aggregated count in system-wide
841 static void print_counter(struct perf_stat_config
*config
,
842 struct evsel
*counter
, char *prefix
)
844 FILE *output
= config
->output
;
849 for (cpu
= 0; cpu
< evsel__nr_cpus(counter
); cpu
++) {
850 struct aggr_data ad
= { .cpu
= cpu
};
852 if (!collect_data(config
, counter
, counter_cb
, &ad
))
859 fprintf(output
, "%s", prefix
);
861 uval
= val
* counter
->scale
;
862 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
869 static void print_no_aggr_metric(struct perf_stat_config
*config
,
870 struct evlist
*evlist
,
875 struct evsel
*counter
;
879 nrcpus
= evlist
->core
.cpus
->nr
;
880 for (cpu
= 0; cpu
< nrcpus
; cpu
++) {
884 fputs(prefix
, config
->output
);
885 evlist__for_each_entry(evlist
, counter
) {
887 aggr_printout(config
, counter
, cpu
, 0);
890 val
= perf_counts(counter
->counts
, cpu
, 0)->val
;
891 ena
= perf_counts(counter
->counts
, cpu
, 0)->ena
;
892 run
= perf_counts(counter
->counts
, cpu
, 0)->run
;
894 uval
= val
* counter
->scale
;
895 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
898 fputc('\n', config
->output
);
902 static int aggr_header_lens
[] = {
911 static const char *aggr_header_csv
[] = {
912 [AGGR_CORE
] = "core,cpus,",
913 [AGGR_DIE
] = "die,cpus",
914 [AGGR_SOCKET
] = "socket,cpus",
915 [AGGR_NONE
] = "cpu,",
916 [AGGR_THREAD
] = "comm-pid,",
920 static void print_metric_headers(struct perf_stat_config
*config
,
921 struct evlist
*evlist
,
922 const char *prefix
, bool no_indent
)
924 struct perf_stat_output_ctx out
;
925 struct evsel
*counter
;
926 struct outstate os
= {
931 fprintf(config
->output
, "%s", prefix
);
933 if (!config
->csv_output
&& !no_indent
)
934 fprintf(config
->output
, "%*s",
935 aggr_header_lens
[config
->aggr_mode
], "");
936 if (config
->csv_output
) {
937 if (config
->interval
)
938 fputs("time,", config
->output
);
939 fputs(aggr_header_csv
[config
->aggr_mode
], config
->output
);
942 /* Print metrics headers only */
943 evlist__for_each_entry(evlist
, counter
) {
946 out
.print_metric
= print_metric_header
;
947 out
.new_line
= new_line_metric
;
948 out
.force_header
= true;
950 perf_stat__print_shadow_stats(config
, counter
, 0,
953 &config
->metric_events
,
956 fputc('\n', config
->output
);
959 static void print_interval(struct perf_stat_config
*config
,
960 struct evlist
*evlist
,
961 char *prefix
, struct timespec
*ts
)
963 bool metric_only
= config
->metric_only
;
964 unsigned int unit_width
= config
->unit_width
;
965 FILE *output
= config
->output
;
966 static int num_print_interval
;
968 if (config
->interval_clear
)
971 sprintf(prefix
, "%6lu.%09lu%s", ts
->tv_sec
, ts
->tv_nsec
, config
->csv_sep
);
973 if ((num_print_interval
== 0 && !config
->csv_output
) || config
->interval_clear
) {
974 switch (config
->aggr_mode
) {
976 fprintf(output
, "# time node cpus");
978 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
981 fprintf(output
, "# time socket cpus");
983 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
986 fprintf(output
, "# time die cpus");
988 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
991 fprintf(output
, "# time core cpus");
993 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
996 fprintf(output
, "# time CPU ");
998 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1001 fprintf(output
, "# time comm-pid");
1003 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1007 fprintf(output
, "# time");
1009 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1015 if ((num_print_interval
== 0 || config
->interval_clear
) && metric_only
)
1016 print_metric_headers(config
, evlist
, " ", true);
1017 if (++num_print_interval
== 25)
1018 num_print_interval
= 0;
1021 static void print_header(struct perf_stat_config
*config
,
1022 struct target
*_target
,
1023 int argc
, const char **argv
)
1025 FILE *output
= config
->output
;
1030 if (!config
->csv_output
) {
1031 fprintf(output
, "\n");
1032 fprintf(output
, " Performance counter stats for ");
1033 if (_target
->system_wide
)
1034 fprintf(output
, "\'system wide");
1035 else if (_target
->cpu_list
)
1036 fprintf(output
, "\'CPU(s) %s", _target
->cpu_list
);
1037 else if (!target__has_task(_target
)) {
1038 fprintf(output
, "\'%s", argv
? argv
[0] : "pipe");
1039 for (i
= 1; argv
&& (i
< argc
); i
++)
1040 fprintf(output
, " %s", argv
[i
]);
1041 } else if (_target
->pid
)
1042 fprintf(output
, "process id \'%s", _target
->pid
);
1044 fprintf(output
, "thread id \'%s", _target
->tid
);
1046 fprintf(output
, "\'");
1047 if (config
->run_count
> 1)
1048 fprintf(output
, " (%d runs)", config
->run_count
);
1049 fprintf(output
, ":\n\n");
1053 static int get_precision(double num
)
1058 return lround(ceil(-log10(num
)));
1061 static void print_table(struct perf_stat_config
*config
,
1062 FILE *output
, int precision
, double avg
)
1065 int idx
, indent
= 0;
1067 scnprintf(tmp
, 64, " %17.*f", precision
, avg
);
1068 while (tmp
[indent
] == ' ')
1071 fprintf(output
, "%*s# Table of individual measurements:\n", indent
, "");
1073 for (idx
= 0; idx
< config
->run_count
; idx
++) {
1074 double run
= (double) config
->walltime_run
[idx
] / NSEC_PER_SEC
;
1075 int h
, n
= 1 + abs((int) (100.0 * (run
- avg
)/run
) / 5);
1077 fprintf(output
, " %17.*f (%+.*f) ",
1078 precision
, run
, precision
, run
- avg
);
1080 for (h
= 0; h
< n
; h
++)
1081 fprintf(output
, "#");
1083 fprintf(output
, "\n");
1086 fprintf(output
, "\n%*s# Final result:\n", indent
, "");
1089 static double timeval2double(struct timeval
*t
)
1091 return t
->tv_sec
+ (double) t
->tv_usec
/USEC_PER_SEC
;
1094 static void print_footer(struct perf_stat_config
*config
)
1096 double avg
= avg_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1097 FILE *output
= config
->output
;
1099 if (!config
->null_run
)
1100 fprintf(output
, "\n");
1102 if (config
->run_count
== 1) {
1103 fprintf(output
, " %17.9f seconds time elapsed", avg
);
1105 if (config
->ru_display
) {
1106 double ru_utime
= timeval2double(&config
->ru_data
.ru_utime
);
1107 double ru_stime
= timeval2double(&config
->ru_data
.ru_stime
);
1109 fprintf(output
, "\n\n");
1110 fprintf(output
, " %17.9f seconds user\n", ru_utime
);
1111 fprintf(output
, " %17.9f seconds sys\n", ru_stime
);
1114 double sd
= stddev_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1116 * Display at most 2 more significant
1117 * digits than the stddev inaccuracy.
1119 int precision
= get_precision(sd
) + 2;
1121 if (config
->walltime_run_table
)
1122 print_table(config
, output
, precision
, avg
);
1124 fprintf(output
, " %17.*f +- %.*f seconds time elapsed",
1125 precision
, avg
, precision
, sd
);
1127 print_noise_pct(config
, sd
, avg
);
1129 fprintf(output
, "\n\n");
1131 if (config
->print_free_counters_hint
&& sysctl__nmi_watchdog_enabled())
1133 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1134 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1136 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1138 if (config
->print_mixed_hw_group_error
)
1140 "The events in group usually have to be from "
1141 "the same PMU. Try reorganizing the group.\n");
1144 static void print_percore_thread(struct perf_stat_config
*config
,
1145 struct evsel
*counter
, char *prefix
)
1150 for (int i
= 0; i
< evsel__nr_cpus(counter
); i
++) {
1151 s2
= config
->aggr_get_id(config
, evsel__cpus(counter
), i
);
1152 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
1153 id
= config
->aggr_map
->map
[s
];
1158 print_counter_aggrdata(config
, counter
, s
,
1164 static void print_percore(struct perf_stat_config
*config
,
1165 struct evsel
*counter
, char *prefix
)
1167 bool metric_only
= config
->metric_only
;
1168 FILE *output
= config
->output
;
1172 if (!config
->aggr_map
|| !config
->aggr_get_id
)
1175 if (config
->percore_show_thread
)
1176 return print_percore_thread(config
, counter
, prefix
);
1178 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
1179 if (prefix
&& metric_only
)
1180 fprintf(output
, "%s", prefix
);
1182 print_counter_aggrdata(config
, counter
, s
,
1183 prefix
, metric_only
,
1188 fputc('\n', output
);
1192 perf_evlist__print_counters(struct evlist
*evlist
,
1193 struct perf_stat_config
*config
,
1194 struct target
*_target
,
1195 struct timespec
*ts
,
1196 int argc
, const char **argv
)
1198 bool metric_only
= config
->metric_only
;
1199 int interval
= config
->interval
;
1200 struct evsel
*counter
;
1201 char buf
[64], *prefix
= NULL
;
1204 print_interval(config
, evlist
, prefix
= buf
, ts
);
1206 print_header(config
, _target
, argc
, argv
);
1209 static int num_print_iv
;
1211 if (num_print_iv
== 0 && !interval
)
1212 print_metric_headers(config
, evlist
, prefix
, false);
1213 if (num_print_iv
++ == 25)
1215 if (config
->aggr_mode
== AGGR_GLOBAL
&& prefix
)
1216 fprintf(config
->output
, "%s", prefix
);
1219 switch (config
->aggr_mode
) {
1224 print_aggr(config
, evlist
, prefix
);
1227 evlist__for_each_entry(evlist
, counter
) {
1228 print_aggr_thread(config
, _target
, counter
, prefix
);
1232 evlist__for_each_entry(evlist
, counter
) {
1233 print_counter_aggr(config
, counter
, prefix
);
1236 fputc('\n', config
->output
);
1240 print_no_aggr_metric(config
, evlist
, prefix
);
1242 evlist__for_each_entry(evlist
, counter
) {
1243 if (counter
->percore
)
1244 print_percore(config
, counter
, prefix
);
1246 print_counter(config
, counter
, prefix
);
1255 if (!interval
&& !config
->csv_output
)
1256 print_footer(config
);
1258 fflush(config
->output
);