Merge v5.14-rc3 into usb-next
[linux-2.6-microblaze.git] / tools / perf / util / pmu.c
index 46fd0f9..a1bd700 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/compiler.h>
 #include <linux/string.h>
 #include <linux/zalloc.h>
+#include <linux/ctype.h>
 #include <subcmd/pager.h>
 #include <sys/types.h>
 #include <errno.h>
@@ -17,6 +18,7 @@
 #include <locale.h>
 #include <regex.h>
 #include <perf/cpumap.h>
+#include <fnmatch.h>
 #include "debug.h"
 #include "evsel.h"
 #include "pmu.h"
@@ -25,6 +27,7 @@
 #include "string2.h"
 #include "strbuf.h"
 #include "fncache.h"
+#include "pmu-hybrid.h"
 
 struct perf_pmu perf_pmu__fake;
 
@@ -39,6 +42,7 @@ int perf_pmu_parse(struct list_head *list, char *name);
 extern FILE *perf_pmu_in;
 
 static LIST_HEAD(pmus);
+static bool hybrid_scanned;
 
 /*
  * Parse & process all the sysfs attributes located under
@@ -283,6 +287,7 @@ void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
        zfree(&newalias->str);
        zfree(&newalias->metric_expr);
        zfree(&newalias->metric_name);
+       zfree(&newalias->pmu_name);
        parse_events_terms__purge(&newalias->terms);
        free(newalias);
 }
@@ -297,6 +302,10 @@ static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
 
        list_for_each_entry(a, alist, list) {
                if (!strcasecmp(newalias->name, a->name)) {
+                       if (newalias->pmu_name && a->pmu_name &&
+                           !strcasecmp(newalias->pmu_name, a->pmu_name)) {
+                               continue;
+                       }
                        perf_pmu_update_alias(a, newalias);
                        perf_pmu_free_alias(newalias);
                        return true;
@@ -306,18 +315,27 @@ static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
 }
 
 static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
-                                char *desc, char *val,
-                                char *long_desc, char *topic,
-                                char *unit, char *perpkg,
-                                char *metric_expr,
-                                char *metric_name,
-                                char *deprecated)
+                                char *desc, char *val, struct pmu_event *pe)
 {
        struct parse_events_term *term;
        struct perf_pmu_alias *alias;
        int ret;
        int num;
        char newval[256];
+       char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL,
+            *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL,
+            *pmu_name = NULL;
+
+       if (pe) {
+               long_desc = (char *)pe->long_desc;
+               topic = (char *)pe->topic;
+               unit = (char *)pe->unit;
+               perpkg = (char *)pe->perpkg;
+               metric_expr = (char *)pe->metric_expr;
+               metric_name = (char *)pe->metric_name;
+               deprecated = (char *)pe->deprecated;
+               pmu_name = (char *)pe->pmu;
+       }
 
        alias = malloc(sizeof(*alias));
        if (!alias)
@@ -382,6 +400,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
        }
        alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
        alias->str = strdup(newval);
+       alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL;
 
        if (deprecated)
                alias->deprecated = true;
@@ -406,8 +425,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
        /* Remove trailing newline from sysfs file */
        strim(buf);
 
-       return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
-                                    NULL, NULL, NULL, NULL);
+       return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL);
 }
 
 static inline bool pmu_alias_info_file(char *name)
@@ -599,7 +617,6 @@ static struct perf_cpu_map *__pmu_cpumask(const char *path)
  */
 #define SYS_TEMPLATE_ID        "./bus/event_source/devices/%s/identifier"
 #define CPUS_TEMPLATE_UNCORE   "%s/bus/event_source/devices/%s/cpumask"
-#define CPUS_TEMPLATE_CPU      "%s/bus/event_source/devices/%s/cpus"
 
 static struct perf_cpu_map *pmu_cpumask(const char *name)
 {
@@ -631,6 +648,9 @@ static bool pmu_is_uncore(const char *name)
        char path[PATH_MAX];
        const char *sysfs;
 
+       if (perf_pmu__hybrid_mounted(name))
+               return false;
+
        sysfs = sysfs__mountpoint();
        snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
        return file_available(path);
@@ -717,6 +737,32 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
        return map;
 }
 
+struct pmu_events_map *__weak pmu_events_map__find(void)
+{
+       return perf_pmu__find_map(NULL);
+}
+
+static bool perf_pmu__valid_suffix(char *pmu_name, char *tok)
+{
+       char *p;
+
+       if (strncmp(pmu_name, tok, strlen(tok)))
+               return false;
+
+       p = pmu_name + strlen(tok);
+       if (*p == 0)
+               return true;
+
+       if (*p != '_')
+               return false;
+
+       ++p;
+       if (*p == 0 || !isdigit(*p))
+               return false;
+
+       return true;
+}
+
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
 {
        char *tmp = NULL, *tok, *str;
@@ -745,7 +791,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
         */
        for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
                name = strstr(name, tok);
-               if (!name) {
+               if (!name || !perf_pmu__valid_suffix((char *)name, tok)) {
                        res = false;
                        goto out;
                }
@@ -793,11 +839,7 @@ new_alias:
                /* need type casts to override 'const' */
                __perf_pmu__new_alias(head, NULL, (char *)pe->name,
                                (char *)pe->desc, (char *)pe->event,
-                               (char *)pe->long_desc, (char *)pe->topic,
-                               (char *)pe->unit, (char *)pe->perpkg,
-                               (char *)pe->metric_expr,
-                               (char *)pe->metric_name,
-                               (char *)pe->deprecated);
+                               pe);
        }
 }
 
@@ -864,13 +906,7 @@ static int pmu_add_sys_aliases_iter_fn(struct pmu_event *pe, void *data)
                                      (char *)pe->name,
                                      (char *)pe->desc,
                                      (char *)pe->event,
-                                     (char *)pe->long_desc,
-                                     (char *)pe->topic,
-                                     (char *)pe->unit,
-                                     (char *)pe->perpkg,
-                                     (char *)pe->metric_expr,
-                                     (char *)pe->metric_name,
-                                     (char *)pe->deprecated);
+                                     pe);
        }
 
        return 0;
@@ -914,6 +950,13 @@ static struct perf_pmu *pmu_lookup(const char *name)
        LIST_HEAD(format);
        LIST_HEAD(aliases);
        __u32 type;
+       bool is_hybrid = perf_pmu__hybrid_mounted(name);
+
+       /*
+        * Check pmu name for hybrid and the pmu may be invalid in sysfs
+        */
+       if (!strncmp(name, "cpu_", 4) && !is_hybrid)
+               return NULL;
 
        /*
         * The pmu data we store & need consists of the pmu
@@ -942,6 +985,7 @@ static struct perf_pmu *pmu_lookup(const char *name)
        pmu->is_uncore = pmu_is_uncore(name);
        if (pmu->is_uncore)
                pmu->id = pmu_id(name);
+       pmu->is_hybrid = is_hybrid;
        pmu->max_precise = pmu_max_precise(name);
        pmu_add_cpu_aliases(&aliases, pmu);
        pmu_add_sys_aliases(&aliases, pmu);
@@ -953,6 +997,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
        list_splice(&aliases, &pmu->aliases);
        list_add_tail(&pmu->list, &pmus);
 
+       if (pmu->is_hybrid)
+               list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus);
+
        pmu->default_config = perf_pmu__get_default_config(pmu);
 
        return pmu;
@@ -1069,7 +1116,7 @@ int perf_pmu__format_type(struct list_head *formats, const char *name)
 
 /*
  * Sets value based on the format definition (format parameter)
- * and unformated value (value parameter).
+ * and unformatted value (value parameter).
  */
 static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
                             bool zero)
@@ -1408,7 +1455,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
        }
 
        /*
-        * if no unit or scale foundin aliases, then
+        * if no unit or scale found in aliases, then
         * set defaults as for evsel
         * unit cannot left to NULL
         */
@@ -1845,3 +1892,24 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
                   "'%llx' not supported by kernel)!\n",
                   name ?: "N/A", buf, config);
 }
+
+bool perf_pmu__has_hybrid(void)
+{
+       if (!hybrid_scanned) {
+               hybrid_scanned = true;
+               perf_pmu__scan(NULL);
+       }
+
+       return !list_empty(&perf_pmu__hybrid_pmus);
+}
+
+int perf_pmu__match(char *pattern, char *name, char *tok)
+{
+       if (fnmatch(pattern, name, 0))
+               return -1;
+
+       if (tok && !perf_pmu__valid_suffix(name, tok))
+               return -1;
+
+       return 0;
+}