perf stat: Fix group lookup for metric group

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: b18f3e3650 ("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>
This commit is contained in:
Andi Kleen 2019-06-24 12:37:10 -07:00 committed by Arnaldo Carvalho de Melo
parent 6c5f4e5cb3
commit 2f87f33f42
1 changed files with 35 additions and 12 deletions

View 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);