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>
20 #define CNTR_NOT_SUPPORTED "<not supported>"
21 #define CNTR_NOT_COUNTED "<not counted>"
23 static void print_running(struct perf_stat_config
*config
,
26 if (config
->csv_output
) {
27 fprintf(config
->output
, "%s%" PRIu64
"%s%.2f",
31 ena
? 100.0 * run
/ ena
: 100.0);
32 } else if (run
!= ena
) {
33 fprintf(config
->output
, " (%.2f%%)", 100.0 * run
/ ena
);
37 static void print_noise_pct(struct perf_stat_config
*config
,
38 double total
, double avg
)
40 double pct
= rel_stddev_stats(total
, avg
);
42 if (config
->csv_output
)
43 fprintf(config
->output
, "%s%.2f%%", config
->csv_sep
, pct
);
45 fprintf(config
->output
, " ( +-%6.2f%% )", pct
);
48 static void print_noise(struct perf_stat_config
*config
,
49 struct evsel
*evsel
, double avg
)
51 struct perf_stat_evsel
*ps
;
53 if (config
->run_count
== 1)
57 print_noise_pct(config
, stddev_stats(&ps
->res_stats
[0]), avg
);
60 static void print_cgroup(struct perf_stat_config
*config
, struct evsel
*evsel
)
63 const char *cgrp_name
= evsel
->cgrp
? evsel
->cgrp
->name
: "";
64 fprintf(config
->output
, "%s%s", config
->csv_sep
, cgrp_name
);
69 static void aggr_printout(struct perf_stat_config
*config
,
70 struct evsel
*evsel
, int id
, int nr
)
72 switch (config
->aggr_mode
) {
74 fprintf(config
->output
, "S%d-D%d-C%*d%s%*d%s",
75 cpu_map__id_to_socket(id
),
76 cpu_map__id_to_die(id
),
77 config
->csv_output
? 0 : -8,
78 cpu_map__id_to_cpu(id
),
80 config
->csv_output
? 0 : 4,
85 fprintf(config
->output
, "S%d-D%*d%s%*d%s",
86 cpu_map__id_to_socket(id
<< 16),
87 config
->csv_output
? 0 : -8,
88 cpu_map__id_to_die(id
<< 16),
90 config
->csv_output
? 0 : 4,
95 fprintf(config
->output
, "S%*d%s%*d%s",
96 config
->csv_output
? 0 : -5,
99 config
->csv_output
? 0 : 4,
104 fprintf(config
->output
, "N%*d%s%*d%s",
105 config
->csv_output
? 0 : -5,
108 config
->csv_output
? 0 : 4,
113 if (evsel
->percore
) {
114 fprintf(config
->output
, "S%d-D%d-C%*d%s",
115 cpu_map__id_to_socket(id
),
116 cpu_map__id_to_die(id
),
117 config
->csv_output
? 0 : -5,
118 cpu_map__id_to_cpu(id
), config
->csv_sep
);
120 fprintf(config
->output
, "CPU%*d%s ",
121 config
->csv_output
? 0 : -5,
122 evsel__cpus(evsel
)->map
[id
],
127 fprintf(config
->output
, "%*s-%*d%s",
128 config
->csv_output
? 0 : 16,
129 perf_thread_map__comm(evsel
->core
.threads
, id
),
130 config
->csv_output
? 0 : -8,
131 perf_thread_map__pid(evsel
->core
.threads
, id
),
150 #define METRIC_LEN 35
152 static void new_line_std(struct perf_stat_config
*config __maybe_unused
,
155 struct outstate
*os
= ctx
;
160 static void do_new_line_std(struct perf_stat_config
*config
,
164 fputs(os
->prefix
, os
->fh
);
165 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
166 if (config
->aggr_mode
== AGGR_NONE
)
167 fprintf(os
->fh
, " ");
168 fprintf(os
->fh
, " ");
171 static void print_metric_std(struct perf_stat_config
*config
,
172 void *ctx
, const char *color
, const char *fmt
,
173 const char *unit
, double val
)
175 struct outstate
*os
= ctx
;
178 bool newline
= os
->newline
;
182 if (unit
== NULL
|| fmt
== NULL
) {
183 fprintf(out
, "%-*s", METRIC_LEN
, "");
188 do_new_line_std(config
, os
);
190 n
= fprintf(out
, " # ");
192 n
+= color_fprintf(out
, color
, fmt
, val
);
194 n
+= fprintf(out
, fmt
, val
);
195 fprintf(out
, " %-*s", METRIC_LEN
- n
- 1, unit
);
198 static void new_line_csv(struct perf_stat_config
*config
, void *ctx
)
200 struct outstate
*os
= ctx
;
205 fprintf(os
->fh
, "%s%s", os
->prefix
, config
->csv_sep
);
206 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
207 for (i
= 0; i
< os
->nfields
; i
++)
208 fputs(config
->csv_sep
, os
->fh
);
211 static void print_metric_csv(struct perf_stat_config
*config __maybe_unused
,
213 const char *color __maybe_unused
,
214 const char *fmt
, const char *unit
, double val
)
216 struct outstate
*os
= ctx
;
218 char buf
[64], *vals
, *ends
;
220 if (unit
== NULL
|| fmt
== NULL
) {
221 fprintf(out
, "%s%s", config
->csv_sep
, config
->csv_sep
);
224 snprintf(buf
, sizeof(buf
), fmt
, val
);
225 ends
= vals
= skip_spaces(buf
);
226 while (isdigit(*ends
) || *ends
== '.')
229 fprintf(out
, "%s%s%s%s", config
->csv_sep
, vals
, config
->csv_sep
, skip_spaces(unit
));
232 /* Filter out some columns that don't work well in metrics only mode */
234 static bool valid_only_metric(const char *unit
)
238 if (strstr(unit
, "/sec") ||
239 strstr(unit
, "hz") ||
240 strstr(unit
, "Hz") ||
241 strstr(unit
, "CPUs utilized"))
246 static const char *fixunit(char *buf
, struct evsel
*evsel
,
249 if (!strncmp(unit
, "of all", 6)) {
250 snprintf(buf
, 1024, "%s %s", perf_evsel__name(evsel
),
257 static void print_metric_only(struct perf_stat_config
*config
,
258 void *ctx
, const char *color
, const char *fmt
,
259 const char *unit
, double val
)
261 struct outstate
*os
= ctx
;
263 char buf
[1024], str
[1024];
264 unsigned mlen
= config
->metric_only_len
;
266 if (!valid_only_metric(unit
))
268 unit
= fixunit(buf
, os
->evsel
, unit
);
269 if (mlen
< strlen(unit
))
270 mlen
= strlen(unit
) + 1;
273 mlen
+= strlen(color
) + sizeof(PERF_COLOR_RESET
) - 1;
275 color_snprintf(str
, sizeof(str
), color
?: "", fmt
, val
);
276 fprintf(out
, "%*s ", mlen
, str
);
279 static void print_metric_only_csv(struct perf_stat_config
*config __maybe_unused
,
280 void *ctx
, const char *color __maybe_unused
,
282 const char *unit
, double val
)
284 struct outstate
*os
= ctx
;
286 char buf
[64], *vals
, *ends
;
289 if (!valid_only_metric(unit
))
291 unit
= fixunit(tbuf
, os
->evsel
, unit
);
292 snprintf(buf
, sizeof buf
, fmt
, val
);
293 ends
= vals
= skip_spaces(buf
);
294 while (isdigit(*ends
) || *ends
== '.')
297 fprintf(out
, "%s%s", vals
, config
->csv_sep
);
300 static void new_line_metric(struct perf_stat_config
*config __maybe_unused
,
301 void *ctx __maybe_unused
)
305 static void print_metric_header(struct perf_stat_config
*config
,
306 void *ctx
, const char *color __maybe_unused
,
307 const char *fmt __maybe_unused
,
308 const char *unit
, double val __maybe_unused
)
310 struct outstate
*os
= ctx
;
313 if (!valid_only_metric(unit
))
315 unit
= fixunit(tbuf
, os
->evsel
, unit
);
316 if (config
->csv_output
)
317 fprintf(os
->fh
, "%s%s", unit
, config
->csv_sep
);
319 fprintf(os
->fh
, "%*s ", config
->metric_only_len
, unit
);
322 static int first_shadow_cpu(struct perf_stat_config
*config
,
323 struct evsel
*evsel
, int id
)
325 struct evlist
*evlist
= evsel
->evlist
;
328 if (!config
->aggr_get_id
)
331 if (config
->aggr_mode
== AGGR_NONE
)
334 if (config
->aggr_mode
== AGGR_GLOBAL
)
337 for (i
= 0; i
< perf_evsel__nr_cpus(evsel
); i
++) {
338 int cpu2
= evsel__cpus(evsel
)->map
[i
];
340 if (config
->aggr_get_id(config
, evlist
->core
.cpus
, cpu2
) == id
)
346 static void abs_printout(struct perf_stat_config
*config
,
347 int id
, int nr
, struct evsel
*evsel
, double avg
)
349 FILE *output
= config
->output
;
350 double sc
= evsel
->scale
;
353 if (config
->csv_output
) {
354 fmt
= floor(sc
) != sc
? "%.2f%s" : "%.0f%s";
357 fmt
= floor(sc
) != sc
? "%'18.2f%s" : "%'18.0f%s";
359 fmt
= floor(sc
) != sc
? "%18.2f%s" : "%18.0f%s";
362 aggr_printout(config
, evsel
, id
, nr
);
364 fprintf(output
, fmt
, avg
, config
->csv_sep
);
367 fprintf(output
, "%-*s%s",
368 config
->csv_output
? 0 : config
->unit_width
,
369 evsel
->unit
, config
->csv_sep
);
371 fprintf(output
, "%-*s", config
->csv_output
? 0 : 25, perf_evsel__name(evsel
));
373 print_cgroup(config
, evsel
);
376 static bool is_mixed_hw_group(struct evsel
*counter
)
378 struct evlist
*evlist
= counter
->evlist
;
379 u32 pmu_type
= counter
->core
.attr
.type
;
382 if (counter
->core
.nr_members
< 2)
385 evlist__for_each_entry(evlist
, pos
) {
386 /* software events can be part of any hardware group */
387 if (pos
->core
.attr
.type
== PERF_TYPE_SOFTWARE
)
389 if (pmu_type
== PERF_TYPE_SOFTWARE
) {
390 pmu_type
= pos
->core
.attr
.type
;
393 if (pmu_type
!= pos
->core
.attr
.type
)
400 static void printout(struct perf_stat_config
*config
, int id
, int nr
,
401 struct evsel
*counter
, double uval
,
402 char *prefix
, u64 run
, u64 ena
, double noise
,
403 struct runtime_stat
*st
)
405 struct perf_stat_output_ctx out
;
406 struct outstate os
= {
407 .fh
= config
->output
,
408 .prefix
= prefix
? prefix
: "",
413 print_metric_t pm
= print_metric_std
;
416 if (config
->metric_only
) {
417 nl
= new_line_metric
;
418 if (config
->csv_output
)
419 pm
= print_metric_only_csv
;
421 pm
= print_metric_only
;
425 if (config
->csv_output
&& !config
->metric_only
) {
426 static int aggr_fields
[] = {
435 pm
= print_metric_csv
;
438 os
.nfields
+= aggr_fields
[config
->aggr_mode
];
442 if (run
== 0 || ena
== 0 || counter
->counts
->scaled
== -1) {
443 if (config
->metric_only
) {
444 pm(config
, &os
, NULL
, "", "", 0);
447 aggr_printout(config
, counter
, id
, nr
);
449 fprintf(config
->output
, "%*s%s",
450 config
->csv_output
? 0 : 18,
451 counter
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
,
454 if (counter
->supported
) {
455 config
->print_free_counters_hint
= 1;
456 if (is_mixed_hw_group(counter
))
457 config
->print_mixed_hw_group_error
= 1;
460 fprintf(config
->output
, "%-*s%s",
461 config
->csv_output
? 0 : config
->unit_width
,
462 counter
->unit
, config
->csv_sep
);
464 fprintf(config
->output
, "%*s",
465 config
->csv_output
? 0 : -25,
466 perf_evsel__name(counter
));
468 print_cgroup(config
, counter
);
470 if (!config
->csv_output
)
471 pm(config
, &os
, NULL
, NULL
, "", 0);
472 print_noise(config
, counter
, noise
);
473 print_running(config
, run
, ena
);
474 if (config
->csv_output
)
475 pm(config
, &os
, NULL
, NULL
, "", 0);
479 if (!config
->metric_only
)
480 abs_printout(config
, id
, nr
, counter
, uval
);
482 out
.print_metric
= pm
;
485 out
.force_header
= false;
487 if (config
->csv_output
&& !config
->metric_only
) {
488 print_noise(config
, counter
, noise
);
489 print_running(config
, run
, ena
);
492 perf_stat__print_shadow_stats(config
, counter
, uval
,
493 first_shadow_cpu(config
, counter
, id
),
494 &out
, &config
->metric_events
, st
);
495 if (!config
->csv_output
&& !config
->metric_only
) {
496 print_noise(config
, counter
, noise
);
497 print_running(config
, run
, ena
);
501 static void aggr_update_shadow(struct perf_stat_config
*config
,
502 struct evlist
*evlist
)
506 struct evsel
*counter
;
508 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
509 id
= config
->aggr_map
->map
[s
];
510 evlist__for_each_entry(evlist
, counter
) {
512 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
513 s2
= config
->aggr_get_id(config
, evlist
->core
.cpus
, cpu
);
516 val
+= perf_counts(counter
->counts
, cpu
, 0)->val
;
518 perf_stat__update_shadow_stats(counter
, val
,
519 first_shadow_cpu(config
, counter
, id
),
525 static void uniquify_event_name(struct evsel
*counter
)
530 if (counter
->uniquified_name
||
531 !counter
->pmu_name
|| !strncmp(counter
->name
, counter
->pmu_name
,
532 strlen(counter
->pmu_name
)))
535 config
= strchr(counter
->name
, '/');
537 if (asprintf(&new_name
,
538 "%s%s", counter
->pmu_name
, config
) > 0) {
540 counter
->name
= new_name
;
543 if (asprintf(&new_name
,
544 "%s [%s]", counter
->name
, counter
->pmu_name
) > 0) {
546 counter
->name
= new_name
;
550 counter
->uniquified_name
= true;
553 static void collect_all_aliases(struct perf_stat_config
*config
, struct evsel
*counter
,
554 void (*cb
)(struct perf_stat_config
*config
, struct evsel
*counter
, void *data
,
558 struct evlist
*evlist
= counter
->evlist
;
561 alias
= list_prepare_entry(counter
, &(evlist
->core
.entries
), core
.node
);
562 list_for_each_entry_continue (alias
, &evlist
->core
.entries
, core
.node
) {
563 if (strcmp(perf_evsel__name(alias
), perf_evsel__name(counter
)) ||
564 alias
->scale
!= counter
->scale
||
565 alias
->cgrp
!= counter
->cgrp
||
566 strcmp(alias
->unit
, counter
->unit
) ||
567 perf_evsel__is_clock(alias
) != perf_evsel__is_clock(counter
) ||
568 !strcmp(alias
->pmu_name
, counter
->pmu_name
))
570 alias
->merged_stat
= true;
571 cb(config
, alias
, data
, false);
575 static bool collect_data(struct perf_stat_config
*config
, struct evsel
*counter
,
576 void (*cb
)(struct perf_stat_config
*config
, struct evsel
*counter
, void *data
,
580 if (counter
->merged_stat
)
582 cb(config
, counter
, data
, true);
583 if (config
->no_merge
)
584 uniquify_event_name(counter
);
585 else if (counter
->auto_merge_stats
)
586 collect_all_aliases(config
, counter
, cb
, data
);
597 static void aggr_cb(struct perf_stat_config
*config
,
598 struct evsel
*counter
, void *data
, bool first
)
600 struct aggr_data
*ad
= data
;
603 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
604 struct perf_counts_values
*counts
;
606 s2
= config
->aggr_get_id(config
, evsel__cpus(counter
), cpu
);
611 counts
= perf_counts(counter
->counts
, cpu
, 0);
613 * When any result is bad, make them all to give
614 * consistent output in interval mode.
616 if (counts
->ena
== 0 || counts
->run
== 0 ||
617 counter
->counts
->scaled
== -1) {
622 ad
->val
+= counts
->val
;
623 ad
->ena
+= counts
->ena
;
624 ad
->run
+= counts
->run
;
628 static void print_counter_aggrdata(struct perf_stat_config
*config
,
629 struct evsel
*counter
, int s
,
630 char *prefix
, bool metric_only
,
634 FILE *output
= config
->output
;
639 ad
.id
= id
= config
->aggr_map
->map
[s
];
640 ad
.val
= ad
.ena
= ad
.run
= 0;
642 if (!collect_data(config
, counter
, aggr_cb
, &ad
))
649 if (*first
&& metric_only
) {
651 aggr_printout(config
, counter
, id
, nr
);
653 if (prefix
&& !metric_only
)
654 fprintf(output
, "%s", prefix
);
656 uval
= val
* counter
->scale
;
657 printout(config
, id
, nr
, counter
, uval
, prefix
,
658 run
, ena
, 1.0, &rt_stat
);
663 static void print_aggr(struct perf_stat_config
*config
,
664 struct evlist
*evlist
,
667 bool metric_only
= config
->metric_only
;
668 FILE *output
= config
->output
;
669 struct evsel
*counter
;
673 if (!(config
->aggr_map
|| config
->aggr_get_id
))
676 aggr_update_shadow(config
, evlist
);
679 * With metric_only everything is on a single line.
680 * Without each counter has its own line.
682 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
683 if (prefix
&& metric_only
)
684 fprintf(output
, "%s", prefix
);
687 evlist__for_each_entry(evlist
, counter
) {
688 print_counter_aggrdata(config
, counter
, s
,
697 static int cmp_val(const void *a
, const void *b
)
699 return ((struct perf_aggr_thread_value
*)b
)->val
-
700 ((struct perf_aggr_thread_value
*)a
)->val
;
703 static struct perf_aggr_thread_value
*sort_aggr_thread(
704 struct evsel
*counter
,
705 int nthreads
, int ncpus
,
707 struct target
*_target
)
709 int cpu
, thread
, i
= 0;
711 struct perf_aggr_thread_value
*buf
;
713 buf
= calloc(nthreads
, sizeof(struct perf_aggr_thread_value
));
717 for (thread
= 0; thread
< nthreads
; thread
++) {
718 u64 ena
= 0, run
= 0, val
= 0;
720 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
721 val
+= perf_counts(counter
->counts
, cpu
, thread
)->val
;
722 ena
+= perf_counts(counter
->counts
, cpu
, thread
)->ena
;
723 run
+= perf_counts(counter
->counts
, cpu
, thread
)->run
;
726 uval
= val
* counter
->scale
;
729 * Skip value 0 when enabling --per-thread globally,
730 * otherwise too many 0 output.
732 if (uval
== 0.0 && target__has_per_thread(_target
))
735 buf
[i
].counter
= counter
;
744 qsort(buf
, i
, sizeof(struct perf_aggr_thread_value
), cmp_val
);
752 static void print_aggr_thread(struct perf_stat_config
*config
,
753 struct target
*_target
,
754 struct evsel
*counter
, char *prefix
)
756 FILE *output
= config
->output
;
757 int nthreads
= perf_thread_map__nr(counter
->core
.threads
);
758 int ncpus
= perf_cpu_map__nr(counter
->core
.cpus
);
759 int thread
, sorted_threads
, id
;
760 struct perf_aggr_thread_value
*buf
;
762 buf
= sort_aggr_thread(counter
, nthreads
, ncpus
, &sorted_threads
, _target
);
764 perror("cannot sort aggr thread");
768 for (thread
= 0; thread
< sorted_threads
; thread
++) {
770 fprintf(output
, "%s", prefix
);
774 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
775 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
778 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
779 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
788 double avg
, avg_enabled
, avg_running
;
791 static void counter_aggr_cb(struct perf_stat_config
*config __maybe_unused
,
792 struct evsel
*counter
, void *data
,
793 bool first __maybe_unused
)
795 struct caggr_data
*cd
= data
;
796 struct perf_stat_evsel
*ps
= counter
->stats
;
798 cd
->avg
+= avg_stats(&ps
->res_stats
[0]);
799 cd
->avg_enabled
+= avg_stats(&ps
->res_stats
[1]);
800 cd
->avg_running
+= avg_stats(&ps
->res_stats
[2]);
804 * Print out the results of a single counter:
805 * aggregated counts in system-wide mode
807 static void print_counter_aggr(struct perf_stat_config
*config
,
808 struct evsel
*counter
, char *prefix
)
810 bool metric_only
= config
->metric_only
;
811 FILE *output
= config
->output
;
813 struct caggr_data cd
= { .avg
= 0.0 };
815 if (!collect_data(config
, counter
, counter_aggr_cb
, &cd
))
818 if (prefix
&& !metric_only
)
819 fprintf(output
, "%s", prefix
);
821 uval
= cd
.avg
* counter
->scale
;
822 printout(config
, -1, 0, counter
, uval
, prefix
, cd
.avg_running
, cd
.avg_enabled
,
825 fprintf(output
, "\n");
828 static void counter_cb(struct perf_stat_config
*config __maybe_unused
,
829 struct evsel
*counter
, void *data
,
830 bool first __maybe_unused
)
832 struct aggr_data
*ad
= data
;
834 ad
->val
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->val
;
835 ad
->ena
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->ena
;
836 ad
->run
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->run
;
840 * Print out the results of a single counter:
841 * does not use aggregated count in system-wide
843 static void print_counter(struct perf_stat_config
*config
,
844 struct evsel
*counter
, char *prefix
)
846 FILE *output
= config
->output
;
851 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
852 struct aggr_data ad
= { .cpu
= cpu
};
854 if (!collect_data(config
, counter
, counter_cb
, &ad
))
861 fprintf(output
, "%s", prefix
);
863 uval
= val
* counter
->scale
;
864 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
871 static void print_no_aggr_metric(struct perf_stat_config
*config
,
872 struct evlist
*evlist
,
877 struct evsel
*counter
;
881 nrcpus
= evlist
->core
.cpus
->nr
;
882 for (cpu
= 0; cpu
< nrcpus
; cpu
++) {
886 fputs(prefix
, config
->output
);
887 evlist__for_each_entry(evlist
, counter
) {
889 aggr_printout(config
, counter
, cpu
, 0);
892 val
= perf_counts(counter
->counts
, cpu
, 0)->val
;
893 ena
= perf_counts(counter
->counts
, cpu
, 0)->ena
;
894 run
= perf_counts(counter
->counts
, cpu
, 0)->run
;
896 uval
= val
* counter
->scale
;
897 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
900 fputc('\n', config
->output
);
904 static int aggr_header_lens
[] = {
913 static const char *aggr_header_csv
[] = {
914 [AGGR_CORE
] = "core,cpus,",
915 [AGGR_DIE
] = "die,cpus",
916 [AGGR_SOCKET
] = "socket,cpus",
917 [AGGR_NONE
] = "cpu,",
918 [AGGR_THREAD
] = "comm-pid,",
922 static void print_metric_headers(struct perf_stat_config
*config
,
923 struct evlist
*evlist
,
924 const char *prefix
, bool no_indent
)
926 struct perf_stat_output_ctx out
;
927 struct evsel
*counter
;
928 struct outstate os
= {
933 fprintf(config
->output
, "%s", prefix
);
935 if (!config
->csv_output
&& !no_indent
)
936 fprintf(config
->output
, "%*s",
937 aggr_header_lens
[config
->aggr_mode
], "");
938 if (config
->csv_output
) {
939 if (config
->interval
)
940 fputs("time,", config
->output
);
941 fputs(aggr_header_csv
[config
->aggr_mode
], config
->output
);
944 /* Print metrics headers only */
945 evlist__for_each_entry(evlist
, counter
) {
948 out
.print_metric
= print_metric_header
;
949 out
.new_line
= new_line_metric
;
950 out
.force_header
= true;
952 perf_stat__print_shadow_stats(config
, counter
, 0,
955 &config
->metric_events
,
958 fputc('\n', config
->output
);
961 static void print_interval(struct perf_stat_config
*config
,
962 struct evlist
*evlist
,
963 char *prefix
, struct timespec
*ts
)
965 bool metric_only
= config
->metric_only
;
966 unsigned int unit_width
= config
->unit_width
;
967 FILE *output
= config
->output
;
968 static int num_print_interval
;
970 if (config
->interval_clear
)
973 sprintf(prefix
, "%6lu.%09lu%s", ts
->tv_sec
, ts
->tv_nsec
, config
->csv_sep
);
975 if ((num_print_interval
== 0 && !config
->csv_output
) || config
->interval_clear
) {
976 switch (config
->aggr_mode
) {
978 fprintf(output
, "# time node cpus");
980 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
983 fprintf(output
, "# time socket cpus");
985 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
988 fprintf(output
, "# time die cpus");
990 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
993 fprintf(output
, "# time core cpus");
995 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
998 fprintf(output
, "# time CPU ");
1000 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1003 fprintf(output
, "# time comm-pid");
1005 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1009 fprintf(output
, "# time");
1011 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1017 if ((num_print_interval
== 0 || config
->interval_clear
) && metric_only
)
1018 print_metric_headers(config
, evlist
, " ", true);
1019 if (++num_print_interval
== 25)
1020 num_print_interval
= 0;
1023 static void print_header(struct perf_stat_config
*config
,
1024 struct target
*_target
,
1025 int argc
, const char **argv
)
1027 FILE *output
= config
->output
;
1032 if (!config
->csv_output
) {
1033 fprintf(output
, "\n");
1034 fprintf(output
, " Performance counter stats for ");
1035 if (_target
->system_wide
)
1036 fprintf(output
, "\'system wide");
1037 else if (_target
->cpu_list
)
1038 fprintf(output
, "\'CPU(s) %s", _target
->cpu_list
);
1039 else if (!target__has_task(_target
)) {
1040 fprintf(output
, "\'%s", argv
? argv
[0] : "pipe");
1041 for (i
= 1; argv
&& (i
< argc
); i
++)
1042 fprintf(output
, " %s", argv
[i
]);
1043 } else if (_target
->pid
)
1044 fprintf(output
, "process id \'%s", _target
->pid
);
1046 fprintf(output
, "thread id \'%s", _target
->tid
);
1048 fprintf(output
, "\'");
1049 if (config
->run_count
> 1)
1050 fprintf(output
, " (%d runs)", config
->run_count
);
1051 fprintf(output
, ":\n\n");
1055 static int get_precision(double num
)
1060 return lround(ceil(-log10(num
)));
1063 static void print_table(struct perf_stat_config
*config
,
1064 FILE *output
, int precision
, double avg
)
1067 int idx
, indent
= 0;
1069 scnprintf(tmp
, 64, " %17.*f", precision
, avg
);
1070 while (tmp
[indent
] == ' ')
1073 fprintf(output
, "%*s# Table of individual measurements:\n", indent
, "");
1075 for (idx
= 0; idx
< config
->run_count
; idx
++) {
1076 double run
= (double) config
->walltime_run
[idx
] / NSEC_PER_SEC
;
1077 int h
, n
= 1 + abs((int) (100.0 * (run
- avg
)/run
) / 5);
1079 fprintf(output
, " %17.*f (%+.*f) ",
1080 precision
, run
, precision
, run
- avg
);
1082 for (h
= 0; h
< n
; h
++)
1083 fprintf(output
, "#");
1085 fprintf(output
, "\n");
1088 fprintf(output
, "\n%*s# Final result:\n", indent
, "");
1091 static double timeval2double(struct timeval
*t
)
1093 return t
->tv_sec
+ (double) t
->tv_usec
/USEC_PER_SEC
;
1096 static void print_footer(struct perf_stat_config
*config
)
1098 double avg
= avg_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1099 FILE *output
= config
->output
;
1102 if (!config
->null_run
)
1103 fprintf(output
, "\n");
1105 if (config
->run_count
== 1) {
1106 fprintf(output
, " %17.9f seconds time elapsed", avg
);
1108 if (config
->ru_display
) {
1109 double ru_utime
= timeval2double(&config
->ru_data
.ru_utime
);
1110 double ru_stime
= timeval2double(&config
->ru_data
.ru_stime
);
1112 fprintf(output
, "\n\n");
1113 fprintf(output
, " %17.9f seconds user\n", ru_utime
);
1114 fprintf(output
, " %17.9f seconds sys\n", ru_stime
);
1117 double sd
= stddev_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1119 * Display at most 2 more significant
1120 * digits than the stddev inaccuracy.
1122 int precision
= get_precision(sd
) + 2;
1124 if (config
->walltime_run_table
)
1125 print_table(config
, output
, precision
, avg
);
1127 fprintf(output
, " %17.*f +- %.*f seconds time elapsed",
1128 precision
, avg
, precision
, sd
);
1130 print_noise_pct(config
, sd
, avg
);
1132 fprintf(output
, "\n\n");
1134 if (config
->print_free_counters_hint
&&
1135 sysctl__read_int("kernel/nmi_watchdog", &n
) >= 0 &&
1138 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1139 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1141 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1143 if (config
->print_mixed_hw_group_error
)
1145 "The events in group usually have to be from "
1146 "the same PMU. Try reorganizing the group.\n");
1149 static void print_percore(struct perf_stat_config
*config
,
1150 struct evsel
*counter
, char *prefix
)
1152 bool metric_only
= config
->metric_only
;
1153 FILE *output
= config
->output
;
1157 if (!(config
->aggr_map
|| config
->aggr_get_id
))
1160 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
1161 if (prefix
&& metric_only
)
1162 fprintf(output
, "%s", prefix
);
1164 print_counter_aggrdata(config
, counter
, s
,
1165 prefix
, metric_only
,
1170 fputc('\n', output
);
1174 perf_evlist__print_counters(struct evlist
*evlist
,
1175 struct perf_stat_config
*config
,
1176 struct target
*_target
,
1177 struct timespec
*ts
,
1178 int argc
, const char **argv
)
1180 bool metric_only
= config
->metric_only
;
1181 int interval
= config
->interval
;
1182 struct evsel
*counter
;
1183 char buf
[64], *prefix
= NULL
;
1186 print_interval(config
, evlist
, prefix
= buf
, ts
);
1188 print_header(config
, _target
, argc
, argv
);
1191 static int num_print_iv
;
1193 if (num_print_iv
== 0 && !interval
)
1194 print_metric_headers(config
, evlist
, prefix
, false);
1195 if (num_print_iv
++ == 25)
1197 if (config
->aggr_mode
== AGGR_GLOBAL
&& prefix
)
1198 fprintf(config
->output
, "%s", prefix
);
1201 switch (config
->aggr_mode
) {
1206 print_aggr(config
, evlist
, prefix
);
1209 evlist__for_each_entry(evlist
, counter
) {
1210 print_aggr_thread(config
, _target
, counter
, prefix
);
1214 evlist__for_each_entry(evlist
, counter
) {
1215 print_counter_aggr(config
, counter
, prefix
);
1218 fputc('\n', config
->output
);
1222 print_no_aggr_metric(config
, evlist
, prefix
);
1224 evlist__for_each_entry(evlist
, counter
) {
1225 if (counter
->percore
)
1226 print_percore(config
, counter
, prefix
);
1228 print_counter(config
, counter
, prefix
);
1237 if (!interval
&& !config
->csv_output
)
1238 print_footer(config
);
1240 fflush(config
->output
);