perf stat: Collapse identically named events
authorAndi Kleen <ak@linux.intel.com>
Mon, 20 Mar 2017 20:17:00 +0000 (13:17 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 21 Mar 2017 19:04:11 +0000 (16:04 -0300)
The uncore PMU has a lot of duplicated PMUs for different subsystems.
When expanding an uncore alias we usually end up with a large
number of identically named aliases, which makes perf stat
output difficult to read.

Automatically sum them up in perf stat, unless --no-merge is specified.

This can be default because only the uncores generally have duplicated
aliases. Other PMUs have unique names.

Before:

  % perf stat --no-merge -a -e unc_c_llc_lookup.any sleep 1

  Performance counter stats for 'system wide':

           694,976 Bytes unc_c_llc_lookup.any
           706,304 Bytes unc_c_llc_lookup.any
           956,608 Bytes unc_c_llc_lookup.any
           782,720 Bytes unc_c_llc_lookup.any
           605,696 Bytes unc_c_llc_lookup.any
           442,816 Bytes unc_c_llc_lookup.any
           659,328 Bytes unc_c_llc_lookup.any
           509,312 Bytes unc_c_llc_lookup.any
           263,936 Bytes unc_c_llc_lookup.any
           592,448 Bytes unc_c_llc_lookup.any
           672,448 Bytes unc_c_llc_lookup.any
           608,640 Bytes unc_c_llc_lookup.any
           641,024 Bytes unc_c_llc_lookup.any
           856,896 Bytes unc_c_llc_lookup.any
           808,832 Bytes unc_c_llc_lookup.any
           684,864 Bytes unc_c_llc_lookup.any
           710,464 Bytes unc_c_llc_lookup.any
           538,304 Bytes unc_c_llc_lookup.any

       1.002577660 seconds time elapsed

After:

  % perf stat -a -e unc_c_llc_lookup.any sleep 1

  Performance counter stats for 'system wide':

         2,685,120 Bytes unc_c_llc_lookup.any

       1.002648032 seconds time elapsed

v2: Split collect_aliases. Rename alias flag.
v3: Make sure unsupported/not counted is always printed.
v4: Factor out callback change into separate patch.
v5: Move check for bad results here
    Move merged check into collect_data

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/20170320201711.14142-3-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-stat.txt
tools/perf/builtin-stat.c
tools/perf/util/evsel.h

index 978548138624db3c0203f5d57d0a60e2f06aaafb..bd0e4417f2be63f892a870ec5ad60ae0fd5d9994 100644 (file)
@@ -236,6 +236,9 @@ To interpret the results it is usually needed to know on which
 CPUs the workload runs on. If needed the CPUs can be forced using
 taskset.
 
+--no-merge::
+Do not merge results from same PMUs.
+
 EXAMPLES
 --------
 
index 5c13a0f40adc04ae6abba9e06ecd4d60222a2d01..a4da10a506dd533acea6682d7054a0c0561ba3a1 100644 (file)
@@ -140,6 +140,7 @@ static unsigned int         unit_width                      = 4; /* strlen("unit") */
 static bool                    forever                         = false;
 static bool                    metric_only                     = false;
 static bool                    force_metric_only               = false;
+static bool                    no_merge                        = false;
 static struct timespec         ref_time;
 static struct cpu_map          *aggr_map;
 static aggr_get_id_t           aggr_get_id;
@@ -1182,12 +1183,37 @@ static void aggr_update_shadow(void)
        }
 }
 
-static void collect_data(struct perf_evsel *counter,
+static void collect_all_aliases(struct perf_evsel *counter,
                            void (*cb)(struct perf_evsel *counter, void *data,
                                       bool first),
                            void *data)
 {
+       struct perf_evsel *alias;
+
+       alias = list_prepare_entry(counter, &(evsel_list->entries), node);
+       list_for_each_entry_continue (alias, &evsel_list->entries, node) {
+               if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
+                   alias->scale != counter->scale ||
+                   alias->cgrp != counter->cgrp ||
+                   strcmp(alias->unit, counter->unit) ||
+                   nsec_counter(alias) != nsec_counter(counter))
+                       break;
+               alias->merged_stat = true;
+               cb(alias, data, false);
+       }
+}
+
+static bool collect_data(struct perf_evsel *counter,
+                           void (*cb)(struct perf_evsel *counter, void *data,
+                                      bool first),
+                           void *data)
+{
+       if (counter->merged_stat)
+               return false;
        cb(counter, data, true);
+       if (!no_merge)
+               collect_all_aliases(counter, cb, data);
+       return true;
 }
 
 struct aggr_data {
@@ -1245,7 +1271,8 @@ static void print_aggr(char *prefix)
                evlist__for_each_entry(evsel_list, counter) {
                        ad.val = ad.ena = ad.run = 0;
                        ad.nr = 0;
-                       collect_data(counter, aggr_cb, &ad);
+                       if (!collect_data(counter, aggr_cb, &ad))
+                               continue;
                        nr = ad.nr;
                        ena = ad.ena;
                        run = ad.run;
@@ -1318,7 +1345,8 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
        double uval;
        struct caggr_data cd = { .avg = 0.0 };
 
-       collect_data(counter, counter_aggr_cb, &cd);
+       if (!collect_data(counter, counter_aggr_cb, &cd))
+               return;
 
        if (prefix && !metric_only)
                fprintf(output, "%s", prefix);
@@ -1353,7 +1381,8 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
        for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
                struct aggr_data ad = { .cpu = cpu };
 
-               collect_data(counter, counter_cb, &ad);
+               if (!collect_data(counter, counter_cb, &ad))
+                       return;
                val = ad.val;
                ena = ad.ena;
                run = ad.run;
@@ -1701,6 +1730,7 @@ static const struct option stat_options[] = {
                    "list of cpus to monitor in system-wide"),
        OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
                    "disable CPU count aggregation", AGGR_NONE),
+       OPT_BOOLEAN(0, "no-merge", &no_merge, "Do not merge identical named events"),
        OPT_STRING('x', "field-separator", &csv_sep, "separator",
                   "print counts with custom separator"),
        OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
index 06ef6f29efa12a6c1300eca641e9446a0a4d17f8..bd2e9b112d49b1f1654db3de97f2d13ff593d693 100644 (file)
@@ -131,6 +131,7 @@ struct perf_evsel {
        bool                    cmdline_group_boundary;
        struct list_head        config_terms;
        int                     bpf_fd;
+       bool                    merged_stat;
 };
 
 union u64_swap {