perf stat: Fix group lookup for metric group
authorAndi Kleen <ak@linux.intel.com>
Mon, 24 Jun 2019 19:37:10 +0000 (12:37 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 2 Jul 2019 01:50:41 +0000 (22:50 -0300)
The metric group code tries to find a group it added earlier in the
evlist. Fix the lookup to handle groups with partially overlaps
correctly. When a sub string match fails and we reset the match, we have
to compare the first element again.

I also renamed the find_evsel function to find_evsel_group to make its
purpose clearer.

With the earlier changes this fixes:

Before:

  % perf stat -M UPI,IPC sleep 1
  ...
         1,032,922      uops_retired.retire_slots #      1.1 UPI
         1,896,096      inst_retired.any
         1,896,096      inst_retired.any
         1,177,254      cpu_clk_unhalted.thread

After:

  % perf stat -M UPI,IPC sleep 1
  ...
        1,013,193      uops_retired.retire_slots #      1.1 UPI
           932,033      inst_retired.any
           932,033      inst_retired.any          #      0.9 IPC
         1,091,245      cpu_clk_unhalted.thread

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Fixes: b18f3e365019 ("perf stat: Support JSON metrics in perf stat")
Link: http://lkml.kernel.org/r/20190624193711.35241-4-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/metricgroup.c

index 90cd84e..bc25995 100644 (file)
@@ -85,26 +85,49 @@ struct egroup {
        const char *metric_expr;
 };
 
-static struct perf_evsel *find_evsel(struct perf_evlist *perf_evlist,
-                                    const char **ids,
-                                    int idnum,
-                                    struct perf_evsel **metric_events)
+static bool record_evsel(int *ind, struct perf_evsel **start,
+                        int idnum,
+                        struct perf_evsel **metric_events,
+                        struct perf_evsel *ev)
+{
+       metric_events[*ind] = ev;
+       if (*ind == 0)
+               *start = ev;
+       if (++*ind == idnum) {
+               metric_events[*ind] = NULL;
+               return true;
+       }
+       return false;
+}
+
+static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
+                                          const char **ids,
+                                          int idnum,
+                                          struct perf_evsel **metric_events)
 {
        struct perf_evsel *ev, *start = NULL;
        int ind = 0;
 
        evlist__for_each_entry (perf_evlist, ev) {
+               if (ev->collect_stat)
+                       continue;
                if (!strcmp(ev->name, ids[ind])) {
-                       metric_events[ind] = ev;
-                       if (ind == 0)
-                               start = ev;
-                       if (++ind == idnum) {
-                               metric_events[ind] = NULL;
+                       if (record_evsel(&ind, &start, idnum,
+                                        metric_events, ev))
                                return start;
-                       }
                } else {
+                       /*
+                        * We saw some other event that is not
+                        * in our list of events. Discard
+                        * the whole match and start again.
+                        */
                        ind = 0;
                        start = NULL;
+                       if (!strcmp(ev->name, ids[ind])) {
+                               if (record_evsel(&ind, &start, idnum,
+                                                metric_events, ev))
+                                       return start;
+                       }
                }
        }
        /*
@@ -134,8 +157,8 @@ static int metricgroup__setup_events(struct list_head *groups,
                        ret = -ENOMEM;
                        break;
                }
-               evsel = find_evsel(perf_evlist, eg->ids, eg->idnum,
-                                  metric_events);
+               evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum,
+                                        metric_events);
                if (!evsel) {
                        pr_debug("Cannot resolve %s: %s\n",
                                        eg->metric_name, eg->metric_expr);