From: Andi Kleen
It can be useful to specify branch type state per event, for example
if we want to collect both software trace points and last branch PMU
events in a single collection. Currently this doesn't work because
the software trace point errors out with -b.
There was already a branch-type parameter to configure branch sample
types per event in the parser, but it was stubbed out. This patch
implements the necessary plumbing to actually enable it.
Now
perf record -e sched:sched_switch,cpu/cpu-cycles,branch_type=any/ ...
works
Signed-off-by: Andi Kleen
---
tools/perf/util/evsel.c| 9
tools/perf/util/evsel.h| 2 +
tools/perf/util/parse-branch-options.c | 85 +++---
tools/perf/util/parse-branch-options.h | 3 +-
tools/perf/util/parse-events.c | 15 --
5 files changed, 71 insertions(+), 43 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8bc271141d9d..e58a2fbf3b16 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -28,6 +28,7 @@
#include "debug.h"
#include "trace-event.h"
#include "stat.h"
+#include "util/parse-branch-options.h"
static struct {
bool sample_id_all;
@@ -708,6 +709,14 @@ static void apply_config_terms(struct perf_evsel *evsel,
case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
callgraph_buf = term->val.callgraph;
break;
+ case PERF_EVSEL__CONFIG_TERM_BRANCH:
+ if (term->val.branch && strcmp(term->val.branch, "no"))
{
+ perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
+ parse_branch_str(term->val.branch,
+&attr->branch_sample_type);
+ } else
+ perf_evsel__reset_sample_bit(evsel,
BRANCH_STACK);
+ break;
case PERF_EVSEL__CONFIG_TERM_STACK_USER:
dump_size = term->val.stack_user;
break;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b1503b0ecdff..8cd7cd227483 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -47,6 +47,7 @@ enum {
PERF_EVSEL__CONFIG_TERM_MAX_STACK,
PERF_EVSEL__CONFIG_TERM_OVERWRITE,
PERF_EVSEL__CONFIG_TERM_DRV_CFG,
+ PERF_EVSEL__CONFIG_TERM_BRANCH,
PERF_EVSEL__CONFIG_TERM_MAX,
};
@@ -63,6 +64,7 @@ struct perf_evsel_config_term {
int max_stack;
boolinherit;
booloverwrite;
+ char*branch;
} val;
};
diff --git a/tools/perf/util/parse-branch-options.c
b/tools/perf/util/parse-branch-options.c
index afc088dd7d20..3634d6974300 100644
--- a/tools/perf/util/parse-branch-options.c
+++ b/tools/perf/util/parse-branch-options.c
@@ -31,59 +31,51 @@ static const struct branch_mode branch_modes[] = {
BRANCH_END
};
-int
-parse_branch_stack(const struct option *opt, const char *str, int unset)
+int parse_branch_str(const char *str, __u64 *mode)
{
#define ONLY_PLM \
(PERF_SAMPLE_BRANCH_USER|\
PERF_SAMPLE_BRANCH_KERNEL |\
PERF_SAMPLE_BRANCH_HV)
- uint64_t *mode = (uint64_t *)opt->value;
+ int ret = 0;
+ char *p, *s;
+ char *os = NULL;
const struct branch_mode *br;
- char *s, *os = NULL, *p;
- int ret = -1;
- if (unset)
+ if (str == NULL) {
+ *mode = PERF_SAMPLE_BRANCH_ANY;
return 0;
+ }
- /*
-* cannot set it twice, -b + --branch-filter for instance
-*/
- if (*mode)
+ /* because str is read-only */
+ s = os = strdup(str);
+ if (!s)
return -1;
- /* str may be NULL in case no arg is passed to -b */
- if (str) {
- /* because str is read-only */
- s = os = strdup(str);
- if (!s)
- return -1;
-
- for (;;) {
- p = strchr(s, ',');
- if (p)
- *p = '\0';
-
- for (br = branch_modes; br->name; br++) {
- if (!strcasecmp(s, br->name))
- break;
- }
- if (!br->name) {
- ui__warning("unknown branch filter %s,"
- " check man page\n", s);
- goto error;
- }
-
- *mode |= br->mode;
-
- if (!p)
- break;
+ for (;;) {
+ p = strchr(s, ',');
+ if (p)
+ *p = '\0';
- s = p + 1;
+ for (b