diff options
author | Roberto Agostino Vitillo <ravitillo@lbl.gov> | 2012-02-09 17:21:02 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-03-09 02:26:05 -0500 |
commit | bdfebd848f2a14e639031a0b0e61d7c7ee5e5fd2 (patch) | |
tree | 8ebcc7afda6b506dcd22d44bccdbd925c02b6768 /tools | |
parent | b5387528f31d98acedf06e930554b563d87e2383 (diff) |
perf record: Add support for sampling taken branch
This patch adds a new option to enable taken branch stack
sampling, i.e., leverage the PERF_SAMPLE_BRANCH_STACK feature
of perf_events.
There is a new option to active this mode: -b.
It is possible to pass a set of filters to select the type of
branches to sample.
The following filters are available:
- any : any type of branches
- any_call : any function call or system call
- any_ret : any function return or system call return
- any_ind : any indirect branch
- u: only when the branch target is at the user level
- k: only when the branch target is in the kernel
- hv: only when the branch target is in the hypervisor
Filters can be combined by passing a comma separated list
to the option:
$ perf record -b any_call,u -e cycles:u branchy
Signed-off-by: Roberto Agostino Vitillo <ravitillo@lbl.gov>
Signed-off-by: Stephane Eranian <eranian@google.com>
Cc: peterz@infradead.org
Cc: acme@redhat.com
Cc: robert.richter@amd.com
Cc: ming.m.lin@intel.com
Cc: andi@firstfloor.org
Cc: asharma@fb.com
Cc: vweaver1@eecs.utk.edu
Cc: khandual@linux.vnet.ibm.com
Cc: dsahern@gmail.com
Link: http://lkml.kernel.org/r/1328826068-11713-13-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 25 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 74 | ||||
-rw-r--r-- | tools/perf/perf.h | 1 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 4 |
4 files changed, 104 insertions, 0 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index a5766b4b0125..60bddaf0e5bd 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -152,6 +152,31 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha | |||
152 | corresponding events, i.e., they always refer to events defined earlier on the command | 152 | corresponding events, i.e., they always refer to events defined earlier on the command |
153 | line. | 153 | line. |
154 | 154 | ||
155 | -b:: | ||
156 | --branch-stack:: | ||
157 | Enable taken branch stack sampling. Each sample captures a series of consecutive | ||
158 | taken branches. The number of branches captured with each sample depends on the | ||
159 | underlying hardware, the type of branches of interest, and the executed code. | ||
160 | It is possible to select the types of branches captured by enabling filters. The | ||
161 | following filters are defined: | ||
162 | |||
163 | - any : any type of branches | ||
164 | - any_call: any function call or system call | ||
165 | - any_ret: any function return or system call return | ||
166 | - any_ind: any indirect branch | ||
167 | - u: only when the branch target is at the user level | ||
168 | - k: only when the branch target is in the kernel | ||
169 | - hv: only when the target is at the hypervisor level | ||
170 | |||
171 | + | ||
172 | At least one of any, any_call, any_ret, any_ind must be provided. The privilege levels may | ||
173 | be ommitted, in which case, the privilege levels of the associated event are applied to the | ||
174 | branch filter. Both kernel (k) and hypervisor (hv) privilege levels are subject to | ||
175 | permissions. When sampling on multiple events, branch stack sampling is enabled for all | ||
176 | the sampling events. The sampled branch type is the same for all events. | ||
177 | Note that taken branch sampling may not be available on all processors. | ||
178 | The various filters must be specified as a comma separated list: -b any_ret,u,k | ||
179 | |||
155 | SEE ALSO | 180 | SEE ALSO |
156 | -------- | 181 | -------- |
157 | linkperf:perf-stat[1], linkperf:perf-list[1] | 182 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 75d230fef202..1c49d4e8767c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -638,6 +638,77 @@ out_delete_session: | |||
638 | return err; | 638 | return err; |
639 | } | 639 | } |
640 | 640 | ||
641 | #define BRANCH_OPT(n, m) \ | ||
642 | { .name = n, .mode = (m) } | ||
643 | |||
644 | #define BRANCH_END { .name = NULL } | ||
645 | |||
646 | struct branch_mode { | ||
647 | const char *name; | ||
648 | int mode; | ||
649 | }; | ||
650 | |||
651 | static const struct branch_mode branch_modes[] = { | ||
652 | BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), | ||
653 | BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), | ||
654 | BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), | ||
655 | BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), | ||
656 | BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), | ||
657 | BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), | ||
658 | BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), | ||
659 | BRANCH_END | ||
660 | }; | ||
661 | |||
662 | static int | ||
663 | parse_branch_stack(const struct option *opt, const char *str, int unset __used) | ||
664 | { | ||
665 | #define ONLY_PLM \ | ||
666 | (PERF_SAMPLE_BRANCH_USER |\ | ||
667 | PERF_SAMPLE_BRANCH_KERNEL |\ | ||
668 | PERF_SAMPLE_BRANCH_HV) | ||
669 | |||
670 | uint64_t *mode = (uint64_t *)opt->value; | ||
671 | const struct branch_mode *br; | ||
672 | char *s, *os, *p; | ||
673 | int ret = -1; | ||
674 | |||
675 | *mode = 0; | ||
676 | |||
677 | /* because str is read-only */ | ||
678 | s = os = strdup(str); | ||
679 | if (!s) | ||
680 | return -1; | ||
681 | |||
682 | for (;;) { | ||
683 | p = strchr(s, ','); | ||
684 | if (p) | ||
685 | *p = '\0'; | ||
686 | |||
687 | for (br = branch_modes; br->name; br++) { | ||
688 | if (!strcasecmp(s, br->name)) | ||
689 | break; | ||
690 | } | ||
691 | if (!br->name) | ||
692 | goto error; | ||
693 | |||
694 | *mode |= br->mode; | ||
695 | |||
696 | if (!p) | ||
697 | break; | ||
698 | |||
699 | s = p + 1; | ||
700 | } | ||
701 | ret = 0; | ||
702 | |||
703 | if ((*mode & ~ONLY_PLM) == 0) { | ||
704 | error("need at least one branch type with -b\n"); | ||
705 | ret = -1; | ||
706 | } | ||
707 | error: | ||
708 | free(os); | ||
709 | return ret; | ||
710 | } | ||
711 | |||
641 | static const char * const record_usage[] = { | 712 | static const char * const record_usage[] = { |
642 | "perf record [<options>] [<command>]", | 713 | "perf record [<options>] [<command>]", |
643 | "perf record [<options>] -- <command> [<options>]", | 714 | "perf record [<options>] -- <command> [<options>]", |
@@ -727,6 +798,9 @@ const struct option record_options[] = { | |||
727 | "monitor event in cgroup name only", | 798 | "monitor event in cgroup name only", |
728 | parse_cgroups), | 799 | parse_cgroups), |
729 | OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), | 800 | OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), |
801 | OPT_CALLBACK('b', "branch-stack", &record.opts.branch_stack, | ||
802 | "branch mode mask", "branch stack sampling modes", | ||
803 | parse_branch_stack), | ||
730 | OPT_END() | 804 | OPT_END() |
731 | }; | 805 | }; |
732 | 806 | ||
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 358f40135c4d..eec392e48067 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -222,6 +222,7 @@ struct perf_record_opts { | |||
222 | unsigned int freq; | 222 | unsigned int freq; |
223 | unsigned int mmap_pages; | 223 | unsigned int mmap_pages; |
224 | unsigned int user_freq; | 224 | unsigned int user_freq; |
225 | int branch_stack; | ||
225 | u64 default_interval; | 226 | u64 default_interval; |
226 | u64 user_interval; | 227 | u64 user_interval; |
227 | const char *cpu_list; | 228 | const char *cpu_list; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a1fd1cd2a5af..f421f7cbc0d3 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -126,6 +126,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) | |||
126 | attr->watermark = 0; | 126 | attr->watermark = 0; |
127 | attr->wakeup_events = 1; | 127 | attr->wakeup_events = 1; |
128 | } | 128 | } |
129 | if (opts->branch_stack) { | ||
130 | attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; | ||
131 | attr->branch_sample_type = opts->branch_stack; | ||
132 | } | ||
129 | 133 | ||
130 | attr->mmap = track; | 134 | attr->mmap = track; |
131 | attr->comm = track; | 135 | attr->comm = track; |