[PATCH 08/10] perf, tools: Expand PMU events by prefix match
From: Andi Kleen When the user specifies a pmu directly, expand it automatically with a prefix match, similar as we do for the normal aliases now. This allows to specify attributes for duplicated boxes quickly. For example uncore_cbox_{0,6}/.../ can be now specified as cbox/.../ and it gets automatically expanded. Before % perf stat -a -e uncore_cbox_0/event=0x35,umask=0x1,filter_opc=0x19C/,\ uncore_cbox_1/event=0x35,umask=0x1,filter_opc=0x19C/,\ uncore_cbox_2/event=0x35,umask=0x1,filter_opc=0x19C/,\ uncore_cbox_3/event=0x35,umask=0x1,filter_opc=0x19C/,\ uncore_cbox_4/event=0x35,umask=0x1,filter_opc=0x19C/,\ uncore_cbox_5/event=0x35,umask=0x1,filter_opc=0x19C/ sleep 1 After perf stat -a -e cbox/event=0x35,umask=0x1,filter_opc=0x19C/ sleep 1 v2: Handle all bison rules. Move multi add code to separate function. Handle uncore_ prefix correctly. Signed-off-by: Andi Kleen --- tools/perf/util/parse-events.c | 71 tools/perf/util/parse-events.h | 8 + tools/perf/util/parse-events.y | 73 +- 3 files changed, 109 insertions(+), 43 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6dbcba7f0969..fba53ba22431 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1257,6 +1257,52 @@ int parse_events_add_pmu(struct parse_events_evlist *data, return evsel ? 0 : -ENOMEM; } +int parse_events_multi_pmu_add(struct parse_events_evlist *data, + char *str, struct list_head **listp) +{ + struct list_head *head; + struct parse_events_term *term; + struct list_head *list; + struct perf_pmu *pmu = NULL; + int ok = 0; + + *listp = NULL; + /* Add it for all PMUs that support the alias */ + list = malloc(sizeof(struct list_head)); + if (!list) + return -1; + INIT_LIST_HEAD(list); + while ((pmu = perf_pmu__scan(pmu)) != NULL) { + struct perf_pmu_alias *alias; + + list_for_each_entry(alias, &pmu->aliases, list) { + if (!strcasecmp(alias->name, str)) { + head = malloc(sizeof(struct list_head)); + if (!head) + return -1; + INIT_LIST_HEAD(head); + if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, + str, 1, &str, NULL) < 0) + return -1; + list_add_tail(&term->list, head); + + if (!parse_events_add_pmu(data, list, + pmu->name, head)) { + pr_debug("%s -> %s/%s/\n", str, +pmu->name, alias->str); + ok++; + } + + parse_events_terms__delete(head); + } + } + } + if (!ok) + return -1; + *listp = list; + return 0; +} + int parse_events__modifier_group(struct list_head *list, char *event_mod) { @@ -2406,6 +2452,31 @@ int parse_events_term__clone(struct parse_events_term **new, term->err_term, term->err_val); } +int parse_events_copy_term_list(struct list_head *old, +struct list_head **new) +{ + struct parse_events_term *term, *n; + int ret; + + if (!old) { + *new = NULL; + return 0; + } + + *new = malloc(sizeof(struct list_head)); + if (!*new) + return -ENOMEM; + INIT_LIST_HEAD(*new); + + list_for_each_entry (term, old, list) { + ret = parse_events_term__clone(&n, term); + if (ret) + return ret; + list_add_tail(&n->list, *new); + } + return 0; +} + void parse_events_terms__purge(struct list_head *terms) { struct parse_events_term *term, *h; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index da246a3ddb69..33b3e52cd9b8 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -164,6 +164,14 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, int parse_events_add_pmu(struct parse_events_evlist *data, struct list_head *list, char *name, struct list_head *head_config); + +int parse_events_multi_pmu_add(struct parse_events_evlist *data, + char *str, + struct list_head **listp); + +int parse_events_copy_term_list(struct list_head *old, +
Re: [PATCH 08/10] perf, tools: Expand PMU events by prefix match
On Mon, Oct 17, 2016 at 09:56:42AM -0700, Andi Kleen wrote: > > so there's a special treatment for uncore events, > > what if user says 'uncore_box/..' then? > > It should work. There's nothing special for uncore later, this > is just for convenience so that I have less to type. really.. 'uncore_cbox_0/clockticks/' [jolsa@krava perf]$ sudo ./perf stat -e 'uncore_cbox_0/clockticks/' -a ^C Performance counter stats for 'system wide': 0 uncore_cbox_0/clockticks/ 0.676237018 seconds time elapsed 'cbox_0/clockticks/' [jolsa@krava perf]$ sudo ./perf stat -e 'cbox_0/clockticks/' -a ^C Performance counter stats for 'system wide': 0 cbox_0/clockticks/ 0.991623038 seconds time elapsed 'cbox/clockticks' [jolsa@krava perf]$ sudo ./perf stat -e 'cbox/clockticks/' -a ^C Performance counter stats for 'system wide': 0 cbox/clockticks/ 0.708006656 seconds time elapsed 'uncore_cbox/clockticks/' [jolsa@krava perf]$ sudo ./perf stat -e 'uncore_cbox/clockticks/' -a invalid or unsupported event: 'uncore_cbox/clockticks/' Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --eventevent selector. use 'perf list' to list available events jirka
Re: [PATCH 08/10] perf, tools: Expand PMU events by prefix match
> so there's a special treatment for uncore events, > what if user says 'uncore_box/..' then? It should work. There's nothing special for uncore later, this is just for convenience so that I have less to type. > > + if (!strncmp($1, name, strlen($1))) { > > + if (parse_events_copy_term_list(orig_terms, > > &terms)) > > + YYABORT; > > + if (!parse_events_add_pmu(data, list, > > pmu->name, terms)) > > + ok++; > > so we're ok if some of the events is not added? > do we warn at least? It would warn a lot because most PMUs don't have a given aliases. So you would get an warning for every extra PMU. Trying to warn only for those that have the alias would need a lot of extra tracking, and it didn't seem worth the complexity. -Andi
Re: [PATCH 08/10] perf, tools: Expand PMU events by prefix match
On Thu, Oct 13, 2016 at 02:15:30PM -0700, Andi Kleen wrote: SNIP > diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y > index 3a5196380609..790f0dd598b9 100644 > --- a/tools/perf/util/parse-events.y > +++ b/tools/perf/util/parse-events.y > @@ -224,11 +224,34 @@ event_pmu: > PE_NAME opt_event_config > { > struct parse_events_evlist *data = _data; > - struct list_head *list; > + struct list_head *list, *orig_terms, *terms; > + > + if (parse_events_copy_term_list($2, &orig_terms)) > + YYABORT; > > ALLOC_LIST(list); > - ABORT_ON(parse_events_add_pmu(data, list, $1, $2)); > + if (parse_events_add_pmu(data, list, $1, $2)) { > + struct perf_pmu *pmu = NULL; > + int ok = 0; > + > + while ((pmu = perf_pmu__scan(pmu)) != NULL) { > + char *name = pmu->name; > + > + if (!strncmp(name, "uncore_", 7)) > + name += 7; so there's a special treatment for uncore events, what if user says 'uncore_box/..' then? > + if (!strncmp($1, name, strlen($1))) { > + if (parse_events_copy_term_list(orig_terms, > &terms)) > + YYABORT; > + if (!parse_events_add_pmu(data, list, > pmu->name, terms)) > + ok++; so we're ok if some of the events is not added? do we warn at least? thanks, jirka
Re: [PATCH 08/10] perf, tools: Expand PMU events by prefix match
On Thu, Oct 13, 2016 at 02:15:30PM -0700, Andi Kleen wrote: > From: Andi Kleen > > When the user specifies a pmu directly, expand it automatically > with a prefix match, similar as we do for the normal aliases now. > > This allows to specify attributes for duplicated boxes quickly. > For example uncore_cbox_{0,8}/.../ can be now specified as cbox/.../ > and it gets automatically expanded. so expand here means adding all the events, right? could you please state and example and make clear what happens as outcome thanks, jirka
[PATCH 08/10] perf, tools: Expand PMU events by prefix match
From: Andi Kleen When the user specifies a pmu directly, expand it automatically with a prefix match, similar as we do for the normal aliases now. This allows to specify attributes for duplicated boxes quickly. For example uncore_cbox_{0,8}/.../ can be now specified as cbox/.../ and it gets automatically expanded. Signed-off-by: Andi Kleen --- tools/perf/util/parse-events.c | 25 + tools/perf/util/parse-events.h | 3 +++ tools/perf/util/parse-events.y | 27 +-- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a2bbd17a0dc3..8b2333278988 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2399,6 +2399,31 @@ int parse_events_term__clone(struct parse_events_term **new, term->err_term, term->err_val); } +int parse_events_copy_term_list(struct list_head *old, +struct list_head **new) +{ + struct parse_events_term *term, *n; + int ret; + + if (!old) { + *new = NULL; + return 0; + } + + *new = malloc(sizeof(struct list_head)); + if (!*new) + return -ENOMEM; + INIT_LIST_HEAD(*new); + + list_for_each_entry (term, old, list) { + ret = parse_events_term__clone(&n, term); + if (ret) + return ret; + list_add_tail(&n->list, *new); + } + return 0; +} + void parse_events_terms__purge(struct list_head *terms) { struct parse_events_term *term, *h; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index da246a3ddb69..7ea95c35095c 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -164,6 +164,9 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, int parse_events_add_pmu(struct parse_events_evlist *data, struct list_head *list, char *name, struct list_head *head_config); +int parse_events_copy_term_list(struct list_head *old, +struct list_head **new); + enum perf_pmu_event_symbol_type perf_pmu__parse_check(const char *name); void parse_events__set_leader(char *name, struct list_head *list); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 3a5196380609..790f0dd598b9 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -224,11 +224,34 @@ event_pmu: PE_NAME opt_event_config { struct parse_events_evlist *data = _data; - struct list_head *list; + struct list_head *list, *orig_terms, *terms; + + if (parse_events_copy_term_list($2, &orig_terms)) + YYABORT; ALLOC_LIST(list); - ABORT_ON(parse_events_add_pmu(data, list, $1, $2)); + if (parse_events_add_pmu(data, list, $1, $2)) { + struct perf_pmu *pmu = NULL; + int ok = 0; + + while ((pmu = perf_pmu__scan(pmu)) != NULL) { + char *name = pmu->name; + + if (!strncmp(name, "uncore_", 7)) + name += 7; + if (!strncmp($1, name, strlen($1))) { + if (parse_events_copy_term_list(orig_terms, &terms)) + YYABORT; + if (!parse_events_add_pmu(data, list, pmu->name, terms)) + ok++; + parse_events_terms__delete(terms); + } + } + if (!ok) + YYABORT; + } parse_events_terms__delete($2); + parse_events_terms__delete(orig_terms); $$ = list; } | -- 2.5.5