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@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Allison Randal <allison@lohutok.net>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Anju T Sudhakar <anju@linux.vnet.ibm.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Link: http://lore.kernel.org/lkml/20191116074652.9960-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers
2019-11-15 23:46:52 -08:00
committed by Arnaldo Carvalho de Melo
parent cb40273085
commit a910e4666d
7 changed files with 80 additions and 29 deletions

View File

@@ -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);