Commit ac12f676 authored by Andi Kleen's avatar Andi Kleen Committed by Arnaldo Carvalho de Melo

perf tools: Implement branch_type event parameter

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: default avatarAndi Kleen <ak@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/1476306127-19721-1-git-send-email-andi@firstfloor.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 84ee74af
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "debug.h" #include "debug.h"
#include "trace-event.h" #include "trace-event.h"
#include "stat.h" #include "stat.h"
#include "util/parse-branch-options.h"
static struct { static struct {
bool sample_id_all; bool sample_id_all;
...@@ -708,6 +709,14 @@ static void apply_config_terms(struct perf_evsel *evsel, ...@@ -708,6 +709,14 @@ static void apply_config_terms(struct perf_evsel *evsel,
case PERF_EVSEL__CONFIG_TERM_CALLGRAPH: case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
callgraph_buf = term->val.callgraph; callgraph_buf = term->val.callgraph;
break; 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: case PERF_EVSEL__CONFIG_TERM_STACK_USER:
dump_size = term->val.stack_user; dump_size = term->val.stack_user;
break; break;
......
...@@ -47,6 +47,7 @@ enum { ...@@ -47,6 +47,7 @@ enum {
PERF_EVSEL__CONFIG_TERM_MAX_STACK, PERF_EVSEL__CONFIG_TERM_MAX_STACK,
PERF_EVSEL__CONFIG_TERM_OVERWRITE, PERF_EVSEL__CONFIG_TERM_OVERWRITE,
PERF_EVSEL__CONFIG_TERM_DRV_CFG, PERF_EVSEL__CONFIG_TERM_DRV_CFG,
PERF_EVSEL__CONFIG_TERM_BRANCH,
PERF_EVSEL__CONFIG_TERM_MAX, PERF_EVSEL__CONFIG_TERM_MAX,
}; };
...@@ -63,6 +64,7 @@ struct perf_evsel_config_term { ...@@ -63,6 +64,7 @@ struct perf_evsel_config_term {
int max_stack; int max_stack;
bool inherit; bool inherit;
bool overwrite; bool overwrite;
char *branch;
} val; } val;
}; };
......
...@@ -31,59 +31,51 @@ static const struct branch_mode branch_modes[] = { ...@@ -31,59 +31,51 @@ static const struct branch_mode branch_modes[] = {
BRANCH_END BRANCH_END
}; };
int int parse_branch_str(const char *str, __u64 *mode)
parse_branch_stack(const struct option *opt, const char *str, int unset)
{ {
#define ONLY_PLM \ #define ONLY_PLM \
(PERF_SAMPLE_BRANCH_USER |\ (PERF_SAMPLE_BRANCH_USER |\
PERF_SAMPLE_BRANCH_KERNEL |\ PERF_SAMPLE_BRANCH_KERNEL |\
PERF_SAMPLE_BRANCH_HV) 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; 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; return 0;
}
/* /* because str is read-only */
* cannot set it twice, -b + --branch-filter for instance s = os = strdup(str);
*/ if (!s)
if (*mode)
return -1; return -1;
/* str may be NULL in case no arg is passed to -b */ for (;;) {
if (str) { p = strchr(s, ',');
/* because str is read-only */ if (p)
s = os = strdup(str); *p = '\0';
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;
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 */ /* default to any branch */
if ((*mode & ~ONLY_PLM) == 0) { if ((*mode & ~ONLY_PLM) == 0) {
...@@ -93,3 +85,20 @@ parse_branch_stack(const struct option *opt, const char *str, int unset) ...@@ -93,3 +85,20 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
free(os); free(os);
return ret; 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 #ifndef _PERF_PARSE_BRANCH_OPTIONS_H
#define _PERF_PARSE_BRANCH_OPTIONS_H 1 #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_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 */ #endif /* _PERF_PARSE_BRANCH_OPTIONS_H */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "cpumap.h" #include "cpumap.h"
#include "probe-file.h" #include "probe-file.h"
#include "asm/bug.h" #include "asm/bug.h"
#include "util/parse-branch-options.h"
#define MAX_NAME_LEN 100 #define MAX_NAME_LEN 100
...@@ -973,10 +974,13 @@ do { \ ...@@ -973,10 +974,13 @@ do { \
CHECK_TYPE_VAL(NUM); CHECK_TYPE_VAL(NUM);
break; break;
case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
/* CHECK_TYPE_VAL(STR);
* TODO uncomment when the field is available if (strcmp(term->val.str, "no") &&
* attr->branch_sample_type = term->val.num; 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; break;
case PARSE_EVENTS__TERM_TYPE_TIME: case PARSE_EVENTS__TERM_TYPE_TIME:
CHECK_TYPE_VAL(NUM); CHECK_TYPE_VAL(NUM);
...@@ -1119,6 +1123,9 @@ do { \ ...@@ -1119,6 +1123,9 @@ do { \
case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str); ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str);
break; break;
case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
ADD_CONFIG_TERM(BRANCH, branch, term->val.str);
break;
case PARSE_EVENTS__TERM_TYPE_STACKSIZE: case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num); ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment