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 <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/1476306127-19721-1-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
#include "debug.h"
#include "trace-event.h"
#include "stat.h"
+#include "util/parse-branch-options.h"
static struct {
bool sample_id_all;
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;
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,
};
int max_stack;
bool inherit;
bool overwrite;
+ char *branch;
} val;
};
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 (br = branch_modes; br->name; br++) {
+ if (!strcasecmp(s, br->name))
+ break;
+ }
+ if (!br->name) {
+ ret = -1;
+ ui__warning("unknown branch filter %s,"
+ " check man page\n", s);
+ goto error;
}
+
+ *mode |= br->mode;
+
+ if (!p)
+ break;
+
+ s = p + 1;
}
- ret = 0;
/* default to any branch */
if ((*mode & ~ONLY_PLM) == 0) {
free(os);
return ret;
}
+
+int
+parse_branch_stack(const struct option *opt, const char *str, int unset)
+{
+ __u64 *mode = (__u64 *)opt->value;
+
+ if (unset)
+ return 0;
+
+ /*
+ * cannot set it twice, -b + --branch-filter for instance
+ */
+ if (*mode)
+ return -1;
+
+ return parse_branch_str(str, mode);
+}
#ifndef _PERF_PARSE_BRANCH_OPTIONS_H
#define _PERF_PARSE_BRANCH_OPTIONS_H 1
-struct option;
+#include <stdint.h>
int parse_branch_stack(const struct option *opt, const char *str, int unset);
+int parse_branch_str(const char *str, __u64 *mode);
#endif /* _PERF_PARSE_BRANCH_OPTIONS_H */
#include "cpumap.h"
#include "probe-file.h"
#include "asm/bug.h"
+#include "util/parse-branch-options.h"
#define MAX_NAME_LEN 100
CHECK_TYPE_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;
- */
+ CHECK_TYPE_VAL(STR);
+ if (strcmp(term->val.str, "no") &&
+ parse_branch_str(term->val.str, &attr->branch_sample_type)) {
+ err->str = strdup("invalid branch sample type");
+ err->idx = term->err_val;
+ return -EINVAL;
+ }
break;
case PARSE_EVENTS__TERM_TYPE_TIME:
CHECK_TYPE_VAL(NUM);
case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str);
break;
+ case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+ ADD_CONFIG_TERM(BRANCH, branch, term->val.str);
+ break;
case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
break;