Commit e64b020b authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo

perf tools: Add term support for parse_events_error

Allowing event's term processing to report back error, like:

  $ perf record -e 'cpu/even=0x1/' ls
  event syntax error: 'cpu/even=0x1/'
                           \___ unknown term

  valid terms: pc,any,inv,edge,cmask,event,in_tx,ldlat,umask,in_tx_cp,offcore_rsp,config,config1,config2,name,period,branch_type
Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1429729824-13932-7-git-send-email-jolsa@kernel.org
[ Renamed 'error' variables to 'err', not to clash with util.h error() ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent cecf3a2e
...@@ -152,7 +152,8 @@ int test__pmu(void) ...@@ -152,7 +152,8 @@ int test__pmu(void)
if (ret) if (ret)
break; break;
ret = perf_pmu__config_terms(&formats, &attr, terms, false); ret = perf_pmu__config_terms(&formats, &attr, terms,
false, NULL);
if (ret) if (ret)
break; break;
......
...@@ -675,7 +675,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data, ...@@ -675,7 +675,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
if (config_attr(&attr, head_config)) if (config_attr(&attr, head_config))
return -EINVAL; return -EINVAL;
if (perf_pmu__config(pmu, &attr, head_config)) if (perf_pmu__config(pmu, &attr, head_config, data->error))
return -EINVAL; return -EINVAL;
evsel = __add_event(list, &data->idx, &attr, evsel = __add_event(list, &data->idx, &attr,
......
...@@ -174,6 +174,10 @@ modifier_bp [rwx]{1,3} ...@@ -174,6 +174,10 @@ modifier_bp [rwx]{1,3}
} }
<config>{ <config>{
/*
* Please update formats_error_string any time
* new static term is added.
*/
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
......
...@@ -579,6 +579,38 @@ static int pmu_resolve_param_term(struct parse_events_term *term, ...@@ -579,6 +579,38 @@ static int pmu_resolve_param_term(struct parse_events_term *term,
return -1; return -1;
} }
static char *formats_error_string(struct list_head *formats)
{
struct perf_pmu_format *format;
char *err, *str;
static const char *static_terms = "config,config1,config2,name,period,branch_type\n";
unsigned i = 0;
if (!asprintf(&str, "valid terms:"))
return NULL;
/* sysfs exported terms */
list_for_each_entry(format, formats, list) {
char c = i++ ? ',' : ' ';
err = str;
if (!asprintf(&str, "%s%c%s", err, c, format->name))
goto fail;
free(err);
}
/* static terms */
err = str;
if (!asprintf(&str, "%s,%s", err, static_terms))
goto fail;
free(err);
return str;
fail:
free(err);
return NULL;
}
/* /*
* Setup one of config[12] attr members based on the * Setup one of config[12] attr members based on the
* user input data - term parameter. * user input data - term parameter.
...@@ -587,7 +619,7 @@ static int pmu_config_term(struct list_head *formats, ...@@ -587,7 +619,7 @@ static int pmu_config_term(struct list_head *formats,
struct perf_event_attr *attr, struct perf_event_attr *attr,
struct parse_events_term *term, struct parse_events_term *term,
struct list_head *head_terms, struct list_head *head_terms,
bool zero) bool zero, struct parse_events_error *err)
{ {
struct perf_pmu_format *format; struct perf_pmu_format *format;
__u64 *vp; __u64 *vp;
...@@ -611,6 +643,11 @@ static int pmu_config_term(struct list_head *formats, ...@@ -611,6 +643,11 @@ static int pmu_config_term(struct list_head *formats,
if (!format) { if (!format) {
if (verbose) if (verbose)
printf("Invalid event/parameter '%s'\n", term->config); printf("Invalid event/parameter '%s'\n", term->config);
if (err) {
err->idx = term->err_term;
err->str = strdup("unknown term");
err->help = formats_error_string(formats);
}
return -EINVAL; return -EINVAL;
} }
...@@ -636,9 +673,14 @@ static int pmu_config_term(struct list_head *formats, ...@@ -636,9 +673,14 @@ static int pmu_config_term(struct list_head *formats,
val = term->val.num; val = term->val.num;
else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
if (strcmp(term->val.str, "?")) { if (strcmp(term->val.str, "?")) {
if (verbose) if (verbose) {
pr_info("Invalid sysfs entry %s=%s\n", pr_info("Invalid sysfs entry %s=%s\n",
term->config, term->val.str); term->config, term->val.str);
}
if (err) {
err->idx = term->err_val;
err->str = strdup("expected numeric value");
}
return -EINVAL; return -EINVAL;
} }
...@@ -654,12 +696,13 @@ static int pmu_config_term(struct list_head *formats, ...@@ -654,12 +696,13 @@ static int pmu_config_term(struct list_head *formats,
int perf_pmu__config_terms(struct list_head *formats, int perf_pmu__config_terms(struct list_head *formats,
struct perf_event_attr *attr, struct perf_event_attr *attr,
struct list_head *head_terms, struct list_head *head_terms,
bool zero) bool zero, struct parse_events_error *err)
{ {
struct parse_events_term *term; struct parse_events_term *term;
list_for_each_entry(term, head_terms, list) { list_for_each_entry(term, head_terms, list) {
if (pmu_config_term(formats, attr, term, head_terms, zero)) if (pmu_config_term(formats, attr, term, head_terms,
zero, err))
return -EINVAL; return -EINVAL;
} }
...@@ -672,12 +715,14 @@ int perf_pmu__config_terms(struct list_head *formats, ...@@ -672,12 +715,14 @@ int perf_pmu__config_terms(struct list_head *formats,
* 2) pmu format definitions - specified by pmu parameter * 2) pmu format definitions - specified by pmu parameter
*/ */
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
struct list_head *head_terms) struct list_head *head_terms,
struct parse_events_error *err)
{ {
bool zero = !!pmu->default_config; bool zero = !!pmu->default_config;
attr->type = pmu->type; attr->type = pmu->type;
return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); return perf_pmu__config_terms(&pmu->format, attr, head_terms,
zero, err);
} }
static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <stdbool.h> #include <stdbool.h>
#include "parse-events.h"
enum { enum {
PERF_PMU_FORMAT_VALUE_CONFIG, PERF_PMU_FORMAT_VALUE_CONFIG,
...@@ -47,11 +48,12 @@ struct perf_pmu_alias { ...@@ -47,11 +48,12 @@ struct perf_pmu_alias {
struct perf_pmu *perf_pmu__find(const char *name); struct perf_pmu *perf_pmu__find(const char *name);
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
struct list_head *head_terms); struct list_head *head_terms,
struct parse_events_error *error);
int perf_pmu__config_terms(struct list_head *formats, int perf_pmu__config_terms(struct list_head *formats,
struct perf_event_attr *attr, struct perf_event_attr *attr,
struct list_head *head_terms, struct list_head *head_terms,
bool zero); bool zero, struct parse_events_error *error);
int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
struct perf_pmu_info *info); struct perf_pmu_info *info);
struct list_head *perf_pmu__alias(struct perf_pmu *pmu, struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment