driver inclusion category: driver bugzilla: https://gitee.com/openeuler/kernel/issues/IAMH2B CVE: NA
----------------------------------------------------------------------
Upstream: Yes AR20220107954521 Bugfix or Feature: Bugfix DTS2024072721521
Mainstream version before @9bce13ea88f8 may have issue parsing perf events aliased with dashes (e.g. 'foo-bar-baz').
Fix patches of community has been merged to mainstream but not openeuler. This commit fixes some conflicts produced during applying above patches to openeuler.
The original commit is @fb0811535e92c, commit message is as follows.
perf parse-events: Allow config on kernel PMU events
An event like inst_retired.any on an Intel skylake is found in the pmu-events code created from the pipeline event JSON.
The event is an alias for cpu/event=0xc0,period=2000003/ and parse-events recognizes the event with the token PE_KERNEL_PMU_EVENT.
The parser doesn't currently allow extra configuration on such events, except for modifiers, so:
$ perf stat -e inst_retired.any// /bin/true event syntax error: 'inst_retired.any//' ___ parser error Run 'perf list' for a list of valid events
Usage: perf stat [<options>] [<command>]
-e, --event <event> event selector. use 'perf list' to list available events
This patch adds configuration to these events which can be useful for a number of parameters like name and call-graph:
$ sudo perf record -e inst_retired.any/call-graph=lbr/ -a sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 1.856 MB perf.data (44 samples) ]
It is necessary for the metric code so that we may add metric-id values to these events before they are parsed.
Signed-off-by: Yushan Wang wangyushan12@huawei.com Signed-off-by: zhangqz 14294317+zwx1160575@user.noreply.gitee.com --- tools/perf/tests/parse-events.c | 2 +- tools/perf/util/parse-events.c | 92 ++++++++++++++++++++++----------- tools/perf/util/parse-events.h | 6 ++- tools/perf/util/parse-events.y | 17 +++++- 4 files changed, 83 insertions(+), 34 deletions(-)
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 9ae39cd857c8..4ad0343f2ce9 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -2050,7 +2050,7 @@ static int test_pmu_events(void) closedir(dir); return ret; } - + static int test_pmu_events_alias2(void) { static const char events[][30] = { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4005887dfda8..4f988f768697 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1567,44 +1567,48 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, }
int parse_events_multi_pmu_add(struct parse_events_state *parse_state, - char *str, struct list_head **listp) + char *str, struct list_head *head, + struct list_head **listp) { struct parse_events_term *term; - struct list_head *list; + struct list_head *list = NULL; struct perf_pmu *pmu = NULL; int ok = 0; + char *config;
*listp = NULL; + + if (!head) { + head = malloc(sizeof(struct list_head)); + if (!head) + goto out_err; + + INIT_LIST_HEAD(head); + } + config = strdup(str); + if (!config) + goto out_err; + + if (parse_events_term__num(&term, + PARSE_EVENTS__TERM_TYPE_USER, + config, 1, false, &config, + NULL) < 0) { + free(config); + goto out_err; + } + list_add_tail(&term->list, head); + /* Add it for all PMUs that support the alias */ list = malloc(sizeof(struct list_head)); if (!list) - return -1; + goto out_err; + 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)) { - struct list_head *head; - char *config; - - head = malloc(sizeof(struct list_head)); - if (!head) - return -1; - INIT_LIST_HEAD(head); - config = strdup(str); - if (!config) - return -1; - if (parse_events_term__num(&term, - PARSE_EVENTS__TERM_TYPE_USER, - config, 1, false, &config, - NULL) < 0) { - free(list); - free(config); - return -1; - } - list_add_tail(&term->list, head); - if (!parse_events_add_pmu(parse_state, list, pmu->name, head, true, true)) { @@ -1612,8 +1616,6 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, pmu->name, alias->str); ok++; } - - parse_events_terms__delete(head); } } } @@ -1626,12 +1628,14 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, } }
- if (!ok) { +out_err: + if (ok) + *listp = list; + else free(list); - return -1; - } - *listp = list; - return 0; + + parse_events_terms__delete(head); + return ok ? 0 : -1; }
int parse_events__modifier_group(struct list_head *list, @@ -2234,6 +2238,19 @@ int __parse_events(struct evlist *evlist, const char *str, return ret; }
+void parse_events_error__init(struct parse_events_error *err) +{ + bzero(err, sizeof(*err)); +} + +void parse_events_error__exit(struct parse_events_error *err) +{ + zfree(&err->str); + zfree(&err->help); + zfree(&err->first_str); + zfree(&err->first_help); +} + #define MAX_WIDTH 1000 static int get_term_width(void) { @@ -2298,6 +2315,21 @@ static void __parse_events_print_error(int err_idx, const char *err_str, } }
+void parse_events_error__print(struct parse_events_error *err, + const char *event) +{ + if (!err->num_errors) + return; + + __parse_events_print_error(err->idx, err->str, err->help, event); + + if (err->num_errors > 1) { + fputs("\nInitial error:\n", stderr); + __parse_events_print_error(err->first_idx, err->first_str, + err->first_help, event); + } +} + void parse_events_print_error(struct parse_events_error *err, const char *event) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a0c6f95b5683..014d268426e6 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -202,7 +202,7 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, char *name, struct perf_pmu *pmu);
int parse_events_multi_pmu_add(struct parse_events_state *parse_state, - char *str, + char *str, struct list_head *head, struct list_head **listp);
int parse_events_copy_term_list(struct list_head *old, @@ -242,6 +242,10 @@ char *parse_events_formats_error_string(char *additional_terms);
void parse_events_print_error(struct parse_events_error *err, const char *event); +void parse_events_error__init(struct parse_events_error *err); +void parse_events_error__exit(struct parse_events_error *err); +void parse_events_error__print(struct parse_events_error *err, + const char *event);
#ifdef HAVE_LIBELF_SUPPORT /* diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index b6dd7f8b5a6c..15e3c90f1c27 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -337,7 +337,7 @@ PE_KERNEL_PMU_EVENT sep_dc struct list_head *list; int err;
- err = parse_events_multi_pmu_add(_parse_state, $1, &list); + err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list); free($1); if (err < 0) YYABORT; @@ -357,6 +357,19 @@ PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF '-' PE_PMU_EVENT_SUF2 sep_dc $$ = list; } | +PE_KERNEL_PMU_EVENT opt_pmu_config +{ + struct list_head *list; + int err; + + /* frees $2 */ + err = parse_events_multi_pmu_add(_parse_state, $1, $2, &list); + free($1); + if (err < 0) + YYABORT; + $$ = list; +} +| PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc { struct list_head *list; @@ -365,7 +378,7 @@ PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc snprintf(pmu_name, sizeof(pmu_name), "%s-%s", $1, $3); free($1); free($3); - if (parse_events_multi_pmu_add(_parse_state, pmu_name, &list) < 0) + if (parse_events_multi_pmu_add(_parse_state, pmu_name, NULL, &list) < 0) YYABORT; $$ = list; }