Merge branch 'akpm' (patches from Andrew)
[linux-2.6-microblaze.git] / tools / perf / util / pmu.c
index 44b90d6..bdabd62 100644 (file)
@@ -742,9 +742,13 @@ 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)
+/*
+ * 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)
 {
-       char *p;
+       const char *p;
 
        if (strncmp(pmu_name, tok, strlen(tok)))
                return false;
@@ -753,12 +757,16 @@ static bool perf_pmu__valid_suffix(char *pmu_name, char *tok)
        if (*p == 0)
                return true;
 
-       if (*p != '_')
-               return false;
+       if (*p == '_')
+               ++p;
 
-       ++p;
-       if (*p == 0 || !isdigit(*p))
-               return false;
+       /* Ensure we end in a number */
+       while (1) {
+               if (!isdigit(*p))
+                       return false;
+               if (*(++p) == 0)
+                       break;
+       }
 
        return true;
 }
@@ -789,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 || !perf_pmu__valid_suffix((char *)name, tok)) {
+               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;
@@ -828,8 +843,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
                        break;
                }
 
-               if (pmu_is_uncore(name) &&
-                   pmu_uncore_alias_match(pname, name))
+               if (pmu->is_uncore && pmu_uncore_alias_match(pname, name))
                        goto new_alias;
 
                if (strcmp(pname, name))
@@ -912,7 +926,7 @@ static int pmu_add_sys_aliases_iter_fn(struct pmu_event *pe, void *data)
        return 0;
 }
 
-static void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu)
+void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu)
 {
        struct pmu_sys_event_iter_data idata = {
                .head = head,
@@ -931,6 +945,18 @@ perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
        return NULL;
 }
 
+char * __weak
+pmu_find_real_name(const char *name)
+{
+       return (char *)name;
+}
+
+char * __weak
+pmu_find_alias_name(const char *name __maybe_unused)
+{
+       return NULL;
+}
+
 static int pmu_max_precise(const char *name)
 {
        char path[PATH_MAX];
@@ -944,12 +970,21 @@ static int pmu_max_precise(const char *name)
        return max_precise;
 }
 
-static struct perf_pmu *pmu_lookup(const char *name)
+static struct perf_pmu *pmu_lookup(const char *lookup_name)
 {
        struct perf_pmu *pmu;
        LIST_HEAD(format);
        LIST_HEAD(aliases);
        __u32 type;
+       char *name = pmu_find_real_name(lookup_name);
+       bool is_hybrid = perf_pmu__hybrid_mounted(name);
+       char *alias_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
@@ -974,11 +1009,21 @@ static struct perf_pmu *pmu_lookup(const char *name)
 
        pmu->cpus = pmu_cpumask(name);
        pmu->name = strdup(name);
+       if (!pmu->name)
+               goto err;
+
+       alias_name = pmu_find_alias_name(name);
+       if (alias_name) {
+               pmu->alias_name = strdup(alias_name);
+               if (!pmu->alias_name)
+                       goto err;
+       }
+
        pmu->type = type;
        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);
@@ -996,15 +1041,22 @@ static struct perf_pmu *pmu_lookup(const char *name)
        pmu->default_config = perf_pmu__get_default_config(pmu);
 
        return pmu;
+err:
+       if (pmu->name)
+               free(pmu->name);
+       free(pmu);
+       return NULL;
 }
 
 static struct perf_pmu *pmu_find(const char *name)
 {
        struct perf_pmu *pmu;
 
-       list_for_each_entry(pmu, &pmus, list)
-               if (!strcmp(pmu->name, name))
+       list_for_each_entry(pmu, &pmus, list) {
+               if (!strcmp(pmu->name, name) ||
+                   (pmu->alias_name && !strcmp(pmu->alias_name, name)))
                        return pmu;
+       }
 
        return NULL;
 }
@@ -1898,6 +1950,9 @@ bool perf_pmu__has_hybrid(void)
 
 int perf_pmu__match(char *pattern, char *name, char *tok)
 {
+       if (!name)
+               return -1;
+
        if (fnmatch(pattern, name, 0))
                return -1;
 
@@ -1906,3 +1961,38 @@ int perf_pmu__match(char *pattern, char *name, char *tok)
 
        return 0;
 }
+
+int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus,
+                        struct perf_cpu_map **mcpus_ptr,
+                        struct perf_cpu_map **ucpus_ptr)
+{
+       struct perf_cpu_map *pmu_cpus = pmu->cpus;
+       struct perf_cpu_map *matched_cpus, *unmatched_cpus;
+       int matched_nr = 0, unmatched_nr = 0;
+
+       matched_cpus = perf_cpu_map__default_new();
+       if (!matched_cpus)
+               return -1;
+
+       unmatched_cpus = perf_cpu_map__default_new();
+       if (!unmatched_cpus) {
+               perf_cpu_map__put(matched_cpus);
+               return -1;
+       }
+
+       for (int i = 0; i < cpus->nr; i++) {
+               int cpu;
+
+               cpu = perf_cpu_map__idx(pmu_cpus, cpus->map[i]);
+               if (cpu == -1)
+                       unmatched_cpus->map[unmatched_nr++] = cpus->map[i];
+               else
+                       matched_cpus->map[matched_nr++] = cpus->map[i];
+       }
+
+       unmatched_cpus->nr = unmatched_nr;
+       matched_cpus->nr = matched_nr;
+       *mcpus_ptr = matched_cpus;
+       *ucpus_ptr = unmatched_cpus;
+       return 0;
+}