]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - tools/perf/util/pmu.c
perf pmu: Fix core PMU alias list for X86 platform
[mirror_ubuntu-bionic-kernel.git] / tools / perf / util / pmu.c
index 80fb1593913a9227a742a1a2ed56330c877facad..60d0419bd41ef849c800599e1d78041054e14b4f 100644 (file)
@@ -12,6 +12,7 @@
 #include <dirent.h>
 #include <api/fs/fs.h>
 #include <locale.h>
+#include <regex.h>
 #include "util.h"
 #include "pmu.h"
 #include "parse-events.h"
@@ -536,18 +537,41 @@ static bool pmu_is_uncore(const char *name)
        return !!cpus;
 }
 
+/*
+ *  PMU CORE devices have different name other than cpu in sysfs on some
+ *  platforms.
+ *  Looking for possible sysfs files to identify the arm core device.
+ */
+static int is_arm_pmu_core(const char *name)
+{
+       struct stat st;
+       char path[PATH_MAX];
+       const char *sysfs = sysfs__mountpoint();
+
+       if (!sysfs)
+               return 0;
+
+       /* Look for cpu sysfs (specific to arm) */
+       scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus",
+                               sysfs, name);
+       if (stat(path, &st) == 0)
+               return 1;
+
+       return 0;
+}
+
 /*
  * Return the CPU id as a raw string.
  *
  * Each architecture should provide a more precise id string that
  * can be use to match the architecture's "mapfile".
  */
-char * __weak get_cpuid_str(void)
+char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
 {
        return NULL;
 }
 
-static char *perf_pmu__getcpuid(void)
+static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
 {
        char *cpuid;
        static bool printed;
@@ -556,7 +580,7 @@ static char *perf_pmu__getcpuid(void)
        if (cpuid)
                cpuid = strdup(cpuid);
        if (!cpuid)
-               cpuid = get_cpuid_str();
+               cpuid = get_cpuid_str(pmu);
        if (!cpuid)
                return NULL;
 
@@ -567,22 +591,45 @@ static char *perf_pmu__getcpuid(void)
        return cpuid;
 }
 
-struct pmu_events_map *perf_pmu__find_map(void)
+struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
 {
        struct pmu_events_map *map;
-       char *cpuid = perf_pmu__getcpuid();
+       char *cpuid = perf_pmu__getcpuid(pmu);
        int i;
 
+       /* on some platforms which uses cpus map, cpuid can be NULL for
+        * PMUs other than CORE PMUs.
+        */
+       if (!cpuid)
+               return NULL;
+
        i = 0;
        for (;;) {
+               regex_t re;
+               regmatch_t pmatch[1];
+               int match;
+
                map = &pmu_events_map[i++];
                if (!map->table) {
                        map = NULL;
                        break;
                }
 
-               if (!strcmp(map->cpuid, cpuid))
+               if (regcomp(&re, map->cpuid, REG_EXTENDED) != 0) {
+                       /* Warn unable to generate match particular string. */
+                       pr_info("Invalid regular expression %s\n", map->cpuid);
                        break;
+               }
+
+               match = !regexec(&re, cpuid, 1, pmatch, 0);
+               regfree(&re);
+               if (match) {
+                       size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
+
+                       /* Verify the entire string matched. */
+                       if (match_len == strlen(cpuid))
+                               break;
+               }
        }
        free(cpuid);
        return map;
@@ -593,13 +640,15 @@ struct pmu_events_map *perf_pmu__find_map(void)
  * to the current running CPU. Then, add all PMU events from that table
  * as aliases.
  */
-static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
+static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
        int i;
        struct pmu_events_map *map;
        struct pmu_event *pe;
+       const char *name = pmu->name;
+       const char *pname;
 
-       map = perf_pmu__find_map();
+       map = perf_pmu__find_map(pmu);
        if (!map)
                return;
 
@@ -608,7 +657,6 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
         */
        i = 0;
        while (1) {
-               const char *pname;
 
                pe = &map->table[i++];
                if (!pe->name) {
@@ -617,9 +665,11 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
                        break;
                }
 
-               pname = pe->pmu ? pe->pmu : "cpu";
-               if (strncmp(pname, name, strlen(pname)))
-                       continue;
+               if (!is_arm_pmu_core(name)) {
+                       pname = pe->pmu ? pe->pmu : "cpu";
+                       if (strncmp(pname, name, strlen(pname)))
+                               continue;
+               }
 
                /* need type casts to override 'const' */
                __perf_pmu__new_alias(head, NULL, (char *)pe->name,
@@ -661,21 +711,20 @@ static struct perf_pmu *pmu_lookup(const char *name)
        if (pmu_aliases(name, &aliases))
                return NULL;
 
-       pmu_add_cpu_aliases(&aliases, name);
        pmu = zalloc(sizeof(*pmu));
        if (!pmu)
                return NULL;
 
        pmu->cpus = pmu_cpumask(name);
-
+       pmu->name = strdup(name);
+       pmu->type = type;
        pmu->is_uncore = pmu_is_uncore(name);
+       pmu_add_cpu_aliases(&aliases, pmu);
 
        INIT_LIST_HEAD(&pmu->format);
        INIT_LIST_HEAD(&pmu->aliases);
        list_splice(&format, &pmu->format);
        list_splice(&aliases, &pmu->aliases);
-       pmu->name = strdup(name);
-       pmu->type = type;
        list_add_tail(&pmu->list, &pmus);
 
        pmu->default_config = perf_pmu__get_default_config(pmu);