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 bool is_duration_time(struct perf_evsel
*evsel
)
23 return !strcmp(evsel
->name
, "duration_time");
26 static void print_running(struct perf_stat_config
*config
,
29 if (config
->csv_output
) {
30 fprintf(config
->output
, "%s%" PRIu64
"%s%.2f",
34 ena
? 100.0 * run
/ ena
: 100.0);
35 } else if (run
!= ena
) {
36 fprintf(config
->output
, " (%.2f%%)", 100.0 * run
/ ena
);
40 static void print_noise_pct(struct perf_stat_config
*config
,
41 double total
, double avg
)
43 double pct
= rel_stddev_stats(total
, avg
);
45 if (config
->csv_output
)
46 fprintf(config
->output
, "%s%.2f%%", config
->csv_sep
, pct
);
48 fprintf(config
->output
, " ( +-%6.2f%% )", pct
);
51 static void print_noise(struct perf_stat_config
*config
,
52 struct perf_evsel
*evsel
, double avg
)
54 struct perf_stat_evsel
*ps
;
56 if (config
->run_count
== 1)
60 print_noise_pct(config
, stddev_stats(&ps
->res_stats
[0]), avg
);
63 static void print_cgroup(struct perf_stat_config
*config
, struct perf_evsel
*evsel
)
66 const char *cgrp_name
= evsel
->cgrp
? evsel
->cgrp
->name
: "";
67 fprintf(config
->output
, "%s%s", config
->csv_sep
, cgrp_name
);
72 static void aggr_printout(struct perf_stat_config
*config
,
73 struct perf_evsel
*evsel
, int id
, int nr
)
75 switch (config
->aggr_mode
) {
77 fprintf(config
->output
, "S%d-C%*d%s%*d%s",
78 cpu_map__id_to_socket(id
),
79 config
->csv_output
? 0 : -8,
80 cpu_map__id_to_cpu(id
),
82 config
->csv_output
? 0 : 4,
87 fprintf(config
->output
, "S%*d%s%*d%s",
88 config
->csv_output
? 0 : -5,
91 config
->csv_output
? 0 : 4,
96 fprintf(config
->output
, "CPU%*d%s",
97 config
->csv_output
? 0 : -4,
98 perf_evsel__cpus(evsel
)->map
[id
], config
->csv_sep
);
101 fprintf(config
->output
, "%*s-%*d%s",
102 config
->csv_output
? 0 : 16,
103 thread_map__comm(evsel
->threads
, id
),
104 config
->csv_output
? 0 : -8,
105 thread_map__pid(evsel
->threads
, id
),
121 struct perf_evsel
*evsel
;
124 #define METRIC_LEN 35
126 static void new_line_std(struct perf_stat_config
*config __maybe_unused
,
129 struct outstate
*os
= ctx
;
134 static void do_new_line_std(struct perf_stat_config
*config
,
138 fputs(os
->prefix
, os
->fh
);
139 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
140 if (config
->aggr_mode
== AGGR_NONE
)
141 fprintf(os
->fh
, " ");
142 fprintf(os
->fh
, " ");
145 static void print_metric_std(struct perf_stat_config
*config
,
146 void *ctx
, const char *color
, const char *fmt
,
147 const char *unit
, double val
)
149 struct outstate
*os
= ctx
;
152 bool newline
= os
->newline
;
156 if (unit
== NULL
|| fmt
== NULL
) {
157 fprintf(out
, "%-*s", METRIC_LEN
, "");
162 do_new_line_std(config
, os
);
164 n
= fprintf(out
, " # ");
166 n
+= color_fprintf(out
, color
, fmt
, val
);
168 n
+= fprintf(out
, fmt
, val
);
169 fprintf(out
, " %-*s", METRIC_LEN
- n
- 1, unit
);
172 static void new_line_csv(struct perf_stat_config
*config
, void *ctx
)
174 struct outstate
*os
= ctx
;
179 fprintf(os
->fh
, "%s%s", os
->prefix
, config
->csv_sep
);
180 aggr_printout(config
, os
->evsel
, os
->id
, os
->nr
);
181 for (i
= 0; i
< os
->nfields
; i
++)
182 fputs(config
->csv_sep
, os
->fh
);
185 static void print_metric_csv(struct perf_stat_config
*config __maybe_unused
,
187 const char *color __maybe_unused
,
188 const char *fmt
, const char *unit
, double val
)
190 struct outstate
*os
= ctx
;
192 char buf
[64], *vals
, *ends
;
194 if (unit
== NULL
|| fmt
== NULL
) {
195 fprintf(out
, "%s%s", config
->csv_sep
, config
->csv_sep
);
198 snprintf(buf
, sizeof(buf
), fmt
, val
);
199 ends
= vals
= ltrim(buf
);
200 while (isdigit(*ends
) || *ends
== '.')
203 while (isspace(*unit
))
205 fprintf(out
, "%s%s%s%s", config
->csv_sep
, vals
, config
->csv_sep
, unit
);
208 /* Filter out some columns that don't work well in metrics only mode */
210 static bool valid_only_metric(const char *unit
)
214 if (strstr(unit
, "/sec") ||
215 strstr(unit
, "hz") ||
216 strstr(unit
, "Hz") ||
217 strstr(unit
, "CPUs utilized"))
222 static const char *fixunit(char *buf
, struct perf_evsel
*evsel
,
225 if (!strncmp(unit
, "of all", 6)) {
226 snprintf(buf
, 1024, "%s %s", perf_evsel__name(evsel
),
233 static void print_metric_only(struct perf_stat_config
*config
,
234 void *ctx
, const char *color
, const char *fmt
,
235 const char *unit
, double val
)
237 struct outstate
*os
= ctx
;
239 char buf
[1024], str
[1024];
240 unsigned mlen
= config
->metric_only_len
;
242 if (!valid_only_metric(unit
))
244 unit
= fixunit(buf
, os
->evsel
, unit
);
245 if (mlen
< strlen(unit
))
246 mlen
= strlen(unit
) + 1;
249 mlen
+= strlen(color
) + sizeof(PERF_COLOR_RESET
) - 1;
251 color_snprintf(str
, sizeof(str
), color
?: "", fmt
, val
);
252 fprintf(out
, "%*s ", mlen
, str
);
255 static void print_metric_only_csv(struct perf_stat_config
*config __maybe_unused
,
256 void *ctx
, const char *color __maybe_unused
,
258 const char *unit
, double val
)
260 struct outstate
*os
= ctx
;
262 char buf
[64], *vals
, *ends
;
265 if (!valid_only_metric(unit
))
267 unit
= fixunit(tbuf
, os
->evsel
, unit
);
268 snprintf(buf
, sizeof buf
, fmt
, val
);
269 ends
= vals
= ltrim(buf
);
270 while (isdigit(*ends
) || *ends
== '.')
273 fprintf(out
, "%s%s", vals
, config
->csv_sep
);
276 static void new_line_metric(struct perf_stat_config
*config __maybe_unused
,
277 void *ctx __maybe_unused
)
281 static void print_metric_header(struct perf_stat_config
*config
,
282 void *ctx
, const char *color __maybe_unused
,
283 const char *fmt __maybe_unused
,
284 const char *unit
, double val __maybe_unused
)
286 struct outstate
*os
= ctx
;
289 if (!valid_only_metric(unit
))
291 unit
= fixunit(tbuf
, os
->evsel
, unit
);
292 if (config
->csv_output
)
293 fprintf(os
->fh
, "%s%s", unit
, config
->csv_sep
);
295 fprintf(os
->fh
, "%*s ", config
->metric_only_len
, unit
);
298 static int first_shadow_cpu(struct perf_stat_config
*config
,
299 struct perf_evsel
*evsel
, int id
)
301 struct perf_evlist
*evlist
= evsel
->evlist
;
304 if (!config
->aggr_get_id
)
307 if (config
->aggr_mode
== AGGR_NONE
)
310 if (config
->aggr_mode
== AGGR_GLOBAL
)
313 for (i
= 0; i
< perf_evsel__nr_cpus(evsel
); i
++) {
314 int cpu2
= perf_evsel__cpus(evsel
)->map
[i
];
316 if (config
->aggr_get_id(config
, evlist
->cpus
, cpu2
) == id
)
322 static void abs_printout(struct perf_stat_config
*config
,
323 int id
, int nr
, struct perf_evsel
*evsel
, double avg
)
325 FILE *output
= config
->output
;
326 double sc
= evsel
->scale
;
329 if (config
->csv_output
) {
330 fmt
= floor(sc
) != sc
? "%.2f%s" : "%.0f%s";
333 fmt
= floor(sc
) != sc
? "%'18.2f%s" : "%'18.0f%s";
335 fmt
= floor(sc
) != sc
? "%18.2f%s" : "%18.0f%s";
338 aggr_printout(config
, evsel
, id
, nr
);
340 fprintf(output
, fmt
, avg
, config
->csv_sep
);
343 fprintf(output
, "%-*s%s",
344 config
->csv_output
? 0 : config
->unit_width
,
345 evsel
->unit
, config
->csv_sep
);
347 fprintf(output
, "%-*s", config
->csv_output
? 0 : 25, perf_evsel__name(evsel
));
349 print_cgroup(config
, evsel
);
352 static bool is_mixed_hw_group(struct perf_evsel
*counter
)
354 struct perf_evlist
*evlist
= counter
->evlist
;
355 u32 pmu_type
= counter
->attr
.type
;
356 struct perf_evsel
*pos
;
358 if (counter
->nr_members
< 2)
361 evlist__for_each_entry(evlist
, pos
) {
362 /* software events can be part of any hardware group */
363 if (pos
->attr
.type
== PERF_TYPE_SOFTWARE
)
365 if (pmu_type
== PERF_TYPE_SOFTWARE
) {
366 pmu_type
= pos
->attr
.type
;
369 if (pmu_type
!= pos
->attr
.type
)
376 static void printout(struct perf_stat_config
*config
, int id
, int nr
,
377 struct perf_evsel
*counter
, double uval
,
378 char *prefix
, u64 run
, u64 ena
, double noise
,
379 struct runtime_stat
*st
)
381 struct perf_stat_output_ctx out
;
382 struct outstate os
= {
383 .fh
= config
->output
,
384 .prefix
= prefix
? prefix
: "",
389 print_metric_t pm
= print_metric_std
;
392 if (config
->metric_only
) {
393 nl
= new_line_metric
;
394 if (config
->csv_output
)
395 pm
= print_metric_only_csv
;
397 pm
= print_metric_only
;
401 if (config
->csv_output
&& !config
->metric_only
) {
402 static int aggr_fields
[] = {
410 pm
= print_metric_csv
;
413 os
.nfields
+= aggr_fields
[config
->aggr_mode
];
417 if (run
== 0 || ena
== 0 || counter
->counts
->scaled
== -1) {
418 if (config
->metric_only
) {
419 pm(config
, &os
, NULL
, "", "", 0);
422 aggr_printout(config
, counter
, id
, nr
);
424 fprintf(config
->output
, "%*s%s",
425 config
->csv_output
? 0 : 18,
426 counter
->supported
? CNTR_NOT_COUNTED
: CNTR_NOT_SUPPORTED
,
429 if (counter
->supported
) {
430 config
->print_free_counters_hint
= 1;
431 if (is_mixed_hw_group(counter
))
432 config
->print_mixed_hw_group_error
= 1;
435 fprintf(config
->output
, "%-*s%s",
436 config
->csv_output
? 0 : config
->unit_width
,
437 counter
->unit
, config
->csv_sep
);
439 fprintf(config
->output
, "%*s",
440 config
->csv_output
? 0 : -25,
441 perf_evsel__name(counter
));
443 print_cgroup(config
, counter
);
445 if (!config
->csv_output
)
446 pm(config
, &os
, NULL
, NULL
, "", 0);
447 print_noise(config
, counter
, noise
);
448 print_running(config
, run
, ena
);
449 if (config
->csv_output
)
450 pm(config
, &os
, NULL
, NULL
, "", 0);
454 if (!config
->metric_only
)
455 abs_printout(config
, id
, nr
, counter
, uval
);
457 out
.print_metric
= pm
;
460 out
.force_header
= false;
462 if (config
->csv_output
&& !config
->metric_only
) {
463 print_noise(config
, counter
, noise
);
464 print_running(config
, run
, ena
);
467 perf_stat__print_shadow_stats(config
, counter
, uval
,
468 first_shadow_cpu(config
, counter
, id
),
469 &out
, &config
->metric_events
, st
);
470 if (!config
->csv_output
&& !config
->metric_only
) {
471 print_noise(config
, counter
, noise
);
472 print_running(config
, run
, ena
);
476 static void aggr_update_shadow(struct perf_stat_config
*config
,
477 struct perf_evlist
*evlist
)
481 struct perf_evsel
*counter
;
483 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
484 id
= config
->aggr_map
->map
[s
];
485 evlist__for_each_entry(evlist
, counter
) {
487 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
488 s2
= config
->aggr_get_id(config
, evlist
->cpus
, cpu
);
491 val
+= perf_counts(counter
->counts
, cpu
, 0)->val
;
493 perf_stat__update_shadow_stats(counter
, val
,
494 first_shadow_cpu(config
, counter
, id
),
500 static void uniquify_event_name(struct perf_evsel
*counter
)
505 if (counter
->uniquified_name
||
506 !counter
->pmu_name
|| !strncmp(counter
->name
, counter
->pmu_name
,
507 strlen(counter
->pmu_name
)))
510 config
= strchr(counter
->name
, '/');
512 if (asprintf(&new_name
,
513 "%s%s", counter
->pmu_name
, config
) > 0) {
515 counter
->name
= new_name
;
518 if (asprintf(&new_name
,
519 "%s [%s]", counter
->name
, counter
->pmu_name
) > 0) {
521 counter
->name
= new_name
;
525 counter
->uniquified_name
= true;
528 static void collect_all_aliases(struct perf_stat_config
*config
, struct perf_evsel
*counter
,
529 void (*cb
)(struct perf_stat_config
*config
, struct perf_evsel
*counter
, void *data
,
533 struct perf_evlist
*evlist
= counter
->evlist
;
534 struct perf_evsel
*alias
;
536 alias
= list_prepare_entry(counter
, &(evlist
->entries
), node
);
537 list_for_each_entry_continue (alias
, &evlist
->entries
, node
) {
538 if (strcmp(perf_evsel__name(alias
), perf_evsel__name(counter
)) ||
539 alias
->scale
!= counter
->scale
||
540 alias
->cgrp
!= counter
->cgrp
||
541 strcmp(alias
->unit
, counter
->unit
) ||
542 perf_evsel__is_clock(alias
) != perf_evsel__is_clock(counter
))
544 alias
->merged_stat
= true;
545 cb(config
, alias
, data
, false);
549 static bool collect_data(struct perf_stat_config
*config
, struct perf_evsel
*counter
,
550 void (*cb
)(struct perf_stat_config
*config
, struct perf_evsel
*counter
, void *data
,
554 if (counter
->merged_stat
)
556 cb(config
, counter
, data
, true);
557 if (config
->no_merge
)
558 uniquify_event_name(counter
);
559 else if (counter
->auto_merge_stats
)
560 collect_all_aliases(config
, counter
, cb
, data
);
571 static void aggr_cb(struct perf_stat_config
*config
,
572 struct perf_evsel
*counter
, void *data
, bool first
)
574 struct aggr_data
*ad
= data
;
577 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
578 struct perf_counts_values
*counts
;
580 s2
= config
->aggr_get_id(config
, perf_evsel__cpus(counter
), cpu
);
585 counts
= perf_counts(counter
->counts
, cpu
, 0);
587 * When any result is bad, make them all to give
588 * consistent output in interval mode.
590 if (counts
->ena
== 0 || counts
->run
== 0 ||
591 counter
->counts
->scaled
== -1) {
596 ad
->val
+= counts
->val
;
597 ad
->ena
+= counts
->ena
;
598 ad
->run
+= counts
->run
;
602 static void print_aggr(struct perf_stat_config
*config
,
603 struct perf_evlist
*evlist
,
606 bool metric_only
= config
->metric_only
;
607 FILE *output
= config
->output
;
608 struct perf_evsel
*counter
;
614 if (!(config
->aggr_map
|| config
->aggr_get_id
))
617 aggr_update_shadow(config
, evlist
);
620 * With metric_only everything is on a single line.
621 * Without each counter has its own line.
623 for (s
= 0; s
< config
->aggr_map
->nr
; s
++) {
625 if (prefix
&& metric_only
)
626 fprintf(output
, "%s", prefix
);
628 ad
.id
= id
= config
->aggr_map
->map
[s
];
630 evlist__for_each_entry(evlist
, counter
) {
631 if (is_duration_time(counter
))
634 ad
.val
= ad
.ena
= ad
.run
= 0;
636 if (!collect_data(config
, counter
, aggr_cb
, &ad
))
642 if (first
&& metric_only
) {
644 aggr_printout(config
, counter
, id
, nr
);
646 if (prefix
&& !metric_only
)
647 fprintf(output
, "%s", prefix
);
649 uval
= val
* counter
->scale
;
650 printout(config
, id
, nr
, counter
, uval
, prefix
,
651 run
, ena
, 1.0, &rt_stat
);
660 static int cmp_val(const void *a
, const void *b
)
662 return ((struct perf_aggr_thread_value
*)b
)->val
-
663 ((struct perf_aggr_thread_value
*)a
)->val
;
666 static struct perf_aggr_thread_value
*sort_aggr_thread(
667 struct perf_evsel
*counter
,
668 int nthreads
, int ncpus
,
670 struct target
*_target
)
672 int cpu
, thread
, i
= 0;
674 struct perf_aggr_thread_value
*buf
;
676 buf
= calloc(nthreads
, sizeof(struct perf_aggr_thread_value
));
680 for (thread
= 0; thread
< nthreads
; thread
++) {
681 u64 ena
= 0, run
= 0, val
= 0;
683 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
684 val
+= perf_counts(counter
->counts
, cpu
, thread
)->val
;
685 ena
+= perf_counts(counter
->counts
, cpu
, thread
)->ena
;
686 run
+= perf_counts(counter
->counts
, cpu
, thread
)->run
;
689 uval
= val
* counter
->scale
;
692 * Skip value 0 when enabling --per-thread globally,
693 * otherwise too many 0 output.
695 if (uval
== 0.0 && target__has_per_thread(_target
))
698 buf
[i
].counter
= counter
;
707 qsort(buf
, i
, sizeof(struct perf_aggr_thread_value
), cmp_val
);
715 static void print_aggr_thread(struct perf_stat_config
*config
,
716 struct target
*_target
,
717 struct perf_evsel
*counter
, char *prefix
)
719 FILE *output
= config
->output
;
720 int nthreads
= thread_map__nr(counter
->threads
);
721 int ncpus
= cpu_map__nr(counter
->cpus
);
722 int thread
, sorted_threads
, id
;
723 struct perf_aggr_thread_value
*buf
;
725 buf
= sort_aggr_thread(counter
, nthreads
, ncpus
, &sorted_threads
, _target
);
727 perror("cannot sort aggr thread");
731 for (thread
= 0; thread
< sorted_threads
; thread
++) {
733 fprintf(output
, "%s", prefix
);
737 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
738 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
741 printout(config
, id
, 0, buf
[thread
].counter
, buf
[thread
].uval
,
742 prefix
, buf
[thread
].run
, buf
[thread
].ena
, 1.0,
751 double avg
, avg_enabled
, avg_running
;
754 static void counter_aggr_cb(struct perf_stat_config
*config __maybe_unused
,
755 struct perf_evsel
*counter
, void *data
,
756 bool first __maybe_unused
)
758 struct caggr_data
*cd
= data
;
759 struct perf_stat_evsel
*ps
= counter
->stats
;
761 cd
->avg
+= avg_stats(&ps
->res_stats
[0]);
762 cd
->avg_enabled
+= avg_stats(&ps
->res_stats
[1]);
763 cd
->avg_running
+= avg_stats(&ps
->res_stats
[2]);
767 * Print out the results of a single counter:
768 * aggregated counts in system-wide mode
770 static void print_counter_aggr(struct perf_stat_config
*config
,
771 struct perf_evsel
*counter
, char *prefix
)
773 bool metric_only
= config
->metric_only
;
774 FILE *output
= config
->output
;
776 struct caggr_data cd
= { .avg
= 0.0 };
778 if (!collect_data(config
, counter
, counter_aggr_cb
, &cd
))
781 if (prefix
&& !metric_only
)
782 fprintf(output
, "%s", prefix
);
784 uval
= cd
.avg
* counter
->scale
;
785 printout(config
, -1, 0, counter
, uval
, prefix
, cd
.avg_running
, cd
.avg_enabled
,
788 fprintf(output
, "\n");
791 static void counter_cb(struct perf_stat_config
*config __maybe_unused
,
792 struct perf_evsel
*counter
, void *data
,
793 bool first __maybe_unused
)
795 struct aggr_data
*ad
= data
;
797 ad
->val
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->val
;
798 ad
->ena
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->ena
;
799 ad
->run
+= perf_counts(counter
->counts
, ad
->cpu
, 0)->run
;
803 * Print out the results of a single counter:
804 * does not use aggregated count in system-wide
806 static void print_counter(struct perf_stat_config
*config
,
807 struct perf_evsel
*counter
, char *prefix
)
809 FILE *output
= config
->output
;
814 for (cpu
= 0; cpu
< perf_evsel__nr_cpus(counter
); cpu
++) {
815 struct aggr_data ad
= { .cpu
= cpu
};
817 if (!collect_data(config
, counter
, counter_cb
, &ad
))
824 fprintf(output
, "%s", prefix
);
826 uval
= val
* counter
->scale
;
827 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
834 static void print_no_aggr_metric(struct perf_stat_config
*config
,
835 struct perf_evlist
*evlist
,
840 struct perf_evsel
*counter
;
844 nrcpus
= evlist
->cpus
->nr
;
845 for (cpu
= 0; cpu
< nrcpus
; cpu
++) {
849 fputs(prefix
, config
->output
);
850 evlist__for_each_entry(evlist
, counter
) {
851 if (is_duration_time(counter
))
854 aggr_printout(config
, counter
, cpu
, 0);
857 val
= perf_counts(counter
->counts
, cpu
, 0)->val
;
858 ena
= perf_counts(counter
->counts
, cpu
, 0)->ena
;
859 run
= perf_counts(counter
->counts
, cpu
, 0)->run
;
861 uval
= val
* counter
->scale
;
862 printout(config
, cpu
, 0, counter
, uval
, prefix
, run
, ena
, 1.0,
865 fputc('\n', config
->output
);
869 static int aggr_header_lens
[] = {
877 static const char *aggr_header_csv
[] = {
878 [AGGR_CORE
] = "core,cpus,",
879 [AGGR_SOCKET
] = "socket,cpus",
880 [AGGR_NONE
] = "cpu,",
881 [AGGR_THREAD
] = "comm-pid,",
885 static void print_metric_headers(struct perf_stat_config
*config
,
886 struct perf_evlist
*evlist
,
887 const char *prefix
, bool no_indent
)
889 struct perf_stat_output_ctx out
;
890 struct perf_evsel
*counter
;
891 struct outstate os
= {
896 fprintf(config
->output
, "%s", prefix
);
898 if (!config
->csv_output
&& !no_indent
)
899 fprintf(config
->output
, "%*s",
900 aggr_header_lens
[config
->aggr_mode
], "");
901 if (config
->csv_output
) {
902 if (config
->interval
)
903 fputs("time,", config
->output
);
904 fputs(aggr_header_csv
[config
->aggr_mode
], config
->output
);
907 /* Print metrics headers only */
908 evlist__for_each_entry(evlist
, counter
) {
909 if (is_duration_time(counter
))
913 out
.print_metric
= print_metric_header
;
914 out
.new_line
= new_line_metric
;
915 out
.force_header
= true;
917 perf_stat__print_shadow_stats(config
, counter
, 0,
920 &config
->metric_events
,
923 fputc('\n', config
->output
);
926 static void print_interval(struct perf_stat_config
*config
,
927 struct perf_evlist
*evlist
,
928 char *prefix
, struct timespec
*ts
)
930 bool metric_only
= config
->metric_only
;
931 unsigned int unit_width
= config
->unit_width
;
932 FILE *output
= config
->output
;
933 static int num_print_interval
;
935 if (config
->interval_clear
)
938 sprintf(prefix
, "%6lu.%09lu%s", ts
->tv_sec
, ts
->tv_nsec
, config
->csv_sep
);
940 if ((num_print_interval
== 0 && !config
->csv_output
) || config
->interval_clear
) {
941 switch (config
->aggr_mode
) {
943 fprintf(output
, "# time socket cpus");
945 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
948 fprintf(output
, "# time core cpus");
950 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
953 fprintf(output
, "# time CPU ");
955 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
958 fprintf(output
, "# time comm-pid");
960 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
964 fprintf(output
, "# time");
966 fprintf(output
, " counts %*s events\n", unit_width
, "unit");
972 if ((num_print_interval
== 0 || config
->interval_clear
) && metric_only
)
973 print_metric_headers(config
, evlist
, " ", true);
974 if (++num_print_interval
== 25)
975 num_print_interval
= 0;
978 static void print_header(struct perf_stat_config
*config
,
979 struct target
*_target
,
980 int argc
, const char **argv
)
982 FILE *output
= config
->output
;
987 if (!config
->csv_output
) {
988 fprintf(output
, "\n");
989 fprintf(output
, " Performance counter stats for ");
990 if (_target
->system_wide
)
991 fprintf(output
, "\'system wide");
992 else if (_target
->cpu_list
)
993 fprintf(output
, "\'CPU(s) %s", _target
->cpu_list
);
994 else if (!target__has_task(_target
)) {
995 fprintf(output
, "\'%s", argv
? argv
[0] : "pipe");
996 for (i
= 1; argv
&& (i
< argc
); i
++)
997 fprintf(output
, " %s", argv
[i
]);
998 } else if (_target
->pid
)
999 fprintf(output
, "process id \'%s", _target
->pid
);
1001 fprintf(output
, "thread id \'%s", _target
->tid
);
1003 fprintf(output
, "\'");
1004 if (config
->run_count
> 1)
1005 fprintf(output
, " (%d runs)", config
->run_count
);
1006 fprintf(output
, ":\n\n");
1010 static int get_precision(double num
)
1015 return lround(ceil(-log10(num
)));
1018 static void print_table(struct perf_stat_config
*config
,
1019 FILE *output
, int precision
, double avg
)
1022 int idx
, indent
= 0;
1024 scnprintf(tmp
, 64, " %17.*f", precision
, avg
);
1025 while (tmp
[indent
] == ' ')
1028 fprintf(output
, "%*s# Table of individual measurements:\n", indent
, "");
1030 for (idx
= 0; idx
< config
->run_count
; idx
++) {
1031 double run
= (double) config
->walltime_run
[idx
] / NSEC_PER_SEC
;
1032 int h
, n
= 1 + abs((int) (100.0 * (run
- avg
)/run
) / 5);
1034 fprintf(output
, " %17.*f (%+.*f) ",
1035 precision
, run
, precision
, run
- avg
);
1037 for (h
= 0; h
< n
; h
++)
1038 fprintf(output
, "#");
1040 fprintf(output
, "\n");
1043 fprintf(output
, "\n%*s# Final result:\n", indent
, "");
1046 static double timeval2double(struct timeval
*t
)
1048 return t
->tv_sec
+ (double) t
->tv_usec
/USEC_PER_SEC
;
1051 static void print_footer(struct perf_stat_config
*config
)
1053 double avg
= avg_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1054 FILE *output
= config
->output
;
1057 if (!config
->null_run
)
1058 fprintf(output
, "\n");
1060 if (config
->run_count
== 1) {
1061 fprintf(output
, " %17.9f seconds time elapsed", avg
);
1063 if (config
->ru_display
) {
1064 double ru_utime
= timeval2double(&config
->ru_data
.ru_utime
);
1065 double ru_stime
= timeval2double(&config
->ru_data
.ru_stime
);
1067 fprintf(output
, "\n\n");
1068 fprintf(output
, " %17.9f seconds user\n", ru_utime
);
1069 fprintf(output
, " %17.9f seconds sys\n", ru_stime
);
1072 double sd
= stddev_stats(config
->walltime_nsecs_stats
) / NSEC_PER_SEC
;
1074 * Display at most 2 more significant
1075 * digits than the stddev inaccuracy.
1077 int precision
= get_precision(sd
) + 2;
1079 if (config
->walltime_run_table
)
1080 print_table(config
, output
, precision
, avg
);
1082 fprintf(output
, " %17.*f +- %.*f seconds time elapsed",
1083 precision
, avg
, precision
, sd
);
1085 print_noise_pct(config
, sd
, avg
);
1087 fprintf(output
, "\n\n");
1089 if (config
->print_free_counters_hint
&&
1090 sysctl__read_int("kernel/nmi_watchdog", &n
) >= 0 &&
1093 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1094 " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1096 " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1098 if (config
->print_mixed_hw_group_error
)
1100 "The events in group usually have to be from "
1101 "the same PMU. Try reorganizing the group.\n");
1105 perf_evlist__print_counters(struct perf_evlist
*evlist
,
1106 struct perf_stat_config
*config
,
1107 struct target
*_target
,
1108 struct timespec
*ts
,
1109 int argc
, const char **argv
)
1111 bool metric_only
= config
->metric_only
;
1112 int interval
= config
->interval
;
1113 struct perf_evsel
*counter
;
1114 char buf
[64], *prefix
= NULL
;
1117 print_interval(config
, evlist
, prefix
= buf
, ts
);
1119 print_header(config
, _target
, argc
, argv
);
1122 static int num_print_iv
;
1124 if (num_print_iv
== 0 && !interval
)
1125 print_metric_headers(config
, evlist
, prefix
, false);
1126 if (num_print_iv
++ == 25)
1128 if (config
->aggr_mode
== AGGR_GLOBAL
&& prefix
)
1129 fprintf(config
->output
, "%s", prefix
);
1132 switch (config
->aggr_mode
) {
1135 print_aggr(config
, evlist
, prefix
);
1138 evlist__for_each_entry(evlist
, counter
) {
1139 if (is_duration_time(counter
))
1141 print_aggr_thread(config
, _target
, counter
, prefix
);
1145 evlist__for_each_entry(evlist
, counter
) {
1146 if (is_duration_time(counter
))
1148 print_counter_aggr(config
, counter
, prefix
);
1151 fputc('\n', config
->output
);
1155 print_no_aggr_metric(config
, evlist
, prefix
);
1157 evlist__for_each_entry(evlist
, counter
) {
1158 if (is_duration_time(counter
))
1160 print_counter(config
, counter
, prefix
);
1169 if (!interval
&& !config
->csv_output
)
1170 print_footer(config
);
1172 fflush(config
->output
);