From: "Yan, Zheng" <zheng.z....@intel.com>

Allow wildcard in PMU name, so we can measure events on all
uncore boxes of same type. For example:

Signed-off-by: Yan, Zheng <zheng.z....@intel.com>
---
 tools/perf/builtin-stat.c      |   8 ++-
 tools/perf/util/evsel.c        |  31 ++++++++--
 tools/perf/util/evsel.h        |   2 +
 tools/perf/util/parse-events.c | 126 ++++++++++++++++++++++++++++++-----------
 4 files changed, 128 insertions(+), 39 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index acdfd24..bebfd8c 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -557,7 +557,8 @@ static int run_perf_stat(int argc __used, const char **argv)
                }
        } else {
                list_for_each_entry(counter, &evsel_list->entries, node) {
-                       read_counter_aggr(counter);
+                       if (!counter->aggr_slave)
+                               read_counter_aggr(counter);
                        perf_evsel__close_fd(counter, 
perf_evsel__nr_cpus(counter),
                                             evsel_list->threads->nr);
                }
@@ -1023,8 +1024,11 @@ static void print_stat(int argc, const char **argv)
                list_for_each_entry(counter, &evsel_list->entries, node)
                        print_counter(counter);
        } else {
-               list_for_each_entry(counter, &evsel_list->entries, node)
+               list_for_each_entry(counter, &evsel_list->entries, node) {
+                       if (counter->aggr_slave)
+                               continue;
                        print_counter_aggr(counter);
+               }
        }
 
        if (!csv_output) {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7ff3c8f..b99b892 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -54,6 +54,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
        evsel->idx         = idx;
        evsel->attr        = *attr;
        INIT_LIST_HEAD(&evsel->node);
+       INIT_LIST_HEAD(&evsel->sibling);
        hists__init(&evsel->hists);
        evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
 }
@@ -525,14 +526,13 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
        return 0;
 }
 
-int __perf_evsel__read(struct perf_evsel *evsel,
-                      int ncpus, int nthreads, bool scale)
+static int read_evsel(struct perf_counts_values *aggr,
+                     struct perf_evsel *evsel,
+                     int ncpus, int nthreads, bool scale)
 {
+       struct perf_counts_values count;
        size_t nv = scale ? 3 : 1;
        int cpu, thread;
-       struct perf_counts_values *aggr = &evsel->counts->aggr, count;
-
-       aggr->val = aggr->ena = aggr->run = 0;
 
        for (cpu = 0; cpu < ncpus; cpu++) {
                for (thread = 0; thread < nthreads; thread++) {
@@ -550,6 +550,27 @@ int __perf_evsel__read(struct perf_evsel *evsel,
                        }
                }
        }
+       return 0;
+}
+
+int __perf_evsel__read(struct perf_evsel *evsel,
+                      int ncpus, int nthreads, bool scale)
+{
+       int ret;
+       struct perf_counts_values *aggr = &evsel->counts->aggr;
+       struct perf_evsel *child;
+
+       aggr->val = aggr->ena = aggr->run = 0;
+
+       ret = read_evsel(aggr, evsel, ncpus, nthreads, scale);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(child, &evsel->sibling, node) {
+               ret = read_evsel(aggr, evsel, ncpus, nthreads, scale);
+               if (ret)
+                       return ret;
+       }
 
        evsel->counts->scaled = 0;
        if (scale) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 956c0a0..bcb5a8a 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -46,6 +46,7 @@ struct perf_sample_id {
  */
 struct perf_evsel {
        struct list_head        node;
+       struct list_head        sibling;
        struct perf_event_attr  attr;
        char                    *filter;
        struct xyarray          *fd;
@@ -69,6 +70,7 @@ struct perf_evsel {
        struct cpu_map          *cpus;
        unsigned int            sample_size;
        bool                    supported;
+       bool                    aggr_slave;
        /* parse modifier helper */
        int                     exclude_GH;
        struct perf_evsel       *leader;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 3aa9be4..32288f2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -239,14 +239,40 @@ const char *event_type(int type)
        return "unknown";
 }
 
+static void free_event_list(struct list_head *list)
+{
+       struct perf_evsel *evsel;
 
+       while (!list_empty(list)) {
+               evsel = list_entry(list->next, struct perf_evsel, node);
+               list_del(&evsel->node);
+               perf_evsel__delete(evsel);
+       }
+       free(list);
+}
 
-static int __add_event(struct list_head **_list, int *idx,
-                      struct perf_event_attr *attr,
-                      char *name, struct cpu_map *cpus)
+static struct perf_evsel *__add_event(int *idx, struct perf_event_attr *attr,
+                                     char *name, struct cpu_map *cpus)
 {
        struct perf_evsel *evsel;
+
+       event_attr_init(attr);
+
+       evsel = perf_evsel__new(attr, (*idx)++);
+       if (!evsel)
+               return NULL;
+
+       evsel->cpus = cpus;
+       if (name)
+               evsel->name = strdup(name);
+       return evsel;
+}
+
+static int add_event(struct list_head **_list, int *idx,
+                    struct perf_event_attr *attr, char *name)
+{
        struct list_head *list = *_list;
+       struct perf_evsel *evsel;
 
        if (!list) {
                list = malloc(sizeof(*list));
@@ -255,28 +281,17 @@ static int __add_event(struct list_head **_list, int *idx,
                INIT_LIST_HEAD(list);
        }
 
-       event_attr_init(attr);
-
-       evsel = perf_evsel__new(attr, (*idx)++);
+       evsel = __add_event(idx, attr, name, NULL);
        if (!evsel) {
                free(list);
                return -ENOMEM;
        }
 
-       evsel->cpus = cpus;
-       if (name)
-               evsel->name = strdup(name);
        list_add_tail(&evsel->node, list);
        *_list = list;
        return 0;
 }
 
-static int add_event(struct list_head **_list, int *idx,
-                    struct perf_event_attr *attr, char *name)
-{
-       return __add_event(_list, idx, attr, name, NULL);
-}
-
 static int parse_aliases(char *str, const char 
*names[][PERF_EVSEL__MAX_ALIASES], int size)
 {
        int i, j;
@@ -593,32 +608,79 @@ static char *pmu_event_name(struct list_head *head_terms)
        return NULL;
 }
 
-int parse_events_add_pmu(struct list_head **list, int *idx,
+static int pmu_name_match(char *name, char *pattern)
+{
+       int idx;
+       char *c;
+
+       if (!strcasecmp(name, pattern))
+               return 0;
+
+       c = strchr(pattern, '*');
+       if (!c || c[1] != '\0')
+               return 1;
+
+       idx = c - pattern;
+       if (strncasecmp(name, pattern, idx))
+               return 1;
+
+       for (; name[idx]; idx++) {
+               if (name[idx] < '0' || name[idx] > '9')
+                       return 1;
+       }
+       return 0;
+}
+
+int parse_events_add_pmu(struct list_head **_list, int *idx,
                         char *name, struct list_head *head_config)
 {
        struct perf_event_attr attr;
-       struct perf_pmu *pmu;
+       struct list_head *list;
+       struct perf_pmu *pmu = NULL;
+       struct perf_evsel *evsel, *first = NULL;
+       int orig_idx = *idx;
 
-       pmu = perf_pmu__find(name);
-       if (!pmu)
-               return -EINVAL;
+       list = malloc(sizeof(*list));
+       if (!list)
+               return -ENOMEM;
+       INIT_LIST_HEAD(list);
 
-       memset(&attr, 0, sizeof(attr));
+       while ((pmu = perf_pmu__scan(pmu))) {
+               if (pmu_name_match(pmu->name, name))
+                       continue;
 
-       if (perf_pmu__check_alias(pmu, head_config))
-               return -EINVAL;
+               memset(&attr, 0, sizeof(attr));
 
-       /*
-        * Configure hardcoded terms first, no need to check
-        * return value when called with fail == 0 ;)
-        */
-       config_attr(&attr, head_config, 0);
+               if (perf_pmu__check_alias(pmu, head_config))
+                       return -EINVAL;
 
-       if (perf_pmu__config(pmu, &attr, head_config))
-               return -EINVAL;
+               /*
+                * Configure hardcoded terms first, no need to check
+                * return value when called with fail == 0 ;)
+                */
+               config_attr(&attr, head_config, 0);
+
+               if (perf_pmu__config(pmu, &attr, head_config))
+                       return -EINVAL;
 
-       return __add_event(list, idx, &attr, pmu_event_name(head_config),
-                          pmu->cpus);
+               evsel = __add_event(idx, &attr, pmu_event_name(head_config),
+                                   pmu->cpus);
+               if (!evsel) {
+                       *idx = orig_idx;
+                       free_event_list(list);
+                       return -ENOMEM;
+               }
+               list_add_tail(&evsel->node, list);
+               if (first) {
+                       list_add_tail(&evsel->sibling, &first->sibling);
+                       evsel->aggr_slave = true;
+               } else {
+                       first = evsel;
+               }
+       }
+
+       *_list = list;
+       return 0;
 }
 
 int parse_events__modifier_group(struct list_head *list,
-- 
1.7.11.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to