The following commit has been merged into the perf/core branch of tip: Commit-ID: a910e4666d61712840c78de33cc7f89de8affa78 Gitweb: https://git.kernel.org/tip/a910e4666d61712840c78de33cc7f89de8affa78 Author: Ian Rogers <irogers@xxxxxxxxxx> AuthorDate: Fri, 15 Nov 2019 23:46:52 -08:00 Committer: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> CommitterDate: Mon, 18 Nov 2019 19:14:29 -03:00 perf parse: Report initial event parsing error Record the first event parsing error and report. Implementing feedback from Jiri Olsa: https://lkml.org/lkml/2019/10/28/680 An example error is: $ tools/perf/perf stat -e c/c/ WARNING: multiple event parsing errors event syntax error: 'c/c/' \___ unknown term valid terms: event,filter_rem,filter_opc0,edge,filter_isoc,filter_tid,filter_loc,filter_nc,inv,umask,filter_opc1,tid_en,thresh,filter_all_op,filter_not_nm,filter_state,filter_nm,config,config1,config2,name,period,percore Initial error: event syntax error: 'c/c/' \___ Cannot find PMU `c'. Missing kernel support? 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 Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx> Tested-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx> Cc: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx> Cc: Allison Randal <allison@xxxxxxxxxxx> Cc: Andi Kleen <ak@xxxxxxxxxxxxxxx> Cc: Anju T Sudhakar <anju@xxxxxxxxxxxxxxxxxx> Cc: Christian Borntraeger <borntraeger@xxxxxxxxxx> Cc: Davidlohr Bueso <dave@xxxxxxxxxxxx> Cc: Jin Yao <yao.jin@xxxxxxxxxxxxxxx> Cc: Jiri Olsa <jolsa@xxxxxxxxxx> Cc: Mark Rutland <mark.rutland@xxxxxxx> Cc: Namhyung Kim <namhyung@xxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Ravi Bangoria <ravi.bangoria@xxxxxxxxxxxxx> Cc: Stephane Eranian <eranian@xxxxxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Thomas Richter <tmricht@xxxxxxxxxxxxx> Link: http://lore.kernel.org/lkml/20191116074652.9960-1-irogers@xxxxxxxxxx Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> --- tools/perf/arch/powerpc/util/kvm-stat.c | 4 +- tools/perf/builtin-stat.c | 2 +- tools/perf/builtin-trace.c | 16 +++-- tools/perf/tests/parse-events.c | 3 +- tools/perf/util/metricgroup.c | 2 +- tools/perf/util/parse-events.c | 78 +++++++++++++++++------- tools/perf/util/parse-events.h | 4 +- 7 files changed, 80 insertions(+), 29 deletions(-) diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c index 9cc1c4a..1680726 100644 --- a/tools/perf/arch/powerpc/util/kvm-stat.c +++ b/tools/perf/arch/powerpc/util/kvm-stat.c @@ -113,10 +113,10 @@ static int is_tracepoint_available(const char *str, struct evlist *evlist) struct parse_events_error err; int ret; - err.str = NULL; + bzero(&err, sizeof(err)); ret = parse_events(evlist, str, &err); if (err.str) - pr_err("%s : %s\n", str, err.str); + parse_events_print_error(&err, "tracepoint"); return ret; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5964e80..0a15253 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1307,6 +1307,7 @@ static int add_default_attributes(void) if (stat_config.null_run) return 0; + bzero(&errinfo, sizeof(errinfo)); if (transaction_run) { /* Handle -T as -M transaction. Once platform specific metrics * support has been added to the json files, all archictures @@ -1364,6 +1365,7 @@ static int add_default_attributes(void) return -1; } if (err) { + parse_events_print_error(&errinfo, smi_cost_attrs); fprintf(stderr, "Cannot set up SMI cost events\n"); return -1; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 43c05ea..46a72ec 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3016,11 +3016,18 @@ static bool evlist__add_vfs_getname(struct evlist *evlist) { bool found = false; struct evsel *evsel, *tmp; - struct parse_events_error err = { .idx = 0, }; - int ret = parse_events(evlist, "probe:vfs_getname*", &err); + struct parse_events_error err; + int ret; - if (ret) + bzero(&err, sizeof(err)); + ret = parse_events(evlist, "probe:vfs_getname*", &err); + if (ret) { + free(err.str); + free(err.help); + free(err.first_str); + free(err.first_help); return false; + } evlist__for_each_entry_safe(evlist, evsel, tmp) { if (!strstarts(perf_evsel__name(evsel), "probe:vfs_getname")) @@ -4832,8 +4839,9 @@ int cmd_trace(int argc, const char **argv) * wrong in more detail. */ if (trace.perfconfig_events != NULL) { - struct parse_events_error parse_err = { .idx = 0, }; + struct parse_events_error parse_err; + bzero(&parse_err, sizeof(parse_err)); err = parse_events(trace.evlist, trace.perfconfig_events, &parse_err); if (err) { parse_events_print_error(&parse_err, trace.perfconfig_events); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 25e0ed2..091c3ae 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1768,10 +1768,11 @@ static struct terms_test test__terms[] = { static int test_event(struct evlist_test *e) { - struct parse_events_error err = { .idx = 0, }; + struct parse_events_error err; struct evlist *evlist; int ret; + bzero(&err, sizeof(err)); if (e->valid && !e->valid()) { pr_debug("... SKIP"); return 0; diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index a7c0424..6a4d350 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -523,7 +523,7 @@ int metricgroup__parse_groups(const struct option *opt, if (ret) return ret; pr_debug("adding %s\n", extra_events.buf); - memset(&parse_error, 0, sizeof(struct parse_events_error)); + bzero(&parse_error, sizeof(parse_error)); ret = parse_events(perf_evlist, extra_events.buf, &parse_error); if (ret) { parse_events_print_error(&parse_error, extra_events.buf); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6d18ff9..6bae9d6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -189,12 +189,29 @@ void parse_events__handle_error(struct parse_events_error *err, int idx, free(help); return; } - WARN_ONCE(err->str, "WARNING: multiple event parsing errors\n"); - err->idx = idx; - free(err->str); - err->str = str; - free(err->help); - err->help = help; + switch (err->num_errors) { + case 0: + err->idx = idx; + err->str = str; + err->help = help; + break; + case 1: + err->first_idx = err->idx; + err->idx = idx; + err->first_str = err->str; + err->str = str; + err->first_help = err->help; + err->help = help; + break; + default: + WARN_ONCE(1, "WARNING: multiple event parsing errors\n"); + free(err->str); + err->str = str; + free(err->help); + err->help = help; + break; + } + err->num_errors++; } struct tracepoint_path *tracepoint_id_to_path(u64 config) @@ -1349,7 +1366,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, if (asprintf(&err_str, "Cannot find PMU `%s'. Missing kernel support?", name) >= 0) - parse_events__handle_error(err, -1, err_str, NULL); + parse_events__handle_error(err, 0, err_str, NULL); return -EINVAL; } @@ -2007,15 +2024,14 @@ static int get_term_width(void) return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col; } -void parse_events_print_error(struct parse_events_error *err, - const char *event) +static void __parse_events_print_error(int err_idx, const char *err_str, + const char *err_help, const char *event) { const char *str = "invalid or unsupported event: "; char _buf[MAX_WIDTH]; char *buf = (char *) event; int idx = 0; - - if (err->str) { + if (err_str) { /* -2 for extra '' in the final fprintf */ int width = get_term_width() - 2; int len_event = strlen(event); @@ -2038,8 +2054,8 @@ void parse_events_print_error(struct parse_events_error *err, buf = _buf; /* We're cutting from the beginning. */ - if (err->idx > max_err_idx) - cut = err->idx - max_err_idx; + if (err_idx > max_err_idx) + cut = err_idx - max_err_idx; strncpy(buf, event + cut, max_len); @@ -2052,16 +2068,33 @@ void parse_events_print_error(struct parse_events_error *err, buf[max_len] = 0; } - idx = len_str + err->idx - cut; + idx = len_str + err_idx - cut; } fprintf(stderr, "%s'%s'\n", str, buf); if (idx) { - fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str); - if (err->help) - fprintf(stderr, "\n%s\n", err->help); - zfree(&err->str); - zfree(&err->help); + fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err_str); + if (err_help) + fprintf(stderr, "\n%s\n", err_help); + } +} + +void parse_events_print_error(struct parse_events_error *err, + const char *event) +{ + if (!err->num_errors) + return; + + __parse_events_print_error(err->idx, err->str, err->help, event); + zfree(&err->str); + zfree(&err->help); + + if (err->num_errors > 1) { + fputs("\nInitial error:\n", stderr); + __parse_events_print_error(err->first_idx, err->first_str, + err->first_help, event); + zfree(&err->first_str); + zfree(&err->first_help); } } @@ -2071,8 +2104,11 @@ int parse_events_option(const struct option *opt, const char *str, int unset __maybe_unused) { struct evlist *evlist = *(struct evlist **)opt->value; - struct parse_events_error err = { .idx = 0, }; - int ret = parse_events(evlist, str, &err); + struct parse_events_error err; + int ret; + + bzero(&err, sizeof(err)); + ret = parse_events(evlist, str, &err); if (ret) { parse_events_print_error(&err, str); diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 5ee8ac9..ff367f2 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -110,9 +110,13 @@ struct parse_events_term { }; struct parse_events_error { + int num_errors; /* number of errors encountered */ int idx; /* index in the parsed string */ char *str; /* string to display at the index */ char *help; /* optional help string */ + int first_idx;/* as above, but for the first encountered error */ + char *first_str; + char *first_help; }; struct parse_events_state {
![]() |