Messages in this thread Patch in this message | | | From | Jiri Olsa <> | Subject | [PATCH 5/8] perf, tool: Add pmu event parse support for branch_sample_type values | Date | Wed, 4 Apr 2012 22:21:35 +0200 |
| |
Adding a support to specify branch_type as a hardcoded term inside the pmu event definition.
It is possible to specify pmu event like: "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u"
Following string values could be used as value for branch_type: u (PERF_SAMPLE_BRANCH_USER) k (PERF_SAMPLE_BRANCH_KERNEL) hv (PERF_SAMPLE_BRANCH_HV) any (PERF_SAMPLE_BRANCH_ANY) any_call (PERF_SAMPLE_BRANCH_ANY_CALL) any_ret (PERF_SAMPLE_BRANCH_ANY_RETURN) ind_call (PERF_SAMPLE_BRANCH_IND_CALL)
Also a number could be specified as value.
CC: Stephane Eranian <eranian@google.com>
Signed-off-by: Jiri Olsa <jolsa@redhat.com> --- tools/perf/builtin-record.c | 31 +----------- tools/perf/builtin-test.c | 27 +++++++++++ tools/perf/util/parse-events.c | 100 ++++++++++++++++++++++++++++++++++++++-- tools/perf/util/parse-events.h | 1 + 4 files changed, 127 insertions(+), 32 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index be4e1ee..87fc68d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -641,27 +641,6 @@ out_delete_session: return err; } -#define BRANCH_OPT(n, m) \ - { .name = n, .mode = (m) } - -#define BRANCH_END { .name = NULL } - -struct branch_mode { - const char *name; - int mode; -}; - -static const struct branch_mode branch_modes[] = { - BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), - BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), - BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), - BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), - BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), - BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), - BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), - BRANCH_END -}; - static int parse_branch_stack(const struct option *opt, const char *str, int unset) { @@ -671,7 +650,6 @@ parse_branch_stack(const struct option *opt, const char *str, int unset) PERF_SAMPLE_BRANCH_HV) uint64_t *mode = (uint64_t *)opt->value; - const struct branch_mode *br; char *s, *os = NULL, *p; int ret = -1; @@ -692,21 +670,18 @@ parse_branch_stack(const struct option *opt, const char *str, int unset) return -1; for (;;) { + u64 bmode; p = strchr(s, ','); if (p) *p = '\0'; - for (br = branch_modes; br->name; br++) { - if (!strcasecmp(s, br->name)) - break; - } - if (!br->name) { + if (parse_events__branch_type(&bmode, s)) { ui__warning("unknown branch filter %s," " check man page\n", s); goto error; } - *mode |= br->mode; + *mode |= bmode; if (!p) break; diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index d522cf4..2e4dc0a 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -1008,6 +1008,29 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist) return 0; } +static int test__checkevent_pmu_branch_type(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong config2", 2 == evsel->attr.config2); + +#define BT (PERF_SAMPLE_BRANCH_USER | \ + PERF_SAMPLE_BRANCH_HV | \ + PERF_SAMPLE_BRANCH_ANY_RETURN) + + TEST_ASSERT_VAL("wrong sample_type", + PERF_SAMPLE_BRANCH_STACK && evsel->attr.sample_type); + TEST_ASSERT_VAL("wrong branch_type", + BT == evsel->attr.branch_sample_type); + +#undef BT + return 0; +} + static struct test__event_st { const char *name; __u32 type; @@ -1117,6 +1140,10 @@ static struct test__event_st { .name = "cpu/config=1,name=krava/u,cpu/config=2/u", .check = test__checkevent_pmu_name, }, + { + .name = "cpu/config=1,branch_type=hv|any_ret|1,config2=2/u", + .check = test__checkevent_pmu_branch_type, + }, }; #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c349cf3..076b1f8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -590,6 +590,99 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx, return add_event(list, idx, &attr, name); } +#define BRANCH_OPT(n, m) { .name = n, .mode = (m) } +#define BRANCH_END { .name = NULL } + +struct branch_mode { + const char *name; + int mode; +}; + +static const struct branch_mode branch_modes[] = { + BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), + BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), + BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), + BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), + BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), + BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), + BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), + BRANCH_END +}; + +int parse_events__branch_type(u64 *_type, char *str) +{ + const struct branch_mode *br; + + for (br = branch_modes; br->name; br++) { + if (!strcasecmp(str, br->name)) { + *_type = br->mode; + return 0; + } + } + + return -EINVAL; +} + +typedef int (process_term_list_cb)(struct parse_events__term_elem *elem, + void *arg); + +static int branch_type_cb(struct parse_events__term_elem *elem, void *arg) +{ + u64 *_type = arg; + u64 type; + + switch (elem->type_val) { + case PARSE_EVENTS__TERM_TYPE_NUM: + type = elem->val.num; + break; + case PARSE_EVENTS__TERM_TYPE_STR: + if (parse_events__branch_type(&type, elem->val.str)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + *_type |= type; + return 0; +} + +static int process_term_list(struct parse_events__term *term, + process_term_list_cb cb, void *arg) +{ + struct parse_events__term_elem *elem; + + list_for_each_entry(elem, &term->val.list, list) + if (cb(elem, arg)) + return -EINVAL; + + return 0; +} + +static int branch_type(struct parse_events__term *term, u64 *_type) +{ + u64 type = 0; + + switch (term->type_val) { + case PARSE_EVENTS__TERM_TYPE_NUM: + type = term->val.num; + break; + case PARSE_EVENTS__TERM_TYPE_STR: + if (parse_events__branch_type(&type, term->val.str)) + return -EINVAL; + break; + case PARSE_EVENTS__TERM_TYPE_LIST: + if (process_term_list(term, branch_type_cb, &type)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + *_type = type; + return 0; +} + static int config_term(struct perf_event_attr *attr, struct parse_events__term *term) { @@ -617,10 +710,9 @@ do { \ attr->sample_period = term->val.num; break; case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: - /* - * TODO uncomment when the field is available - * attr->branch_sample_type = term->val.num; - */ + attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; + if (branch_type(term, (u64 *)&attr->branch_sample_type)) + return -EINVAL; break; default: return -EINVAL; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index cabcbc1..8bb673d 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -83,6 +83,7 @@ int parse_events__term_list(struct parse_events__term **_term, struct list_head *list); int parse_events__term_elem(struct parse_events__term_elem **_e, int type_val, char *str, long num); +int parse_events__branch_type(u64 *_type, char *str); void parse_events__free_terms(struct list_head *terms); int parse_events_modifier(struct list_head *list __used, char *str __used); int parse_events_add_tracepoint(struct list_head *list, int *idx, -- 1.7.7.6
| |