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