Merge branch 'linus' into perf/core, to fix conflicts
[linux-2.6-microblaze.git] / tools / perf / util / pmu.c
index ac16a9d..07cb2ac 100644 (file)
@@ -1,7 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 #include <linux/list.h>
 #include <linux/compiler.h>
 #include <sys/types.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -470,17 +472,36 @@ static void pmu_read_sysfs(void)
        closedir(dir);
 }
 
+static struct cpu_map *__pmu_cpumask(const char *path)
+{
+       FILE *file;
+       struct cpu_map *cpus;
+
+       file = fopen(path, "r");
+       if (!file)
+               return NULL;
+
+       cpus = cpu_map__read(file);
+       fclose(file);
+       return cpus;
+}
+
+/*
+ * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
+ * may have a "cpus" file.
+ */
+#define CPUS_TEMPLATE_UNCORE   "%s/bus/event_source/devices/%s/cpumask"
+#define CPUS_TEMPLATE_CPU      "%s/bus/event_source/devices/%s/cpus"
+
 static struct cpu_map *pmu_cpumask(const char *name)
 {
-       struct stat st;
        char path[PATH_MAX];
-       FILE *file;
        struct cpu_map *cpus;
        const char *sysfs = sysfs__mountpoint();
        const char *templates[] = {
-                "%s/bus/event_source/devices/%s/cpumask",
-                "%s/bus/event_source/devices/%s/cpus",
-                NULL
+               CPUS_TEMPLATE_UNCORE,
+               CPUS_TEMPLATE_CPU,
+               NULL
        };
        const char **template;
 
@@ -489,20 +510,25 @@ static struct cpu_map *pmu_cpumask(const char *name)
 
        for (template = templates; *template; template++) {
                snprintf(path, PATH_MAX, *template, sysfs, name);
-               if (stat(path, &st) == 0)
-                       break;
+               cpus = __pmu_cpumask(path);
+               if (cpus)
+                       return cpus;
        }
 
-       if (!*template)
-               return NULL;
+       return NULL;
+}
 
-       file = fopen(path, "r");
-       if (!file)
-               return NULL;
+static bool pmu_is_uncore(const char *name)
+{
+       char path[PATH_MAX];
+       struct cpu_map *cpus;
+       const char *sysfs = sysfs__mountpoint();
 
-       cpus = cpu_map__read(file);
-       fclose(file);
-       return cpus;
+       snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
+       cpus = __pmu_cpumask(path);
+       cpu_map__put(cpus);
+
+       return !!cpus;
 }
 
 /*
@@ -516,16 +542,8 @@ char * __weak get_cpuid_str(void)
        return NULL;
 }
 
-/*
- * From the pmu_events_map, find the table of PMU events that corresponds
- * 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 char *perf_pmu__getcpuid(void)
 {
-       int i;
-       struct pmu_events_map *map;
-       struct pmu_event *pe;
        char *cpuid;
        static bool printed;
 
@@ -535,22 +553,50 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
        if (!cpuid)
                cpuid = get_cpuid_str();
        if (!cpuid)
-               return;
+               return NULL;
 
        if (!printed) {
                pr_debug("Using CPUID %s\n", cpuid);
                printed = true;
        }
+       return cpuid;
+}
+
+struct pmu_events_map *perf_pmu__find_map(void)
+{
+       struct pmu_events_map *map;
+       char *cpuid = perf_pmu__getcpuid();
+       int i;
 
        i = 0;
-       while (1) {
+       for (;;) {
                map = &pmu_events_map[i++];
-               if (!map->table)
-                       goto out;
+               if (!map->table) {
+                       map = NULL;
+                       break;
+               }
 
                if (!strcmp(map->cpuid, cpuid))
                        break;
        }
+       free(cpuid);
+       return map;
+}
+
+/*
+ * From the pmu_events_map, find the table of PMU events that corresponds
+ * 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)
+{
+       int i;
+       struct pmu_events_map *map;
+       struct pmu_event *pe;
+
+       map = perf_pmu__find_map();
+       if (!map)
+               return;
 
        /*
         * Found a matching PMU events table. Create aliases
@@ -560,8 +606,11 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
                const char *pname;
 
                pe = &map->table[i++];
-               if (!pe->name)
+               if (!pe->name) {
+                       if (pe->metric_group || pe->metric_name)
+                               continue;
                        break;
+               }
 
                pname = pe->pmu ? pe->pmu : "cpu";
                if (strncmp(pname, name, strlen(pname)))
@@ -575,9 +624,6 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
                                (char *)pe->metric_expr,
                                (char *)pe->metric_name);
        }
-
-out:
-       free(cpuid);
 }
 
 struct perf_event_attr * __weak
@@ -617,6 +663,8 @@ static struct perf_pmu *pmu_lookup(const char *name)
 
        pmu->cpus = pmu_cpumask(name);
 
+       pmu->is_uncore = pmu_is_uncore(name);
+
        INIT_LIST_HEAD(&pmu->format);
        INIT_LIST_HEAD(&pmu->aliases);
        list_splice(&format, &pmu->format);