[PATCH RFC 5/7] perf pmu: Support matching by sysid

From: John Garry
Date: Fri Jan 24 2020 - 09:39:30 EST


Match system or uncore PMU aliases by system id, SYSID.

We use a SYSID read from sysfs or from an env variable to match against
uncore or system PMU events.

For x86, they want to match uncore events with cpuid - this still works
fine for x86 as it would not have system event tables for uncore PMUs.

Signed-off-by: John Garry <john.garry@xxxxxxxxxx>
---
tools/perf/util/pmu.c | 105 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 94 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 569aba4cec89..4d4fe0c1ae22 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -672,11 +672,78 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
return cpuid;
}

+static char *get_sysid_str(void)
+{
+ char *buf = NULL;
+ char path[PATH_MAX];
+ const char *sysfs = sysfs__mountpoint();
+ FILE *file;
+ int s, i;
+
+ if (!sysfs)
+ return NULL;
+
+ buf = malloc(PATH_MAX);
+ if (!buf) {
+ pr_err("%s alloc failed\n", __func__);
+ return NULL;
+ }
+
+ scnprintf(path, PATH_MAX, "%s/devices/soc0/machine", sysfs);
+
+ file = fopen(path, "r");
+ if (!file) {
+ pr_debug("fopen failed for file %s\n", path);
+ free(buf);
+ return NULL;
+ }
+
+ if (!fgets(buf, PATH_MAX, file)) {
+ fclose(file);
+ pr_debug("gets failed for file %s\n", path);
+ free(buf);
+ return NULL;
+ }
+ fclose(file);
+
+ /* Remove any whitespace, this could be from ACPI HID */
+ s = strlen(buf);
+ for (i = 0; i < s; i++) {
+ if (buf[i] == ' ') {
+ buf[i] = 0;
+ break;
+ };
+ }
+
+ return buf;
+}
+
+static char *perf_pmu__getsysid(void)
+{
+ char *sysid;
+ static bool printed;
+
+ sysid = getenv("PERF_SYSID");
+ if (sysid)
+ sysid = strdup(sysid);
+
+ if (!sysid)
+ sysid = get_sysid_str();
+ if (!sysid)
+ return NULL;
+
+ if (!printed) {
+ pr_debug("Using SYSID %s\n", sysid);
+ printed = true;
+ }
+ return sysid;
+}
+
struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
{
- struct pmu_events_map *map;
+ struct pmu_events_map *map, *found_map = NULL;
char *cpuid = perf_pmu__getcpuid(pmu);
- int i;
+ char *sysid;

/* on some platforms which uses cpus map, cpuid can be NULL for
* PMUs other than CORE PMUs.
@@ -684,19 +751,35 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
if (!cpuid)
return NULL;

- i = 0;
- for (;;) {
- map = &pmu_events_map[i++];
- if (!map->table) {
- map = NULL;
- break;
+ sysid = perf_pmu__getsysid();
+
+ /*
+ * Match sysid as first perference for uncore/sys PMUs.
+ *
+ * x86 uncore events match by cpuid, but we would not have map->socid
+ * set for that arch (so any matching here would fail for that).
+ */
+ if (pmu && pmu_is_uncore_or_sys(pmu->name) &&
+ !is_arm_pmu_core(pmu->name) && sysid) {
+ for (map = &pmu_events_map[0]; map->table; map++) {
+ if (map->sysid && !strcmp(map->sysid, sysid)) {
+ found_map = map;
+ goto out;
+ }
}
+ }

- if (!strcmp_cpuid_str(map->cpuid, cpuid))
- break;
+ for (map = &pmu_events_map[0]; map->table; map++) {
+ if (map->cpuid && cpuid &&
+ !strcmp_cpuid_str(map->cpuid, cpuid)) {
+ found_map = map;
+ goto out;
+ }
}
+out:
free(cpuid);
- return map;
+ free(sysid); /* Can safely handle is sysid is NULL */
+ return found_map;
}

static bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
--
2.17.1