[PATCH v3 11/27] perf pmu: Support 'cycles' and 'branches' inside hybrid PMU

From: Jin Yao
Date: Mon Mar 29 2021 - 03:03:14 EST


On hybrid platform, user may want to enable the hardware event
only on one PMU. So following syntax is supported:

cpu_core/<hardware event>/
cpu_atom/<hardware event>/

# perf stat -e cpu_core/cpu-cycles/ -a -- sleep 1

Performance counter stats for 'system wide':

6,049,336 cpu_core/cpu-cycles/

1.003577042 seconds time elapsed

It enables the event 'cpu-cycles' only on cpu_core pmu.

But for 'cycles' and 'branches', the syntax doesn't work.

Before:

# perf stat -e cpu_core/cycles/ -a -- sleep 1
event syntax error: 'cpu_core/cycles/'
\___ unknown term 'cycles' for pmu 'cpu_core'

# perf stat -e cpu_core/branches/ -a -- sleep 1
event syntax error: 'cpu_core/branches/'
\___ unknown term 'branches' for pmu 'cpu_core'

For 'cpu-cycles', why it works is because the event is defined in
/sys/devices/cpu_core/events/. It's added as alias by
pmu_add_sys_aliases and it's treated as 'event' when parsing the
term->config.

We use a similar idea, create a pme_hybrid_fixup table for
'cycles' and 'branches' and add them as aliases.

After:

# perf stat -e cpu_core/cycles/ -a -- sleep 1

Performance counter stats for 'system wide':

5,769,631 cpu_core/cycles/

1.003833235 seconds time elapsed

# perf stat -e cpu_core/branches/ -a -- sleep 1

Performance counter stats for 'system wide':

490,951 cpu_core/branches/

1.003693946 seconds time elapsed

Signed-off-by: Jin Yao <yao.jin@xxxxxxxxxxxxxxx>
---
v3:
- New patch in v3.

tools/perf/util/pmu.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index beff29981101..72e5ae5e868e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -916,6 +916,35 @@ static int pmu_max_precise(const char *name)
return max_precise;
}

+static void perf_pmu__add_hybrid_aliases(struct list_head *head)
+{
+ static struct pmu_event pme_hybrid_fixup[] = {
+ {
+ .name = "cycles",
+ .event = "event=0x3c",
+ },
+ {
+ .name = "branches",
+ .event = "event=0xc4",
+ },
+ {
+ .name = 0,
+ .event = 0,
+ },
+ };
+ int i = 0;
+
+ while (1) {
+ struct pmu_event *pe = &pme_hybrid_fixup[i++];
+
+ if (!pe->name)
+ break;
+
+ __perf_pmu__new_alias(head, NULL, (char *)pe->name, NULL,
+ (char *)pe->event, NULL);
+ }
+}
+
static struct perf_pmu *pmu_lookup(const char *name)
{
struct perf_pmu *pmu;
@@ -955,6 +984,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
pmu_add_cpu_aliases(&aliases, pmu);
pmu_add_sys_aliases(&aliases, pmu);

+ if (pmu->is_hybrid)
+ perf_pmu__add_hybrid_aliases(&aliases);
+
INIT_LIST_HEAD(&pmu->format);
INIT_LIST_HEAD(&pmu->aliases);
INIT_LIST_HEAD(&pmu->caps);
--
2.17.1