]> Git Repo - J-linux.git/blob - tools/perf/util/stat-display.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.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 "debug.h"
11 #include "evlist.h"
12 #include "evsel.h"
13 #include "stat.h"
14 #include "top.h"
15 #include "thread_map.h"
16 #include "cpumap.h"
17 #include "string2.h"
18 #include <linux/ctype.h>
19 #include "cgroup.h"
20 #include <api/fs/fs.h>
21 #include "util.h"
22 #include "iostat.h"
23 #include "pmu.h"
24 #include "pmus.h"
25 #include "tool_pmu.h"
26
27 #define CNTR_NOT_SUPPORTED      "<not supported>"
28 #define CNTR_NOT_COUNTED        "<not counted>"
29
30 #define MGROUP_LEN   50
31 #define METRIC_LEN   38
32 #define EVNAME_LEN   32
33 #define COUNTS_LEN   18
34 #define INTERVAL_LEN 16
35 #define CGROUP_LEN   16
36 #define COMM_LEN     16
37 #define PID_LEN       7
38 #define CPUS_LEN      4
39
40 static int aggr_header_lens[] = {
41         [AGGR_CORE]     = 18,
42         [AGGR_CACHE]    = 22,
43         [AGGR_CLUSTER]  = 20,
44         [AGGR_DIE]      = 12,
45         [AGGR_SOCKET]   = 6,
46         [AGGR_NODE]     = 6,
47         [AGGR_NONE]     = 6,
48         [AGGR_THREAD]   = 16,
49         [AGGR_GLOBAL]   = 0,
50 };
51
52 static const char *aggr_header_csv[] = {
53         [AGGR_CORE]     =       "core,cpus,",
54         [AGGR_CACHE]    =       "cache,cpus,",
55         [AGGR_CLUSTER]  =       "cluster,cpus,",
56         [AGGR_DIE]      =       "die,cpus,",
57         [AGGR_SOCKET]   =       "socket,cpus,",
58         [AGGR_NONE]     =       "cpu,",
59         [AGGR_THREAD]   =       "comm-pid,",
60         [AGGR_NODE]     =       "node,",
61         [AGGR_GLOBAL]   =       ""
62 };
63
64 static const char *aggr_header_std[] = {
65         [AGGR_CORE]     =       "core",
66         [AGGR_CACHE]    =       "cache",
67         [AGGR_CLUSTER]  =       "cluster",
68         [AGGR_DIE]      =       "die",
69         [AGGR_SOCKET]   =       "socket",
70         [AGGR_NONE]     =       "cpu",
71         [AGGR_THREAD]   =       "comm-pid",
72         [AGGR_NODE]     =       "node",
73         [AGGR_GLOBAL]   =       ""
74 };
75
76 const char *metric_threshold_classify__color(enum metric_threshold_classify thresh)
77 {
78         const char * const colors[] = {
79                 "", /* unknown */
80                 PERF_COLOR_RED,     /* bad */
81                 PERF_COLOR_MAGENTA, /* nearly bad */
82                 PERF_COLOR_YELLOW,  /* less good */
83                 PERF_COLOR_GREEN,   /* good */
84         };
85         static_assert(ARRAY_SIZE(colors) - 1  == METRIC_THRESHOLD_GOOD, "missing enum value");
86         return colors[thresh];
87 }
88
89 static const char *metric_threshold_classify__str(enum metric_threshold_classify thresh)
90 {
91         const char * const strs[] = {
92                 "unknown",
93                 "bad",
94                 "nearly bad",
95                 "less good",
96                 "good",
97         };
98         static_assert(ARRAY_SIZE(strs) - 1  == METRIC_THRESHOLD_GOOD, "missing enum value");
99         return strs[thresh];
100 }
101
102 static void print_running_std(struct perf_stat_config *config, u64 run, u64 ena)
103 {
104         if (run != ena)
105                 fprintf(config->output, "  (%.2f%%)", 100.0 * run / ena);
106 }
107
108 static void print_running_csv(struct perf_stat_config *config, u64 run, u64 ena)
109 {
110         double enabled_percent = 100;
111
112         if (run != ena)
113                 enabled_percent = 100 * run / ena;
114         fprintf(config->output, "%s%" PRIu64 "%s%.2f",
115                 config->csv_sep, run, config->csv_sep, enabled_percent);
116 }
117
118 static void print_running_json(struct perf_stat_config *config, u64 run, u64 ena)
119 {
120         double enabled_percent = 100;
121
122         if (run != ena)
123                 enabled_percent = 100 * run / ena;
124         fprintf(config->output, "\"event-runtime\" : %" PRIu64 ", \"pcnt-running\" : %.2f, ",
125                 run, enabled_percent);
126 }
127
128 static void print_running(struct perf_stat_config *config,
129                           u64 run, u64 ena, bool before_metric)
130 {
131         if (config->json_output) {
132                 if (before_metric)
133                         print_running_json(config, run, ena);
134         } else if (config->csv_output) {
135                 if (before_metric)
136                         print_running_csv(config, run, ena);
137         } else {
138                 if (!before_metric)
139                         print_running_std(config, run, ena);
140         }
141 }
142
143 static void print_noise_pct_std(struct perf_stat_config *config,
144                                 double pct)
145 {
146         if (pct)
147                 fprintf(config->output, "  ( +-%6.2f%% )", pct);
148 }
149
150 static void print_noise_pct_csv(struct perf_stat_config *config,
151                                 double pct)
152 {
153         fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
154 }
155
156 static void print_noise_pct_json(struct perf_stat_config *config,
157                                  double pct)
158 {
159         fprintf(config->output, "\"variance\" : %.2f, ", pct);
160 }
161
162 static void print_noise_pct(struct perf_stat_config *config,
163                             double total, double avg, bool before_metric)
164 {
165         double pct = rel_stddev_stats(total, avg);
166
167         if (config->json_output) {
168                 if (before_metric)
169                         print_noise_pct_json(config, pct);
170         } else if (config->csv_output) {
171                 if (before_metric)
172                         print_noise_pct_csv(config, pct);
173         } else {
174                 if (!before_metric)
175                         print_noise_pct_std(config, pct);
176         }
177 }
178
179 static void print_noise(struct perf_stat_config *config,
180                         struct evsel *evsel, double avg, bool before_metric)
181 {
182         struct perf_stat_evsel *ps;
183
184         if (config->run_count == 1)
185                 return;
186
187         ps = evsel->stats;
188         print_noise_pct(config, stddev_stats(&ps->res_stats), avg, before_metric);
189 }
190
191 static void print_cgroup_std(struct perf_stat_config *config, const char *cgrp_name)
192 {
193         fprintf(config->output, " %-*s", CGROUP_LEN, cgrp_name);
194 }
195
196 static void print_cgroup_csv(struct perf_stat_config *config, const char *cgrp_name)
197 {
198         fprintf(config->output, "%s%s", config->csv_sep, cgrp_name);
199 }
200
201 static void print_cgroup_json(struct perf_stat_config *config, const char *cgrp_name)
202 {
203         fprintf(config->output, "\"cgroup\" : \"%s\", ", cgrp_name);
204 }
205
206 static void print_cgroup(struct perf_stat_config *config, struct cgroup *cgrp)
207 {
208         if (nr_cgroups || config->cgroup_list) {
209                 const char *cgrp_name = cgrp ? cgrp->name  : "";
210
211                 if (config->json_output)
212                         print_cgroup_json(config, cgrp_name);
213                 else if (config->csv_output)
214                         print_cgroup_csv(config, cgrp_name);
215                 else
216                         print_cgroup_std(config, cgrp_name);
217         }
218 }
219
220 static void print_aggr_id_std(struct perf_stat_config *config,
221                               struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
222 {
223         FILE *output = config->output;
224         int idx = config->aggr_mode;
225         char buf[128];
226
227         switch (config->aggr_mode) {
228         case AGGR_CORE:
229                 snprintf(buf, sizeof(buf), "S%d-D%d-C%d", id.socket, id.die, id.core);
230                 break;
231         case AGGR_CACHE:
232                 snprintf(buf, sizeof(buf), "S%d-D%d-L%d-ID%d",
233                          id.socket, id.die, id.cache_lvl, id.cache);
234                 break;
235         case AGGR_CLUSTER:
236                 snprintf(buf, sizeof(buf), "S%d-D%d-CLS%d", id.socket, id.die, id.cluster);
237                 break;
238         case AGGR_DIE:
239                 snprintf(buf, sizeof(buf), "S%d-D%d", id.socket, id.die);
240                 break;
241         case AGGR_SOCKET:
242                 snprintf(buf, sizeof(buf), "S%d", id.socket);
243                 break;
244         case AGGR_NODE:
245                 snprintf(buf, sizeof(buf), "N%d", id.node);
246                 break;
247         case AGGR_NONE:
248                 if (evsel->percore && !config->percore_show_thread) {
249                         snprintf(buf, sizeof(buf), "S%d-D%d-C%d ",
250                                 id.socket, id.die, id.core);
251                         fprintf(output, "%-*s ",
252                                 aggr_header_lens[AGGR_CORE], buf);
253                 } else if (id.cpu.cpu > -1) {
254                         fprintf(output, "CPU%-*d ",
255                                 aggr_header_lens[AGGR_NONE] - 3, id.cpu.cpu);
256                 }
257                 return;
258         case AGGR_THREAD:
259                 fprintf(output, "%*s-%-*d ",
260                         COMM_LEN, perf_thread_map__comm(evsel->core.threads, id.thread_idx),
261                         PID_LEN, perf_thread_map__pid(evsel->core.threads, id.thread_idx));
262                 return;
263         case AGGR_GLOBAL:
264         case AGGR_UNSET:
265         case AGGR_MAX:
266         default:
267                 return;
268         }
269
270         fprintf(output, "%-*s %*d ", aggr_header_lens[idx], buf, 4, aggr_nr);
271 }
272
273 static void print_aggr_id_csv(struct perf_stat_config *config,
274                               struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
275 {
276         FILE *output = config->output;
277         const char *sep = config->csv_sep;
278
279         switch (config->aggr_mode) {
280         case AGGR_CORE:
281                 fprintf(output, "S%d-D%d-C%d%s%d%s",
282                         id.socket, id.die, id.core, sep, aggr_nr, sep);
283                 break;
284         case AGGR_CACHE:
285                 fprintf(config->output, "S%d-D%d-L%d-ID%d%s%d%s",
286                         id.socket, id.die, id.cache_lvl, id.cache, sep, aggr_nr, sep);
287                 break;
288         case AGGR_CLUSTER:
289                 fprintf(config->output, "S%d-D%d-CLS%d%s%d%s",
290                         id.socket, id.die, id.cluster, sep, aggr_nr, sep);
291                 break;
292         case AGGR_DIE:
293                 fprintf(output, "S%d-D%d%s%d%s",
294                         id.socket, id.die, sep, aggr_nr, sep);
295                 break;
296         case AGGR_SOCKET:
297                 fprintf(output, "S%d%s%d%s",
298                         id.socket, sep, aggr_nr, sep);
299                 break;
300         case AGGR_NODE:
301                 fprintf(output, "N%d%s%d%s",
302                         id.node, sep, aggr_nr, sep);
303                 break;
304         case AGGR_NONE:
305                 if (evsel->percore && !config->percore_show_thread) {
306                         fprintf(output, "S%d-D%d-C%d%s",
307                                 id.socket, id.die, id.core, sep);
308                 } else if (id.cpu.cpu > -1) {
309                         fprintf(output, "CPU%d%s",
310                                 id.cpu.cpu, sep);
311                 }
312                 break;
313         case AGGR_THREAD:
314                 fprintf(output, "%s-%d%s",
315                         perf_thread_map__comm(evsel->core.threads, id.thread_idx),
316                         perf_thread_map__pid(evsel->core.threads, id.thread_idx),
317                         sep);
318                 break;
319         case AGGR_GLOBAL:
320         case AGGR_UNSET:
321         case AGGR_MAX:
322         default:
323                 break;
324         }
325 }
326
327 static void print_aggr_id_json(struct perf_stat_config *config,
328                                struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
329 {
330         FILE *output = config->output;
331
332         switch (config->aggr_mode) {
333         case AGGR_CORE:
334                 fprintf(output, "\"core\" : \"S%d-D%d-C%d\", \"aggregate-number\" : %d, ",
335                         id.socket, id.die, id.core, aggr_nr);
336                 break;
337         case AGGR_CACHE:
338                 fprintf(output, "\"cache\" : \"S%d-D%d-L%d-ID%d\", \"aggregate-number\" : %d, ",
339                         id.socket, id.die, id.cache_lvl, id.cache, aggr_nr);
340                 break;
341         case AGGR_CLUSTER:
342                 fprintf(output, "\"cluster\" : \"S%d-D%d-CLS%d\", \"aggregate-number\" : %d, ",
343                         id.socket, id.die, id.cluster, aggr_nr);
344                 break;
345         case AGGR_DIE:
346                 fprintf(output, "\"die\" : \"S%d-D%d\", \"aggregate-number\" : %d, ",
347                         id.socket, id.die, aggr_nr);
348                 break;
349         case AGGR_SOCKET:
350                 fprintf(output, "\"socket\" : \"S%d\", \"aggregate-number\" : %d, ",
351                         id.socket, aggr_nr);
352                 break;
353         case AGGR_NODE:
354                 fprintf(output, "\"node\" : \"N%d\", \"aggregate-number\" : %d, ",
355                         id.node, aggr_nr);
356                 break;
357         case AGGR_NONE:
358                 if (evsel->percore && !config->percore_show_thread) {
359                         fprintf(output, "\"core\" : \"S%d-D%d-C%d\"",
360                                 id.socket, id.die, id.core);
361                 } else if (id.cpu.cpu > -1) {
362                         fprintf(output, "\"cpu\" : \"%d\", ",
363                                 id.cpu.cpu);
364                 }
365                 break;
366         case AGGR_THREAD:
367                 fprintf(output, "\"thread\" : \"%s-%d\", ",
368                         perf_thread_map__comm(evsel->core.threads, id.thread_idx),
369                         perf_thread_map__pid(evsel->core.threads, id.thread_idx));
370                 break;
371         case AGGR_GLOBAL:
372         case AGGR_UNSET:
373         case AGGR_MAX:
374         default:
375                 break;
376         }
377 }
378
379 static void aggr_printout(struct perf_stat_config *config,
380                           struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr)
381 {
382         if (config->json_output)
383                 print_aggr_id_json(config, evsel, id, aggr_nr);
384         else if (config->csv_output)
385                 print_aggr_id_csv(config, evsel, id, aggr_nr);
386         else
387                 print_aggr_id_std(config, evsel, id, aggr_nr);
388 }
389
390 struct outstate {
391         FILE *fh;
392         bool newline;
393         bool first;
394         const char *prefix;
395         int  nfields;
396         int  aggr_nr;
397         struct aggr_cpu_id id;
398         struct evsel *evsel;
399         struct cgroup *cgrp;
400 };
401
402 static void new_line_std(struct perf_stat_config *config __maybe_unused,
403                          void *ctx)
404 {
405         struct outstate *os = ctx;
406
407         os->newline = true;
408 }
409
410 static inline void __new_line_std_csv(struct perf_stat_config *config,
411                                       struct outstate *os)
412 {
413         fputc('\n', os->fh);
414         if (os->prefix)
415                 fputs(os->prefix, os->fh);
416         aggr_printout(config, os->evsel, os->id, os->aggr_nr);
417 }
418
419 static inline void __new_line_std(struct outstate *os)
420 {
421         fprintf(os->fh, "                                                 ");
422 }
423
424 static void do_new_line_std(struct perf_stat_config *config,
425                             struct outstate *os)
426 {
427         __new_line_std_csv(config, os);
428         if (config->aggr_mode == AGGR_NONE)
429                 fprintf(os->fh, "        ");
430         __new_line_std(os);
431 }
432
433 static void print_metric_std(struct perf_stat_config *config,
434                              void *ctx, enum metric_threshold_classify thresh,
435                              const char *fmt, const char *unit, double val)
436 {
437         struct outstate *os = ctx;
438         FILE *out = os->fh;
439         int n;
440         bool newline = os->newline;
441         const char *color = metric_threshold_classify__color(thresh);
442
443         os->newline = false;
444
445         if (unit == NULL || fmt == NULL) {
446                 fprintf(out, "%-*s", METRIC_LEN, "");
447                 return;
448         }
449
450         if (newline)
451                 do_new_line_std(config, os);
452
453         n = fprintf(out, " # ");
454         if (color)
455                 n += color_fprintf(out, color, fmt, val);
456         else
457                 n += fprintf(out, fmt, val);
458         fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
459 }
460
461 static void new_line_csv(struct perf_stat_config *config, void *ctx)
462 {
463         struct outstate *os = ctx;
464         int i;
465
466         __new_line_std_csv(config, os);
467         for (i = 0; i < os->nfields; i++)
468                 fputs(config->csv_sep, os->fh);
469 }
470
471 static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
472                              void *ctx,
473                              enum metric_threshold_classify thresh __maybe_unused,
474                              const char *fmt, const char *unit, double val)
475 {
476         struct outstate *os = ctx;
477         FILE *out = os->fh;
478         char buf[64], *vals, *ends;
479
480         if (unit == NULL || fmt == NULL) {
481                 fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
482                 return;
483         }
484         snprintf(buf, sizeof(buf), fmt, val);
485         ends = vals = skip_spaces(buf);
486         while (isdigit(*ends) || *ends == '.')
487                 ends++;
488         *ends = 0;
489         fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
490 }
491
492 static void print_metric_json(struct perf_stat_config *config __maybe_unused,
493                              void *ctx,
494                              enum metric_threshold_classify thresh,
495                              const char *fmt __maybe_unused,
496                              const char *unit, double val)
497 {
498         struct outstate *os = ctx;
499         FILE *out = os->fh;
500
501         if (unit) {
502                 fprintf(out, "\"metric-value\" : \"%f\", \"metric-unit\" : \"%s\"", val, unit);
503                 if (thresh != METRIC_THRESHOLD_UNKNOWN) {
504                         fprintf(out, ", \"metric-threshold\" : \"%s\"",
505                                 metric_threshold_classify__str(thresh));
506                 }
507         }
508         if (!config->metric_only)
509                 fprintf(out, "}");
510 }
511
512 static void new_line_json(struct perf_stat_config *config, void *ctx)
513 {
514         struct outstate *os = ctx;
515
516         fputs("\n{", os->fh);
517         if (os->prefix)
518                 fprintf(os->fh, "%s", os->prefix);
519         aggr_printout(config, os->evsel, os->id, os->aggr_nr);
520 }
521
522 static void print_metricgroup_header_json(struct perf_stat_config *config,
523                                           void *ctx,
524                                           const char *metricgroup_name)
525 {
526         if (!metricgroup_name)
527                 return;
528
529         fprintf(config->output, "\"metricgroup\" : \"%s\"}", metricgroup_name);
530         new_line_json(config, ctx);
531 }
532
533 static void print_metricgroup_header_csv(struct perf_stat_config *config,
534                                          void *ctx,
535                                          const char *metricgroup_name)
536 {
537         struct outstate *os = ctx;
538         int i;
539
540         if (!metricgroup_name) {
541                 /* Leave space for running and enabling */
542                 for (i = 0; i < os->nfields - 2; i++)
543                         fputs(config->csv_sep, os->fh);
544                 return;
545         }
546
547         for (i = 0; i < os->nfields; i++)
548                 fputs(config->csv_sep, os->fh);
549         fprintf(config->output, "%s", metricgroup_name);
550         new_line_csv(config, ctx);
551 }
552
553 static void print_metricgroup_header_std(struct perf_stat_config *config,
554                                          void *ctx,
555                                          const char *metricgroup_name)
556 {
557         struct outstate *os = ctx;
558         int n;
559
560         if (!metricgroup_name) {
561                 __new_line_std(os);
562                 return;
563         }
564
565         n = fprintf(config->output, " %*s", EVNAME_LEN, metricgroup_name);
566
567         fprintf(config->output, "%*s", MGROUP_LEN - n - 1, "");
568 }
569
570 /* Filter out some columns that don't work well in metrics only mode */
571
572 static bool valid_only_metric(const char *unit)
573 {
574         if (!unit)
575                 return false;
576         if (strstr(unit, "/sec") ||
577             strstr(unit, "CPUs utilized"))
578                 return false;
579         return true;
580 }
581
582 static const char *fixunit(char *buf, struct evsel *evsel,
583                            const char *unit)
584 {
585         if (!strncmp(unit, "of all", 6)) {
586                 snprintf(buf, 1024, "%s %s", evsel__name(evsel),
587                          unit);
588                 return buf;
589         }
590         return unit;
591 }
592
593 static void print_metric_only(struct perf_stat_config *config,
594                               void *ctx, enum metric_threshold_classify thresh,
595                               const char *fmt, const char *unit, double val)
596 {
597         struct outstate *os = ctx;
598         FILE *out = os->fh;
599         char buf[1024], str[1024];
600         unsigned mlen = config->metric_only_len;
601         const char *color = metric_threshold_classify__color(thresh);
602
603         if (!valid_only_metric(unit))
604                 return;
605         unit = fixunit(buf, os->evsel, unit);
606         if (mlen < strlen(unit))
607                 mlen = strlen(unit) + 1;
608
609         if (color)
610                 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
611
612         color_snprintf(str, sizeof(str), color ?: "", fmt ?: "", val);
613         fprintf(out, "%*s ", mlen, str);
614         os->first = false;
615 }
616
617 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
618                                   void *ctx,
619                                   enum metric_threshold_classify thresh __maybe_unused,
620                                   const char *fmt,
621                                   const char *unit, double val)
622 {
623         struct outstate *os = ctx;
624         FILE *out = os->fh;
625         char buf[64], *vals, *ends;
626         char tbuf[1024];
627
628         if (!valid_only_metric(unit))
629                 return;
630         unit = fixunit(tbuf, os->evsel, unit);
631         snprintf(buf, sizeof(buf), fmt ?: "", val);
632         ends = vals = skip_spaces(buf);
633         while (isdigit(*ends) || *ends == '.')
634                 ends++;
635         *ends = 0;
636         fprintf(out, "%s%s", vals, config->csv_sep);
637         os->first = false;
638 }
639
640 static void print_metric_only_json(struct perf_stat_config *config __maybe_unused,
641                                   void *ctx,
642                                   enum metric_threshold_classify thresh __maybe_unused,
643                                   const char *fmt,
644                                   const char *unit, double val)
645 {
646         struct outstate *os = ctx;
647         FILE *out = os->fh;
648         char buf[64], *ends;
649         char tbuf[1024];
650         const char *vals;
651
652         if (!valid_only_metric(unit))
653                 return;
654         unit = fixunit(tbuf, os->evsel, unit);
655         if (!unit[0])
656                 return;
657         snprintf(buf, sizeof(buf), fmt ?: "", val);
658         vals = ends = skip_spaces(buf);
659         while (isdigit(*ends) || *ends == '.')
660                 ends++;
661         *ends = 0;
662         if (!vals[0])
663                 vals = "none";
664         fprintf(out, "%s\"%s\" : \"%s\"", os->first ? "" : ", ", unit, vals);
665         os->first = false;
666 }
667
668 static void new_line_metric(struct perf_stat_config *config __maybe_unused,
669                             void *ctx __maybe_unused)
670 {
671 }
672
673 static void print_metric_header(struct perf_stat_config *config,
674                                 void *ctx,
675                                 enum metric_threshold_classify thresh __maybe_unused,
676                                 const char *fmt __maybe_unused,
677                                 const char *unit, double val __maybe_unused)
678 {
679         struct outstate *os = ctx;
680         char tbuf[1024];
681
682         /* In case of iostat, print metric header for first root port only */
683         if (config->iostat_run &&
684             os->evsel->priv != os->evsel->evlist->selected->priv)
685                 return;
686
687         if (os->evsel->cgrp != os->cgrp)
688                 return;
689
690         if (!valid_only_metric(unit))
691                 return;
692         unit = fixunit(tbuf, os->evsel, unit);
693
694         if (config->json_output)
695                 return;
696         else if (config->csv_output)
697                 fprintf(os->fh, "%s%s", unit, config->csv_sep);
698         else
699                 fprintf(os->fh, "%*s ", config->metric_only_len, unit);
700 }
701
702 static void print_counter_value_std(struct perf_stat_config *config,
703                                     struct evsel *evsel, double avg, bool ok)
704 {
705         FILE *output = config->output;
706         double sc =  evsel->scale;
707         const char *fmt;
708         const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
709
710         if (config->big_num)
711                 fmt = floor(sc) != sc ? "%'*.2f " : "%'*.0f ";
712         else
713                 fmt = floor(sc) != sc ? "%*.2f " : "%*.0f ";
714
715         if (ok)
716                 fprintf(output, fmt, COUNTS_LEN, avg);
717         else
718                 fprintf(output, "%*s ", COUNTS_LEN, bad_count);
719
720         if (evsel->unit)
721                 fprintf(output, "%-*s ", config->unit_width, evsel->unit);
722
723         fprintf(output, "%-*s", EVNAME_LEN, evsel__name(evsel));
724 }
725
726 static void print_counter_value_csv(struct perf_stat_config *config,
727                                     struct evsel *evsel, double avg, bool ok)
728 {
729         FILE *output = config->output;
730         double sc =  evsel->scale;
731         const char *sep = config->csv_sep;
732         const char *fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
733         const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
734
735         if (ok)
736                 fprintf(output, fmt, avg, sep);
737         else
738                 fprintf(output, "%s%s", bad_count, sep);
739
740         if (evsel->unit)
741                 fprintf(output, "%s%s", evsel->unit, sep);
742
743         fprintf(output, "%s", evsel__name(evsel));
744 }
745
746 static void print_counter_value_json(struct perf_stat_config *config,
747                                      struct evsel *evsel, double avg, bool ok)
748 {
749         FILE *output = config->output;
750         const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED;
751
752         if (ok)
753                 fprintf(output, "\"counter-value\" : \"%f\", ", avg);
754         else
755                 fprintf(output, "\"counter-value\" : \"%s\", ", bad_count);
756
757         if (evsel->unit)
758                 fprintf(output, "\"unit\" : \"%s\", ", evsel->unit);
759
760         fprintf(output, "\"event\" : \"%s\", ", evsel__name(evsel));
761 }
762
763 static void print_counter_value(struct perf_stat_config *config,
764                                 struct evsel *evsel, double avg, bool ok)
765 {
766         if (config->json_output)
767                 print_counter_value_json(config, evsel, avg, ok);
768         else if (config->csv_output)
769                 print_counter_value_csv(config, evsel, avg, ok);
770         else
771                 print_counter_value_std(config, evsel, avg, ok);
772 }
773
774 static void abs_printout(struct perf_stat_config *config,
775                          struct aggr_cpu_id id, int aggr_nr,
776                          struct evsel *evsel, double avg, bool ok)
777 {
778         aggr_printout(config, evsel, id, aggr_nr);
779         print_counter_value(config, evsel, avg, ok);
780         print_cgroup(config, evsel->cgrp);
781 }
782
783 static bool is_mixed_hw_group(struct evsel *counter)
784 {
785         struct evlist *evlist = counter->evlist;
786         u32 pmu_type = counter->core.attr.type;
787         struct evsel *pos;
788
789         if (counter->core.nr_members < 2)
790                 return false;
791
792         evlist__for_each_entry(evlist, pos) {
793                 /* software events can be part of any hardware group */
794                 if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
795                         continue;
796                 if (pmu_type == PERF_TYPE_SOFTWARE) {
797                         pmu_type = pos->core.attr.type;
798                         continue;
799                 }
800                 if (pmu_type != pos->core.attr.type)
801                         return true;
802         }
803
804         return false;
805 }
806
807 static bool evlist__has_hybrid(struct evlist *evlist)
808 {
809         struct evsel *evsel;
810
811         if (perf_pmus__num_core_pmus() == 1)
812                 return false;
813
814         evlist__for_each_entry(evlist, evsel) {
815                 if (evsel->core.is_pmu_core)
816                         return true;
817         }
818
819         return false;
820 }
821
822 static void printout(struct perf_stat_config *config, struct outstate *os,
823                      double uval, u64 run, u64 ena, double noise, int aggr_idx)
824 {
825         struct perf_stat_output_ctx out;
826         print_metric_t pm;
827         new_line_t nl;
828         print_metricgroup_header_t pmh;
829         bool ok = true;
830         struct evsel *counter = os->evsel;
831
832         if (config->csv_output) {
833                 pm = config->metric_only ? print_metric_only_csv : print_metric_csv;
834                 nl = config->metric_only ? new_line_metric : new_line_csv;
835                 pmh = print_metricgroup_header_csv;
836                 os->nfields = 4 + (counter->cgrp ? 1 : 0);
837         } else if (config->json_output) {
838                 pm = config->metric_only ? print_metric_only_json : print_metric_json;
839                 nl = config->metric_only ? new_line_metric : new_line_json;
840                 pmh = print_metricgroup_header_json;
841         } else {
842                 pm = config->metric_only ? print_metric_only : print_metric_std;
843                 nl = config->metric_only ? new_line_metric : new_line_std;
844                 pmh = print_metricgroup_header_std;
845         }
846
847         if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
848                 if (config->metric_only) {
849                         pm(config, os, METRIC_THRESHOLD_UNKNOWN, "", "", 0);
850                         return;
851                 }
852
853                 ok = false;
854
855                 if (counter->supported) {
856                         if (!evlist__has_hybrid(counter->evlist)) {
857                                 config->print_free_counters_hint = 1;
858                                 if (is_mixed_hw_group(counter))
859                                         config->print_mixed_hw_group_error = 1;
860                         }
861                 }
862         }
863
864         out.print_metric = pm;
865         out.new_line = nl;
866         out.print_metricgroup_header = pmh;
867         out.ctx = os;
868         out.force_header = false;
869
870         if (!config->metric_only && !counter->default_metricgroup) {
871                 abs_printout(config, os->id, os->aggr_nr, counter, uval, ok);
872
873                 print_noise(config, counter, noise, /*before_metric=*/true);
874                 print_running(config, run, ena, /*before_metric=*/true);
875         }
876
877         if (ok) {
878                 if (!config->metric_only && counter->default_metricgroup) {
879                         void *from = NULL;
880
881                         aggr_printout(config, os->evsel, os->id, os->aggr_nr);
882                         /* Print out all the metricgroup with the same metric event. */
883                         do {
884                                 int num = 0;
885
886                                 /* Print out the new line for the next new metricgroup. */
887                                 if (from) {
888                                         if (config->json_output)
889                                                 new_line_json(config, (void *)os);
890                                         else
891                                                 __new_line_std_csv(config, os);
892                                 }
893
894                                 print_noise(config, counter, noise, /*before_metric=*/true);
895                                 print_running(config, run, ena, /*before_metric=*/true);
896                                 from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx,
897                                                                                  &num, from, &out,
898                                                                                  &config->metric_events);
899                         } while (from != NULL);
900                 } else
901                         perf_stat__print_shadow_stats(config, counter, uval, aggr_idx,
902                                                       &out, &config->metric_events);
903         } else {
904                 pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/"", /*val=*/0);
905         }
906
907         if (!config->metric_only) {
908                 print_noise(config, counter, noise, /*before_metric=*/false);
909                 print_running(config, run, ena, /*before_metric=*/false);
910         }
911 }
912
913 static void uniquify_event_name(struct evsel *counter)
914 {
915         const char *name, *pmu_name;
916         char *new_name, *config;
917         int ret;
918
919         /* The evsel was already uniquified. */
920         if (counter->uniquified_name)
921                 return;
922
923         /* Avoid checking to uniquify twice. */
924         counter->uniquified_name = true;
925
926         /* The evsel has a "name=" config term or is from libpfm. */
927         if (counter->use_config_name || counter->is_libpfm_event)
928                 return;
929
930         /* Legacy no PMU event, don't uniquify. */
931         if  (!counter->pmu ||
932              (counter->pmu->type < PERF_TYPE_MAX && counter->pmu->type != PERF_TYPE_RAW))
933                 return;
934
935         /* A sysfs or json event replacing a legacy event, don't uniquify. */
936         if (counter->pmu->is_core && counter->alternate_hw_config != PERF_COUNT_HW_MAX)
937                 return;
938
939         name = evsel__name(counter);
940         pmu_name = counter->pmu->name;
941         /* Already prefixed by the PMU name. */
942         if (!strncmp(name, pmu_name, strlen(pmu_name)))
943                 return;
944
945         config = strchr(name, '/');
946         if (config) {
947                 int len = config - name;
948
949                 if (config[1] == '/') {
950                         /* case: event// */
951                         ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 2);
952                 } else {
953                         /* case: event/.../ */
954                         ret = asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config + 1);
955                 }
956         } else {
957                 config = strchr(name, ':');
958                 if (config) {
959                         /* case: event:.. */
960                         int len = config - name;
961
962                         ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 1);
963                 } else {
964                         /* case: event */
965                         ret = asprintf(&new_name, "%s/%s/", pmu_name, name);
966                 }
967         }
968         if (ret > 0) {
969                 free(counter->name);
970                 counter->name = new_name;
971         } else {
972                 /* ENOMEM from asprintf. */
973                 counter->uniquified_name = false;
974         }
975 }
976
977 static bool hybrid_uniquify(struct evsel *evsel, struct perf_stat_config *config)
978 {
979         return evsel__is_hybrid(evsel) && !config->hybrid_merge;
980 }
981
982 static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter)
983 {
984         if (config->aggr_mode == AGGR_NONE || hybrid_uniquify(counter, config))
985                 uniquify_event_name(counter);
986 }
987
988 /**
989  * should_skip_zero_count() - Check if the event should print 0 values.
990  * @config: The perf stat configuration (including aggregation mode).
991  * @counter: The evsel with its associated cpumap.
992  * @id: The aggregation id that is being queried.
993  *
994  * Due to mismatch between the event cpumap or thread-map and the
995  * aggregation mode, sometimes it'd iterate the counter with the map
996  * which does not contain any values.
997  *
998  * For example, uncore events have dedicated CPUs to manage them,
999  * result for other CPUs should be zero and skipped.
1000  *
1001  * Return: %true if the value should NOT be printed, %false if the value
1002  * needs to be printed like "<not counted>" or "<not supported>".
1003  */
1004 static bool should_skip_zero_counter(struct perf_stat_config *config,
1005                                      struct evsel *counter,
1006                                      const struct aggr_cpu_id *id)
1007 {
1008         struct perf_cpu cpu;
1009         int idx;
1010
1011         /*
1012          * Skip unsupported default events when not verbose. (default events
1013          * are all marked 'skippable').
1014          */
1015         if (verbose == 0 && counter->skippable && !counter->supported)
1016                 return true;
1017
1018         /*
1019          * Skip value 0 when enabling --per-thread globally,
1020          * otherwise it will have too many 0 output.
1021          */
1022         if (config->aggr_mode == AGGR_THREAD && config->system_wide)
1023                 return true;
1024
1025         /*
1026          * Many tool events are only gathered on the first index, skip other
1027          * zero values.
1028          */
1029         if (evsel__is_tool(counter)) {
1030                 struct aggr_cpu_id own_id =
1031                         config->aggr_get_id(config, (struct perf_cpu){ .cpu = 0 });
1032
1033                 return !aggr_cpu_id__equal(id, &own_id);
1034         }
1035
1036         /*
1037          * Skip value 0 when it's an uncore event and the given aggr id
1038          * does not belong to the PMU cpumask.
1039          */
1040         if (!counter->pmu || !counter->pmu->is_uncore)
1041                 return false;
1042
1043         perf_cpu_map__for_each_cpu(cpu, idx, counter->pmu->cpus) {
1044                 struct aggr_cpu_id own_id = config->aggr_get_id(config, cpu);
1045
1046                 if (aggr_cpu_id__equal(id, &own_id))
1047                         return false;
1048         }
1049         return true;
1050 }
1051
1052 static void print_counter_aggrdata(struct perf_stat_config *config,
1053                                    struct evsel *counter, int aggr_idx,
1054                                    struct outstate *os)
1055 {
1056         FILE *output = config->output;
1057         u64 ena, run, val;
1058         double uval;
1059         struct perf_stat_evsel *ps = counter->stats;
1060         struct perf_stat_aggr *aggr = &ps->aggr[aggr_idx];
1061         struct aggr_cpu_id id = config->aggr_map->map[aggr_idx];
1062         double avg = aggr->counts.val;
1063         bool metric_only = config->metric_only;
1064
1065         os->id = id;
1066         os->aggr_nr = aggr->nr;
1067         os->evsel = counter;
1068
1069         /* Skip already merged uncore/hybrid events */
1070         if (counter->merged_stat)
1071                 return;
1072
1073         uniquify_counter(config, counter);
1074
1075         val = aggr->counts.val;
1076         ena = aggr->counts.ena;
1077         run = aggr->counts.run;
1078
1079         if (perf_stat__skip_metric_event(counter, &config->metric_events, ena, run))
1080                 return;
1081
1082         if (val == 0 && should_skip_zero_counter(config, counter, &id))
1083                 return;
1084
1085         if (!metric_only) {
1086                 if (config->json_output)
1087                         fputc('{', output);
1088                 if (os->prefix)
1089                         fprintf(output, "%s", os->prefix);
1090                 else if (config->summary && config->csv_output &&
1091                          !config->no_csv_summary && !config->interval)
1092                         fprintf(output, "%s%s", "summary", config->csv_sep);
1093         }
1094
1095         uval = val * counter->scale;
1096
1097         printout(config, os, uval, run, ena, avg, aggr_idx);
1098
1099         if (!metric_only)
1100                 fputc('\n', output);
1101 }
1102
1103 static void print_metric_begin(struct perf_stat_config *config,
1104                                struct evlist *evlist,
1105                                struct outstate *os, int aggr_idx)
1106 {
1107         struct perf_stat_aggr *aggr;
1108         struct aggr_cpu_id id;
1109         struct evsel *evsel;
1110
1111         os->first = true;
1112         if (!config->metric_only)
1113                 return;
1114
1115         if (config->json_output)
1116                 fputc('{', config->output);
1117         if (os->prefix)
1118                 fprintf(config->output, "%s", os->prefix);
1119
1120         evsel = evlist__first(evlist);
1121         id = config->aggr_map->map[aggr_idx];
1122         aggr = &evsel->stats->aggr[aggr_idx];
1123         aggr_printout(config, evsel, id, aggr->nr);
1124
1125         print_cgroup(config, os->cgrp ? : evsel->cgrp);
1126 }
1127
1128 static void print_metric_end(struct perf_stat_config *config, struct outstate *os)
1129 {
1130         FILE *output = config->output;
1131
1132         if (!config->metric_only)
1133                 return;
1134
1135         if (config->json_output) {
1136                 if (os->first)
1137                         fputs("\"metric-value\" : \"none\"", output);
1138                 fputc('}', output);
1139         }
1140         fputc('\n', output);
1141 }
1142
1143 static void print_aggr(struct perf_stat_config *config,
1144                        struct evlist *evlist,
1145                        struct outstate *os)
1146 {
1147         struct evsel *counter;
1148         int aggr_idx;
1149
1150         if (!config->aggr_map || !config->aggr_get_id)
1151                 return;
1152
1153         /*
1154          * With metric_only everything is on a single line.
1155          * Without each counter has its own line.
1156          */
1157         cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1158                 print_metric_begin(config, evlist, os, aggr_idx);
1159
1160                 evlist__for_each_entry(evlist, counter) {
1161                         print_counter_aggrdata(config, counter, aggr_idx, os);
1162                 }
1163                 print_metric_end(config, os);
1164         }
1165 }
1166
1167 static void print_aggr_cgroup(struct perf_stat_config *config,
1168                               struct evlist *evlist,
1169                               struct outstate *os)
1170 {
1171         struct evsel *counter, *evsel;
1172         int aggr_idx;
1173
1174         if (!config->aggr_map || !config->aggr_get_id)
1175                 return;
1176
1177         evlist__for_each_entry(evlist, evsel) {
1178                 if (os->cgrp == evsel->cgrp)
1179                         continue;
1180
1181                 os->cgrp = evsel->cgrp;
1182
1183                 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1184                         print_metric_begin(config, evlist, os, aggr_idx);
1185
1186                         evlist__for_each_entry(evlist, counter) {
1187                                 if (counter->cgrp != os->cgrp)
1188                                         continue;
1189
1190                                 print_counter_aggrdata(config, counter, aggr_idx, os);
1191                         }
1192                         print_metric_end(config, os);
1193                 }
1194         }
1195 }
1196
1197 static void print_counter(struct perf_stat_config *config,
1198                           struct evsel *counter, struct outstate *os)
1199 {
1200         int aggr_idx;
1201
1202         /* AGGR_THREAD doesn't have config->aggr_get_id */
1203         if (!config->aggr_map)
1204                 return;
1205
1206         cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1207                 print_counter_aggrdata(config, counter, aggr_idx, os);
1208         }
1209 }
1210
1211 static void print_no_aggr_metric(struct perf_stat_config *config,
1212                                  struct evlist *evlist,
1213                                  struct outstate *os)
1214 {
1215         int all_idx;
1216         struct perf_cpu cpu;
1217
1218         perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.user_requested_cpus) {
1219                 struct evsel *counter;
1220                 bool first = true;
1221
1222                 evlist__for_each_entry(evlist, counter) {
1223                         u64 ena, run, val;
1224                         double uval;
1225                         struct perf_stat_evsel *ps = counter->stats;
1226                         int aggr_idx = 0;
1227
1228                         if (!perf_cpu_map__has(evsel__cpus(counter), cpu))
1229                                 continue;
1230
1231                         cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1232                                 if (config->aggr_map->map[aggr_idx].cpu.cpu == cpu.cpu)
1233                                         break;
1234                         }
1235
1236                         os->evsel = counter;
1237                         os->id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
1238                         if (first) {
1239                                 print_metric_begin(config, evlist, os, aggr_idx);
1240                                 first = false;
1241                         }
1242                         val = ps->aggr[aggr_idx].counts.val;
1243                         ena = ps->aggr[aggr_idx].counts.ena;
1244                         run = ps->aggr[aggr_idx].counts.run;
1245
1246                         uval = val * counter->scale;
1247                         printout(config, os, uval, run, ena, 1.0, aggr_idx);
1248                 }
1249                 if (!first)
1250                         print_metric_end(config, os);
1251         }
1252 }
1253
1254 static void print_metric_headers_std(struct perf_stat_config *config,
1255                                      bool no_indent)
1256 {
1257         fputc(' ', config->output);
1258
1259         if (!no_indent) {
1260                 int len = aggr_header_lens[config->aggr_mode];
1261
1262                 if (nr_cgroups || config->cgroup_list)
1263                         len += CGROUP_LEN + 1;
1264
1265                 fprintf(config->output, "%*s", len, "");
1266         }
1267 }
1268
1269 static void print_metric_headers_csv(struct perf_stat_config *config,
1270                                      bool no_indent __maybe_unused)
1271 {
1272         const char *p;
1273
1274         if (config->interval)
1275                 fprintf(config->output, "time%s", config->csv_sep);
1276         if (config->iostat_run)
1277                 return;
1278
1279         p = aggr_header_csv[config->aggr_mode];
1280         while (*p) {
1281                 if (*p == ',')
1282                         fputs(config->csv_sep, config->output);
1283                 else
1284                         fputc(*p, config->output);
1285                 p++;
1286         }
1287 }
1288
1289 static void print_metric_headers_json(struct perf_stat_config *config __maybe_unused,
1290                                       bool no_indent __maybe_unused)
1291 {
1292 }
1293
1294 static void print_metric_headers(struct perf_stat_config *config,
1295                                  struct evlist *evlist, bool no_indent)
1296 {
1297         struct evsel *counter;
1298         struct outstate os = {
1299                 .fh = config->output
1300         };
1301         struct perf_stat_output_ctx out = {
1302                 .ctx = &os,
1303                 .print_metric = print_metric_header,
1304                 .new_line = new_line_metric,
1305                 .force_header = true,
1306         };
1307
1308         if (config->json_output)
1309                 print_metric_headers_json(config, no_indent);
1310         else if (config->csv_output)
1311                 print_metric_headers_csv(config, no_indent);
1312         else
1313                 print_metric_headers_std(config, no_indent);
1314
1315         if (config->iostat_run)
1316                 iostat_print_header_prefix(config);
1317
1318         if (config->cgroup_list)
1319                 os.cgrp = evlist__first(evlist)->cgrp;
1320
1321         /* Print metrics headers only */
1322         evlist__for_each_entry(evlist, counter) {
1323                 if (!config->iostat_run &&
1324                     config->aggr_mode != AGGR_NONE && counter->metric_leader != counter)
1325                         continue;
1326
1327                 os.evsel = counter;
1328
1329                 perf_stat__print_shadow_stats(config, counter, 0,
1330                                               0,
1331                                               &out,
1332                                               &config->metric_events);
1333         }
1334
1335         if (!config->json_output)
1336                 fputc('\n', config->output);
1337 }
1338
1339 static void prepare_interval(struct perf_stat_config *config,
1340                              char *prefix, size_t len, struct timespec *ts)
1341 {
1342         if (config->iostat_run)
1343                 return;
1344
1345         if (config->json_output)
1346                 scnprintf(prefix, len, "\"interval\" : %lu.%09lu, ",
1347                           (unsigned long) ts->tv_sec, ts->tv_nsec);
1348         else if (config->csv_output)
1349                 scnprintf(prefix, len, "%lu.%09lu%s",
1350                           (unsigned long) ts->tv_sec, ts->tv_nsec, config->csv_sep);
1351         else
1352                 scnprintf(prefix, len, "%6lu.%09lu ",
1353                           (unsigned long) ts->tv_sec, ts->tv_nsec);
1354 }
1355
1356 static void print_header_interval_std(struct perf_stat_config *config,
1357                                       struct target *_target __maybe_unused,
1358                                       struct evlist *evlist,
1359                                       int argc __maybe_unused,
1360                                       const char **argv __maybe_unused)
1361 {
1362         FILE *output = config->output;
1363
1364         switch (config->aggr_mode) {
1365         case AGGR_NODE:
1366         case AGGR_SOCKET:
1367         case AGGR_DIE:
1368         case AGGR_CLUSTER:
1369         case AGGR_CACHE:
1370         case AGGR_CORE:
1371                 fprintf(output, "#%*s %-*s cpus",
1372                         INTERVAL_LEN - 1, "time",
1373                         aggr_header_lens[config->aggr_mode],
1374                         aggr_header_std[config->aggr_mode]);
1375                 break;
1376         case AGGR_NONE:
1377                 fprintf(output, "#%*s %-*s",
1378                         INTERVAL_LEN - 1, "time",
1379                         aggr_header_lens[config->aggr_mode],
1380                         aggr_header_std[config->aggr_mode]);
1381                 break;
1382         case AGGR_THREAD:
1383                 fprintf(output, "#%*s %*s-%-*s",
1384                         INTERVAL_LEN - 1, "time",
1385                         COMM_LEN, "comm", PID_LEN, "pid");
1386                 break;
1387         case AGGR_GLOBAL:
1388         default:
1389                 if (!config->iostat_run)
1390                         fprintf(output, "#%*s",
1391                                 INTERVAL_LEN - 1, "time");
1392         case AGGR_UNSET:
1393         case AGGR_MAX:
1394                 break;
1395         }
1396
1397         if (config->metric_only)
1398                 print_metric_headers(config, evlist, true);
1399         else
1400                 fprintf(output, " %*s %*s events\n",
1401                         COUNTS_LEN, "counts", config->unit_width, "unit");
1402 }
1403
1404 static void print_header_std(struct perf_stat_config *config,
1405                              struct target *_target, struct evlist *evlist,
1406                              int argc, const char **argv)
1407 {
1408         FILE *output = config->output;
1409         int i;
1410
1411         fprintf(output, "\n");
1412         fprintf(output, " Performance counter stats for ");
1413         if (_target->bpf_str)
1414                 fprintf(output, "\'BPF program(s) %s", _target->bpf_str);
1415         else if (_target->system_wide)
1416                 fprintf(output, "\'system wide");
1417         else if (_target->cpu_list)
1418                 fprintf(output, "\'CPU(s) %s", _target->cpu_list);
1419         else if (!target__has_task(_target)) {
1420                 fprintf(output, "\'%s", argv ? argv[0] : "pipe");
1421                 for (i = 1; argv && (i < argc); i++)
1422                         fprintf(output, " %s", argv[i]);
1423         } else if (_target->pid)
1424                 fprintf(output, "process id \'%s", _target->pid);
1425         else
1426                 fprintf(output, "thread id \'%s", _target->tid);
1427
1428         fprintf(output, "\'");
1429         if (config->run_count > 1)
1430                 fprintf(output, " (%d runs)", config->run_count);
1431         fprintf(output, ":\n\n");
1432
1433         if (config->metric_only)
1434                 print_metric_headers(config, evlist, false);
1435 }
1436
1437 static void print_header_csv(struct perf_stat_config *config,
1438                              struct target *_target __maybe_unused,
1439                              struct evlist *evlist,
1440                              int argc __maybe_unused,
1441                              const char **argv __maybe_unused)
1442 {
1443         if (config->metric_only)
1444                 print_metric_headers(config, evlist, true);
1445 }
1446 static void print_header_json(struct perf_stat_config *config,
1447                               struct target *_target __maybe_unused,
1448                               struct evlist *evlist,
1449                               int argc __maybe_unused,
1450                               const char **argv __maybe_unused)
1451 {
1452         if (config->metric_only)
1453                 print_metric_headers(config, evlist, true);
1454 }
1455
1456 static void print_header(struct perf_stat_config *config,
1457                          struct target *_target,
1458                          struct evlist *evlist,
1459                          int argc, const char **argv)
1460 {
1461         static int num_print_iv;
1462
1463         fflush(stdout);
1464
1465         if (config->interval_clear)
1466                 puts(CONSOLE_CLEAR);
1467
1468         if (num_print_iv == 0 || config->interval_clear) {
1469                 if (config->json_output)
1470                         print_header_json(config, _target, evlist, argc, argv);
1471                 else if (config->csv_output)
1472                         print_header_csv(config, _target, evlist, argc, argv);
1473                 else if (config->interval)
1474                         print_header_interval_std(config, _target, evlist, argc, argv);
1475                 else
1476                         print_header_std(config, _target, evlist, argc, argv);
1477         }
1478
1479         if (num_print_iv++ == 25)
1480                 num_print_iv = 0;
1481 }
1482
1483 static int get_precision(double num)
1484 {
1485         if (num > 1)
1486                 return 0;
1487
1488         return lround(ceil(-log10(num)));
1489 }
1490
1491 static void print_table(struct perf_stat_config *config,
1492                         FILE *output, int precision, double avg)
1493 {
1494         char tmp[64];
1495         int idx, indent = 0;
1496
1497         scnprintf(tmp, 64, " %17.*f", precision, avg);
1498         while (tmp[indent] == ' ')
1499                 indent++;
1500
1501         fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1502
1503         for (idx = 0; idx < config->run_count; idx++) {
1504                 double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
1505                 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1506
1507                 fprintf(output, " %17.*f (%+.*f) ",
1508                         precision, run, precision, run - avg);
1509
1510                 for (h = 0; h < n; h++)
1511                         fprintf(output, "#");
1512
1513                 fprintf(output, "\n");
1514         }
1515
1516         fprintf(output, "\n%*s# Final result:\n", indent, "");
1517 }
1518
1519 static double timeval2double(struct timeval *t)
1520 {
1521         return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1522 }
1523
1524 static void print_footer(struct perf_stat_config *config)
1525 {
1526         double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1527         FILE *output = config->output;
1528
1529         if (config->interval || config->csv_output || config->json_output)
1530                 return;
1531
1532         if (!config->null_run)
1533                 fprintf(output, "\n");
1534
1535         if (config->run_count == 1) {
1536                 fprintf(output, " %17.9f seconds time elapsed", avg);
1537
1538                 if (config->ru_display) {
1539                         double ru_utime = timeval2double(&config->ru_data.ru_utime);
1540                         double ru_stime = timeval2double(&config->ru_data.ru_stime);
1541
1542                         fprintf(output, "\n\n");
1543                         fprintf(output, " %17.9f seconds user\n", ru_utime);
1544                         fprintf(output, " %17.9f seconds sys\n", ru_stime);
1545                 }
1546         } else {
1547                 double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1548                 /*
1549                  * Display at most 2 more significant
1550                  * digits than the stddev inaccuracy.
1551                  */
1552                 int precision = get_precision(sd) + 2;
1553
1554                 if (config->walltime_run_table)
1555                         print_table(config, output, precision, avg);
1556
1557                 fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1558                         precision, avg, precision, sd);
1559
1560                 print_noise_pct(config, sd, avg, /*before_metric=*/false);
1561         }
1562         fprintf(output, "\n\n");
1563
1564         if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled())
1565                 fprintf(output,
1566 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1567 "       echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1568 "       perf stat ...\n"
1569 "       echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1570
1571         if (config->print_mixed_hw_group_error)
1572                 fprintf(output,
1573                         "The events in group usually have to be from "
1574                         "the same PMU. Try reorganizing the group.\n");
1575 }
1576
1577 static void print_percore(struct perf_stat_config *config,
1578                           struct evsel *counter, struct outstate *os)
1579 {
1580         bool metric_only = config->metric_only;
1581         FILE *output = config->output;
1582         struct cpu_aggr_map *core_map;
1583         int aggr_idx, core_map_len = 0;
1584
1585         if (!config->aggr_map || !config->aggr_get_id)
1586                 return;
1587
1588         if (config->percore_show_thread)
1589                 return print_counter(config, counter, os);
1590
1591         /*
1592          * core_map will hold the aggr_cpu_id for the cores that have been
1593          * printed so that each core is printed just once.
1594          */
1595         core_map = cpu_aggr_map__empty_new(config->aggr_map->nr);
1596         if (core_map == NULL) {
1597                 fprintf(output, "Cannot allocate per-core aggr map for display\n");
1598                 return;
1599         }
1600
1601         cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) {
1602                 struct perf_cpu curr_cpu = config->aggr_map->map[aggr_idx].cpu;
1603                 struct aggr_cpu_id core_id = aggr_cpu_id__core(curr_cpu, NULL);
1604                 bool found = false;
1605
1606                 for (int i = 0; i < core_map_len; i++) {
1607                         if (aggr_cpu_id__equal(&core_map->map[i], &core_id)) {
1608                                 found = true;
1609                                 break;
1610                         }
1611                 }
1612                 if (found)
1613                         continue;
1614
1615                 print_counter_aggrdata(config, counter, aggr_idx, os);
1616
1617                 core_map->map[core_map_len++] = core_id;
1618         }
1619         free(core_map);
1620
1621         if (metric_only)
1622                 fputc('\n', output);
1623 }
1624
1625 static void print_cgroup_counter(struct perf_stat_config *config, struct evlist *evlist,
1626                                  struct outstate *os)
1627 {
1628         struct evsel *counter;
1629
1630         evlist__for_each_entry(evlist, counter) {
1631                 if (os->cgrp != counter->cgrp) {
1632                         if (os->cgrp != NULL)
1633                                 print_metric_end(config, os);
1634
1635                         os->cgrp = counter->cgrp;
1636                         print_metric_begin(config, evlist, os, /*aggr_idx=*/0);
1637                 }
1638
1639                 print_counter(config, counter, os);
1640         }
1641         if (os->cgrp)
1642                 print_metric_end(config, os);
1643 }
1644
1645 static void disable_uniquify(struct evlist *evlist)
1646 {
1647         struct evsel *counter;
1648         struct perf_pmu *last_pmu = NULL;
1649         bool first = true;
1650
1651         evlist__for_each_entry(evlist, counter) {
1652                 /* If PMUs vary then uniquify can be useful. */
1653                 if (!first && counter->pmu != last_pmu)
1654                         return;
1655                 first = false;
1656                 if (counter->pmu) {
1657                         /* Allow uniquify for uncore PMUs. */
1658                         if (!counter->pmu->is_core)
1659                                 return;
1660                         /* Keep hybrid event names uniquified for clarity. */
1661                         if (perf_pmus__num_core_pmus() > 1)
1662                                 return;
1663                 }
1664         }
1665         evlist__for_each_entry_continue(evlist, counter) {
1666                 counter->uniquified_name = true;
1667         }
1668 }
1669
1670 void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
1671                             struct target *_target, struct timespec *ts,
1672                             int argc, const char **argv)
1673 {
1674         bool metric_only = config->metric_only;
1675         int interval = config->interval;
1676         struct evsel *counter;
1677         char buf[64];
1678         struct outstate os = {
1679                 .fh = config->output,
1680                 .first = true,
1681         };
1682
1683         disable_uniquify(evlist);
1684
1685         if (config->iostat_run)
1686                 evlist->selected = evlist__first(evlist);
1687
1688         if (interval) {
1689                 os.prefix = buf;
1690                 prepare_interval(config, buf, sizeof(buf), ts);
1691         }
1692
1693         print_header(config, _target, evlist, argc, argv);
1694
1695         switch (config->aggr_mode) {
1696         case AGGR_CORE:
1697         case AGGR_CACHE:
1698         case AGGR_CLUSTER:
1699         case AGGR_DIE:
1700         case AGGR_SOCKET:
1701         case AGGR_NODE:
1702                 if (config->cgroup_list)
1703                         print_aggr_cgroup(config, evlist, &os);
1704                 else
1705                         print_aggr(config, evlist, &os);
1706                 break;
1707         case AGGR_THREAD:
1708         case AGGR_GLOBAL:
1709                 if (config->iostat_run) {
1710                         iostat_print_counters(evlist, config, ts, buf,
1711                                               (iostat_print_counter_t)print_counter, &os);
1712                 } else if (config->cgroup_list) {
1713                         print_cgroup_counter(config, evlist, &os);
1714                 } else {
1715                         print_metric_begin(config, evlist, &os, /*aggr_idx=*/0);
1716                         evlist__for_each_entry(evlist, counter) {
1717                                 print_counter(config, counter, &os);
1718                         }
1719                         print_metric_end(config, &os);
1720                 }
1721                 break;
1722         case AGGR_NONE:
1723                 if (metric_only)
1724                         print_no_aggr_metric(config, evlist, &os);
1725                 else {
1726                         evlist__for_each_entry(evlist, counter) {
1727                                 if (counter->percore)
1728                                         print_percore(config, counter, &os);
1729                                 else
1730                                         print_counter(config, counter, &os);
1731                         }
1732                 }
1733                 break;
1734         case AGGR_MAX:
1735         case AGGR_UNSET:
1736         default:
1737                 break;
1738         }
1739
1740         print_footer(config);
1741
1742         fflush(config->output);
1743 }
This page took 0.125647 seconds and 4 git commands to generate.