perf metricgroup: Support multiple events for metricgroup
Some uncore metrics don't work as expected. For example, on cascadelakex: root@lkp-csl-2sp2:~# perf stat -M UNC_M_PMM_BANDWIDTH.TOTAL -a -- sleep 1 Performance counter stats for 'system wide': 1841092 unc_m_pmm_rpq_inserts 3680816 unc_m_pmm_wpq_inserts 1.001775055 seconds time elapsed root@lkp-csl-2sp2:~# perf stat -M UNC_M_PMM_READ_LATENCY -a -- sleep 1 Performance counter stats for 'system wide': 860649746 unc_m_pmm_rpq_occupancy.all 1840557 unc_m_pmm_rpq_inserts 12790627455 unc_m_clockticks 1.001773348 seconds time elapsed No metrics 'UNC_M_PMM_BANDWIDTH.TOTAL' or 'UNC_M_PMM_READ_LATENCY' are reported. The issue is, the case of an alias expanding to mulitple events is not supported, typically the uncore events. (see comments in find_evsel_group()). For UNC_M_PMM_BANDWIDTH.TOTAL in above example, the expanded event group is '{unc_m_pmm_rpq_inserts,unc_m_pmm_wpq_inserts}:W', but the actual events passed to find_evsel_group are: unc_m_pmm_rpq_inserts unc_m_pmm_rpq_inserts unc_m_pmm_rpq_inserts unc_m_pmm_rpq_inserts unc_m_pmm_rpq_inserts unc_m_pmm_rpq_inserts unc_m_pmm_wpq_inserts unc_m_pmm_wpq_inserts unc_m_pmm_wpq_inserts unc_m_pmm_wpq_inserts unc_m_pmm_wpq_inserts unc_m_pmm_wpq_inserts For this multiple events case, it's not supported well. This patch introduces a new field 'metric_leader' in struct evsel. The first event is considered as a metric leader. For the rest of same events, they point to the first event via it's metric_leader field in struct evsel. This design is for adding the counting results of all same events to the first event in group (the metric_leader). With this patch, root@lkp-csl-2sp2:~# perf stat -M UNC_M_PMM_BANDWIDTH.TOTAL -a -- sleep 1 Performance counter stats for 'system wide': 1842108 unc_m_pmm_rpq_inserts # 337.2 MB/sec UNC_M_PMM_BANDWIDTH.TOTAL 3682209 unc_m_pmm_wpq_inserts 1.001819706 seconds time elapsed root@lkp-csl-2sp2:~# perf stat -M UNC_M_PMM_READ_LATENCY -a -- sleep 1 Performance counter stats for 'system wide': 861970685 unc_m_pmm_rpq_occupancy.all # 219.4 ns UNC_M_PMM_READ_LATENCY 1842772 unc_m_pmm_rpq_inserts 12790196356 unc_m_clockticks 1.001749103 seconds time elapsed Now we can see the correct metrics 'UNC_M_PMM_BANDWIDTH.TOTAL' and 'UNC_M_PMM_READ_LATENCY'. Signed-off-by: Jin Yao <yao.jin@linux.intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lore.kernel.org/lkml/20190828055932.8269-5-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:

committed by
Arnaldo Carvalho de Melo

parent
287f2649f7
commit
f01642e491
@@ -90,57 +90,61 @@ struct egroup {
|
||||
const char *metric_unit;
|
||||
};
|
||||
|
||||
static bool record_evsel(int *ind, struct evsel **start,
|
||||
int idnum,
|
||||
struct evsel **metric_events,
|
||||
struct evsel *ev)
|
||||
{
|
||||
metric_events[*ind] = ev;
|
||||
if (*ind == 0)
|
||||
*start = ev;
|
||||
if (++*ind == idnum) {
|
||||
metric_events[*ind] = NULL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct evsel *find_evsel_group(struct evlist *perf_evlist,
|
||||
const char **ids,
|
||||
int idnum,
|
||||
struct evsel **metric_events)
|
||||
{
|
||||
struct evsel *ev, *start = NULL;
|
||||
int ind = 0;
|
||||
struct evsel *ev;
|
||||
int i = 0;
|
||||
bool leader_found;
|
||||
|
||||
evlist__for_each_entry (perf_evlist, ev) {
|
||||
if (ev->collect_stat)
|
||||
continue;
|
||||
if (!strcmp(ev->name, ids[ind])) {
|
||||
if (record_evsel(&ind, &start, idnum,
|
||||
metric_events, ev))
|
||||
return start;
|
||||
if (!strcmp(ev->name, ids[i])) {
|
||||
if (!metric_events[i])
|
||||
metric_events[i] = ev;
|
||||
} 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;
|
||||
if (++i == idnum) {
|
||||
/* Discard the whole match and start again */
|
||||
i = 0;
|
||||
memset(metric_events, 0,
|
||||
sizeof(struct evsel *) * idnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(ev->name, ids[i]))
|
||||
metric_events[i] = ev;
|
||||
else {
|
||||
/* Discard the whole match and start again */
|
||||
i = 0;
|
||||
memset(metric_events, 0,
|
||||
sizeof(struct evsel *) * idnum);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This can happen when an alias expands to multiple
|
||||
* events, like for uncore events.
|
||||
* We don't support this case for now.
|
||||
*/
|
||||
return NULL;
|
||||
|
||||
if (i != idnum - 1) {
|
||||
/* Not whole match */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
metric_events[idnum] = NULL;
|
||||
|
||||
for (i = 0; i < idnum; i++) {
|
||||
leader_found = false;
|
||||
evlist__for_each_entry(perf_evlist, ev) {
|
||||
if (!leader_found && (ev == metric_events[i]))
|
||||
leader_found = true;
|
||||
|
||||
if (leader_found &&
|
||||
!strcmp(ev->name, metric_events[i]->name)) {
|
||||
ev->metric_leader = metric_events[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metric_events[0];
|
||||
}
|
||||
|
||||
static int metricgroup__setup_events(struct list_head *groups,
|
||||
|
Reference in New Issue
Block a user