perf tools: Support parsing parameterized events
Enable event specification like: pmu/event_name,param1=0x1,param2=0x4/ Assuming that /sys/bus/event_source/devices/pmu/events/event_name Contains something like param2=?,bar=1,param1=? Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com> Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Cody P Schafer <dev@codyps.com> Cc: Haren Myneni <hbabu@us.ibm.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/1420679633-28856-2-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
c8defe2494
commit
688d4dfcdd
|
@ -71,6 +71,7 @@ struct parse_events_term {
|
||||||
int type_val;
|
int type_val;
|
||||||
int type_term;
|
int type_term;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
bool used;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct parse_events_evlist {
|
struct parse_events_evlist {
|
||||||
|
|
|
@ -550,6 +550,35 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Term is a string term, and might be a param-term. Try to look up it's value
|
||||||
|
* in the remaining terms.
|
||||||
|
* - We have a term like "base-or-format-term=param-term",
|
||||||
|
* - We need to find the value supplied for "param-term" (with param-term named
|
||||||
|
* in a config string) later on in the term list.
|
||||||
|
*/
|
||||||
|
static int pmu_resolve_param_term(struct parse_events_term *term,
|
||||||
|
struct list_head *head_terms,
|
||||||
|
__u64 *value)
|
||||||
|
{
|
||||||
|
struct parse_events_term *t;
|
||||||
|
|
||||||
|
list_for_each_entry(t, head_terms, list) {
|
||||||
|
if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
|
||||||
|
if (!strcmp(t->config, term->config)) {
|
||||||
|
t->used = true;
|
||||||
|
*value = t->val.num;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
printf("Required parameter '%s' not specified\n", term->config);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
|
@ -557,25 +586,33 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
|
||||||
static int pmu_config_term(struct list_head *formats,
|
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,
|
||||||
bool zero)
|
bool zero)
|
||||||
{
|
{
|
||||||
struct perf_pmu_format *format;
|
struct perf_pmu_format *format;
|
||||||
__u64 *vp;
|
__u64 *vp;
|
||||||
|
__u64 val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is a parameter we've already used for parameterized-eval,
|
||||||
|
* skip it in normal eval.
|
||||||
|
*/
|
||||||
|
if (term->used)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Support only for hardcoded and numnerial terms.
|
|
||||||
* Hardcoded terms should be already in, so nothing
|
* Hardcoded terms should be already in, so nothing
|
||||||
* to be done for them.
|
* to be done for them.
|
||||||
*/
|
*/
|
||||||
if (parse_events__is_hardcoded_term(term))
|
if (parse_events__is_hardcoded_term(term))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
format = pmu_find_format(formats, term->config);
|
format = pmu_find_format(formats, term->config);
|
||||||
if (!format)
|
if (!format) {
|
||||||
|
if (verbose)
|
||||||
|
printf("Invalid event/parameter '%s'\n", term->config);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
switch (format->value) {
|
switch (format->value) {
|
||||||
case PERF_PMU_FORMAT_VALUE_CONFIG:
|
case PERF_PMU_FORMAT_VALUE_CONFIG:
|
||||||
|
@ -592,11 +629,25 @@ static int pmu_config_term(struct list_head *formats,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX If we ever decide to go with string values for
|
* Either directly use a numeric term, or try to translate string terms
|
||||||
* non-hardcoded terms, here's the place to translate
|
* using event parameters.
|
||||||
* them into value.
|
|
||||||
*/
|
*/
|
||||||
pmu_format_value(format->bits, term->val.num, vp, zero);
|
if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
|
||||||
|
val = term->val.num;
|
||||||
|
else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
|
||||||
|
if (strcmp(term->val.str, "?")) {
|
||||||
|
if (verbose)
|
||||||
|
pr_info("Invalid sysfs entry %s=%s\n",
|
||||||
|
term->config, term->val.str);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pmu_resolve_param_term(term, head_terms, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
} else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pmu_format_value(format->bits, val, vp, zero);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,9 +658,10 @@ int perf_pmu__config_terms(struct list_head *formats,
|
||||||
{
|
{
|
||||||
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, zero))
|
if (pmu_config_term(formats, attr, term, head_terms, zero))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue