GNU Linux-libre 5.19-rc6-gnu
[releases.git] / tools / perf / util / stat-display.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <inttypes.h>
4 #include <linux/string.h>
5 #include <linux/time64.h>
6 #include <math.h>
7 #include <perf/cpumap.h>
8 #include "color.h"
9 #include "counts.h"
10 #include "evlist.h"
11 #include "evsel.h"
12 #include "stat.h"
13 #include "top.h"
14 #include "thread_map.h"
15 #include "cpumap.h"
16 #include "string2.h"
17 #include <linux/ctype.h>
18 #include "cgroup.h"
19 #include <api/fs/fs.h>
20 #include "util.h"
21 #include "iostat.h"
22 #include "pmu-hybrid.h"
23 #include "evlist-hybrid.h"
24
25 #define CNTR_NOT_SUPPORTED      "<not supported>"
26 #define CNTR_NOT_COUNTED        "<not counted>"
27
28 static void print_running(struct perf_stat_config *config,
29                           u64 run, u64 ena)
30 {
31         if (config->csv_output) {
32                 fprintf(config->output, "%s%" PRIu64 "%s%.2f",
33                                         config->csv_sep,
34                                         run,
35                                         config->csv_sep,
36                                         ena ? 100.0 * run / ena : 100.0);
37         } else if (run != ena) {
38                 fprintf(config->output, "  (%.2f%%)", 100.0 * run / ena);
39         }
40 }
41
42 static void print_noise_pct(struct perf_stat_config *config,
43                             double total, double avg)
44 {
45         double pct = rel_stddev_stats(total, avg);
46
47         if (config->csv_output)
48                 fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
49         else if (pct)
50                 fprintf(config->output, "  ( +-%6.2f%% )", pct);
51 }
52
53 static void print_noise(struct perf_stat_config *config,
54                         struct evsel *evsel, double avg)
55 {
56         struct perf_stat_evsel *ps;
57
58         if (config->run_count == 1)
59                 return;
60
61         ps = evsel->stats;
62         print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg);
63 }
64
65 static void print_cgroup(struct perf_stat_config *config, struct evsel *evsel)
66 {
67         if (nr_cgroups) {
68                 const char *cgrp_name = evsel->cgrp ? evsel->cgrp->name  : "";
69                 fprintf(config->output, "%s%s", config->csv_sep, cgrp_name);
70         }
71 }
72
73
74 static void aggr_printout(struct perf_stat_config *config,
75                           struct evsel *evsel, struct aggr_cpu_id id, int nr)
76 {
77         switch (config->aggr_mode) {
78         case AGGR_CORE:
79                 fprintf(config->output, "S%d-D%d-C%*d%s%*d%s",
80                         id.socket,
81                         id.die,
82                         config->csv_output ? 0 : -8,
83                         id.core,
84                         config->csv_sep,
85                         config->csv_output ? 0 : 4,
86                         nr,
87                         config->csv_sep);
88                 break;
89         case AGGR_DIE:
90                 fprintf(config->output, "S%d-D%*d%s%*d%s",
91                         id.socket,
92                         config->csv_output ? 0 : -8,
93                         id.die,
94                         config->csv_sep,
95                         config->csv_output ? 0 : 4,
96                         nr,
97                         config->csv_sep);
98                 break;
99         case AGGR_SOCKET:
100                 fprintf(config->output, "S%*d%s%*d%s",
101                         config->csv_output ? 0 : -5,
102                         id.socket,
103                         config->csv_sep,
104                         config->csv_output ? 0 : 4,
105                         nr,
106                         config->csv_sep);
107                         break;
108         case AGGR_NODE:
109                 fprintf(config->output, "N%*d%s%*d%s",
110                         config->csv_output ? 0 : -5,
111                         id.node,
112                         config->csv_sep,
113                         config->csv_output ? 0 : 4,
114                         nr,
115                         config->csv_sep);
116                         break;
117         case AGGR_NONE:
118                 if (evsel->percore && !config->percore_show_thread) {
119                         fprintf(config->output, "S%d-D%d-C%*d%s",
120                                 id.socket,
121                                 id.die,
122                                 config->csv_output ? 0 : -3,
123                                 id.core, config->csv_sep);
124                 } else if (id.cpu.cpu > -1) {
125                         fprintf(config->output, "CPU%*d%s",
126                                 config->csv_output ? 0 : -7,
127                                 id.cpu.cpu, config->csv_sep);
128                 }
129                 break;
130         case AGGR_THREAD:
131                 fprintf(config->output, "%*s-%*d%s",
132                         config->csv_output ? 0 : 16,
133                         perf_thread_map__comm(evsel->core.threads, id.thread),
134                         config->csv_output ? 0 : -8,
135                         perf_thread_map__pid(evsel->core.threads, id.thread),
136                         config->csv_sep);
137                 break;
138         case AGGR_GLOBAL:
139         case AGGR_UNSET:
140         default:
141                 break;
142         }
143 }
144
145 struct outstate {
146         FILE *fh;
147         bool newline;
148         const char *prefix;
149         int  nfields;
150         int  nr;
151         struct aggr_cpu_id id;
152         struct evsel *evsel;
153 };
154
155 #define METRIC_LEN  35
156
157 static void new_line_std(struct perf_stat_config *config __maybe_unused,
158                          void *ctx)
159 {
160         struct outstate *os = ctx;
161
162         os->newline = true;
163 }
164
165 static void do_new_line_std(struct perf_stat_config *config,
166                             struct outstate *os)
167 {
168         fputc('\n', os->fh);
169         fputs(os->prefix, os->fh);
170         aggr_printout(config, os->evsel, os->id, os->nr);
171         if (config->aggr_mode == AGGR_NONE)
172                 fprintf(os->fh, "        ");
173         fprintf(os->fh, "                                                 ");
174 }
175
176 static void print_metric_std(struct perf_stat_config *config,
177                              void *ctx, const char *color, const char *fmt,
178                              const char *unit, double val)
179 {
180         struct outstate *os = ctx;
181         FILE *out = os->fh;
182         int n;
183         bool newline = os->newline;
184
185         os->newline = false;
186
187         if (unit == NULL || fmt == NULL) {
188                 fprintf(out, "%-*s", METRIC_LEN, "");
189                 return;
190         }
191
192         if (newline)
193                 do_new_line_std(config, os);
194
195         n = fprintf(out, " # ");
196         if (color)
197                 n += color_fprintf(out, color, fmt, val);
198         else
199                 n += fprintf(out, fmt, val);
200         fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
201 }
202
203 static void new_line_csv(struct perf_stat_config *config, void *ctx)
204 {
205         struct outstate *os = ctx;
206         int i;
207
208         fputc('\n', os->fh);
209         if (os->prefix)
210                 fprintf(os->fh, "%s%s", os->prefix, config->csv_sep);
211         aggr_printout(config, os->evsel, os->id, os->nr);
212         for (i = 0; i < os->nfields; i++)
213                 fputs(config->csv_sep, os->fh);
214 }
215
216 static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
217                              void *ctx,
218                              const char *color __maybe_unused,
219                              const char *fmt, const char *unit, double val)
220 {
221         struct outstate *os = ctx;
222         FILE *out = os->fh;
223         char buf[64], *vals, *ends;
224
225         if (unit == NULL || fmt == NULL) {
226                 fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
227                 return;
228         }
229         snprintf(buf, sizeof(buf), fmt, val);
230         ends = vals = skip_spaces(buf);
231         while (isdigit(*ends) || *ends == '.')
232                 ends++;
233         *ends = 0;
234         fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
235 }
236
237 /* Filter out some columns that don't work well in metrics only mode */
238
239 static bool valid_only_metric(const char *unit)
240 {
241         if (!unit)
242                 return false;
243         if (strstr(unit, "/sec") ||
244             strstr(unit, "CPUs utilized"))
245                 return false;
246         return true;
247 }
248
249 static const char *fixunit(char *buf, struct evsel *evsel,
250                            const char *unit)
251 {
252         if (!strncmp(unit, "of all", 6)) {
253                 snprintf(buf, 1024, "%s %s", evsel__name(evsel),
254                          unit);
255                 return buf;
256         }
257         return unit;
258 }
259
260 static void print_metric_only(struct perf_stat_config *config,
261                               void *ctx, const char *color, const char *fmt,
262                               const char *unit, double val)
263 {
264         struct outstate *os = ctx;
265         FILE *out = os->fh;
266         char buf[1024], str[1024];
267         unsigned mlen = config->metric_only_len;
268
269         if (!valid_only_metric(unit))
270                 return;
271         unit = fixunit(buf, os->evsel, unit);
272         if (mlen < strlen(unit))
273                 mlen = strlen(unit) + 1;
274
275         if (color)
276                 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
277
278         color_snprintf(str, sizeof(str), color ?: "", fmt, val);
279         fprintf(out, "%*s ", mlen, str);
280 }
281
282 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
283                                   void *ctx, const char *color __maybe_unused,
284                                   const char *fmt,
285                                   const char *unit, double val)
286 {
287         struct outstate *os = ctx;
288         FILE *out = os->fh;
289         char buf[64], *vals, *ends;
290         char tbuf[1024];
291
292         if (!valid_only_metric(unit))
293                 return;
294         unit = fixunit(tbuf, os->evsel, unit);
295         snprintf(buf, sizeof buf, fmt, val);
296         ends = vals = skip_spaces(buf);
297         while (isdigit(*ends) || *ends == '.')
298                 ends++;
299         *ends = 0;
300         fprintf(out, "%s%s", vals, config->csv_sep);
301 }
302
303 static void new_line_metric(struct perf_stat_config *config __maybe_unused,
304                             void *ctx __maybe_unused)
305 {
306 }
307
308 static void print_metric_header(struct perf_stat_config *config,
309                                 void *ctx, const char *color __maybe_unused,
310                                 const char *fmt __maybe_unused,
311                                 const char *unit, double val __maybe_unused)
312 {
313         struct outstate *os = ctx;
314         char tbuf[1024];
315
316         /* In case of iostat, print metric header for first root port only */
317         if (config->iostat_run &&
318             os->evsel->priv != os->evsel->evlist->selected->priv)
319                 return;
320
321         if (!valid_only_metric(unit))
322                 return;
323         unit = fixunit(tbuf, os->evsel, unit);
324         if (config->csv_output)
325                 fprintf(os->fh, "%s%s", unit, config->csv_sep);
326         else
327                 fprintf(os->fh, "%*s ", config->metric_only_len, unit);
328 }
329
330 static int first_shadow_cpu_map_idx(struct perf_stat_config *config,
331                                 struct evsel *evsel, const struct aggr_cpu_id *id)
332 {
333         struct perf_cpu_map *cpus = evsel__cpus(evsel);
334         struct perf_cpu cpu;
335         int idx;
336
337         if (config->aggr_mode == AGGR_NONE)
338                 return perf_cpu_map__idx(cpus, id->cpu);
339
340         if (!config->aggr_get_id)
341                 return 0;
342
343         perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
344                 struct aggr_cpu_id cpu_id = config->aggr_get_id(config, cpu);
345
346                 if (aggr_cpu_id__equal(&cpu_id, id))
347                         return idx;
348         }
349         return 0;
350 }
351
352 static void abs_printout(struct perf_stat_config *config,
353                          struct aggr_cpu_id id, int nr, struct evsel *evsel, double avg)
354 {
355         FILE *output = config->output;
356         double sc =  evsel->scale;
357         const char *fmt;
358
359         if (config->csv_output) {
360                 fmt = floor(sc) != sc ?  "%.2f%s" : "%.0f%s";
361         } else {
362                 if (config->big_num)
363                         fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s";
364                 else
365                         fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s";
366         }
367
368         aggr_printout(config, evsel, id, nr);
369
370         fprintf(output, fmt, avg, config->csv_sep);
371
372         if (evsel->unit)
373                 fprintf(output, "%-*s%s",
374                         config->csv_output ? 0 : config->unit_width,
375                         evsel->unit, config->csv_sep);
376
377         fprintf(output, "%-*s", config->csv_output ? 0 : 25, evsel__name(evsel));
378
379         print_cgroup(config, evsel);
380 }
381
382 static bool is_mixed_hw_group(struct evsel *counter)
383 {
384         struct evlist *evlist = counter->evlist;
385         u32 pmu_type = counter->core.attr.type;
386         struct evsel *pos;
387
388         if (counter->core.nr_members < 2)
389                 return false;
390
391         evlist__for_each_entry(evlist, pos) {
392                 /* software events can be part of any hardware group */
393                 if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
394                         continue;
395                 if (pmu_type == PERF_TYPE_SOFTWARE) {
396                         pmu_type = pos->core.attr.type;
397                         continue;
398                 }
399                 if (pmu_type != pos->core.attr.type)
400                         return true;
401         }
402
403         return false;
404 }
405
406 static void printout(struct perf_stat_config *config, struct aggr_cpu_id id, int nr,
407                      struct evsel *counter, double uval,
408                      char *prefix, u64 run, u64 ena, double noise,
409                      struct runtime_stat *st)
410 {
411         struct perf_stat_output_ctx out;
412         struct outstate os = {
413                 .fh = config->output,
414                 .prefix = prefix ? prefix : "",
415                 .id = id,
416                 .nr = nr,
417                 .evsel = counter,
418         };
419         print_metric_t pm = print_metric_std;
420         new_line_t nl;
421
422         if (config->metric_only) {
423                 nl = new_line_metric;
424                 if (config->csv_output)
425                         pm = print_metric_only_csv;
426                 else
427                         pm = print_metric_only;
428         } else
429                 nl = new_line_std;
430
431         if (config->csv_output && !config->metric_only) {
432                 static int aggr_fields[] = {
433                         [AGGR_GLOBAL] = 0,
434                         [AGGR_THREAD] = 1,
435                         [AGGR_NONE] = 1,
436                         [AGGR_SOCKET] = 2,
437                         [AGGR_DIE] = 2,
438                         [AGGR_CORE] = 2,
439                 };
440
441                 pm = print_metric_csv;
442                 nl = new_line_csv;
443                 os.nfields = 3;
444                 os.nfields += aggr_fields[config->aggr_mode];
445                 if (counter->cgrp)
446                         os.nfields++;
447         }
448
449         if (!config->no_csv_summary && config->csv_output &&
450             config->summary && !config->interval) {
451                 fprintf(config->output, "%16s%s", "summary", config->csv_sep);
452         }
453
454         if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
455                 if (config->metric_only) {
456                         pm(config, &os, NULL, "", "", 0);
457                         return;
458                 }
459                 aggr_printout(config, counter, id, nr);
460
461                 fprintf(config->output, "%*s%s",
462                         config->csv_output ? 0 : 18,
463                         counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
464                         config->csv_sep);
465
466                 if (counter->supported) {
467                         if (!evlist__has_hybrid(counter->evlist)) {
468                                 config->print_free_counters_hint = 1;
469                                 if (is_mixed_hw_group(counter))
470                                         config->print_mixed_hw_group_error = 1;
471                         }
472                 }
473
474                 fprintf(config->output, "%-*s%s",
475                         config->csv_output ? 0 : config->unit_width,
476                         counter->unit, config->csv_sep);
477
478                 fprintf(config->output, "%*s",
479                         config->csv_output ? 0 : -25, evsel__name(counter));
480
481                 print_cgroup(config, counter);
482
483                 if (!config->csv_output)
484                         pm(config, &os, NULL, NULL, "", 0);
485                 print_noise(config, counter, noise);
486                 print_running(config, run, ena);
487                 if (config->csv_output)
488                         pm(config, &os, NULL, NULL, "", 0);
489                 return;
490         }
491
492         if (!config->metric_only)
493                 abs_printout(config, id, nr, counter, uval);
494
495         out.print_metric = pm;
496         out.new_line = nl;
497         out.ctx = &os;
498         out.force_header = false;
499
500         if (config->csv_output && !config->metric_only) {
501                 print_noise(config, counter, noise);
502                 print_running(config, run, ena);
503         }
504
505         perf_stat__print_shadow_stats(config, counter, uval,
506                                 first_shadow_cpu_map_idx(config, counter, &id),
507                                 &out, &config->metric_events, st);
508         if (!config->csv_output && !config->metric_only) {
509                 print_noise(config, counter, noise);
510                 print_running(config, run, ena);
511         }
512 }
513
514 static void aggr_update_shadow(struct perf_stat_config *config,
515                                struct evlist *evlist)
516 {
517         int idx, s;
518         struct perf_cpu cpu;
519         struct aggr_cpu_id s2, id;
520         u64 val;
521         struct evsel *counter;
522         struct perf_cpu_map *cpus;
523
524         for (s = 0; s < config->aggr_map->nr; s++) {
525                 id = config->aggr_map->map[s];
526                 evlist__for_each_entry(evlist, counter) {
527                         cpus = evsel__cpus(counter);
528                         val = 0;
529                         perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
530                                 s2 = config->aggr_get_id(config, cpu);
531                                 if (!aggr_cpu_id__equal(&s2, &id))
532                                         continue;
533                                 val += perf_counts(counter->counts, idx, 0)->val;
534                         }
535                         perf_stat__update_shadow_stats(counter, val,
536                                         first_shadow_cpu_map_idx(config, counter, &id),
537                                         &rt_stat);
538                 }
539         }
540 }
541
542 static void uniquify_event_name(struct evsel *counter)
543 {
544         char *new_name;
545         char *config;
546         int ret = 0;
547
548         if (counter->uniquified_name || counter->use_config_name ||
549             !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
550                                            strlen(counter->pmu_name)))
551                 return;
552
553         config = strchr(counter->name, '/');
554         if (config) {
555                 if (asprintf(&new_name,
556                              "%s%s", counter->pmu_name, config) > 0) {
557                         free(counter->name);
558                         counter->name = new_name;
559                 }
560         } else {
561                 if (perf_pmu__has_hybrid()) {
562                         ret = asprintf(&new_name, "%s/%s/",
563                                        counter->pmu_name, counter->name);
564                 } else {
565                         ret = asprintf(&new_name, "%s [%s]",
566                                        counter->name, counter->pmu_name);
567                 }
568
569                 if (ret) {
570                         free(counter->name);
571                         counter->name = new_name;
572                 }
573         }
574
575         counter->uniquified_name = true;
576 }
577
578 static void collect_all_aliases(struct perf_stat_config *config, struct evsel *counter,
579                             void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
580                                        bool first),
581                             void *data)
582 {
583         struct evlist *evlist = counter->evlist;
584         struct evsel *alias;
585
586         alias = list_prepare_entry(counter, &(evlist->core.entries), core.node);
587         list_for_each_entry_continue (alias, &evlist->core.entries, core.node) {
588                 /* Merge events with the same name, etc. but on different PMUs. */
589                 if (!strcmp(evsel__name(alias), evsel__name(counter)) &&
590                         alias->scale == counter->scale &&
591                         alias->cgrp == counter->cgrp &&
592                         !strcmp(alias->unit, counter->unit) &&
593                         evsel__is_clock(alias) == evsel__is_clock(counter) &&
594                         strcmp(alias->pmu_name, counter->pmu_name)) {
595                         alias->merged_stat = true;
596                         cb(config, alias, data, false);
597                 }
598         }
599 }
600
601 static bool is_uncore(struct evsel *evsel)
602 {
603         struct perf_pmu *pmu = evsel__find_pmu(evsel);
604
605         return pmu && pmu->is_uncore;
606 }
607
608 static bool hybrid_uniquify(struct evsel *evsel)
609 {
610         return perf_pmu__has_hybrid() && !is_uncore(evsel);
611 }
612
613 static bool hybrid_merge(struct evsel *counter, struct perf_stat_config *config,
614                          bool check)
615 {
616         if (hybrid_uniquify(counter)) {
617                 if (check)
618                         return config && config->hybrid_merge;
619                 else
620                         return config && !config->hybrid_merge;
621         }
622
623         return false;
624 }
625
626 static bool collect_data(struct perf_stat_config *config, struct evsel *counter,
627                             void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
628                                        bool first),
629                             void *data)
630 {
631         if (counter->merged_stat)
632                 return false;
633         cb(config, counter, data, true);
634         if (config->no_merge || hybrid_merge(counter, config, false))
635                 uniquify_event_name(counter);
636         else if (counter->auto_merge_stats || hybrid_merge(counter, config, true))
637                 collect_all_aliases(config, counter, cb, data);
638         return true;
639 }
640
641 struct aggr_data {
642         u64 ena, run, val;
643         struct aggr_cpu_id id;
644         int nr;
645         int cpu_map_idx;
646 };
647
648 static void aggr_cb(struct perf_stat_config *config,
649                     struct evsel *counter, void *data, bool first)
650 {
651         struct aggr_data *ad = data;
652         int idx;
653         struct perf_cpu cpu;
654         struct perf_cpu_map *cpus;
655         struct aggr_cpu_id s2;
656
657         cpus = evsel__cpus(counter);
658         perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
659                 struct perf_counts_values *counts;
660
661                 s2 = config->aggr_get_id(config, cpu);
662                 if (!aggr_cpu_id__equal(&s2, &ad->id))
663                         continue;
664                 if (first)
665                         ad->nr++;
666                 counts = perf_counts(counter->counts, idx, 0);
667                 /*
668                  * When any result is bad, make them all to give
669                  * consistent output in interval mode.
670                  */
671                 if (counts->ena == 0 || counts->run == 0 ||
672                     counter->counts->scaled == -1) {
673                         ad->ena = 0;
674                         ad->run = 0;
675                         break;
676                 }
677                 ad->val += counts->val;
678                 ad->ena += counts->ena;
679                 ad->run += counts->run;
680         }
681 }
682
683 static void print_counter_aggrdata(struct perf_stat_config *config,
684                                    struct evsel *counter, int s,
685                                    char *prefix, bool metric_only,
686                                    bool *first, struct perf_cpu cpu)
687 {
688         struct aggr_data ad;
689         FILE *output = config->output;
690         u64 ena, run, val;
691         int nr;
692         struct aggr_cpu_id id;
693         double uval;
694
695         ad.id = id = config->aggr_map->map[s];
696         ad.val = ad.ena = ad.run = 0;
697         ad.nr = 0;
698         if (!collect_data(config, counter, aggr_cb, &ad))
699                 return;
700
701         if (perf_pmu__has_hybrid() && ad.ena == 0)
702                 return;
703
704         nr = ad.nr;
705         ena = ad.ena;
706         run = ad.run;
707         val = ad.val;
708         if (*first && metric_only) {
709                 *first = false;
710                 aggr_printout(config, counter, id, nr);
711         }
712         if (prefix && !metric_only)
713                 fprintf(output, "%s", prefix);
714
715         uval = val * counter->scale;
716         if (cpu.cpu != -1)
717                 id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
718
719         printout(config, id, nr, counter, uval,
720                  prefix, run, ena, 1.0, &rt_stat);
721         if (!metric_only)
722                 fputc('\n', output);
723 }
724
725 static void print_aggr(struct perf_stat_config *config,
726                        struct evlist *evlist,
727                        char *prefix)
728 {
729         bool metric_only = config->metric_only;
730         FILE *output = config->output;
731         struct evsel *counter;
732         int s;
733         bool first;
734
735         if (!config->aggr_map || !config->aggr_get_id)
736                 return;
737
738         aggr_update_shadow(config, evlist);
739
740         /*
741          * With metric_only everything is on a single line.
742          * Without each counter has its own line.
743          */
744         for (s = 0; s < config->aggr_map->nr; s++) {
745                 if (prefix && metric_only)
746                         fprintf(output, "%s", prefix);
747
748                 first = true;
749                 evlist__for_each_entry(evlist, counter) {
750                         print_counter_aggrdata(config, counter, s,
751                                         prefix, metric_only,
752                                         &first, (struct perf_cpu){ .cpu = -1 });
753                 }
754                 if (metric_only)
755                         fputc('\n', output);
756         }
757 }
758
759 static int cmp_val(const void *a, const void *b)
760 {
761         return ((struct perf_aggr_thread_value *)b)->val -
762                 ((struct perf_aggr_thread_value *)a)->val;
763 }
764
765 static struct perf_aggr_thread_value *sort_aggr_thread(
766                                         struct evsel *counter,
767                                         int *ret,
768                                         struct target *_target)
769 {
770         int nthreads = perf_thread_map__nr(counter->core.threads);
771         int i = 0;
772         double uval;
773         struct perf_aggr_thread_value *buf;
774
775         buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
776         if (!buf)
777                 return NULL;
778
779         for (int thread = 0; thread < nthreads; thread++) {
780                 int idx;
781                 u64 ena = 0, run = 0, val = 0;
782
783                 perf_cpu_map__for_each_idx(idx, evsel__cpus(counter)) {
784                         struct perf_counts_values *counts =
785                                 perf_counts(counter->counts, idx, thread);
786
787                         val += counts->val;
788                         ena += counts->ena;
789                         run += counts->run;
790                 }
791
792                 uval = val * counter->scale;
793
794                 /*
795                  * Skip value 0 when enabling --per-thread globally,
796                  * otherwise too many 0 output.
797                  */
798                 if (uval == 0.0 && target__has_per_thread(_target))
799                         continue;
800
801                 buf[i].counter = counter;
802                 buf[i].id = aggr_cpu_id__empty();
803                 buf[i].id.thread = thread;
804                 buf[i].uval = uval;
805                 buf[i].val = val;
806                 buf[i].run = run;
807                 buf[i].ena = ena;
808                 i++;
809         }
810
811         qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
812
813         if (ret)
814                 *ret = i;
815
816         return buf;
817 }
818
819 static void print_aggr_thread(struct perf_stat_config *config,
820                               struct target *_target,
821                               struct evsel *counter, char *prefix)
822 {
823         FILE *output = config->output;
824         int thread, sorted_threads;
825         struct aggr_cpu_id id;
826         struct perf_aggr_thread_value *buf;
827
828         buf = sort_aggr_thread(counter, &sorted_threads, _target);
829         if (!buf) {
830                 perror("cannot sort aggr thread");
831                 return;
832         }
833
834         for (thread = 0; thread < sorted_threads; thread++) {
835                 if (prefix)
836                         fprintf(output, "%s", prefix);
837
838                 id = buf[thread].id;
839                 if (config->stats)
840                         printout(config, id, 0, buf[thread].counter, buf[thread].uval,
841                                  prefix, buf[thread].run, buf[thread].ena, 1.0,
842                                  &config->stats[id.thread]);
843                 else
844                         printout(config, id, 0, buf[thread].counter, buf[thread].uval,
845                                  prefix, buf[thread].run, buf[thread].ena, 1.0,
846                                  &rt_stat);
847                 fputc('\n', output);
848         }
849
850         free(buf);
851 }
852
853 struct caggr_data {
854         double avg, avg_enabled, avg_running;
855 };
856
857 static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused,
858                             struct evsel *counter, void *data,
859                             bool first __maybe_unused)
860 {
861         struct caggr_data *cd = data;
862         struct perf_counts_values *aggr = &counter->counts->aggr;
863
864         cd->avg += aggr->val;
865         cd->avg_enabled += aggr->ena;
866         cd->avg_running += aggr->run;
867 }
868
869 /*
870  * Print out the results of a single counter:
871  * aggregated counts in system-wide mode
872  */
873 static void print_counter_aggr(struct perf_stat_config *config,
874                                struct evsel *counter, char *prefix)
875 {
876         bool metric_only = config->metric_only;
877         FILE *output = config->output;
878         double uval;
879         struct caggr_data cd = { .avg = 0.0 };
880
881         if (!collect_data(config, counter, counter_aggr_cb, &cd))
882                 return;
883
884         if (prefix && !metric_only)
885                 fprintf(output, "%s", prefix);
886
887         uval = cd.avg * counter->scale;
888         printout(config, aggr_cpu_id__empty(), 0, counter, uval, prefix, cd.avg_running,
889                  cd.avg_enabled, cd.avg, &rt_stat);
890         if (!metric_only)
891                 fprintf(output, "\n");
892 }
893
894 static void counter_cb(struct perf_stat_config *config __maybe_unused,
895                        struct evsel *counter, void *data,
896                        bool first __maybe_unused)
897 {
898         struct aggr_data *ad = data;
899
900         ad->val += perf_counts(counter->counts, ad->cpu_map_idx, 0)->val;
901         ad->ena += perf_counts(counter->counts, ad->cpu_map_idx, 0)->ena;
902         ad->run += perf_counts(counter->counts, ad->cpu_map_idx, 0)->run;
903 }
904
905 /*
906  * Print out the results of a single counter:
907  * does not use aggregated count in system-wide
908  */
909 static void print_counter(struct perf_stat_config *config,
910                           struct evsel *counter, char *prefix)
911 {
912         FILE *output = config->output;
913         u64 ena, run, val;
914         double uval;
915         int idx;
916         struct perf_cpu cpu;
917         struct aggr_cpu_id id;
918
919         perf_cpu_map__for_each_cpu(cpu, idx, evsel__cpus(counter)) {
920                 struct aggr_data ad = { .cpu_map_idx = idx };
921
922                 if (!collect_data(config, counter, counter_cb, &ad))
923                         return;
924                 val = ad.val;
925                 ena = ad.ena;
926                 run = ad.run;
927
928                 if (prefix)
929                         fprintf(output, "%s", prefix);
930
931                 uval = val * counter->scale;
932                 id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
933                 printout(config, id, 0, counter, uval, prefix,
934                          run, ena, 1.0, &rt_stat);
935
936                 fputc('\n', output);
937         }
938 }
939
940 static void print_no_aggr_metric(struct perf_stat_config *config,
941                                  struct evlist *evlist,
942                                  char *prefix)
943 {
944         int all_idx;
945         struct perf_cpu cpu;
946
947         perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.user_requested_cpus) {
948                 struct evsel *counter;
949                 bool first = true;
950
951                 evlist__for_each_entry(evlist, counter) {
952                         u64 ena, run, val;
953                         double uval;
954                         struct aggr_cpu_id id;
955                         int counter_idx = perf_cpu_map__idx(evsel__cpus(counter), cpu);
956
957                         if (counter_idx < 0)
958                                 continue;
959
960                         id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
961                         if (first) {
962                                 if (prefix)
963                                         fputs(prefix, config->output);
964                                 aggr_printout(config, counter, id, 0);
965                                 first = false;
966                         }
967                         val = perf_counts(counter->counts, counter_idx, 0)->val;
968                         ena = perf_counts(counter->counts, counter_idx, 0)->ena;
969                         run = perf_counts(counter->counts, counter_idx, 0)->run;
970
971                         uval = val * counter->scale;
972                         printout(config, id, 0, counter, uval, prefix,
973                                  run, ena, 1.0, &rt_stat);
974                 }
975                 if (!first)
976                         fputc('\n', config->output);
977         }
978 }
979
980 static int aggr_header_lens[] = {
981         [AGGR_CORE] = 24,
982         [AGGR_DIE] = 18,
983         [AGGR_SOCKET] = 12,
984         [AGGR_NONE] = 6,
985         [AGGR_THREAD] = 24,
986         [AGGR_GLOBAL] = 0,
987 };
988
989 static const char *aggr_header_csv[] = {
990         [AGGR_CORE]     =       "core,cpus,",
991         [AGGR_DIE]      =       "die,cpus",
992         [AGGR_SOCKET]   =       "socket,cpus",
993         [AGGR_NONE]     =       "cpu,",
994         [AGGR_THREAD]   =       "comm-pid,",
995         [AGGR_GLOBAL]   =       ""
996 };
997
998 static void print_metric_headers(struct perf_stat_config *config,
999                                  struct evlist *evlist,
1000                                  const char *prefix, bool no_indent)
1001 {
1002         struct perf_stat_output_ctx out;
1003         struct evsel *counter;
1004         struct outstate os = {
1005                 .fh = config->output
1006         };
1007
1008         if (prefix)
1009                 fprintf(config->output, "%s", prefix);
1010
1011         if (!config->csv_output && !no_indent)
1012                 fprintf(config->output, "%*s",
1013                         aggr_header_lens[config->aggr_mode], "");
1014         if (config->csv_output) {
1015                 if (config->interval)
1016                         fputs("time,", config->output);
1017                 if (!config->iostat_run)
1018                         fputs(aggr_header_csv[config->aggr_mode], config->output);
1019         }
1020         if (config->iostat_run)
1021                 iostat_print_header_prefix(config);
1022
1023         /* Print metrics headers only */
1024         evlist__for_each_entry(evlist, counter) {
1025                 os.evsel = counter;
1026                 out.ctx = &os;
1027                 out.print_metric = print_metric_header;
1028                 out.new_line = new_line_metric;
1029                 out.force_header = true;
1030                 perf_stat__print_shadow_stats(config, counter, 0,
1031                                               0,
1032                                               &out,
1033                                               &config->metric_events,
1034                                               &rt_stat);
1035         }
1036         fputc('\n', config->output);
1037 }
1038
1039 static void print_interval(struct perf_stat_config *config,
1040                            struct evlist *evlist,
1041                            char *prefix, struct timespec *ts)
1042 {
1043         bool metric_only = config->metric_only;
1044         unsigned int unit_width = config->unit_width;
1045         FILE *output = config->output;
1046         static int num_print_interval;
1047
1048         if (config->interval_clear)
1049                 puts(CONSOLE_CLEAR);
1050
1051         if (!config->iostat_run)
1052                 sprintf(prefix, "%6lu.%09lu%s", (unsigned long) ts->tv_sec, ts->tv_nsec, config->csv_sep);
1053
1054         if ((num_print_interval == 0 && !config->csv_output) || config->interval_clear) {
1055                 switch (config->aggr_mode) {
1056                 case AGGR_NODE:
1057                         fprintf(output, "#           time node   cpus");
1058                         if (!metric_only)
1059                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
1060                         break;
1061                 case AGGR_SOCKET:
1062                         fprintf(output, "#           time socket cpus");
1063                         if (!metric_only)
1064                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
1065                         break;
1066                 case AGGR_DIE:
1067                         fprintf(output, "#           time die          cpus");
1068                         if (!metric_only)
1069                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
1070                         break;
1071                 case AGGR_CORE:
1072                         fprintf(output, "#           time core            cpus");
1073                         if (!metric_only)
1074                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
1075                         break;
1076                 case AGGR_NONE:
1077                         fprintf(output, "#           time CPU    ");
1078                         if (!metric_only)
1079                                 fprintf(output, "                counts %*s events\n", unit_width, "unit");
1080                         break;
1081                 case AGGR_THREAD:
1082                         fprintf(output, "#           time             comm-pid");
1083                         if (!metric_only)
1084                                 fprintf(output, "                  counts %*s events\n", unit_width, "unit");
1085                         break;
1086                 case AGGR_GLOBAL:
1087                 default:
1088                         if (!config->iostat_run) {
1089                                 fprintf(output, "#           time");
1090                                 if (!metric_only)
1091                                         fprintf(output, "             counts %*s events\n", unit_width, "unit");
1092                         }
1093                 case AGGR_UNSET:
1094                         break;
1095                 }
1096         }
1097
1098         if ((num_print_interval == 0 || config->interval_clear) && metric_only)
1099                 print_metric_headers(config, evlist, " ", true);
1100         if (++num_print_interval == 25)
1101                 num_print_interval = 0;
1102 }
1103
1104 static void print_header(struct perf_stat_config *config,
1105                          struct target *_target,
1106                          int argc, const char **argv)
1107 {
1108         FILE *output = config->output;
1109         int i;
1110
1111         fflush(stdout);
1112
1113         if (!config->csv_output) {
1114                 fprintf(output, "\n");
1115                 fprintf(output, " Performance counter stats for ");
1116                 if (_target->bpf_str)
1117                         fprintf(output, "\'BPF program(s) %s", _target->bpf_str);
1118                 else if (_target->system_wide)
1119                         fprintf(output, "\'system wide");
1120                 else if (_target->cpu_list)
1121                         fprintf(output, "\'CPU(s) %s", _target->cpu_list);
1122                 else if (!target__has_task(_target)) {
1123                         fprintf(output, "\'%s", argv ? argv[0] : "pipe");
1124                         for (i = 1; argv && (i < argc); i++)
1125                                 fprintf(output, " %s", argv[i]);
1126                 } else if (_target->pid)
1127                         fprintf(output, "process id \'%s", _target->pid);
1128                 else
1129                         fprintf(output, "thread id \'%s", _target->tid);
1130
1131                 fprintf(output, "\'");
1132                 if (config->run_count > 1)
1133                         fprintf(output, " (%d runs)", config->run_count);
1134                 fprintf(output, ":\n\n");
1135         }
1136 }
1137
1138 static int get_precision(double num)
1139 {
1140         if (num > 1)
1141                 return 0;
1142
1143         return lround(ceil(-log10(num)));
1144 }
1145
1146 static void print_table(struct perf_stat_config *config,
1147                         FILE *output, int precision, double avg)
1148 {
1149         char tmp[64];
1150         int idx, indent = 0;
1151
1152         scnprintf(tmp, 64, " %17.*f", precision, avg);
1153         while (tmp[indent] == ' ')
1154                 indent++;
1155
1156         fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1157
1158         for (idx = 0; idx < config->run_count; idx++) {
1159                 double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
1160                 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1161
1162                 fprintf(output, " %17.*f (%+.*f) ",
1163                         precision, run, precision, run - avg);
1164
1165                 for (h = 0; h < n; h++)
1166                         fprintf(output, "#");
1167
1168                 fprintf(output, "\n");
1169         }
1170
1171         fprintf(output, "\n%*s# Final result:\n", indent, "");
1172 }
1173
1174 static double timeval2double(struct timeval *t)
1175 {
1176         return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1177 }
1178
1179 static void print_footer(struct perf_stat_config *config)
1180 {
1181         double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1182         FILE *output = config->output;
1183
1184         if (!config->null_run)
1185                 fprintf(output, "\n");
1186
1187         if (config->run_count == 1) {
1188                 fprintf(output, " %17.9f seconds time elapsed", avg);
1189
1190                 if (config->ru_display) {
1191                         double ru_utime = timeval2double(&config->ru_data.ru_utime);
1192                         double ru_stime = timeval2double(&config->ru_data.ru_stime);
1193
1194                         fprintf(output, "\n\n");
1195                         fprintf(output, " %17.9f seconds user\n", ru_utime);
1196                         fprintf(output, " %17.9f seconds sys\n", ru_stime);
1197                 }
1198         } else {
1199                 double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1200                 /*
1201                  * Display at most 2 more significant
1202                  * digits than the stddev inaccuracy.
1203                  */
1204                 int precision = get_precision(sd) + 2;
1205
1206                 if (config->walltime_run_table)
1207                         print_table(config, output, precision, avg);
1208
1209                 fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1210                         precision, avg, precision, sd);
1211
1212                 print_noise_pct(config, sd, avg);
1213         }
1214         fprintf(output, "\n\n");
1215
1216         if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled())
1217                 fprintf(output,
1218 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1219 "       echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1220 "       perf stat ...\n"
1221 "       echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1222
1223         if (config->print_mixed_hw_group_error)
1224                 fprintf(output,
1225                         "The events in group usually have to be from "
1226                         "the same PMU. Try reorganizing the group.\n");
1227 }
1228
1229 static void print_percore_thread(struct perf_stat_config *config,
1230                                  struct evsel *counter, char *prefix)
1231 {
1232         int s;
1233         struct aggr_cpu_id s2, id;
1234         struct perf_cpu_map *cpus;
1235         bool first = true;
1236         int idx;
1237         struct perf_cpu cpu;
1238
1239         cpus = evsel__cpus(counter);
1240         perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
1241                 s2 = config->aggr_get_id(config, cpu);
1242                 for (s = 0; s < config->aggr_map->nr; s++) {
1243                         id = config->aggr_map->map[s];
1244                         if (aggr_cpu_id__equal(&s2, &id))
1245                                 break;
1246                 }
1247
1248                 print_counter_aggrdata(config, counter, s,
1249                                        prefix, false,
1250                                        &first, cpu);
1251         }
1252 }
1253
1254 static void print_percore(struct perf_stat_config *config,
1255                           struct evsel *counter, char *prefix)
1256 {
1257         bool metric_only = config->metric_only;
1258         FILE *output = config->output;
1259         int s;
1260         bool first = true;
1261
1262         if (!config->aggr_map || !config->aggr_get_id)
1263                 return;
1264
1265         if (config->percore_show_thread)
1266                 return print_percore_thread(config, counter, prefix);
1267
1268         for (s = 0; s < config->aggr_map->nr; s++) {
1269                 if (prefix && metric_only)
1270                         fprintf(output, "%s", prefix);
1271
1272                 print_counter_aggrdata(config, counter, s,
1273                                 prefix, metric_only,
1274                                 &first, (struct perf_cpu){ .cpu = -1 });
1275         }
1276
1277         if (metric_only)
1278                 fputc('\n', output);
1279 }
1280
1281 void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
1282                             struct target *_target, struct timespec *ts, int argc, const char **argv)
1283 {
1284         bool metric_only = config->metric_only;
1285         int interval = config->interval;
1286         struct evsel *counter;
1287         char buf[64], *prefix = NULL;
1288
1289         if (config->iostat_run)
1290                 evlist->selected = evlist__first(evlist);
1291
1292         if (interval)
1293                 print_interval(config, evlist, prefix = buf, ts);
1294         else
1295                 print_header(config, _target, argc, argv);
1296
1297         if (metric_only) {
1298                 static int num_print_iv;
1299
1300                 if (num_print_iv == 0 && !interval)
1301                         print_metric_headers(config, evlist, prefix, false);
1302                 if (num_print_iv++ == 25)
1303                         num_print_iv = 0;
1304                 if (config->aggr_mode == AGGR_GLOBAL && prefix && !config->iostat_run)
1305                         fprintf(config->output, "%s", prefix);
1306         }
1307
1308         switch (config->aggr_mode) {
1309         case AGGR_CORE:
1310         case AGGR_DIE:
1311         case AGGR_SOCKET:
1312         case AGGR_NODE:
1313                 print_aggr(config, evlist, prefix);
1314                 break;
1315         case AGGR_THREAD:
1316                 evlist__for_each_entry(evlist, counter) {
1317                         print_aggr_thread(config, _target, counter, prefix);
1318                 }
1319                 break;
1320         case AGGR_GLOBAL:
1321                 if (config->iostat_run)
1322                         iostat_print_counters(evlist, config, ts, prefix = buf,
1323                                               print_counter_aggr);
1324                 else {
1325                         evlist__for_each_entry(evlist, counter) {
1326                                 print_counter_aggr(config, counter, prefix);
1327                         }
1328                         if (metric_only)
1329                                 fputc('\n', config->output);
1330                 }
1331                 break;
1332         case AGGR_NONE:
1333                 if (metric_only)
1334                         print_no_aggr_metric(config, evlist, prefix);
1335                 else {
1336                         evlist__for_each_entry(evlist, counter) {
1337                                 if (counter->percore)
1338                                         print_percore(config, counter, prefix);
1339                                 else
1340                                         print_counter(config, counter, prefix);
1341                         }
1342                 }
1343                 break;
1344         case AGGR_UNSET:
1345         default:
1346                 break;
1347         }
1348
1349         if (!interval && !config->csv_output)
1350                 print_footer(config);
1351
1352         fflush(config->output);
1353 }