perf pmu: Fix alias matching
[linux-2.6-microblaze.git] / tools / perf / util / pmu.c
index 88c8ecd..fc683bc 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"
@@ -740,6 +742,35 @@ struct pmu_events_map *__weak pmu_events_map__find(void)
        return perf_pmu__find_map(NULL);
 }
 
+/*
+ * Suffix must be in form tok_{digits}, or tok{digits}, or same as pmu_name
+ * to be valid.
+ */
+static bool perf_pmu__valid_suffix(const char *pmu_name, char *tok)
+{
+       const char *p;
+
+       if (strncmp(pmu_name, tok, strlen(tok)))
+               return false;
+
+       p = pmu_name + strlen(tok);
+       if (*p == 0)
+               return true;
+
+       if (*p == '_')
+               ++p;
+
+       /* Ensure we end in a number */
+       while (1) {
+               if (!isdigit(*p))
+                       return false;
+               if (*(++p) == 0)
+                       break;
+       }
+
+       return true;
+}
+
 bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
 {
        char *tmp = NULL, *tok, *str;
@@ -766,12 +797,19 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
         *          match "socket" in "socketX_pmunameY" and then "pmuname" in
         *          "pmunameY".
         */
-       for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
+       while (1) {
+               char *next_tok = strtok_r(NULL, ",", &tmp);
+
                name = strstr(name, tok);
-               if (!name) {
+               if (!name ||
+                   (!next_tok && !perf_pmu__valid_suffix(name, tok))) {
                        res = false;
                        goto out;
                }
+               if (!next_tok)
+                       break;
+               tok = next_tok;
+               name += strlen(tok);
        }
 
        res = true;
@@ -927,6 +965,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
@@ -955,7 +1000,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 = perf_pmu__hybrid_mounted(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);
@@ -1872,3 +1917,14 @@ bool perf_pmu__has_hybrid(void)
 
        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;
+}