summaryrefslogtreecommitdiff
path: root/tools/perf/util/metricgroup.c
diff options
context:
space:
mode:
authorJin Yao <yao.jin@linux.intel.com>2019-08-28 13:59:32 +0800
committerArnaldo Carvalho de Melo <acme@redhat.com>2019-08-31 22:27:52 -0300
commitf01642e4912bb80a01d693f4cc6fb0897207a090 (patch)
tree8ccfe4ebc337e7076f1e4f59c88b482b1a923d7a /tools/perf/util/metricgroup.c
parent287f2649f791819dd2d8f32f0213c8c521d6dfa0 (diff)
downloadlwn-f01642e4912bb80a01d693f4cc6fb0897207a090.tar.gz
lwn-f01642e4912bb80a01d693f4cc6fb0897207a090.zip
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>
Diffstat (limited to 'tools/perf/util/metricgroup.c')
-rw-r--r--tools/perf/util/metricgroup.c84
1 files changed, 44 insertions, 40 deletions
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index f474a29f1b69..a7c0424dbda3 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -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,