3 #include <linux/time64.h>
10 #include "thread_map.h"
13 #include "sane_ctype.h"
16 #include <api/fs/fs.h>
18 #define CNTR_NOT_SUPPORTED "<not supported>"
19 #define CNTR_NOT_COUNTED "<not counted>"
21 static void print_running(struct perf_stat_config
*config
,
24 if (config
->csv_output
) {
25 fprintf(config
->output
, "%s%" PRIu64
"%s%.2f",
29 ena
? 100.0 * run
/ ena
: 100.0);
30 } else if (run
!= ena
) {
31 fprintf(config
->output
, " (%.2f%%)", 100.0 * run
/ ena
);
35 static void print_noise_pct(struct perf_stat_config
*config
,
36 double total
, double avg
)
38 double pct
= rel_stddev_stats(total
, avg
);
40 if (config
->csv_output
)
41 fprintf(config
->output
, "%s%.2f%%", config
->csv_sep
, pct
);
43 fprintf(config
->output
, " ( +-%6.2f%% )", pct
);
46 static void print_noise(struct perf_stat_config
*config
,
47 struct perf_evsel
*evsel
, double avg
)
49 struct perf_stat_evsel
*ps
;
51 if (config
->run_count
== 1)
55 print_noise_pct(config
, stddev_stats(&ps
->res_stats
[0]), avg
);
58 static void print_cgroup(struct perf_stat_config
*config
, struct perf_evsel
*evsel
)
61 const char *cgrp_name
= evsel
->cgrp
? evsel
->cgrp
->name
: "";
62 fprintf(config
->output
, "%s%s", config
->csv_sep
, cgrp_name
);
67 static void aggr_printout(struct perf_stat_config
*config
,
68 struct perf_evsel
*evsel
, int id
, int nr
)
70 switch (config
->aggr_mode
) {
72 fprintf(config
->output
, "S%d-D%d-C%*d%s%*d%s",
73 cpu_map__id_to_socket(id
),
74 cpu_map__id_to_die(id
),
75 config
->csv_output
? 0 : -8,
76 cpu_map__id_to_cpu(id
),
78 config
->csv_output
? 0 : 4,
83 fprintf(config
->output
, "S%d-D%*d%s%*d%s",
84 cpu_map__id_to_socket(id
<< 16),
85 config
->csv_output
? 0 : -8,
86 cpu_map__id_to_die(id
<< 16),
88 config
->csv_output
? 0 : 4,
93 fprintf(config
->output
, "S%*d%s%*d%s",
94 config
->csv_output
? 0 : -5,
97 config
->csv_output
? 0 : 4,
102 if (evsel
->percore
) {
103 fprintf(config
->output
, "S%d-D%d-C%*d%s",
104 cpu_map__id_to_socket(id
),
105 cpu_map__id_to_die(id
),
106 config
->csv_output
? 0 : -5,
107 cpu_map__id_to_cpu(id
), config
->csv_sep
);
109 fprintf(config
->output
, "CPU%*d%s ",
110 config
->csv_output
? 0 : -5,
111 perf_evsel__cpus(evsel
)->map
[id
],
116 fprintf(config
->output
, "%*s-%*d%s",
117 config
->csv_output
? 0 : 16,
118 thread_map__comm(evsel
->threads
, id
),
119 config
->csv_output
? 0 : -8,
120 thread_map__pid(evsel
->threads
, id
),
136 struct perf_evsel
*evsel
;
139 #define METRIC_LEN 35
141 static void new_line_std(struct perf_stat_config
*config __maybe_unused
,
144 struct outstate
*os
= ctx
;
149 static void do_new_line_std(struct perf_stat_config
*config
,
153 fputs(os
->prefix
, os
->fh
);
154 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
155 if (config
->aggr_mode
== AGGR_NONE
)
156 fprintf(os
->fh
, " ");
157 fprintf(os
->fh
, " ");
160 static void print_metric_std(struct perf_stat_config
*config
,
161 void *ctx
, const char *color
, const char *fmt
,
162 const char *unit
, double val
)
164 struct outstate
*os
= ctx
;
167 bool newline
= os
->newline
;
171 if (unit
== NULL
|| fmt
== NULL
) {
172 fprintf(out
, "%-*s", METRIC_LEN
, "");
177 do_new_line_std(config
, os
);
179 n
= fprintf(out
, " # ");
181 n
+= color_fprintf(out
, color
, fmt
, val
);
183 n
+= fprintf(out
, fmt
, val
);
184 fprintf(out
, " %-*s", METRIC_LEN
- n
- 1, unit
);
187 static void new_line_csv(struct perf_stat_config
*config
, void *ctx
)
189 struct outstate
*os
= ctx
;
194 fprintf(os
->fh
, "%s%s", os
->prefix
, config
->csv_sep
);
195 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
196 for (i
= 0; i
< os
->nfields
; i
++)
197 fputs(config
->csv_sep
, os
->fh
);
200 static void print_metric_csv(struct perf_stat_config
*config __maybe_unused
,
202 const char *color __maybe_unused
,
203 const char *fmt
, const char *unit
, double val
)
205 struct outstate
*os
= ctx
;
207 char buf
[64], *vals
, *ends
;
209 if (unit
== NULL
|| fmt
== NULL
) {
210 fprintf(out
, "%s%s", config
->csv_sep
, config
->csv_sep
);
213 snprintf(buf
, sizeof(buf
), fmt
, val
);
214 ends
= vals
= ltrim(buf
);
215 while (isdigit(*ends
) || *ends
== '.')
218 while (isspace(*unit
))
220 fprintf(out
, "%s%s%s%s", config
->csv_sep
, vals
, config
->csv_sep
, unit
);
223 /* Filter out some columns that don't work well in metrics only mode */
225 static bool valid_only_metric(const char *unit
)
229 if (strstr(unit
, "/sec") ||
230 strstr(unit
, "hz") ||
231 strstr(unit
, "Hz") ||
232 strstr(unit
, "CPUs utilized"))
237 static const char *fixunit(char *buf
, struct perf_evsel
*evsel
,
240 if (!strncmp(unit
, "of all", 6)) {
241 snprintf(buf
, 1024, "%s %s", perf_evsel__name(evsel
),
248 static void print_metric_only(struct perf_stat_config
*config
,
249 void *ctx
, const char *color
, const char *fmt
,
250 const char *unit
, double val
)
252 struct outstate
*os
= ctx
;
254 char buf
[1024], str
[1024];
255 unsigned mlen
= config
->metric_only_len
;
257 if (!valid_only_metric(unit
))
259 unit
= fixunit(buf
, os
->evsel
, unit
);
260 if (mlen
< strlen(unit
))
261 mlen
= strlen(unit
) + 1;
264 mlen
+= strlen(color
) + sizeof(PERF_COLOR_RESET
) - 1;
266 color_snprintf(str
, sizeof(str
), color
?: "", fmt
, val
);
267 fprintf(out
, "%*s ", mlen
, str
);
270 static void print_metric_only_csv(struct perf_stat_config
*config __maybe_unused
,
271 void *ctx
, const char *color __maybe_unused
,
273 const char *unit
, double val
)
275 struct outstate
*os
= ctx
;
277 char buf
[64], *vals
, *ends
;
280 if (!valid_only_metric(unit
))
282 unit
= fixunit(tbuf
, os
->evsel
, unit
);
283 snprintf(buf
, sizeof buf
, fmt
, val
);
284 ends
= vals
= ltrim(buf
);
285 while (isdigit(*ends
) || *ends
== '.')
288 fprintf(out
, "%s%s", vals
, config
->csv_sep
);
291 static void new_line_metric(struct perf_stat_config
*config __maybe_unused
,
292 void *ctx __maybe_unused
)
296 static void print_metric_header(struct perf_stat_config
*config
,
297 void *ctx
, const char *color __maybe_unused
,
298 const char *fmt __maybe_unused
,
299 const char *unit
, double val __maybe_unused
)
301 struct outstate
*os
= ctx
;
304 if (!valid_only_metric(unit
))
306 unit
= fixunit(tbuf
, os
->evsel
, unit
);
307 if (config
->csv_output
)
308 fprintf(os
->fh
, "%s%s", unit
, config
->csv_sep
);
310 fprintf(os
->fh
, "%*s ", config
->metric_only_len
, unit
);
313 static int first_shadow_cpu(struct perf_stat_config
*config
,
314 struct perf_evsel
*evsel
, int id
)
316 struct perf_evlist
*evlist
= evsel
->evlist
;
319 if (!config
->aggr_get_id
)
322 if (config
->aggr_mode
== AGGR_NONE
)
325 if (config
->aggr_mode
== AGGR_GLOBAL
)
328 for (i
= 0; i
< perf_evsel__nr_cpus(evsel
); i
++) {
329 int cpu2
= perf_evsel__cpus(evsel
)->map
[i
];
331 if (config
->aggr_get_id(config
, evlist
->cpus
, cpu2
) == id
)
337 static void abs_printout(struct perf_stat_config
*config
,
338 int id
, int nr
, struct perf_evsel
*evsel
, double avg
)
340 FILE *output
= config
->output
;
341 double sc
= evsel
->scale
;
344 if (config
->csv_output
) {
345 fmt
= floor(sc
) != sc
? "%.2f%s" : "%.0f%s";
348 fmt
= floor(sc
) != sc
? "%'18.2f%s" : "%'18.0f%s";
350 fmt
= floor(sc
) != sc
? "%18.2f%s" : "%18.0f%s";
353 aggr_printout(config
, evsel
, id
, nr
);
355 fprintf(output
, fmt
, avg
, config
->csv_sep
);
358 fprintf(output
, "%-*s%s",
359 config
->csv_output
? 0 : config
->unit_width
,
360 evsel
->unit
, config
->csv_sep
);
362 fprintf(output
, "%-*s", config
->csv_output
? 0 : 25, perf_evsel__name(evsel
));
364 print_cgroup(config
, evsel
);
367 static bool is_mixed_hw_group(struct perf_evsel
*counter
)
369 struct perf_evlist
*evlist
= counter
->evlist
;
370 u32 pmu_type
= counter
->attr
.type
;
371 struct perf_evsel
*pos
;
373 if (counter
->nr_members
< 2)
376 evlist__for_each_entry(evlist
, pos
) {
377 /* software events can be part of any hardware group */
378 if (pos
->attr
.type
== PERF_TYPE_SOFTWARE
)
380 if (pmu_type
== PERF_TYPE_SOFTWARE
) {
381 pmu_type
= pos
->attr
.type
;
384 if (pmu_type
!= pos
->attr
.type
)
391 static void printout(struct perf_stat_config
*config
, int id
, int nr
,
392 struct perf_evsel
*counter
, double uval
,
393 char *prefix
, u64 run
, u64 ena
, double noise
,
394 struct runtime_stat
*st
)
396 struct perf_stat_output_ctx out
;
397 struct outstate os
= {
398 .fh
= config
->output
,
399 .prefix
= prefix
? prefix
: "",
404 print_metric_t pm
= print_metric_std
;
407 if (config
->metric_only
) {
408 nl
= new_line_metric
;
409 if (config
->csv_output
)
410 pm
= print_metric_only_csv
;
412 pm
= print_metric_only
;
416 if (config
->csv_output
&& !config
->metric_only
) {
417 static int aggr_fields
[] = {
426 pm
= print_metric_csv
;
429 os
.nfields
+= aggr_fields
[config
->aggr_mode
];
433 if (run
== 0 || ena
== 0 || counter
->counts
->scaled
== -1) {
434 if (config
->metric_only
) {
435 pm(config
, &os
, NULL
, "", "", 0);
438 aggr_printout(config
, counter
, id
, nr
);
440 fprintf(config
->output
, "%*s%s",
441 config
->csv_output
? 0 : 18,
442 counter
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
,
445 if (counter
->supported
) {
446 config
->print_free_counters_hint
= 1;
447 if (is_mixed_hw_group(counter
))
448 config
->print_mixed_hw_group_error
= 1;
451 fprintf(config
->output
, "%-*s%s",
452 config
->csv_output
? 0 : config
->unit_width
,
453 counter
->unit
, config
->csv_sep
);
455 fprintf(config
->output
, "%*s",
456 config
->csv_output
? 0 : -25,
457 perf_evsel__name(counter
));
459 print_cgroup(config
, counter
);
461 if (!config
->csv_output
)
462 pm(config
, &os
, NULL
, NULL
, "", 0);
463 print_noise(config
, counter
, noise
);
464 print_running(config
, run
, ena
);
465 if (config
->csv_output
)
466 pm(config
, &os
, NULL
, NULL
, "", 0);
470 if (!config
->metric_only
)
471 abs_printout(config
, id
, nr
, counter
, uval
);
473 out
.print_metric
= pm
;
476 out
.force_header
= false;
478 if (config
->csv_output
&& !config
->metric_only
) {
479 print_noise(config
, counter
, noise
);
480 print_running(config
, run
, ena
);
483 perf_stat__print_shadow_stats(config
, counter
, uval
,
484 first_shadow_cpu(config
, counter
, id
),
485 &out
, &config
->metric_events
, st
);
486 if (!config
->csv_output
&& !config
->metric_only
) {
487 print_noise(config
, counter
, noise
);
488 print_running(config
, run
, ena
);
492 static void aggr_update_shadow(struct perf_stat_config
*config
,
493 struct perf_evlist
*evlist
)
497 struct perf_evsel
*counter
;
499 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
500 id
= config
->aggr_map
->map
[s
];
501 evlist__for_each_entry(evlist
, counter
) {
503 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
504 s2
= config
->aggr_get_id(config
, evlist
->cpus
, cpu
);
507 val
+= perf_counts(counter
->counts
, cpu
, 0)->val
;
509 perf_stat__update_shadow_stats(counter
, val
,
510 first_shadow_cpu(config
, counter
, id
),
516 static void uniquify_event_name(struct perf_evsel
*counter
)
521 if (counter
->uniquified_name
||
522 !counter
->pmu_name
|| !strncmp(counter
->name
, counter
->pmu_name
,
523 strlen(counter
->pmu_name
)))
526 config
= strchr(counter
->name
, '/');
528 if (asprintf(&new_name
,
529 "%s%s", counter
->pmu_name
, config
) > 0) {
531 counter
->name
= new_name
;
534 if (asprintf(&new_name
,
535 "%s [%s]", counter
->name
, counter
->pmu_name
) > 0) {
537 counter
->name
= new_name
;
541 counter
->uniquified_name
= true;
544 static void collect_all_aliases(struct perf_stat_config
*config
, struct perf_evsel
*counter
,
545 void (*cb
)(struct perf_stat_config
*config
, struct perf_evsel
*counter
, void *data
,
549 struct perf_evlist
*evlist
= counter
->evlist
;
550 struct perf_evsel
*alias
;
552 alias
= list_prepare_entry(counter
, &(evlist
->entries
), node
);
553 list_for_each_entry_continue (alias
, &evlist
->entries
, node
) {
554 if (strcmp(perf_evsel__name(alias
), perf_evsel__name(counter
)) ||
555 alias
->scale
!= counter
->scale
||
556 alias
->cgrp
!= counter
->cgrp
||
557 strcmp(alias
->unit
, counter
->unit
) ||
558 perf_evsel__is_clock(alias
) != perf_evsel__is_clock(counter
))
560 alias
->merged_stat
= true;
561 cb(config
, alias
, data
, false);
565 static bool collect_data(struct perf_stat_config
*config
, struct perf_evsel
*counter
,
566 void (*cb
)(struct perf_stat_config
*config
, struct perf_evsel
*counter
, void *data
,
570 if (counter
->merged_stat
)
572 cb(config
, counter
, data
, true);
573 if (config
->no_merge
)
574 uniquify_event_name(counter
);
575 else if (counter
->auto_merge_stats
)
576 collect_all_aliases(config
, counter
, cb
, data
);
587 static void aggr_cb(struct perf_stat_config
*config
,
588 struct perf_evsel
*counter
, void *data
, bool first
)
590 struct aggr_data
*ad
= data
;
593 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
594 struct perf_counts_values
*counts
;
596 s2
= config
->aggr_get_id(config
, perf_evsel__cpus(counter
), cpu
);
601 counts
= perf_counts(counter
->counts
, cpu
, 0);
603 * When any result is bad, make them all to give
604 * consistent output in interval mode.
606 if (counts
->ena
== 0 || counts
->run
== 0 ||
607 counter
->counts
->scaled
== -1) {
612 ad
->val
+= counts
->val
;
613 ad
->ena
+= counts
->ena
;
614 ad
->run
+= counts
->run
;
618 static void print_counter_aggrdata(struct perf_stat_config
*config
,
619 struct perf_evsel
*counter
, int s
,
620 char *prefix
, bool metric_only
,
624 FILE *output
= config
->output
;
629 ad
.id
= id
= config
->aggr_map
->map
[s
];
630 ad
.val
= ad
.ena
= ad
.run
= 0;
632 if (!collect_data(config
, counter
, aggr_cb
, &ad
))
639 if (*first
&& metric_only
) {
641 aggr_printout(config
, counter
, id
, nr
);
643 if (prefix
&& !metric_only
)
644 fprintf(output
, "%s", prefix
);
646 uval
= val
* counter
->scale
;
647 printout(config
, id
, nr
, counter
, uval
, prefix
,
648 run
, ena
, 1.0, &rt_stat
);
653 static void print_aggr(struct perf_stat_config
*config
,
654 struct perf_evlist
*evlist
,
657 bool metric_only
= config
->metric_only
;
658 FILE *output
= config
->output
;
659 struct perf_evsel
*counter
;
663 if (!(config
->aggr_map
|| config
->aggr_get_id
))
666 aggr_update_shadow(config
, evlist
);
669 * With metric_only everything is on a single line.
670 * Without each counter has its own line.
672 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
673 if (prefix
&& metric_only
)
674 fprintf(output
, "%s", prefix
);
677 evlist__for_each_entry(evlist
, counter
) {
678 print_counter_aggrdata(config
, counter
, s
,
687 static int cmp_val(const void *a
, const void *b
)
689 return ((struct perf_aggr_thread_value
*)b
)->val
-
690 ((struct perf_aggr_thread_value
*)a
)->val
;
693 static struct perf_aggr_thread_value
*sort_aggr_thread(
694 struct perf_evsel
*counter
,
695 int nthreads
, int ncpus
,
697 struct target
*_target
)
699 int cpu
, thread
, i
= 0;
701 struct perf_aggr_thread_value
*buf
;
703 buf
= calloc(nthreads
, sizeof(struct perf_aggr_thread_value
));
707 for (thread
= 0; thread
< nthreads
; thread
++) {
708 u64 ena
= 0, run
= 0, val
= 0;
710 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
711 val
+= perf_counts(counter
->counts
, cpu
, thread
)->val
;
712 ena
+= perf_counts(counter
->counts
, cpu
, thread
)->ena
;
713 run
+= perf_counts(counter
->counts
, cpu
, thread
)->run
;
716 uval
= val
* counter
->scale
;
719 * Skip value 0 when enabling --per-thread globally,
720 * otherwise too many 0 output.
722 if (uval
== 0.0 && target__has_per_thread(_target
))
725 buf
[i
].counter
= counter
;
734 qsort(buf
, i
, sizeof(struct perf_aggr_thread_value
), cmp_val
);
742 static void print_aggr_thread(struct perf_stat_config
*config
,
743 struct target
*_target
,
744 struct perf_evsel
*counter
, char *prefix
)
746 FILE *output
= config
->output
;
747 int nthreads
= thread_map__nr(counter
->threads
);
748 int ncpus
= cpu_map__nr(counter
->cpus
);
749 int thread
, sorted_threads
, id
;
750 struct perf_aggr_thread_value
*buf
;
752 buf
= sort_aggr_thread(counter
, nthreads
, ncpus
, &sorted_threads
, _target
);
754 perror("cannot sort aggr thread");
758 for (thread
= 0; thread
< sorted_threads
; thread
++) {
760 fprintf(output
, "%s", prefix
);
764 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
765 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
768 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
769 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
778 double avg
, avg_enabled
, avg_running
;
781 static void counter_aggr_cb(struct perf_stat_config
*config __maybe_unused
,
782 struct perf_evsel
*counter
, void *data
,
783 bool first __maybe_unused
)
785 struct caggr_data
*cd
= data
;
786 struct perf_stat_evsel
*ps
= counter
->stats
;
788 cd
->avg
+= avg_stats(&ps
->res_stats
[0]);
789 cd
->avg_enabled
+= avg_stats(&ps
->res_stats
[1]);
790 cd
->avg_running
+= avg_stats(&ps
->res_stats
[2]);
794 * Print out the results of a single counter:
795 * aggregated counts in system-wide mode
797 static void print_counter_aggr(struct perf_stat_config
*config
,
798 struct perf_evsel
*counter
, char *prefix
)
800 bool metric_only
= config
->metric_only
;
801 FILE *output
= config
->output
;
803 struct caggr_data cd
= { .avg
= 0.0 };
805 if (!collect_data(config
, counter
, counter_aggr_cb
, &cd
))
808 if (prefix
&& !metric_only
)
809 fprintf(output
, "%s", prefix
);
811 uval
= cd
.avg
* counter
->scale
;
812 printout(config
, -1, 0, counter
, uval
, prefix
, cd
.avg_running
, cd
.avg_enabled
,
815 fprintf(output
, "\n");
818 static void counter_cb(struct perf_stat_config
*config __maybe_unused
,
819 struct perf_evsel
*counter
, void *data
,
820 bool first __maybe_unused
)
822 struct aggr_data
*ad
= data
;
824 ad
->val
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->val
;
825 ad
->ena
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->ena
;
826 ad
->run
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->run
;
830 * Print out the results of a single counter:
831 * does not use aggregated count in system-wide
833 static void print_counter(struct perf_stat_config
*config
,
834 struct perf_evsel
*counter
, char *prefix
)
836 FILE *output
= config
->output
;
841 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
842 struct aggr_data ad
= { .cpu
= cpu
};
844 if (!collect_data(config
, counter
, counter_cb
, &ad
))
851 fprintf(output
, "%s", prefix
);
853 uval
= val
* counter
->scale
;
854 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
861 static void print_no_aggr_metric(struct perf_stat_config
*config
,
862 struct perf_evlist
*evlist
,
867 struct perf_evsel
*counter
;
871 nrcpus
= evlist
->cpus
->nr
;
872 for (cpu
= 0; cpu
< nrcpus
; cpu
++) {
876 fputs(prefix
, config
->output
);
877 evlist__for_each_entry(evlist
, counter
) {
879 aggr_printout(config
, counter
, cpu
, 0);
882 val
= perf_counts(counter
->counts
, cpu
, 0)->val
;
883 ena
= perf_counts(counter
->counts
, cpu
, 0)->ena
;
884 run
= perf_counts(counter
->counts
, cpu
, 0)->run
;
886 uval
= val
* counter
->scale
;
887 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
890 fputc('\n', config
->output
);
894 static int aggr_header_lens
[] = {
903 static const char *aggr_header_csv
[] = {
904 [AGGR_CORE
] = "core,cpus,",
905 [AGGR_DIE
] = "die,cpus",
906 [AGGR_SOCKET
] = "socket,cpus",
907 [AGGR_NONE
] = "cpu,",
908 [AGGR_THREAD
] = "comm-pid,",
912 static void print_metric_headers(struct perf_stat_config
*config
,
913 struct perf_evlist
*evlist
,
914 const char *prefix
, bool no_indent
)
916 struct perf_stat_output_ctx out
;
917 struct perf_evsel
*counter
;
918 struct outstate os
= {
923 fprintf(config
->output
, "%s", prefix
);
925 if (!config
->csv_output
&& !no_indent
)
926 fprintf(config
->output
, "%*s",
927 aggr_header_lens
[config
->aggr_mode
], "");
928 if (config
->csv_output
) {
929 if (config
->interval
)
930 fputs("time,", config
->output
);
931 fputs(aggr_header_csv
[config
->aggr_mode
], config
->output
);
934 /* Print metrics headers only */
935 evlist__for_each_entry(evlist
, counter
) {
938 out
.print_metric
= print_metric_header
;
939 out
.new_line
= new_line_metric
;
940 out
.force_header
= true;
942 perf_stat__print_shadow_stats(config
, counter
, 0,
945 &config
->metric_events
,
948 fputc('\n', config
->output
);
951 static void print_interval(struct perf_stat_config
*config
,
952 struct perf_evlist
*evlist
,
953 char *prefix
, struct timespec
*ts
)
955 bool metric_only
= config
->metric_only
;
956 unsigned int unit_width
= config
->unit_width
;
957 FILE *output
= config
->output
;
958 static int num_print_interval
;
960 if (config
->interval_clear
)
963 sprintf(prefix
, "%6lu.%09lu%s", ts
->tv_sec
, ts
->tv_nsec
, config
->csv_sep
);
965 if ((num_print_interval
== 0 && !config
->csv_output
) || config
->interval_clear
) {
966 switch (config
->aggr_mode
) {
968 fprintf(output
, "# time socket cpus");
970 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
973 fprintf(output
, "# time die cpus");
975 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
978 fprintf(output
, "# time core cpus");
980 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
983 fprintf(output
, "# time CPU ");
985 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
988 fprintf(output
, "# time comm-pid");
990 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
994 fprintf(output
, "# time");
996 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
1002 if ((num_print_interval
== 0 || config
->interval_clear
) && metric_only
)
1003 print_metric_headers(config
, evlist
, " ", true);
1004 if (++num_print_interval
== 25)
1005 num_print_interval
= 0;
1008 static void print_header(struct perf_stat_config
*config
,
1009 struct target
*_target
,
1010 int argc
, const char **argv
)
1012 FILE *output
= config
->output
;
1017 if (!config
->csv_output
) {
1018 fprintf(output
, "\n");
1019 fprintf(output
, " Performance counter stats for ");
1020 if (_target
->system_wide
)
1021 fprintf(output
, "\'system wide");
1022 else if (_target
->cpu_list
)
1023 fprintf(output
, "\'CPU(s) %s", _target
->cpu_list
);
1024 else if (!target__has_task(_target
)) {
1025 fprintf(output
, "\'%s", argv
? argv
[0] : "pipe");
1026 for (i
= 1; argv
&& (i
< argc
); i
++)
1027 fprintf(output
, " %s", argv
[i
]);
1028 } else if (_target
->pid
)
1029 fprintf(output
, "process id \'%s", _target
->pid
);
1031 fprintf(output
, "thread id \'%s", _target
->tid
);
1033 fprintf(output
, "\'");
1034 if (config
->run_count
> 1)
1035 fprintf(output
, " (%d runs)", config
->run_count
);
1036 fprintf(output
, ":\n\n");
1040 static int get_precision(double num
)
1045 return lround(ceil(-log10(num
)));
1048 static void print_table(struct perf_stat_config
*config
,
1049 FILE *output
, int precision
, double avg
)
1052 int idx
, indent
= 0;
1054 scnprintf(tmp
, 64, " %17.*f", precision
, avg
);
1055 while (tmp
[indent
] == ' ')
1058 fprintf(output
, "%*s# Table of individual measurements:\n", indent
, "");
1060 for (idx
= 0; idx
< config
->run_count
; idx
++) {
1061 double run
= (double) config
->walltime_run
[idx
] / NSEC_PER_SEC
;
1062 int h
, n
= 1 + abs((int) (100.0 * (run
- avg
)/run
) / 5);
1064 fprintf(output
, " %17.*f (%+.*f) ",
1065 precision
, run
, precision
, run
- avg
);
1067 for (h
= 0; h
< n
; h
++)
1068 fprintf(output
, "#");
1070 fprintf(output
, "\n");
1073 fprintf(output
, "\n%*s# Final result:\n", indent
, "");
1076 static double timeval2double(struct timeval
*t
)
1078 return t
->tv_sec
+ (double) t
->tv_usec
/USEC_PER_SEC
;
1081 static void print_footer(struct perf_stat_config
*config
)
1083 double avg
= avg_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1084 FILE *output
= config
->output
;
1087 if (!config
->null_run
)
1088 fprintf(output
, "\n");
1090 if (config
->run_count
== 1) {
1091 fprintf(output
, " %17.9f seconds time elapsed", avg
);
1093 if (config
->ru_display
) {
1094 double ru_utime
= timeval2double(&config
->ru_data
.ru_utime
);
1095 double ru_stime
= timeval2double(&config
->ru_data
.ru_stime
);
1097 fprintf(output
, "\n\n");
1098 fprintf(output
, " %17.9f seconds user\n", ru_utime
);
1099 fprintf(output
, " %17.9f seconds sys\n", ru_stime
);
1102 double sd
= stddev_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1104 * Display at most 2 more significant
1105 * digits than the stddev inaccuracy.
1107 int precision
= get_precision(sd
) + 2;
1109 if (config
->walltime_run_table
)
1110 print_table(config
, output
, precision
, avg
);
1112 fprintf(output
, " %17.*f +- %.*f seconds time elapsed",
1113 precision
, avg
, precision
, sd
);
1115 print_noise_pct(config
, sd
, avg
);
1117 fprintf(output
, "\n\n");
1119 if (config
->print_free_counters_hint
&&
1120 sysctl__read_int("kernel/nmi_watchdog", &n
) >= 0 &&
1123 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1124 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1126 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1128 if (config
->print_mixed_hw_group_error
)
1130 "The events in group usually have to be from "
1131 "the same PMU. Try reorganizing the group.\n");
1134 static void print_percore(struct perf_stat_config
*config
,
1135 struct perf_evsel
*counter
, char *prefix
)
1137 bool metric_only
= config
->metric_only
;
1138 FILE *output
= config
->output
;
1142 if (!(config
->aggr_map
|| config
->aggr_get_id
))
1145 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
1146 if (prefix
&& metric_only
)
1147 fprintf(output
, "%s", prefix
);
1149 print_counter_aggrdata(config
, counter
, s
,
1150 prefix
, metric_only
,
1155 fputc('\n', output
);
1159 perf_evlist__print_counters(struct perf_evlist
*evlist
,
1160 struct perf_stat_config
*config
,
1161 struct target
*_target
,
1162 struct timespec
*ts
,
1163 int argc
, const char **argv
)
1165 bool metric_only
= config
->metric_only
;
1166 int interval
= config
->interval
;
1167 struct perf_evsel
*counter
;
1168 char buf
[64], *prefix
= NULL
;
1171 print_interval(config
, evlist
, prefix
= buf
, ts
);
1173 print_header(config
, _target
, argc
, argv
);
1176 static int num_print_iv
;
1178 if (num_print_iv
== 0 && !interval
)
1179 print_metric_headers(config
, evlist
, prefix
, false);
1180 if (num_print_iv
++ == 25)
1182 if (config
->aggr_mode
== AGGR_GLOBAL
&& prefix
)
1183 fprintf(config
->output
, "%s", prefix
);
1186 switch (config
->aggr_mode
) {
1190 print_aggr(config
, evlist
, prefix
);
1193 evlist__for_each_entry(evlist
, counter
) {
1194 print_aggr_thread(config
, _target
, counter
, prefix
);
1198 evlist__for_each_entry(evlist
, counter
) {
1199 print_counter_aggr(config
, counter
, prefix
);
1202 fputc('\n', config
->output
);
1206 print_no_aggr_metric(config
, evlist
, prefix
);
1208 evlist__for_each_entry(evlist
, counter
) {
1209 if (counter
->percore
)
1210 print_percore(config
, counter
, prefix
);
1212 print_counter(config
, counter
, prefix
);
1221 if (!interval
&& !config
->csv_output
)
1222 print_footer(config
);
1224 fflush(config
->output
);