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: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo 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: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
cecf3a2e18
commit
e64b020ba1
@@ -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,
|
|||||||
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}
|
|||||||
}
|
}
|
||||||
|
|
||||||
<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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
* 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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user