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