3 #include <linux/time64.h>
9 #include "thread_map.h"
12 #include "sane_ctype.h"
15 #include <api/fs/fs.h>
17 #define CNTR_NOT_SUPPORTED "<not supported>"
18 #define CNTR_NOT_COUNTED "<not counted>"
20 static bool is_duration_time(struct perf_evsel
*evsel
)
22 return !strcmp(evsel
->name
, "duration_time");
25 static void print_running(struct perf_stat_config
*config
,
28 if (config
->csv_output
) {
29 fprintf(config
->output
, "%s%" PRIu64
"%s%.2f",
33 ena
? 100.0 * run
/ ena
: 100.0);
34 } else if (run
!= ena
) {
35 fprintf(config
->output
, " (%.2f%%)", 100.0 * run
/ ena
);
39 static void print_noise_pct(struct perf_stat_config
*config
,
40 double total
, double avg
)
42 double pct
= rel_stddev_stats(total
, avg
);
44 if (config
->csv_output
)
45 fprintf(config
->output
, "%s%.2f%%", config
->csv_sep
, pct
);
47 fprintf(config
->output
, " ( +-%6.2f%% )", pct
);
50 static void print_noise(struct perf_stat_config
*config
,
51 struct perf_evsel
*evsel
, double avg
)
53 struct perf_stat_evsel
*ps
;
55 if (config
->run_count
== 1)
59 print_noise_pct(config
, stddev_stats(&ps
->res_stats
[0]), avg
);
62 static void aggr_printout(struct perf_stat_config
*config
,
63 struct perf_evsel
*evsel
, int id
, int nr
)
65 switch (config
->aggr_mode
) {
67 fprintf(config
->output
, "S%d-C%*d%s%*d%s",
68 cpu_map__id_to_socket(id
),
69 config
->csv_output
? 0 : -8,
70 cpu_map__id_to_cpu(id
),
72 config
->csv_output
? 0 : 4,
77 fprintf(config
->output
, "S%*d%s%*d%s",
78 config
->csv_output
? 0 : -5,
81 config
->csv_output
? 0 : 4,
86 fprintf(config
->output
, "CPU%*d%s",
87 config
->csv_output
? 0 : -4,
88 perf_evsel__cpus(evsel
)->map
[id
], config
->csv_sep
);
91 fprintf(config
->output
, "%*s-%*d%s",
92 config
->csv_output
? 0 : 16,
93 thread_map__comm(evsel
->threads
, id
),
94 config
->csv_output
? 0 : -8,
95 thread_map__pid(evsel
->threads
, id
),
111 struct perf_evsel
*evsel
;
114 #define METRIC_LEN 35
116 static void new_line_std(struct perf_stat_config
*config __maybe_unused
,
119 struct outstate
*os
= ctx
;
124 static void do_new_line_std(struct perf_stat_config
*config
,
128 fputs(os
->prefix
, os
->fh
);
129 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
130 if (config
->aggr_mode
== AGGR_NONE
)
131 fprintf(os
->fh
, " ");
132 fprintf(os
->fh
, " ");
135 static void print_metric_std(struct perf_stat_config
*config
,
136 void *ctx
, const char *color
, const char *fmt
,
137 const char *unit
, double val
)
139 struct outstate
*os
= ctx
;
142 bool newline
= os
->newline
;
146 if (unit
== NULL
|| fmt
== NULL
) {
147 fprintf(out
, "%-*s", METRIC_LEN
, "");
152 do_new_line_std(config
, os
);
154 n
= fprintf(out
, " # ");
156 n
+= color_fprintf(out
, color
, fmt
, val
);
158 n
+= fprintf(out
, fmt
, val
);
159 fprintf(out
, " %-*s", METRIC_LEN
- n
- 1, unit
);
162 static void new_line_csv(struct perf_stat_config
*config
, void *ctx
)
164 struct outstate
*os
= ctx
;
169 fprintf(os
->fh
, "%s%s", os
->prefix
, config
->csv_sep
);
170 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
171 for (i
= 0; i
< os
->nfields
; i
++)
172 fputs(config
->csv_sep
, os
->fh
);
175 static void print_metric_csv(struct perf_stat_config
*config __maybe_unused
,
177 const char *color __maybe_unused
,
178 const char *fmt
, const char *unit
, double val
)
180 struct outstate
*os
= ctx
;
182 char buf
[64], *vals
, *ends
;
184 if (unit
== NULL
|| fmt
== NULL
) {
185 fprintf(out
, "%s%s", config
->csv_sep
, config
->csv_sep
);
188 snprintf(buf
, sizeof(buf
), fmt
, val
);
189 ends
= vals
= ltrim(buf
);
190 while (isdigit(*ends
) || *ends
== '.')
193 while (isspace(*unit
))
195 fprintf(out
, "%s%s%s%s", config
->csv_sep
, vals
, config
->csv_sep
, unit
);
198 /* Filter out some columns that don't work well in metrics only mode */
200 static bool valid_only_metric(const char *unit
)
204 if (strstr(unit
, "/sec") ||
205 strstr(unit
, "hz") ||
206 strstr(unit
, "Hz") ||
207 strstr(unit
, "CPUs utilized"))
212 static const char *fixunit(char *buf
, struct perf_evsel
*evsel
,
215 if (!strncmp(unit
, "of all", 6)) {
216 snprintf(buf
, 1024, "%s %s", perf_evsel__name(evsel
),
223 static void print_metric_only(struct perf_stat_config
*config
,
224 void *ctx
, const char *color
, const char *fmt
,
225 const char *unit
, double val
)
227 struct outstate
*os
= ctx
;
229 char buf
[1024], str
[1024];
230 unsigned mlen
= config
->metric_only_len
;
232 if (!valid_only_metric(unit
))
234 unit
= fixunit(buf
, os
->evsel
, unit
);
235 if (mlen
< strlen(unit
))
236 mlen
= strlen(unit
) + 1;
239 mlen
+= strlen(color
) + sizeof(PERF_COLOR_RESET
) - 1;
241 color_snprintf(str
, sizeof(str
), color
?: "", fmt
, val
);
242 fprintf(out
, "%*s ", mlen
, str
);
245 static void print_metric_only_csv(struct perf_stat_config
*config __maybe_unused
,
246 void *ctx
, const char *color __maybe_unused
,
248 const char *unit
, double val
)
250 struct outstate
*os
= ctx
;
252 char buf
[64], *vals
, *ends
;
255 if (!valid_only_metric(unit
))
257 unit
= fixunit(tbuf
, os
->evsel
, unit
);
258 snprintf(buf
, sizeof buf
, fmt
, val
);
259 ends
= vals
= ltrim(buf
);
260 while (isdigit(*ends
) || *ends
== '.')
263 fprintf(out
, "%s%s", vals
, config
->csv_sep
);
266 static void new_line_metric(struct perf_stat_config
*config __maybe_unused
,
267 void *ctx __maybe_unused
)
271 static void print_metric_header(struct perf_stat_config
*config
,
272 void *ctx
, const char *color __maybe_unused
,
273 const char *fmt __maybe_unused
,
274 const char *unit
, double val __maybe_unused
)
276 struct outstate
*os
= ctx
;
279 if (!valid_only_metric(unit
))
281 unit
= fixunit(tbuf
, os
->evsel
, unit
);
282 if (config
->csv_output
)
283 fprintf(os
->fh
, "%s%s", unit
, config
->csv_sep
);
285 fprintf(os
->fh
, "%*s ", config
->metric_only_len
, unit
);
288 static int first_shadow_cpu(struct perf_stat_config
*config
,
289 struct perf_evsel
*evsel
, int id
)
291 struct perf_evlist
*evlist
= evsel
->evlist
;
294 if (!config
->aggr_get_id
)
297 if (config
->aggr_mode
== AGGR_NONE
)
300 if (config
->aggr_mode
== AGGR_GLOBAL
)
303 for (i
= 0; i
< perf_evsel__nr_cpus(evsel
); i
++) {
304 int cpu2
= perf_evsel__cpus(evsel
)->map
[i
];
306 if (config
->aggr_get_id(config
, evlist
->cpus
, cpu2
) == id
)
312 static void abs_printout(struct perf_stat_config
*config
,
313 int id
, int nr
, struct perf_evsel
*evsel
, double avg
)
315 FILE *output
= config
->output
;
316 double sc
= evsel
->scale
;
319 if (config
->csv_output
) {
320 fmt
= floor(sc
) != sc
? "%.2f%s" : "%.0f%s";
323 fmt
= floor(sc
) != sc
? "%'18.2f%s" : "%'18.0f%s";
325 fmt
= floor(sc
) != sc
? "%18.2f%s" : "%18.0f%s";
328 aggr_printout(config
, evsel
, id
, nr
);
330 fprintf(output
, fmt
, avg
, config
->csv_sep
);
333 fprintf(output
, "%-*s%s",
334 config
->csv_output
? 0 : config
->unit_width
,
335 evsel
->unit
, config
->csv_sep
);
337 fprintf(output
, "%-*s", config
->csv_output
? 0 : 25, perf_evsel__name(evsel
));
340 fprintf(output
, "%s%s", config
->csv_sep
, evsel
->cgrp
->name
);
343 static bool is_mixed_hw_group(struct perf_evsel
*counter
)
345 struct perf_evlist
*evlist
= counter
->evlist
;
346 u32 pmu_type
= counter
->attr
.type
;
347 struct perf_evsel
*pos
;
349 if (counter
->nr_members
< 2)
352 evlist__for_each_entry(evlist
, pos
) {
353 /* software events can be part of any hardware group */
354 if (pos
->attr
.type
== PERF_TYPE_SOFTWARE
)
356 if (pmu_type
== PERF_TYPE_SOFTWARE
) {
357 pmu_type
= pos
->attr
.type
;
360 if (pmu_type
!= pos
->attr
.type
)
367 static void printout(struct perf_stat_config
*config
, int id
, int nr
,
368 struct perf_evsel
*counter
, double uval
,
369 char *prefix
, u64 run
, u64 ena
, double noise
,
370 struct runtime_stat
*st
)
372 struct perf_stat_output_ctx out
;
373 struct outstate os
= {
374 .fh
= config
->output
,
375 .prefix
= prefix
? prefix
: "",
380 print_metric_t pm
= print_metric_std
;
383 if (config
->metric_only
) {
384 nl
= new_line_metric
;
385 if (config
->csv_output
)
386 pm
= print_metric_only_csv
;
388 pm
= print_metric_only
;
392 if (config
->csv_output
&& !config
->metric_only
) {
393 static int aggr_fields
[] = {
401 pm
= print_metric_csv
;
404 os
.nfields
+= aggr_fields
[config
->aggr_mode
];
408 if (run
== 0 || ena
== 0 || counter
->counts
->scaled
== -1) {
409 if (config
->metric_only
) {
410 pm(config
, &os
, NULL
, "", "", 0);
413 aggr_printout(config
, counter
, id
, nr
);
415 fprintf(config
->output
, "%*s%s",
416 config
->csv_output
? 0 : 18,
417 counter
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
,
420 if (counter
->supported
) {
421 config
->print_free_counters_hint
= 1;
422 if (is_mixed_hw_group(counter
))
423 config
->print_mixed_hw_group_error
= 1;
426 fprintf(config
->output
, "%-*s%s",
427 config
->csv_output
? 0 : config
->unit_width
,
428 counter
->unit
, config
->csv_sep
);
430 fprintf(config
->output
, "%*s",
431 config
->csv_output
? 0 : -25,
432 perf_evsel__name(counter
));
435 fprintf(config
->output
, "%s%s",
436 config
->csv_sep
, counter
->cgrp
->name
);
438 if (!config
->csv_output
)
439 pm(config
, &os
, NULL
, NULL
, "", 0);
440 print_noise(config
, counter
, noise
);
441 print_running(config
, run
, ena
);
442 if (config
->csv_output
)
443 pm(config
, &os
, NULL
, NULL
, "", 0);
447 if (!config
->metric_only
)
448 abs_printout(config
, id
, nr
, counter
, uval
);
450 out
.print_metric
= pm
;
453 out
.force_header
= false;
455 if (config
->csv_output
&& !config
->metric_only
) {
456 print_noise(config
, counter
, noise
);
457 print_running(config
, run
, ena
);
460 perf_stat__print_shadow_stats(config
, counter
, uval
,
461 first_shadow_cpu(config
, counter
, id
),
462 &out
, &config
->metric_events
, st
);
463 if (!config
->csv_output
&& !config
->metric_only
) {
464 print_noise(config
, counter
, noise
);
465 print_running(config
, run
, ena
);
469 static void aggr_update_shadow(struct perf_stat_config
*config
,
470 struct perf_evlist
*evlist
)
474 struct perf_evsel
*counter
;
476 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
477 id
= config
->aggr_map
->map
[s
];
478 evlist__for_each_entry(evlist
, counter
) {
480 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
481 s2
= config
->aggr_get_id(config
, evlist
->cpus
, cpu
);
484 val
+= perf_counts(counter
->counts
, cpu
, 0)->val
;
486 perf_stat__update_shadow_stats(counter
, val
,
487 first_shadow_cpu(config
, counter
, id
),
493 static void uniquify_event_name(struct perf_evsel
*counter
)
498 if (counter
->uniquified_name
||
499 !counter
->pmu_name
|| !strncmp(counter
->name
, counter
->pmu_name
,
500 strlen(counter
->pmu_name
)))
503 config
= strchr(counter
->name
, '/');
505 if (asprintf(&new_name
,
506 "%s%s", counter
->pmu_name
, config
) > 0) {
508 counter
->name
= new_name
;
511 if (asprintf(&new_name
,
512 "%s [%s]", counter
->name
, counter
->pmu_name
) > 0) {
514 counter
->name
= new_name
;
518 counter
->uniquified_name
= true;
521 static void collect_all_aliases(struct perf_stat_config
*config
, struct perf_evsel
*counter
,
522 void (*cb
)(struct perf_stat_config
*config
, struct perf_evsel
*counter
, void *data
,
526 struct perf_evlist
*evlist
= counter
->evlist
;
527 struct perf_evsel
*alias
;
529 alias
= list_prepare_entry(counter
, &(evlist
->entries
), node
);
530 list_for_each_entry_continue (alias
, &evlist
->entries
, node
) {
531 if (strcmp(perf_evsel__name(alias
), perf_evsel__name(counter
)) ||
532 alias
->scale
!= counter
->scale
||
533 alias
->cgrp
!= counter
->cgrp
||
534 strcmp(alias
->unit
, counter
->unit
) ||
535 perf_evsel__is_clock(alias
) != perf_evsel__is_clock(counter
))
537 alias
->merged_stat
= true;
538 cb(config
, alias
, data
, false);
542 static bool collect_data(struct perf_stat_config
*config
, struct perf_evsel
*counter
,
543 void (*cb
)(struct perf_stat_config
*config
, struct perf_evsel
*counter
, void *data
,
547 if (counter
->merged_stat
)
549 cb(config
, counter
, data
, true);
550 if (config
->no_merge
)
551 uniquify_event_name(counter
);
552 else if (counter
->auto_merge_stats
)
553 collect_all_aliases(config
, counter
, cb
, data
);
564 static void aggr_cb(struct perf_stat_config
*config
,
565 struct perf_evsel
*counter
, void *data
, bool first
)
567 struct aggr_data
*ad
= data
;
570 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
571 struct perf_counts_values
*counts
;
573 s2
= config
->aggr_get_id(config
, perf_evsel__cpus(counter
), cpu
);
578 counts
= perf_counts(counter
->counts
, cpu
, 0);
580 * When any result is bad, make them all to give
581 * consistent output in interval mode.
583 if (counts
->ena
== 0 || counts
->run
== 0 ||
584 counter
->counts
->scaled
== -1) {
589 ad
->val
+= counts
->val
;
590 ad
->ena
+= counts
->ena
;
591 ad
->run
+= counts
->run
;
595 static void print_aggr(struct perf_stat_config
*config
,
596 struct perf_evlist
*evlist
,
599 bool metric_only
= config
->metric_only
;
600 FILE *output
= config
->output
;
601 struct perf_evsel
*counter
;
607 if (!(config
->aggr_map
|| config
->aggr_get_id
))
610 aggr_update_shadow(config
, evlist
);
613 * With metric_only everything is on a single line.
614 * Without each counter has its own line.
616 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
618 if (prefix
&& metric_only
)
619 fprintf(output
, "%s", prefix
);
621 ad
.id
= id
= config
->aggr_map
->map
[s
];
623 evlist__for_each_entry(evlist
, counter
) {
624 if (is_duration_time(counter
))
627 ad
.val
= ad
.ena
= ad
.run
= 0;
629 if (!collect_data(config
, counter
, aggr_cb
, &ad
))
635 if (first
&& metric_only
) {
637 aggr_printout(config
, counter
, id
, nr
);
639 if (prefix
&& !metric_only
)
640 fprintf(output
, "%s", prefix
);
642 uval
= val
* counter
->scale
;
643 printout(config
, id
, nr
, counter
, uval
, prefix
,
644 run
, ena
, 1.0, &rt_stat
);
653 static int cmp_val(const void *a
, const void *b
)
655 return ((struct perf_aggr_thread_value
*)b
)->val
-
656 ((struct perf_aggr_thread_value
*)a
)->val
;
659 static struct perf_aggr_thread_value
*sort_aggr_thread(
660 struct perf_evsel
*counter
,
661 int nthreads
, int ncpus
,
663 struct target
*_target
)
665 int cpu
, thread
, i
= 0;
667 struct perf_aggr_thread_value
*buf
;
669 buf
= calloc(nthreads
, sizeof(struct perf_aggr_thread_value
));
673 for (thread
= 0; thread
< nthreads
; thread
++) {
674 u64 ena
= 0, run
= 0, val
= 0;
676 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
677 val
+= perf_counts(counter
->counts
, cpu
, thread
)->val
;
678 ena
+= perf_counts(counter
->counts
, cpu
, thread
)->ena
;
679 run
+= perf_counts(counter
->counts
, cpu
, thread
)->run
;
682 uval
= val
* counter
->scale
;
685 * Skip value 0 when enabling --per-thread globally,
686 * otherwise too many 0 output.
688 if (uval
== 0.0 && target__has_per_thread(_target
))
691 buf
[i
].counter
= counter
;
700 qsort(buf
, i
, sizeof(struct perf_aggr_thread_value
), cmp_val
);
708 static void print_aggr_thread(struct perf_stat_config
*config
,
709 struct target
*_target
,
710 struct perf_evsel
*counter
, char *prefix
)
712 FILE *output
= config
->output
;
713 int nthreads
= thread_map__nr(counter
->threads
);
714 int ncpus
= cpu_map__nr(counter
->cpus
);
715 int thread
, sorted_threads
, id
;
716 struct perf_aggr_thread_value
*buf
;
718 buf
= sort_aggr_thread(counter
, nthreads
, ncpus
, &sorted_threads
, _target
);
720 perror("cannot sort aggr thread");
724 for (thread
= 0; thread
< sorted_threads
; thread
++) {
726 fprintf(output
, "%s", prefix
);
730 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
731 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
734 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
735 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
744 double avg
, avg_enabled
, avg_running
;
747 static void counter_aggr_cb(struct perf_stat_config
*config __maybe_unused
,
748 struct perf_evsel
*counter
, void *data
,
749 bool first __maybe_unused
)
751 struct caggr_data
*cd
= data
;
752 struct perf_stat_evsel
*ps
= counter
->stats
;
754 cd
->avg
+= avg_stats(&ps
->res_stats
[0]);
755 cd
->avg_enabled
+= avg_stats(&ps
->res_stats
[1]);
756 cd
->avg_running
+= avg_stats(&ps
->res_stats
[2]);
760 * Print out the results of a single counter:
761 * aggregated counts in system-wide mode
763 static void print_counter_aggr(struct perf_stat_config
*config
,
764 struct perf_evsel
*counter
, char *prefix
)
766 bool metric_only
= config
->metric_only
;
767 FILE *output
= config
->output
;
769 struct caggr_data cd
= { .avg
= 0.0 };
771 if (!collect_data(config
, counter
, counter_aggr_cb
, &cd
))
774 if (prefix
&& !metric_only
)
775 fprintf(output
, "%s", prefix
);
777 uval
= cd
.avg
* counter
->scale
;
778 printout(config
, -1, 0, counter
, uval
, prefix
, cd
.avg_running
, cd
.avg_enabled
,
781 fprintf(output
, "\n");
784 static void counter_cb(struct perf_stat_config
*config __maybe_unused
,
785 struct perf_evsel
*counter
, void *data
,
786 bool first __maybe_unused
)
788 struct aggr_data
*ad
= data
;
790 ad
->val
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->val
;
791 ad
->ena
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->ena
;
792 ad
->run
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->run
;
796 * Print out the results of a single counter:
797 * does not use aggregated count in system-wide
799 static void print_counter(struct perf_stat_config
*config
,
800 struct perf_evsel
*counter
, char *prefix
)
802 FILE *output
= config
->output
;
807 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
808 struct aggr_data ad
= { .cpu
= cpu
};
810 if (!collect_data(config
, counter
, counter_cb
, &ad
))
817 fprintf(output
, "%s", prefix
);
819 uval
= val
* counter
->scale
;
820 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
827 static void print_no_aggr_metric(struct perf_stat_config
*config
,
828 struct perf_evlist
*evlist
,
833 struct perf_evsel
*counter
;
837 nrcpus
= evlist
->cpus
->nr
;
838 for (cpu
= 0; cpu
< nrcpus
; cpu
++) {
842 fputs(prefix
, config
->output
);
843 evlist__for_each_entry(evlist
, counter
) {
844 if (is_duration_time(counter
))
847 aggr_printout(config
, counter
, cpu
, 0);
850 val
= perf_counts(counter
->counts
, cpu
, 0)->val
;
851 ena
= perf_counts(counter
->counts
, cpu
, 0)->ena
;
852 run
= perf_counts(counter
->counts
, cpu
, 0)->run
;
854 uval
= val
* counter
->scale
;
855 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
858 fputc('\n', config
->output
);
862 static int aggr_header_lens
[] = {
870 static const char *aggr_header_csv
[] = {
871 [AGGR_CORE
] = "core,cpus,",
872 [AGGR_SOCKET
] = "socket,cpus",
873 [AGGR_NONE
] = "cpu,",
874 [AGGR_THREAD
] = "comm-pid,",
878 static void print_metric_headers(struct perf_stat_config
*config
,
879 struct perf_evlist
*evlist
,
880 const char *prefix
, bool no_indent
)
882 struct perf_stat_output_ctx out
;
883 struct perf_evsel
*counter
;
884 struct outstate os
= {
889 fprintf(config
->output
, "%s", prefix
);
891 if (!config
->csv_output
&& !no_indent
)
892 fprintf(config
->output
, "%*s",
893 aggr_header_lens
[config
->aggr_mode
], "");
894 if (config
->csv_output
) {
895 if (config
->interval
)
896 fputs("time,", config
->output
);
897 fputs(aggr_header_csv
[config
->aggr_mode
], config
->output
);
900 /* Print metrics headers only */
901 evlist__for_each_entry(evlist
, counter
) {
902 if (is_duration_time(counter
))
906 out
.print_metric
= print_metric_header
;
907 out
.new_line
= new_line_metric
;
908 out
.force_header
= true;
910 perf_stat__print_shadow_stats(config
, counter
, 0,
913 &config
->metric_events
,
916 fputc('\n', config
->output
);
919 static void print_interval(struct perf_stat_config
*config
,
920 struct perf_evlist
*evlist
,
921 char *prefix
, struct timespec
*ts
)
923 bool metric_only
= config
->metric_only
;
924 unsigned int unit_width
= config
->unit_width
;
925 FILE *output
= config
->output
;
926 static int num_print_interval
;
928 if (config
->interval_clear
)
931 sprintf(prefix
, "%6lu.%09lu%s", ts
->tv_sec
, ts
->tv_nsec
, config
->csv_sep
);
933 if ((num_print_interval
== 0 && !config
->csv_output
) || config
->interval_clear
) {
934 switch (config
->aggr_mode
) {
936 fprintf(output
, "# time socket cpus");
938 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
941 fprintf(output
, "# time core cpus");
943 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
946 fprintf(output
, "# time CPU ");
948 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
951 fprintf(output
, "# time comm-pid");
953 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
957 fprintf(output
, "# time");
959 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
965 if ((num_print_interval
== 0 || config
->interval_clear
) && metric_only
)
966 print_metric_headers(config
, evlist
, " ", true);
967 if (++num_print_interval
== 25)
968 num_print_interval
= 0;
971 static void print_header(struct perf_stat_config
*config
,
972 struct target
*_target
,
973 int argc
, const char **argv
)
975 FILE *output
= config
->output
;
980 if (!config
->csv_output
) {
981 fprintf(output
, "\n");
982 fprintf(output
, " Performance counter stats for ");
983 if (_target
->system_wide
)
984 fprintf(output
, "\'system wide");
985 else if (_target
->cpu_list
)
986 fprintf(output
, "\'CPU(s) %s", _target
->cpu_list
);
987 else if (!target__has_task(_target
)) {
988 fprintf(output
, "\'%s", argv
? argv
[0] : "pipe");
989 for (i
= 1; argv
&& (i
< argc
); i
++)
990 fprintf(output
, " %s", argv
[i
]);
991 } else if (_target
->pid
)
992 fprintf(output
, "process id \'%s", _target
->pid
);
994 fprintf(output
, "thread id \'%s", _target
->tid
);
996 fprintf(output
, "\'");
997 if (config
->run_count
> 1)
998 fprintf(output
, " (%d runs)", config
->run_count
);
999 fprintf(output
, ":\n\n");
1003 static int get_precision(double num
)
1008 return lround(ceil(-log10(num
)));
1011 static void print_table(struct perf_stat_config
*config
,
1012 FILE *output
, int precision
, double avg
)
1015 int idx
, indent
= 0;
1017 scnprintf(tmp
, 64, " %17.*f", precision
, avg
);
1018 while (tmp
[indent
] == ' ')
1021 fprintf(output
, "%*s# Table of individual measurements:\n", indent
, "");
1023 for (idx
= 0; idx
< config
->run_count
; idx
++) {
1024 double run
= (double) config
->walltime_run
[idx
] / NSEC_PER_SEC
;
1025 int h
, n
= 1 + abs((int) (100.0 * (run
- avg
)/run
) / 5);
1027 fprintf(output
, " %17.*f (%+.*f) ",
1028 precision
, run
, precision
, run
- avg
);
1030 for (h
= 0; h
< n
; h
++)
1031 fprintf(output
, "#");
1033 fprintf(output
, "\n");
1036 fprintf(output
, "\n%*s# Final result:\n", indent
, "");
1039 static double timeval2double(struct timeval
*t
)
1041 return t
->tv_sec
+ (double) t
->tv_usec
/USEC_PER_SEC
;
1044 static void print_footer(struct perf_stat_config
*config
)
1046 double avg
= avg_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1047 FILE *output
= config
->output
;
1050 if (!config
->null_run
)
1051 fprintf(output
, "\n");
1053 if (config
->run_count
== 1) {
1054 fprintf(output
, " %17.9f seconds time elapsed", avg
);
1056 if (config
->ru_display
) {
1057 double ru_utime
= timeval2double(&config
->ru_data
.ru_utime
);
1058 double ru_stime
= timeval2double(&config
->ru_data
.ru_stime
);
1060 fprintf(output
, "\n\n");
1061 fprintf(output
, " %17.9f seconds user\n", ru_utime
);
1062 fprintf(output
, " %17.9f seconds sys\n", ru_stime
);
1065 double sd
= stddev_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1067 * Display at most 2 more significant
1068 * digits than the stddev inaccuracy.
1070 int precision
= get_precision(sd
) + 2;
1072 if (config
->walltime_run_table
)
1073 print_table(config
, output
, precision
, avg
);
1075 fprintf(output
, " %17.*f +- %.*f seconds time elapsed",
1076 precision
, avg
, precision
, sd
);
1078 print_noise_pct(config
, sd
, avg
);
1080 fprintf(output
, "\n\n");
1082 if (config
->print_free_counters_hint
&&
1083 sysctl__read_int("kernel/nmi_watchdog", &n
) >= 0 &&
1086 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1087 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1089 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1091 if (config
->print_mixed_hw_group_error
)
1093 "The events in group usually have to be from "
1094 "the same PMU. Try reorganizing the group.\n");
1098 perf_evlist__print_counters(struct perf_evlist
*evlist
,
1099 struct perf_stat_config
*config
,
1100 struct target
*_target
,
1101 struct timespec
*ts
,
1102 int argc
, const char **argv
)
1104 bool metric_only
= config
->metric_only
;
1105 int interval
= config
->interval
;
1106 struct perf_evsel
*counter
;
1107 char buf
[64], *prefix
= NULL
;
1110 print_interval(config
, evlist
, prefix
= buf
, ts
);
1112 print_header(config
, _target
, argc
, argv
);
1115 static int num_print_iv
;
1117 if (num_print_iv
== 0 && !interval
)
1118 print_metric_headers(config
, evlist
, prefix
, false);
1119 if (num_print_iv
++ == 25)
1121 if (config
->aggr_mode
== AGGR_GLOBAL
&& prefix
)
1122 fprintf(config
->output
, "%s", prefix
);
1125 switch (config
->aggr_mode
) {
1128 print_aggr(config
, evlist
, prefix
);
1131 evlist__for_each_entry(evlist
, counter
) {
1132 if (is_duration_time(counter
))
1134 print_aggr_thread(config
, _target
, counter
, prefix
);
1138 evlist__for_each_entry(evlist
, counter
) {
1139 if (is_duration_time(counter
))
1141 print_counter_aggr(config
, counter
, prefix
);
1144 fputc('\n', config
->output
);
1148 print_no_aggr_metric(config
, evlist
, prefix
);
1150 evlist__for_each_entry(evlist
, counter
) {
1151 if (is_duration_time(counter
))
1153 print_counter(config
, counter
, prefix
);
1162 if (!interval
&& !config
->csv_output
)
1163 print_footer(config
);
1165 fflush(config
->output
);