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