perf_events: add support for sampling taken branches (v3)
Subsystems (9)
cover perf_events: add support for sampling taken branches (v3)
This patchset adds an important and useful new feature toperf_events: branch stack sampling. In other words, the ability to capture taken branches into each sample.
Statistical sampling of taken branch should not be confused for branch tracing. Not all branches are necessarily captured
Sampling taken branches is important for basic block profiling, statistical call graph, function call counts. Many of those measurements can help drive a compiler optimizer.
The branch stack is a software abstraction which sits on top of the PMU hardware. As such, it is not available on all processors. For now, the patch provides the generic interface and the Intel X86 implementation where it leverages the Last Branch Record (LBR) feature (from Core2 to SandyBridge).
Branch stack sampling is supported for both per-thread and system-wide modes.
It is possible to filter the type and privilege level of branches to sample. The target of the branch is used to determine the privilege level.
For each branch, the source and destination are captured. On some hardware platforms, it may be possible to also extract the target prediction and, in that case, it is also exposed to end users.
The branch stack can record a variable number of taken branches per sample. Those branches are always consecutive in time. The number of branches captured depends on the filtering and the underlying hardware. On Intel Nehalem and later, up to 16 consecutive branches can be captured per sample.
Branch sampling is always coupled with an event. It can be any PMU event but it can't be a SW or tracepoint event.
Branch sampling is requested by setting a new sample_type flag called: PERF_SAMPLE_BRANCH_STACK.
To support branch filtering, we introduce a new field to the perf_event_attr struct: branch_sample_type. We chose NOT to overload the config1, config2 field because those are related to the event encoding. Branch stack is a separate feature which is combined with the event.
The branch_sample_type is a bitmask of possible filters. The following filters are defined (more can be added):
- PERF_SAMPLE_BRANCH_ANY : any control flow change - PERF_SAMPLE_BRANCH_USER : capture branches when target is at user level - PERF_SAMPLE_BRANCH_KERNEL : capture branches when target is at user level
- PERF_SAMPLE_BRANCH_ANY_CALL: capture call branches (incl. syscalls)
- PERF_SAMPLE_BRANCH_ANY_RET : capture return branches (incl. syscall returns)
- PERF_SAMPLE_BRANCH_IND_CALL: capture indirect calls
It is possible to combine filters, e.g., IND_CALL|USER|KERNEL.
When the privilege level is not specified, the branch stack inherits that of the associated event.
Some processors may not offer hardware branch filtering, e.g., Intel Atom. Some may have HW filtering bugs (e.g., Nehalem). The Intel X86 implementation in this patchset also provides a SW branch filter which works on a best effort basis. It can compensate for the lack of LBR filtering. But first and foremost, it helps work around LBR filtering errata. The goal is to only capture the type of branches requested by the user.
It is possible to combine branch stack sampling with PEBS on Intel X86 processors. Depending on the precise_sampling mode, there are certain filterting restrictions. When precise_sampling=1, then there are no filtering restrictions. When precise_sampling > 1, then only ANY|USER|KERNEL filter can be used. This comes from the fact that the kernel uses LBR to compensate for the PEBS off-by-1 skid on the instruction pointer.
To demonstrate how the perf_event branch stack sampling interface works, the patchset also modifies perf record to capture taken branches. Similarly perf report is enhanced to display a histogram of taken branches.
I would like to thank Roberto Vitillo @ LBL for his work on the perf tool for this.
Enough talking, let's take a simple example. Our trivial test program goes like this:
void f2(void)
{}
void f3(void)
{}
void f1(unsigned long n)
{
if (n & 1UL)
f2();
else
f3();
}int main(void)
{
unsigned long i;
for (i=0; i < N; i++)
f1(i);
return 0;
}
$ perf record -b any branchy $ perf report -b # Events: 23K cycles # # Overhead Source Symbol Target Symbol # ........ ................ ................
18.13% [.] f1 [.] main
18.10% [.] main [.] main
18.01% [.] main [.] f1
15.69% [.] f1 [.] f1
9.11% [.] f3 [.] f1
6.78% [.] f1 [.] f3
6.74% [.] f1 [.] f2
6.71% [.] f2 [.] f1 Of the total number of branches captured, 18.13% were from f1() -> main().
Let's make this clearer by filtering the user call branches only:
$ perf record -b any_call -e cycles:u branchy
$ perf report -b
# Events: 19K cycles
#
# Overhead Source Symbol Target Symbol
# ........ ......................... .........................
#
52.50% [.] main [.] f1
23.99% [.] f1 [.] f3
23.48% [.] f1 [.] f2
0.03% [.] _IO_default_xsputn [.] _IO_new_file_overflow
0.01% [k] _start [k] __libc_start_main Now it is more obvious. %52 of all the captured branches where calls from main() -> f1(). The rest is split 50/50 between f1() -> f2() and f1() -> f3() which is expected given that f1() dispatches based on odd vs. even values of n which is constantly increasing.
Here is a kernel example, where we want to sample indirect calls:
$ perf record -a -C 1 -b ind_call -e r1c4:k sleep 10
$ perf report -b
#
# Overhead Source Symbol Target Symbol
# ........ .......................... ..........................
#
36.36% [k] __delay [k] delay_tsc
9.09% [k] ktime_get [k] read_tsc
9.09% [k] getnstimeofday [k] read_tsc
9.09% [k] notifier_call_chain [k] tick_notify
4.55% [k] cpuidle_idle_call [k] intel_idle
4.55% [k] cpuidle_idle_call [k] menu_reflect
2.27% [k] handle_irq [k] handle_edge_irq
2.27% [k] ack_apic_edge [k] native_apic_mem_write
2.27% [k] hpet_interrupt_handler [k] hrtimer_interrupt
2.27% [k] __run_hrtimer [k] watchdog_timer_fn
2.27% [k] enqueue_task [k] enqueue_task_rt
2.27% [k] try_to_wake_up [k] select_task_rq_rt
2.27% [k] do_timer [k] read_tsc Due to HW limitations, branch filtering may be approximate on Core, Atom processors. It is more accurate on Nehalem, Westmere and best on Sandy Bridge.
In version 2, we've updated the patch to tip/master (commit 5734857) and we've incoporated the feedback from v1 concerning anynous bitfield struct for branch_stack_entry and the hanlding of i386 ABI binaries on 64-bit host in the instr decoder for the LBR SW filter.
In version 3, we've updated to 3.2.0-tip. The Atom revision check has been put into its own patch. We fixed a browser issue with report report. We fixed all the style issues as well.
---
Roberto Agostino Vitillo (3):
perf: add code to support PERF_SAMPLE_BRANCH_STACK
perf: add support for sampling taken branch to perf record
perf: add support for taken branch sampling to perf report
Stephane Eranian (10):
perf_events: add generic taken branch sampling support (v3)
perf_events: add Intel LBR MSR definitions
perf_events: add Intel X86 LBR sharing logic
perf_events: sync branch stack sampling with X86 precise_sampling
perf_events: add LBR mappings for PERF_SAMPLE_BRANCH filters
perf_events: disable LBR support for older Intel Atom processors
perf_events: implement PERF_SAMPLE_BRANCH for Intel X86
perf_events: add LBR software filter support for Intel X86
perf_events: disable PERF_SAMPLE_BRANCH_* when not supported
perf_events: add hook to flush branch_stack on context switch
arch/alpha/kernel/perf_event.c | 4 + arch/arm/kernel/perf_event.c | 4 + arch/mips/kernel/perf_event_mipsxx.c | 4 + arch/powerpc/kernel/perf_event.c | 4 + arch/sh/kernel/perf_event.c | 4 + arch/sparc/kernel/perf_event.c | 4 + arch/x86/include/asm/msr-index.h | 7 + arch/x86/kernel/cpu/perf_event.c | 47 +++- arch/x86/kernel/cpu/perf_event.h | 19 + arch/x86/kernel/cpu/perf_event_amd.c | 3 + arch/x86/kernel/cpu/perf_event_intel.c | 120 +++++-- arch/x86/kernel/cpu/perf_event_intel_ds.c | 22 +- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 525 ++++++++++++++++++++++++++-- include/linux/perf_event.h | 78 ++++- kernel/events/core.c | 167 +++++++++ kernel/events/hw_breakpoint.c | 6 + tools/perf/Documentation/perf-record.txt | 18 + tools/perf/Documentation/perf-report.txt | 7 + tools/perf/builtin-record.c | 69 ++++ tools/perf/builtin-report.c | 95 +++++- tools/perf/perf.h | 18 + tools/perf/util/annotate.c | 2 +- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 14 + tools/perf/util/hist.c | 93 ++++- tools/perf/util/hist.h | 7 + tools/perf/util/session.c | 72 ++++ tools/perf/util/session.h | 4 + tools/perf/util/sort.c | 361 ++++++++++++++----- tools/perf/util/sort.h | 5 + tools/perf/util/symbol.h | 13 + 31 files changed, 1601 insertions(+), 196 deletions(-)
PATCH 1/13 perf_events: add generic taken branch sampling support (v3)
This patch adds the ability to sample taken branches to the perf_event interface.
The ability to capture taken branches is very useful for all sorts of analysis. For instance, basic block profiling, call counts, statistical call graph.
This new capability requires hardware assist and as such may not be available on all HW platforms. On Intel X86, it is implemented on top of the Last Branch Record (LBR) facility.
To enable taken branches sampling, the PERF_SAMPLE_BRANCH_STACK bit must be set in attr->sample_type.
Sampled taken branches may be filtered by type and/or priv levels.
The patch adds a new field, called branch_sample_type, to the perf_event_attr structure. It contains a bitmask of filters to apply to the sampled taken branches.
Filters may be implemented in HW. If the HW filter does not exist or is not good enough, some arch may also implement a SW filter.
The following generic filters are currently defined:
- PERF_SAMPLE_USER
only branches whose targets are at the user level
- PERF_SAMPLE_KERNEL
only branches whose targets are at the kernel level
- PERF_SAMPLE_ANY
any type of branches (subject to priv levels filters)
- PERF_SAMPLE_ANY_CALL
any call branches (may incl. syscall on some arch)
- PERF_SAMPLE_ANY_RET
any return branches (may incl. syscall returns on some arch)
- PERF_SAMPLE_IND_CALL
indirect call branches
Obviously filter may be combined. The priv level bits are optional. If not provided, the priv level of the associated event are used. It is possible to collect branches at a priv level different from the associated event.
The number of taken branch records present in each sample may vary based on HW, the type of sampled branches, the executed code. Therefore each sample contains the number of taken branches it contains.
--- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 21 +++++--- include/linux/perf_event.h | 66 ++++++++++++++++++++++++++-- kernel/events/core.c | 58 ++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 12 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_lbr.c +13 -8
@@ -144,9 +144,11 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)rdmsrl (x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); - cpuc->lbr_entries[i].from = msr_lastbranch.from; - cpuc->lbr_entries[i].to = msr_lastbranch.to; - cpuc->lbr_entries[i].flags =0 ; + cpuc->lbr_entries[i].from = msr_lastbranch.from; + cpuc->lbr_entries[i].to = msr_lastbranch.to; + cpuc->lbr_entries[i].mispred =0 ; + cpuc->lbr_entries[i].predicted =0 ; + cpuc->lbr_entries[i].reserved =0 ; } cpuc->lbr_stack.nr = i; }
@@ -167,19 +169,22 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)for (i =0 ; i < x86_pmu.lbr_nr; i++) {unsigned long lbr_idx = (tos - i) & mask; -u64 from, to, flags =0 ; +u64 from, to, mis =0 , pred =0 ;rdmsrl (x86_pmu.lbr_from + lbr_idx, from);rdmsrl (x86_pmu.lbr_to + lbr_idx, to);if (lbr_format ==LBR_FORMAT_EIP_FLAGS ) { - flags = !!(from &LBR_FROM_FLAG_MISPRED ); + mis = !!(from &LBR_FROM_FLAG_MISPRED ); + pred = !mis; from = (u64)((((s64 )from) <<1 ) >>1 ); } - cpuc->lbr_entries[i].from = from; - cpuc->lbr_entries[i].to = to; - cpuc->lbr_entries[i].flags = flags; + cpuc->lbr_entries[i].from = from; + cpuc->lbr_entries[i].to = to; + cpuc->lbr_entries[i].mispred = mis; + cpuc->lbr_entries[i].predicted = pred; + cpuc->lbr_entries[i].reserved =0 ; } cpuc->lbr_stack.nr = i; }
include/linux/perf_event.h +62 -4
122 lines not on this page · raw message
kernel/events/core.c +58 -0
76 lines not on this page · raw message
Signature · 1 line
1.7.1
Re: [PATCH 01/13] perf_events: add generic taken branch sampling support (v3)
Quoted 48 lines · Stephane Eranian
This patch adds the ability to sample taken branches to the
perf_eventinterface.The ability to capture taken branches is very useful for all sorts of analysis. For instance, basic block profiling, call counts, statistical call graph.
This new capability requires hardware assist and as such may not be available on all HW platforms. On Intel X86, it is implemented on top of the Last Branch Record (LBR) facility.
To enable taken branches sampling, the
PERF_SAMPLE_BRANCH_STACKbit must be set inattr->sample_type.Sampled taken branches may be filtered by type and/or priv levels.
The patch adds a new field, called
branch_sample_type, to theperf_event_attrstructure. It contains a bitmask of filters to apply to the sampled taken branches.Filters may be implemented in HW. If the HW filter does not exist or is not good enough, some arch may also implement a SW filter.
The following generic filters are currently defined:
-PERF_SAMPLE_USER
only branches whose targets are at the user level-
PERF_SAMPLE_KERNEL
only branches whose targets are at the kernel level-
PERF_SAMPLE_ANY
any type of branches (subject to priv levels filters)-
PERF_SAMPLE_ANY_CALL
any call branches (may incl. syscall on some arch)-
PERF_SAMPLE_ANY_RET
any return branches (may incl. syscall returns on some arch)-
PERF_SAMPLE_IND_CALL
indirect call branchesObviously filter may be combined. The priv level bits are optional. If not provided, the priv level of the associated event are used. It is possible to collect branches at a priv level different from the associated event.
Quoted 5 lines
The number of taken branch records present in each sample may vary based on HW, the type of sampled branches, the executed code. Therefore each sample contains the number of taken branches it contains.
Signed-off-by Stephane Eranian <[email protected]>
Reviewed by: Anshuman Khandual <[email protected]>
Quoted 119 lines
--- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 21 +++++--- include/linux/perf_event.h | 66 ++++++++++++++++++++++++++-- kernel/events/core.c | 58 ++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 12 deletions(-)arch/x86/kernel/cpu/perf_event_intel_lbr.c +13
-8@@ -144,9 +144,11 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)rdmsrl (x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); - cpuc->lbr_entries[i].from = msr_lastbranch.from; - cpuc->lbr_entries[i].to = msr_lastbranch.to; - cpuc->lbr_entries[i].flags =0 ; + cpuc->lbr_entries[i].from = msr_lastbranch.from; + cpuc->lbr_entries[i].to = msr_lastbranch.to; + cpuc->lbr_entries[i].mispred =0 ; + cpuc->lbr_entries[i].predicted =0 ; + cpuc->lbr_entries[i].reserved =0 ; } cpuc->lbr_stack.nr = i; }@@ -167,19 +169,22 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)for (i =0 ; i < x86_pmu.lbr_nr; i++) {unsigned long lbr_idx = (tos - i) & mask; -u64 from, to, flags =0 ; +u64 from, to, mis =0 , pred =0 ;rdmsrl (x86_pmu.lbr_from + lbr_idx, from);rdmsrl (x86_pmu.lbr_to + lbr_idx, to);if (lbr_format ==LBR_FORMAT_EIP_FLAGS ) { - flags = !!(from &LBR_FROM_FLAG_MISPRED ); + mis = !!(from &LBR_FROM_FLAG_MISPRED ); + pred = !mis; from = (u64)((((s64 )from) <<1 ) >>1 ); } - cpuc->lbr_entries[i].from = from; - cpuc->lbr_entries[i].to = to; - cpuc->lbr_entries[i].flags = flags; + cpuc->lbr_entries[i].from = from; + cpuc->lbr_entries[i].to = to; + cpuc->lbr_entries[i].mispred = mis; + cpuc->lbr_entries[i].predicted = pred; + cpuc->lbr_entries[i].reserved =0 ; } cpuc->lbr_stack.nr = i; }include/linux/perf_event.h +32
-1@@ -129,11 +129,38 @@ enum perf_event_sample_format {PERF_SAMPLE_PERIOD =1U <<8 ,PERF_SAMPLE_STREAM_ID =1U <<9 ,PERF_SAMPLE_RAW =1U <<10 , +PERF_SAMPLE_BRANCH_STACK =1U <<11 , - PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ + PERF_SAMPLE_MAX = 1U << 12, /* non-ABI */ };/* +* values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set +* +* If the user does not pass priv level information via branch_sample_type, +* the kernel uses the event's priv level. Branch and event priv levels do +* not have to match. Branch priv level is checked for permissions. +* +* The branch types can be combined, however BRANCH_ANY covers all types +* of branches and therefore it supersedes all the other types. +*/ +enum perf_branch_sample_type { +PERF_SAMPLE_BRANCH_USER =1U <<0 ,/* user level branches */ +PERF_SAMPLE_BRANCH_KERNEL =1U <<1 ,/* kernel level branches */ + +PERF_SAMPLE_BRANCH_ANY =1U <<2 ,/* any branch types */ +PERF_SAMPLE_BRANCH_ANY_CALL =1U <<3 ,/* any call branch */ +PERF_SAMPLE_BRANCH_ANY_RETURN =1U <<4 ,/* any return branch */ +PERF_SAMPLE_BRANCH_IND_CALL =1U <<5 ,/* indirect calls */ + +PERF_SAMPLE_BRANCH_MAX =1U <<6 ,/* non-ABI */ +}; + +#define PERF_SAMPLE_BRANCH_PLM_ALL \ + (PERF_SAMPLE_BRANCH_USER|\ + PERF_SAMPLE_BRANCH_KERNEL) + +/* * The format of the data returned by read() on a perf event fd, * as specified by attr.read_format: * @@ -240,6 +267,7 @@ struct perf_event_attr {__u64 bp_len;__u64 config2;/* extension of config1 */ }; +__u64 branch_sample_type;/* enum branch_sample_type */ };/* @@ -458,6 +486,8 @@ enum perf_event_type {* * { u32 size; * char data[size];}&& PERF_SAMPLE_RAW +* +* { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK * }; */ PERF_RECORD_SAMPLE = 9,@@ -530,12 +560,31 @@ struct perf_raw_record {void *data; }; +/*
include/linux/perf_event.h struct perf_raw_record { · line 573
Quoted 10 lines
include/linux/perf_event.h +10
-0+* single taken branch record layout: +* +* from: source instruction (may not always be a branch insn) +* to: branch target +* mispred: branch target was mispredicted +* predicted: branch target was predicted +* +* support for mispred, predicted is optional. In case it +* is not supported mispred = predicted = 0. +*/
So the user level perf tools would check for ((mispred = 0) && (predicted = 0)) in a sample and report that its not supported by the HW PMU ? Point here is that if its not supported we should say "No HW support" rather than displaying mispred = 0 and predicted = 0 (As this could be misleading)
Quoted 121 lines
include/linux/perf_event.h +20
-3struct perf_branch_entry { -__u64 from; -__u64 to; -__u64 flags; +__u64 from; +__u64 to; +__u64 mispred:1 ,/* target mispredicted */ + predicted:1 ,/* target predicted */ + reserved:62 ; }; +/* +* branch stack layout: +* nr: number of taken branches stored in entries[] +* +* Note that nr can vary from sample to sample +*/ struct perf_branch_stack {__u64 nr;struct perf_branch_entry entries[0 ];@@ -566,7 +615,9 @@ struct hw_perf_event {unsigned long event_base;int idx;int last_cpu; +struct hw_perf_event_extra extra_reg; +struct hw_perf_event_extra branch_reg; };struct {/* software */ struct hrtimer hrtimer;@@ -1003,12 +1054,14 @@ struct perf_sample_data {u64 period;struct perf_callchain_entry *callchain;struct perf_raw_record *raw; +struct perf_branch_stack *br_stack; };static inline void perf_sample_data_init (struct perf_sample_data *data,u64 addr) { data->addr = addr; data->raw =NULL ; + data->br_stack =NULL ; } extern void perf_output_sample(struct perf_output_handle *handle,@@ -1147,6 +1200,11 @@ extern void perf_bp_event(struct perf_event *event, void *data);# define perf_instruction_pointer (regs) instruction_pointer(regs)#endif +static inline bool has_branch_stack (struct perf_event *event) +{ +return event->attr.sample_type &PERF_SAMPLE_BRANCH_STACK ; +} +extern int perf_output_begin (struct perf_output_handle *handle,struct perf_event *event,unsigned int size);extern void perf_output_end (struct perf_output_handle *handle);kernel/events/core.c +42
-0@@ -3877,6 +3877,24 @@ void perf_output_sample(struct perf_output_handle *handle, } } } + +if (sample_type &PERF_SAMPLE_BRANCH_STACK ) { +if (data->br_stack) { +size_t size; + + size = data->br_stack->nr + *sizeof (struct perf_branch_entry ); + +perf_output_put (handle, data->br_stack->nr); +perf_output_copy (handle, data->br_stack->entries, size); + }else { +/* +* we always store at least the value of nr +*/ +u64 nr =0 ; +perf_output_put (handle, nr); + } + } } void perf_prepare_sample(struct perf_event_header *header,@@ -3919,6 +3937,15 @@ void perf_prepare_sample(struct perf_event_header *header,WARN_ON_ONCE (size & (sizeof (u64)-1 )); header->size += size; } + +if (sample_type &PERF_SAMPLE_BRANCH_STACK ) { +int size =sizeof (u64);/* nr */ +if (data->br_stack) { + size += data->br_stack->nr + *sizeof (struct perf_branch_entry ); + } + header->size += size; + } } static void perf_event_output(struct perf_event *event,@@ -5898,6 +5925,37 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,if (attr->read_format & ~(PERF_FORMAT_MAX -1 ))return -EINVAL ; +if (attr->sample_type &PERF_SAMPLE_BRANCH_STACK ) { +u64 mask = attr->branch_sample_type; + +/* only using defined bits */ +if (mask & ~(PERF_SAMPLE_BRANCH_MAX -1 )) +return -EINVAL ; + +/* at least one branch bit must be set */ +if (!(mask & ~PERF_SAMPLE_BRANCH_PLM_ALL )) +return -EINVAL ; + +/* kernel level capture */ +if ((mask &PERF_SAMPLE_BRANCH_KERNEL ) + &&perf_paranoid_kernel () && !capable (CAP_SYS_ADMIN )) +return -EACCES ;
kernel/events/core.c static int perf_copy_attr(struct perf_event_attr __user *uattr, · line 5952
Quoted 10 lines
kernel/events/core.c +10
-0+ +/* propagate priv level, when not set for branch */ +if (!(mask &PERF_SAMPLE_BRANCH_PLM_ALL )) { + +/* exclude_kernel checked on syscall entry */ +if (!attr->exclude_kernel) + mask |=PERF_SAMPLE_BRANCH_KERNEL ; + +if (!attr->exclude_user) + mask |=PERF_SAMPLE_BRANCH_USER ;
Why we are not taking care for attr->exclude_hv ? Should not we define PERF_SAMPLE_BRANCH_HV for hyper-visor level branches ?
Quoted 9 lines
kernel/events/core.c +6
-0+/* +* adjust user setting (for HW filter setup) +*/ + attr->branch_sample_type = mask; + } + } out:return ret;
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
Re: [PATCH 01/13] perf_events: add generic taken branch sampling support (v3)
Quoted 313 lines · Anshuman Khandual
Quoted 48 lines · Stephane Eranian
This patch adds the ability to sample taken branches to the
perf_eventinterface.The ability to capture taken branches is very useful for all sorts of analysis. For instance, basic block profiling, call counts, statistical call graph.
This new capability requires hardware assist and as such may not be available on all HW platforms. On Intel X86, it is implemented on top of the Last Branch Record (LBR) facility.
To enable taken branches sampling, the
PERF_SAMPLE_BRANCH_STACKbit must be set inattr->sample_type.Sampled taken branches may be filtered by type and/or priv levels.
The patch adds a new field, called
branch_sample_type, to theperf_event_attrstructure. It contains a bitmask of filters to apply to the sampled taken branches.Filters may be implemented in HW. If the HW filter does not exist or is not good enough, some arch may also implement a SW filter.
The following generic filters are currently defined:
-PERF_SAMPLE_USER
only branches whose targets are at the user level-
PERF_SAMPLE_KERNEL
only branches whose targets are at the kernel level-
PERF_SAMPLE_ANY
any type of branches (subject to priv levels filters)-
PERF_SAMPLE_ANY_CALL
any call branches (may incl. syscall on some arch)-
PERF_SAMPLE_ANY_RET
any return branches (may incl. syscall returns on some arch)-
PERF_SAMPLE_IND_CALL
indirect call branchesObviously filter may be combined. The priv level bits are optional. If not provided, the priv level of the associated event are used. It is possible to collect branches at a priv level different from the associated event.
Quoted 5 lines
The number of taken branch records present in each sample may vary based on HW, the type of sampled branches, the executed code. Therefore each sample contains the number of taken branches it contains.
Signed-off-by Stephane Eranian <[email protected]>Reviewed by: Anshuman Khandual <[email protected]>
Quoted 119 lines
---
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 21 +++++---include/linux/perf_event.h| 66 ++++++++++++++++++++++++++--kernel/events/core.c| 58 ++++++++++++++++++++++++3 files changed, 133 insertions(+), 12 deletions(-)arch/x86/kernel/cpu/perf_event_intel_lbr.c +13
-8@@ -144,9 +144,11 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); - cpuc->lbr_entries[i].from = msr_lastbranch.from; - cpuc->lbr_entries[i].to = msr_lastbranch.to; - cpuc->lbr_entries[i].flags = 0; + cpuc->lbr_entries[i].from = msr_lastbranch.from; + cpuc->lbr_entries[i].to = msr_lastbranch.to; + cpuc->lbr_entries[i].mispred = 0; + cpuc->lbr_entries[i].predicted = 0; + cpuc->lbr_entries[i].reserved = 0; } cpuc->lbr_stack.nr = i; }@@ -167,19 +169,22 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) for (i = 0; i < x86_pmu.lbr_nr; i++) { unsigned long lbr_idx = (tos - i) & mask; - u64 from, to, flags = 0; + u64 from, to, mis = 0, pred = 0; rdmsrl(x86_pmu.lbr_from + lbr_idx, from); rdmsrl(x86_pmu.lbr_to + lbr_idx, to); if (lbr_format == LBR_FORMAT_EIP_FLAGS) { - flags = !!(from & LBR_FROM_FLAG_MISPRED); + mis = !!(from & LBR_FROM_FLAG_MISPRED); + pred = !mis; from = (u64)((((s64)from) << 1) >> 1); } - cpuc->lbr_entries[i].from = from; - cpuc->lbr_entries[i].to = to; - cpuc->lbr_entries[i].flags = flags; + cpuc->lbr_entries[i].from = from; + cpuc->lbr_entries[i].to = to; + cpuc->lbr_entries[i].mispred = mis; + cpuc->lbr_entries[i].predicted = pred; + cpuc->lbr_entries[i].reserved = 0; } cpuc->lbr_stack.nr = i; }include/linux/perf_event.h +28
-1@@ -129,11 +129,38 @@ enum perf_event_sample_format { PERF_SAMPLE_PERIOD = 1U << 8, PERF_SAMPLE_STREAM_ID = 1U << 9, PERF_SAMPLE_RAW = 1U << 10, + PERF_SAMPLE_BRANCH_STACK = 1U << 11, - PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ + PERF_SAMPLE_MAX = 1U << 12, /* non-ABI */ }; /* +* values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set +* +* If the user does not pass priv level information via branch_sample_type, +* the kernel uses the event's priv level. Branch and event priv levels do +* not have to match. Branch priv level is checked for permissions. +* +* The branch types can be combined, however BRANCH_ANY covers all types +* of branches and therefore it supersedes all the other types. +*/ +enum perf_branch_sample_type { + PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user level branches */ + PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel level branches */ + + PERF_SAMPLE_BRANCH_ANY = 1U << 2, /* any branch types */ + PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 3, /* any call branch */ + PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 4, /* any return branch */ + PERF_SAMPLE_BRANCH_IND_CALL = 1U << 5, /* indirect calls */ + + PERF_SAMPLE_BRANCH_MAX = 1U << 6,/* non-ABI */ +}; + +#define PERF_SAMPLE_BRANCH_PLM_ALL \ + (PERF_SAMPLE_BRANCH_USER|\ + PERF_SAMPLE_BRANCH_KERNEL) + +/* * The format of the data returned by read() on a perf event fd, * as specified by attr.read_format: * @@ -240,6 +267,7 @@ struct perf_event_attr { __u64 bp_len;
__u64config2; /* extension of config1 */ };
+__u64branch_sample_type; /* enumbranch_sample_type*/ };/*
include/linux/perf_event.h +3
-0@@ -458,6 +486,8 @@ enum perf_event_type {* * { u32 size; * char data[size];}&& PERF_SAMPLE_RAW +* +* { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK * }; */ PERF_RECORD_SAMPLE = 9,@@ -530,12 +560,31 @@ struct perf_raw_record { void *data; }; +/* include/linux/perf_event.h struct perf_raw_record { · line 573
Quoted 10 lines
include/linux/perf_event.h +10
-0+* single taken branch record layout: +* +* from: source instruction (may not always be a branch insn) +* to: branch target +* mispred: branch target was mispredicted +* predicted: branch target was predicted +* +* support for mispred, predicted is optional. In case it +* is not supported mispred = predicted = 0. +*/ So the user level perf tools would check for ((mispred = 0) && (predicted = 0)) in a sample and report that its not supported by the HW PMU ? Point here is that if its not supported we should say "No HW support" rather than displaying mispred = 0 and predicted = 0 (As this could be misleading)
Quoted 125 lines
include/linux/perf_event.h +13
-3struct perf_branch_entry { - __u64 from; - __u64 to; - __u64 flags; + __u64 from; + __u64 to; + __u64 mispred:1, /* target mispredicted */ + predicted:1,/* target predicted */ + reserved:62; }; +/* +* branch stack layout: +* nr: number of taken branches stored in entries[] +* +* Note that nr can vary from sample to sample +*/ struct perf_branch_stack { __u64 nr; struct perf_branch_entry entries[0];@@ -566,7 +615,9 @@ struct hw_perf_event { unsigned long event_base; int idx; int last_cpu; + struct hw_perf_event_extra extra_reg; + struct hw_perf_event_extra branch_reg; };struct { /* software */
struct hrtimer hrtimer;include/linux/perf_event.h +7
-0@@ -1003,12 +1054,14 @@ struct perf_sample_data { u64 period; struct perf_callchain_entry *callchain; struct perf_raw_record *raw; + struct perf_branch_stack *br_stack; }; static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr) { data->addr = addr; data->raw = NULL; + data->br_stack = NULL; } extern void perf_output_sample(struct perf_output_handle *handle,@@ -1147,6 +1200,11 @@ extern void perf_bp_event(struct perf_event *event, void *data); # define perf_instruction_pointer(regs) instruction_pointer(regs) #endif +static inline bool has_branch_stack (struct perf_event *event) +{ + return event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK; +} + extern int perf_output_begin(struct perf_output_handle *handle, struct perf_event *event, unsigned int size); extern void perf_output_end(struct perf_output_handle *handle);kernel/events/core.c +46
-0@@ -3877,6 +3877,24 @@ void perf_output_sample(struct perf_output_handle *handle, } } } + + if (sample_type & PERF_SAMPLE_BRANCH_STACK) { + if (data->br_stack) { + size_t size; + + size = data->br_stack->nr + * sizeof(struct perf_branch_entry); + + perf_output_put(handle, data->br_stack->nr); + perf_output_copy(handle, data->br_stack->entries, size); + } else { + /* + * we always store at least the value of nr + */ + u64 nr = 0; + perf_output_put(handle, nr); + } + } } void perf_prepare_sample(struct perf_event_header *header,@@ -3919,6 +3937,15 @@ void perf_prepare_sample(struct perf_event_header *header, WARN_ON_ONCE(size & (sizeof(u64)-1)); header->size += size; } + + if (sample_type & PERF_SAMPLE_BRANCH_STACK) { + int size = sizeof(u64); /* nr */ + if (data->br_stack) { + size += data->br_stack->nr + * sizeof(struct perf_branch_entry); + } + header->size += size; + } } static void perf_event_output(struct perf_event *event,@@ -5898,6 +5925,37 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, if (attr->read_format & ~(PERF_FORMAT_MAX-1)) return -EINVAL; + if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK) { + u64 mask = attr->branch_sample_type; + + /* only using defined bits */ + if (mask & ~(PERF_SAMPLE_BRANCH_MAX-1)) + return -EINVAL; + + /* at least one branch bit must be set */ + if (!(mask & ~PERF_SAMPLE_BRANCH_PLM_ALL)) + return -EINVAL; + + /* kernel level capture */ + if ((mask & PERF_SAMPLE_BRANCH_KERNEL) + && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) + return -EACCES; + + /* propagate priv level, when not set for branch */ + if (!(mask & PERF_SAMPLE_BRANCH_PLM_ALL)) { +
Quoted 8 lines
kernel/events/core.c static int perf_copy_attr(struct perf_event_attr __user *uattr, · line 5952
Quoted 6 lines
kernel/events/core.c +6
-0+ /* exclude_kernel checked on syscall entry */ + if (!attr->exclude_kernel) + mask |= PERF_SAMPLE_BRANCH_KERNEL; + + if (!attr->exclude_user) + mask |= PERF_SAMPLE_BRANCH_USER;Why we are not taking care for
attr->exclude_hv? Should not we definePERF_SAMPLE_BRANCH_HVfor hyper-visor level branches ?
Yes, we can add this, though I don't have any system to test it. I will post a patch to add this priv level.
Quoted 16 lines
Quoted 9 lines
kernel/events/core.c +6
-0+ /* + * adjust user setting (for HW filter setup) + */ + attr->branch_sample_type = mask; + } + }out:
return ret;--
Linux Technology Centre
IBM Systems and Technology Group
Bangalore India
PATCH 2/13 perf_events: add Intel LBR MSR definitions (v3)
In reply to Stephane EranianThis patch adds the LBR definitions for NHM/WSM/SNB and Core. It also adds the definitions for the architected LBR MSR:LBR_SELECT, LBRT_TOS.
--- arch/x86/include/asm/msr-index.h | 7 +++++++ arch/x86/kernel/cpu/perf_event_intel_lbr.c | 18 +++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-)
arch/x86/include/asm/msr-index.h +7 -0
@@ -56,6 +56,13 @@#define MSR_OFFCORE_RSP_0 0x000001a6#define MSR_OFFCORE_RSP_1 0x000001a7 +#define MSR_LBR_SELECT 0x000001c8 +#define MSR_LBR_TOS 0x000001c9 +#define MSR_LBR_NHM_FROM 0x00000680 +#define MSR_LBR_NHM_TO 0x000006c0 +#define MSR_LBR_CORE_FROM 0x00000040 +#define MSR_LBR_CORE_TO 0x00000060 +#define MSR_IA32_PEBS_ENABLE 0x000003f1#define MSR_IA32_DS_AREA 0x00000600#define MSR_IA32_PERF_CAPABILITIES 0x00000345
arch/x86/kernel/cpu/perf_event_intel_lbr.c +9 -9
@@ -205,23 +205,23 @@ void intel_pmu_lbr_read(void)void intel_pmu_lbr_init_core (void ) { x86_pmu.lbr_nr =4 ; - x86_pmu.lbr_tos =0x01c9 ; - x86_pmu.lbr_from =0x40 ; - x86_pmu.lbr_to =0x60 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_CORE_FROM ; + x86_pmu.lbr_to =MSR_LBR_CORE_TO ; }void intel_pmu_lbr_init_nhm (void ) { x86_pmu.lbr_nr =16 ; - x86_pmu.lbr_tos =0x01c9 ; - x86_pmu.lbr_from =0x680 ; - x86_pmu.lbr_to =0x6c0 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_NHM_FROM ; + x86_pmu.lbr_to =MSR_LBR_NHM_TO ; }void intel_pmu_lbr_init_atom (void ) { x86_pmu.lbr_nr =8 ; - x86_pmu.lbr_tos =0x01c9 ; - x86_pmu.lbr_from =0x40 ; - x86_pmu.lbr_to =0x60 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_CORE_FROM ; + x86_pmu.lbr_to =MSR_LBR_CORE_TO ; }
Signature · 1 line
1.7.1
Re: [PATCH 02/13] perf_events: add Intel LBR MSR definitions (v3)
Quoted 5 lines · Stephane Eranian
This patch adds the LBR definitions for NHM/WSM/SNB and Core. It also adds the definitions for the architected LBR MSR:
LBR_SELECT,LBRT_TOS.Signed-off-by Stephane Eranian <[email protected]>
Reviewed by: Anshuman Khandual <[email protected]>
Quoted 60 lines
--- arch/x86/include/asm/msr-index.h | 7 +++++++ arch/x86/kernel/cpu/perf_event_intel_lbr.c | 18 +++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-)arch/x86/include/asm/msr-index.h +7
-0@@ -56,6 +56,13 @@#define MSR_OFFCORE_RSP_0 0x000001a6#define MSR_OFFCORE_RSP_1 0x000001a7 +#define MSR_LBR_SELECT 0x000001c8 +#define MSR_LBR_TOS 0x000001c9 +#define MSR_LBR_NHM_FROM 0x00000680 +#define MSR_LBR_NHM_TO 0x000006c0 +#define MSR_LBR_CORE_FROM 0x00000040 +#define MSR_LBR_CORE_TO 0x00000060 +#define MSR_IA32_PEBS_ENABLE 0x000003f1#define MSR_IA32_DS_AREA 0x00000600#define MSR_IA32_PERF_CAPABILITIES 0x00000345arch/x86/kernel/cpu/perf_event_intel_lbr.c +9
-9@@ -205,23 +205,23 @@ void intel_pmu_lbr_read(void)void intel_pmu_lbr_init_core (void ) { x86_pmu.lbr_nr =4 ; - x86_pmu.lbr_tos =0x01c9 ; - x86_pmu.lbr_from =0x40 ; - x86_pmu.lbr_to =0x60 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_CORE_FROM ; + x86_pmu.lbr_to =MSR_LBR_CORE_TO ; }void intel_pmu_lbr_init_nhm (void ) { x86_pmu.lbr_nr =16 ; - x86_pmu.lbr_tos =0x01c9 ; - x86_pmu.lbr_from =0x680 ; - x86_pmu.lbr_to =0x6c0 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_NHM_FROM ; + x86_pmu.lbr_to =MSR_LBR_NHM_TO ; }void intel_pmu_lbr_init_atom (void ) { x86_pmu.lbr_nr =8 ; - x86_pmu.lbr_tos =0x01c9 ; - x86_pmu.lbr_from =0x40 ; - x86_pmu.lbr_to =0x60 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_CORE_FROM ; + x86_pmu.lbr_to =MSR_LBR_CORE_TO ; }
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
PATCH 3/13 perf_events: add Intel X86 LBR sharing logic (v3)
In reply to Stephane EranianThe Intel LBR on some recent processor is capable of filtering branches by type. The filter is configurable via the LBR_SELECT MSR register.
There are limitation on how this register can be used.
On Nehalem/Westmere, the LBR_SELECT is shared by the two HT threads when HT is on. It is private to each core when HT is off.
On SandyBridge, the LBR_SELECT register is private to each thread when HT is on. It is private to each core when HT is off.
The kernel must manage the sharing of LBR_SELECT. It allows multiple users on the same logical CPU to use LBR_SELECT as long as they program it with the same value. Across sibling CPUs (HT threads), the same restriction applies on NHM/WSM.
This patch implements this sharing logic by leveraging the mechanism put in place for managing the offcore_response shared MSR.
We modify __intel_shared_reg_get_constraints() to cause x86_get_event_constraint() to be called because LBR may be associated with events that may be counter constrained.
--- arch/x86/kernel/cpu/perf_event.c | 4 ++ arch/x86/kernel/cpu/perf_event.h | 4 ++ arch/x86/kernel/cpu/perf_event_intel.c | 70 ++++++++++++++++++++------------ 3 files changed, 52 insertions(+), 26 deletions(-)
arch/x86/kernel/cpu/perf_event.c +4 -0
@@ -426,6 +426,10 @@ static int __x86_pmu_event_init(struct perf_event *event)/* mark unused */ event->hw.extra_reg.idx =EXTRA_REG_NONE ; +/* mark not used */ + event->hw.extra_reg.idx =EXTRA_REG_NONE ; + event->hw.branch_reg.idx =EXTRA_REG_NONE ; +return x86_pmu.hw_config (event); }
arch/x86/kernel/cpu/perf_event.h +4 -0
@@ -33,6 +33,7 @@ enum extra_reg_type {EXTRA_REG_RSP_0 =0 ,/* offcore_response_0 */ EXTRA_REG_RSP_1 =1 ,/* offcore_response_1 */ +EXTRA_REG_LBR =2 ,/* lbr_select */ EXTRA_REG_MAX /* number of entries needed */ };
@@ -130,6 +131,7 @@ struct cpu_hw_events {void *lbr_context;struct perf_branch_stack lbr_stack;struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES ]; +struct er_account *lbr_sel;/* * Intel host/guest exclude bits
@@ -340,6 +342,8 @@ struct x86_pmu {*/ unsigned long lbr_tos, lbr_from, lbr_to;/* MSR base regs */ int lbr_nr;/* hardware stack size */ +u64 lbr_sel_mask;/* LBR_SELECT valid bits */ +const int *lbr_sel_map;/* lbr_select mappings */ /* * Extra registers for events
arch/x86/kernel/cpu/perf_event_intel.c +44 -26
121 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH 4/13 perf_events: sync branch stack sampling with X86 precise_sampling (v3)
In reply to Stephane EranianIf precise sampling is enabled on Intel X86, then perf_event uses PEBS. To correct for the off-by-one error of PEBS, perf_event uses LBR when precise_sample > 1.
On Intel X86 PERF_SAMPLE_BRANCH_STACK is implemented using LBR, therefore both features must be coordinated as they may not configure LBR the same way.
For PEBS, LBR needs to capture all branches at all priv levels. This patch sets this up.
The configuration of PERF_SAMPLE_BRANCH_STACK may not be compatible in which case an error must be returned.
--- arch/x86/kernel/cpu/perf_event.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event.c +22 -0
@@ -356,6 +356,7 @@ int x86_setup_perfctr(struct perf_event *event)int x86_pmu_hw_config (struct perf_event *event) {if (event->attr.precise_ip) { +u64 *br_type, br_sel;int precise =0 ;/* Support for constant skid */
@@ -369,6 +370,27 @@ int x86_pmu_hw_config(struct perf_event *event)if (event->attr.precise_ip > precise)return -EOPNOTSUPP ; +/* +* check that PEBS LBR correction does not conflict with +* whatever the user is asking with attr->branch_sample_type +*/ +if (event->attr.precise_ip >1 ) { + + br_type = &event->attr.branch_sample_type; + +if (has_branch_stack (event)) { + br_sel = *br_type &PERF_SAMPLE_BRANCH_ANY ; +if (br_sel !=PERF_SAMPLE_BRANCH_ANY ) +return -EOPNOTSUPP ; + }else { +/* +* For PEBS fixups, we capture all +* the branches at all priv levels +*/ + *br_type =PERF_SAMPLE_BRANCH_ANY + |PERF_SAMPLE_BRANCH_PLM_ALL ; + } + } }/*
Signature · 1 line
1.7.1
Re: [PATCH 04/13] perf_events: sync branch stack sampling with X86 precise_sampling (v3)
Quoted 8 lines · Stephane Eranian
If precise sampling is enabled on Intel X86, then
perf_eventuses PEBS. To correct for the off-by-one error of PEBS,perf_eventuses LBR whenprecise_sample> 1.On Intel X86
PERF_SAMPLE_BRANCH_STACKis implemented using LBR, therefore both features must be coordinated as they may not configure LBR the same way.
Quoted 7 lines
For PEBS, LBR needs to capture all branches at all priv levels. This patch sets this up.
The configuration of
PERF_SAMPLE_BRANCH_STACKmay not be compatible in which case an error must be returned.Signed-off-by Stephane Eranian <[email protected]>
Reviewed by: Anshuman Khandual<[email protected]>
Quoted 44 lines
--- arch/x86/kernel/cpu/perf_event.c | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-)arch/x86/kernel/cpu/perf_event.c +22
-0@@ -356,6 +356,7 @@ int x86_setup_perfctr(struct perf_event *event)int x86_pmu_hw_config (struct perf_event *event) {if (event->attr.precise_ip) { +u64 *br_type, br_sel;int precise =0 ;/* Support for constant skid */ @@ -369,6 +370,27 @@ int x86_pmu_hw_config(struct perf_event *event)if (event->attr.precise_ip > precise)return -EOPNOTSUPP ; +/* +* check that PEBS LBR correction does not conflict with +* whatever the user is asking with attr->branch_sample_type +*/ +if (event->attr.precise_ip >1 ) { + + br_type = &event->attr.branch_sample_type; + +if (has_branch_stack (event)) { + br_sel = *br_type &PERF_SAMPLE_BRANCH_ANY ; +if (br_sel !=PERF_SAMPLE_BRANCH_ANY ) +return -EOPNOTSUPP ; + }else { +/* +* For PEBS fixups, we capture all +* the branches at all priv levels +*/ + *br_type =PERF_SAMPLE_BRANCH_ANY + |PERF_SAMPLE_BRANCH_PLM_ALL ; + } + } }/*
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
PATCH 5/13 perf_events: add LBR mappings for PERF_SAMPLE_BRANCH filters (v3)
In reply to Stephane EranianThis patch adds the mappings from the generic PERF_SAMPLE_BRANCH_* filters to the actual Intel X86 LBR filters, whenever they exist.
--- arch/x86/kernel/cpu/perf_event.h | 2 + arch/x86/kernel/cpu/perf_event_intel.c | 2 +- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 99 +++++++++++++++++++++++++++- 3 files changed, 100 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.h +2 -0
@@ -535,6 +535,8 @@ void intel_pmu_lbr_init_nhm(void);void intel_pmu_lbr_init_atom (void ); +void intel_pmu_lbr_init_snb (void ); +int p4_pmu_init (void );int p6_pmu_init (void );
arch/x86/kernel/cpu/perf_event_intel.c +1 -1
@@ -1757,7 +1757,7 @@ __init int intel_pmu_init(void)memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids)); -intel_pmu_lbr_init_nhm (); +intel_pmu_lbr_init_snb (); x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints;
arch/x86/kernel/cpu/perf_event_intel_lbr.c +97 -2
137 lines not on this page · raw message
Signature · 1 line
1.7.1
Re: [PATCH 05/13] perf_events: add LBR mappings for PERF_SAMPLE_BRANCH filters (v3)
Quoted 4 lines · Stephane Eranian
This patch adds the mappings from the generic PERF_SAMPLE_BRANCH_* filters to the actual Intel X86 LBR filters, whenever they exist.
Signed-off-by Stephane Eranian <[email protected]>
Reviewed by: Anshuman Khandual <[email protected]>
Quoted 176 lines
--- arch/x86/kernel/cpu/perf_event.h | 2 + arch/x86/kernel/cpu/perf_event_intel.c | 2 +- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 99 +++++++++++++++++++++++++++- 3 files changed, 100 insertions(+), 3 deletions(-)arch/x86/kernel/cpu/perf_event.h +2
-0@@ -535,6 +535,8 @@ void intel_pmu_lbr_init_nhm(void);void intel_pmu_lbr_init_atom (void ); +void intel_pmu_lbr_init_snb (void ); +int p4_pmu_init (void );int p6_pmu_init (void );arch/x86/kernel/cpu/perf_event_intel.c +1
-1@@ -1757,7 +1757,7 @@ __init int intel_pmu_init(void)memcpy (hw_cache_event_ids, snb_hw_cache_event_ids,sizeof (hw_cache_event_ids)); -intel_pmu_lbr_init_nhm (); +intel_pmu_lbr_init_snb (); x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints;arch/x86/kernel/cpu/perf_event_intel_lbr.c +97
-2@@ -14,6 +14,47 @@ enum { };/* +* Intel LBR_SELECT bits +* Intel Vol3a, April 2011, Section 16.7 Table 16-10 +* +* Hardware branch filter (not available on all CPUs) +*/ +#define LBR_KERNEL_BIT 0/* do not capture at ring0 */ +#define LBR_USER_BIT 1/* do not capture at ring > 0 */ +#define LBR_JCC_BIT 2/* do not capture conditional branches */ +#define LBR_REL_CALL_BIT 3/* do not capture relative calls */ +#define LBR_IND_CALL_BIT 4/* do not capture indirect calls */ +#define LBR_RETURN_BIT 5/* do not capture near returns */ +#define LBR_IND_JMP_BIT 6/* do not capture indirect jumps */ +#define LBR_REL_JMP_BIT 7/* do not capture relative jumps */ +#define LBR_FAR_BIT 8/* do not capture far branches */ + +#define LBR_KERNEL (1 << LBR_KERNEL_BIT) +#define LBR_USER (1 << LBR_USER_BIT) +#define LBR_JCC (1 << LBR_JCC_BIT) +#define LBR_REL_CALL (1 << LBR_REL_CALL_BIT) +#define LBR_IND_CALL (1 << LBR_IND_CALL_BIT) +#define LBR_RETURN (1 << LBR_RETURN_BIT) +#define LBR_REL_JMP (1 << LBR_REL_JMP_BIT) +#define LBR_IND_JMP (1 << LBR_IND_JMP_BIT) +#define LBR_FAR (1 << LBR_FAR_BIT) + +#define LBR_PLM (LBR_KERNEL | LBR_USER) + +#define LBR_SEL_MASK 0x1ff/* valid bits in LBR_SELECT */ + +#define LBR_ANY \ + (LBR_JCC |\ + LBR_REL_CALL |\ + LBR_IND_CALL |\ + LBR_RETURN |\ + LBR_REL_JMP |\ + LBR_IND_JMP |\ + LBR_FAR) + +#define LBR_FROM_FLAG_MISPRED (1ULL << 63) + +/* * We only support LBR implementations that have FREEZE_LBRS_ON_PMI * otherwise it becomes near impossible to get a reliable stack. */ @@ -153,8 +194,6 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) cpuc->lbr_stack.nr = i; } -#define LBR_FROM_FLAG_MISPRED (1ULL << 63) -/* * Due to lack of segmentation in Linux the effective address (offset) * is the same as the linear address, allowing us to merge the LIP and EIP @@ -202,26 +241,82 @@ void intel_pmu_lbr_read(void)intel_pmu_lbr_read_64 (cpuc); } +/* +* Map interface branch filters onto LBR filters +*/ +static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX ] = { + [PERF_SAMPLE_BRANCH_ANY ] =LBR_ANY , + [PERF_SAMPLE_BRANCH_USER ] =LBR_USER , + [PERF_SAMPLE_BRANCH_KERNEL ] =LBR_KERNEL , + [PERF_SAMPLE_BRANCH_ANY_RETURN ] =LBR_RETURN |LBR_REL_JMP + |LBR_IND_JMP |LBR_FAR , +/* +* NHM/WSM erratum: must include REL_JMP+IND_JMP to get CALL branches +*/ + [PERF_SAMPLE_BRANCH_ANY_CALL ] = +LBR_REL_CALL |LBR_IND_CALL |LBR_REL_JMP |LBR_IND_JMP |LBR_FAR , +/* +* NHM/WSM erratum: must include IND_JMP to capture IND_CALL +*/ + [PERF_SAMPLE_BRANCH_IND_CALL ] =LBR_IND_CALL |LBR_IND_JMP , +}; + +static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX ] = { + [PERF_SAMPLE_BRANCH_ANY ] =LBR_ANY , + [PERF_SAMPLE_BRANCH_USER ] =LBR_USER , + [PERF_SAMPLE_BRANCH_KERNEL ] =LBR_KERNEL , + [PERF_SAMPLE_BRANCH_ANY_RETURN ] =LBR_RETURN |LBR_FAR , + [PERF_SAMPLE_BRANCH_ANY_CALL ] =LBR_REL_CALL |LBR_IND_CALL + |LBR_FAR , + [PERF_SAMPLE_BRANCH_IND_CALL ] =LBR_IND_CALL , +}; + +/* core */ void intel_pmu_lbr_init_core (void ) { x86_pmu.lbr_nr =4 ; x86_pmu.lbr_tos =MSR_LBR_TOS ; x86_pmu.lbr_from =MSR_LBR_CORE_FROM ; x86_pmu.lbr_to =MSR_LBR_CORE_TO ; + +pr_cont ("4-deep LBR, " ); } +/* nehalem/westmere */ void intel_pmu_lbr_init_nhm (void ) { x86_pmu.lbr_nr =16 ; x86_pmu.lbr_tos =MSR_LBR_TOS ; x86_pmu.lbr_from =MSR_LBR_NHM_FROM ; x86_pmu.lbr_to =MSR_LBR_NHM_TO ; + + x86_pmu.lbr_sel_mask =LBR_SEL_MASK ; + x86_pmu.lbr_sel_map = nhm_lbr_sel_map; + +pr_cont ("16-deep LBR, " ); } +/* sandy bridge */ +void intel_pmu_lbr_init_snb (void ) +{ + x86_pmu.lbr_nr =16 ; + x86_pmu.lbr_tos =MSR_LBR_TOS ; + x86_pmu.lbr_from =MSR_LBR_NHM_FROM ; + x86_pmu.lbr_to =MSR_LBR_NHM_TO ; + + x86_pmu.lbr_sel_mask =LBR_SEL_MASK ; + x86_pmu.lbr_sel_map = snb_lbr_sel_map; + +pr_cont ("16-deep LBR, " ); +} + +/* atom */ void intel_pmu_lbr_init_atom (void ) { x86_pmu.lbr_nr =8 ; x86_pmu.lbr_tos =MSR_LBR_TOS ; x86_pmu.lbr_from =MSR_LBR_CORE_FROM ; x86_pmu.lbr_to =MSR_LBR_CORE_TO ; + +pr_cont ("8-deep LBR, " ); }
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
PATCH 6/13 perf_events: disable LBR support for older Intel Atom processors (v3)
In reply to Stephane EranianThe patch adds a restriction for Intel Atom LBR support. Only steppings 10 (PineView) and more recent are supported. Older models, do not have a functional LBR. Their LBR does not freeze on PMU interrupt which makes LBR unusable in the context of perf_events.
--- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_lbr.c +10 -0
@@ -313,6 +313,16 @@ void intel_pmu_lbr_init_snb(void)/* atom */ void intel_pmu_lbr_init_atom (void ) { +/* +* only models starting at stepping 10 seems +* to have an operational LBR which can freeze +* on PMU interrupt +*/ +if (boot_cpu_data.x86_mask <10 ) { +pr_cont ("LBR disabled due to erratum" ); +return ; + } + x86_pmu.lbr_nr =8 ; x86_pmu.lbr_tos =MSR_LBR_TOS ; x86_pmu.lbr_from =MSR_LBR_CORE_FROM ;
Signature · 1 line
1.7.1
Re: [PATCH 06/13] perf_events: disable LBR support for older Intel Atom processors (v3)
Quoted 6 lines · Stephane Eranian
The patch adds a restriction for Intel Atom LBR support. Only steppings 10 (PineView) and more recent are supported. Older models, do not have a functional LBR. Their LBR does not freeze on PMU interrupt which makes LBR unusable in the context of
perf_events.Signed-off-by Stephane Eranian <[email protected]>
Quoted 25 lines
--- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)arch/x86/kernel/cpu/perf_event_intel_lbr.c +10
-0@@ -313,6 +313,16 @@ void intel_pmu_lbr_init_snb(void)/* atom */ void intel_pmu_lbr_init_atom (void ) { +/* +* only models starting at stepping 10 seems +* to have an operational LBR which can freeze +* on PMU interrupt +*/ +if (boot_cpu_data.x86_mask <10 ) { +pr_cont ("LBR disabled due to erratum" ); +return ; + } + x86_pmu.lbr_nr =8 ; x86_pmu.lbr_tos =MSR_LBR_TOS ; x86_pmu.lbr_from =MSR_LBR_CORE_FROM ;
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
PATCH 7/13 perf_events: implement PERF_SAMPLE_BRANCH for Intel X86 (v3)
In reply to Stephane EranianThis patch implements PERF_SAMPLE_BRANCH support for Intel X86 processors. It connects PERF_SAMPLE_BRANCH to the actual LBR.
The patch adds the hooks in the PMU irq handler to save the LBR on counter overflow for both regular and PEBS modes.
--- arch/x86/kernel/cpu/perf_event_intel.c | 35 +++++++++++++ arch/x86/kernel/cpu/perf_event_intel_ds.c | 10 ++-- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 73 +++++++++++++++++++++++++++- include/linux/perf_event.h | 3 + 4 files changed, 113 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +35 -0
@@ -727,6 +727,19 @@ static __initconst const u64 atom_hw_cache_event_ids }, }; +static inline bool intel_pmu_needs_lbr_smpl (struct perf_event *event) +{ +/* user explicitly requested branch sampling */ +if (has_branch_stack (event)) +return true; + +/* implicit branch sampling to correct PEBS skid */ +if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip >1 ) +return true; + +return false; +} +static void intel_pmu_disable_all (void ) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);
@@ -881,6 +894,13 @@ static void intel_pmu_disable_event(struct perf_event *event) cpuc->intel_ctrl_guest_mask &= ~(1ull << hwc->idx); cpuc->intel_ctrl_host_mask &= ~(1ull << hwc->idx); +/* +* must disable before any actual event +* because any event may be combined with LBR +*/ +if (intel_pmu_needs_lbr_smpl (event)) +intel_pmu_lbr_disable (event); +if (unlikely (hwc->config_base ==MSR_ARCH_PERFMON_FIXED_CTR_CTRL )) {intel_pmu_disable_fixed (hwc);return ;
@@ -935,6 +955,12 @@ static void intel_pmu_enable_event(struct perf_event *event)intel_pmu_enable_bts (hwc->config);return ; } +/* +* must enabled before any actual event +* because any event may be combined with LBR +*/ +if (intel_pmu_needs_lbr_smpl (event)) +intel_pmu_lbr_enable (event);if (event->attr.exclude_host) cpuc->intel_ctrl_guest_mask |= (1ull << hwc->idx);
@@ -1057,6 +1083,9 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) data.period = event->hw.last_period; +if (has_branch_stack (event)) + data.br_stack = &cpuc->lbr_stack; +if (perf_event_overflow (event, &data, regs))x86_pmu_stop (event,0 ); }
@@ -1305,6 +1334,12 @@ static int intel_pmu_hw_config(struct perf_event *event) event->hw.config = alt_config; } +if (intel_pmu_needs_lbr_smpl (event)) { + ret =intel_pmu_setup_lbr_filter (event); +if (ret) +return ret; + } +if (event->attr.type !=PERF_TYPE_RAW )return 0 ;
arch/x86/kernel/cpu/perf_event_intel_ds.c +4 -6
@@ -440,9 +440,6 @@ void intel_pmu_pebs_enable(struct perf_event *event) cpuc->pebs_enabled |=1ULL << hwc->idx;WARN_ON_ONCE (cpuc->enabled); - -if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip >1 ) -intel_pmu_lbr_enable (event); }void intel_pmu_pebs_disable (struct perf_event *event)
@@ -455,9 +452,6 @@ void intel_pmu_pebs_disable(struct perf_event *event)wrmsrl (MSR_IA32_PEBS_ENABLE , cpuc->pebs_enabled); hwc->config |=ARCH_PERFMON_EVENTSEL_INT ; - -if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip >1 ) -intel_pmu_lbr_disable (event); }void intel_pmu_pebs_enable_all (void )
@@ -573,6 +567,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,* both formats and we don't use the other fields in this * routine. */ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);struct pebs_record_core *pebs = __pebs;struct perf_sample_data data;struct pt_regs regs;
@@ -603,6 +598,9 @@ static void __intel_pmu_pebs_event(struct perf_event *event,else regs.flags &= ~PERF_EFLAGS_EXACT ; +if (has_branch_stack (event)) + data.br_stack = &cpuc->lbr_stack; +if (perf_event_overflow (event, &data, ®s))x86_pmu_stop (event,0 ); }
arch/x86/kernel/cpu/perf_event_intel_lbr.c +71 -2
116 lines not on this page · raw message
include/linux/perf_event.h +3 -0
@@ -160,6 +160,9 @@ enum perf_branch_sample_type { (PERF_SAMPLE_BRANCH_USER |\ PERF_SAMPLE_BRANCH_KERNEL) +#define PERF_SAMPLE_BRANCH_ALL \ + (PERF_SAMPLE_BRANCH_PLM_ALL|PERF_SAMPLE_BRANCH_ANY) +/* * The format of the data returned by read() on a perf event fd, * as specified by attr.read_format:
Signature · 1 line
1.7.1
Re: [PATCH 07/13] perf_events: implement PERF_SAMPLE_BRANCH for Intel X86 (v3)
Quoted 6 lines · Stephane Eranian
This patch implements
PERF_SAMPLE_BRANCHsupport for Intel X86 processors. It connectsPERF_SAMPLE_BRANCHto the actual LBR.The patch adds the hooks in the PMU irq handler to save the LBR on counter overflow for both regular and PEBS modes.
Quoted 8 lines
Signed-off-by Stephane Eranian <[email protected]>--- arch/x86/kernel/cpu/perf_event_intel.c | 35 +++++++++++++ arch/x86/kernel/cpu/perf_event_intel_ds.c | 10 ++-- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 73 +++++++++++++++++++++++++++- include/linux/perf_event.h | 3 + 4 files changed, 113 insertions(+), 8 deletions(-)
This patch FAILs to compile independently because of the function 'intel_pmu_setup_lbr_filter' which is defined arch/x86/kernel/ cpu/perf_event_intel_lbr.c but used in arch/x86/kernel/cpu /perf_event_intel.c without making the prototype update in the header arch/x86/kernel/cpu/perf_event.h. Though [PATCH 8/13] rectifies the problem, [PATCH 7/13] fails to compile independently.
arch/x86/kernel/cpu/perf_event_intel_lbr.c:291: warning: ‘intel_pmu_setup_lbr_filter’ defined but not used
CC arch/x86/kernel/cpu/perf_event_intel_ds.o
CC arch/x86/kernel/cpu/perf_event_intel.oarch/x86/kernel/cpu/perf_event_intel.c: In function ‘intel_pmu_hw_config’:arch/x86/kernel/cpu/perf_event_intel.c:1342: error: implicit declaration of function ‘intel_pmu_setup_lbr_filter’ make[3]: *** [arch/x86/kernel/cpu/perf_event_intel.o] Error 1
make[2]: *** [arch/x86/kernel/cpu] Error 2
make[1]: *** [arch/x86/kernel] Error 2
make: *** [arch/x86] Error 2
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
PATCH 8/13 perf_events: add LBR software filter support for Intel X86 (v3)
In reply to Stephane EranianThis patch adds an internal sofware filter to complement the (optional) LBR hardware filter.
The software filter is necessary:
- as a substitute when there is no HW LBR filter (e.g., Atom, Core)
- to complement HW LBR filter in case of errata (e.g., Nehalem/Westmere)
- to provide finer grain filtering (e.g., all processors)
Sometimes, the LBR HW filter cannot distinguish between two types of branches. For instance, to capture syscall as CALLS, it is necessary to enable the LBR_FAR filter which will also capture JMP instructions. Thus, a second pass is necessary to filter those out, this is what the SW filter can do.
The SW filter is built on top of the internal x86 disassembler. It is a best effort filter especially for user level code. It is subject to the availability of the text page of the program.
The SW filter is enabled on all Intel X86 processors. It is bypassed when the user is capturing all branches at all priv levels.
--- arch/x86/kernel/cpu/perf_event.h | 12 + arch/x86/kernel/cpu/perf_event_intel_ds.c | 12 +- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 322 +++++++++++++++++++++++++++- 3 files changed, 326 insertions(+), 20 deletions(-)
arch/x86/kernel/cpu/perf_event.h +12 -0
@@ -132,6 +132,7 @@ struct cpu_hw_events {struct perf_branch_stack lbr_stack;struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES ];struct er_account *lbr_sel; +u64 br_sel;/* * Intel host/guest exclude bits
@@ -455,6 +456,17 @@ extern struct event_constraint emptyconstraint;extern struct event_constraint unconstrained; +static inline bool kernel_ip (unsigned long ip) +{ +#ifdef CONFIG_X86_32 +return ip >PAGE_OFFSET ; +#else +return (long )ip <0 ; +#endif +} + +int intel_pmu_setup_lbr_filter (struct perf_event *event); +#ifdef CONFIG_CPU_SUP_AMD int amd_pmu_init (void );
arch/x86/kernel/cpu/perf_event_intel_ds.c +1 -11
@@ -3,6 +3,7 @@#include <linux/slab.h> #include <asm/perf_event.h> +#include <asm/insn.h> #include "perf_event.h"
@@ -470,17 +471,6 @@ void intel_pmu_pebs_disable_all(void)wrmsrl (MSR_IA32_PEBS_ENABLE ,0 ); } -#include <asm/insn.h> - -static inline bool kernel_ip (unsigned long ip) -{ -#ifdef CONFIG_X86_32 -return ip >PAGE_OFFSET ; -#else -return (long )ip <0 ; -#endif -} -static int intel_pmu_pebs_fixup_ip (struct pt_regs *regs) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);
arch/x86/kernel/cpu/perf_event_intel_lbr.c +313 -9
384 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH 9/13 perf_events: disable PERF_SAMPLE_BRANCH_* when not supported (v3)
In reply to Stephane EranianPERF_SAMPLE_BRANCH_* is disabled for:
- SW events (sw counters, tracepoints)
- HW breakpoints
- ALL but Intel X86 architecture
- AMD64 processors
--- arch/alpha/kernel/perf_event.c | 4 ++++ arch/arm/kernel/perf_event.c | 4 ++++ arch/mips/kernel/perf_event_mipsxx.c | 4 ++++ arch/powerpc/kernel/perf_event.c | 4 ++++ arch/sh/kernel/perf_event.c | 4 ++++ arch/sparc/kernel/perf_event.c | 4 ++++ arch/x86/kernel/cpu/perf_event_amd.c | 3 +++ kernel/events/core.c | 24 ++++++++++++++++++++++++ kernel/events/hw_breakpoint.c | 6 ++++++ 9 files changed, 57 insertions(+), 0 deletions(-)
arch/alpha/kernel/perf_event.c +4 -0
@@ -685,6 +685,10 @@ static int alpha_pmu_event_init(struct perf_event *event) {int err; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_RAW :case PERF_TYPE_HARDWARE :
arch/arm/kernel/perf_event.c +4 -0
@@ -540,6 +540,10 @@ static int armpmu_event_init(struct perf_event *event)int err =0 ;atomic_t *active_events = &armpmu->active_events; +/* does not support taken branch sampling */ +if (has_branch_smpl (event)) +return -EOPNOTSUPP ; +if (armpmu->map_event (event) == -ENOENT )return -ENOENT ;
arch/mips/kernel/perf_event_mipsxx.c +4 -0
@@ -606,6 +606,10 @@ static int mipspmu_event_init(struct perf_event *event) {int err =0 ; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_RAW :case PERF_TYPE_HARDWARE :
arch/powerpc/kernel/perf_event.c +4 -0
@@ -1078,6 +1078,10 @@ static int power_pmu_event_init(struct perf_event *event)if (!ppmu)return -ENOENT ; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_HARDWARE : ev = event->attr.config;
arch/sh/kernel/perf_event.c +4 -0
@@ -310,6 +310,10 @@ static int sh_pmu_event_init(struct perf_event *event) {int err; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_RAW :case PERF_TYPE_HW_CACHE :
arch/sparc/kernel/perf_event.c +4 -0
@@ -1105,6 +1105,10 @@ static int sparc_pmu_event_init(struct perf_event *event)if (atomic_read (&nmi_active) <0 )return -ENODEV ; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (attr->type) {case PERF_TYPE_HARDWARE :if (attr->config >= sparc_pmu->max_events)
arch/x86/kernel/cpu/perf_event_amd.c +3 -0
@@ -138,6 +138,9 @@ static int amd_pmu_hw_config(struct perf_event *event)if (ret)return ret; +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +if (event->attr.exclude_host && event->attr.exclude_guest)/* * When HO == GO == 1 the hardware treats that as GO == HO == 0
kernel/events/core.c +24 -0
@@ -5000,6 +5000,12 @@ static int perf_swevent_init(struct perf_event *event)if (event->attr.type !=PERF_TYPE_SOFTWARE )return -ENOENT ; +/* +* no branch sampling for software events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event_id) {case PERF_COUNT_SW_CPU_CLOCK :case PERF_COUNT_SW_TASK_CLOCK :
@@ -5110,6 +5116,12 @@ static int perf_tp_event_init(struct perf_event *event)if (event->attr.type !=PERF_TYPE_TRACEPOINT )return -ENOENT ; +/* +* no branch sampling for tracepoint events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; + err =perf_trace_init (event);if (err)return err;
@@ -5335,6 +5347,12 @@ static int cpu_clock_event_init(struct perf_event *event)if (event->attr.config !=PERF_COUNT_SW_CPU_CLOCK )return -ENOENT ; +/* +* no branch sampling for software events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +perf_swevent_init_hrtimer (event);return 0 ;
@@ -5409,6 +5427,12 @@ static int task_clock_event_init(struct perf_event *event)if (event->attr.config !=PERF_COUNT_SW_TASK_CLOCK )return -ENOENT ; +/* +* no branch sampling for software events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +perf_swevent_init_hrtimer (event);return 0 ;
kernel/events/hw_breakpoint.c +6 -0
@@ -581,6 +581,12 @@ static int hw_breakpoint_event_init(struct perf_event *bp)if (bp->attr.type !=PERF_TYPE_BREAKPOINT )return -ENOENT ; +/* +* no branch sampling for breakpoint events +*/ +if (has_branch_stack (bp)) +return -EOPNOTSUPP ; + err =register_perf_hw_breakpoint (bp);if (err)return err;
Signature · 1 line
1.7.1
Re: [PATCH 09/13] perf_events: disable PERF_SAMPLE_BRANCH_* when not supported (v3)
Quoted 39 lines · Stephane Eranian
PERF_SAMPLE_BRANCH_* is disabled for:
- SW events (sw counters, tracepoints)
- HW breakpoints
- ALL but Intel X86 architecture
- AMD64 processorsSigned-off-by Stephane Eranian <[email protected]>--- arch/alpha/kernel/perf_event.c | 4 ++++ arch/arm/kernel/perf_event.c | 4 ++++ arch/mips/kernel/perf_event_mipsxx.c | 4 ++++ arch/powerpc/kernel/perf_event.c | 4 ++++ arch/sh/kernel/perf_event.c | 4 ++++ arch/sparc/kernel/perf_event.c | 4 ++++ arch/x86/kernel/cpu/perf_event_amd.c | 3 +++ kernel/events/core.c | 24 ++++++++++++++++++++++++ kernel/events/hw_breakpoint.c | 6 ++++++ 9 files changed, 57 insertions(+), 0 deletions(-)arch/alpha/kernel/perf_event.c +4
-0@@ -685,6 +685,10 @@ static int alpha_pmu_event_init(struct perf_event *event) {int err; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_RAW :case PERF_TYPE_HARDWARE :arch/arm/kernel/perf_event.c +0
-0
arch/arm/kernel/perf_event.c static int armpmu_event_init(struct perf_event *event) · line 544
Quoted 5 lines
arch/arm/kernel/perf_event.c +2
-0@@ -540,6 +540,10 @@ static int armpmu_event_init(struct perf_event *event)int err =0 ;atomic_t *active_events = &armpmu->active_events; +/* does not support taken branch sampling */ +if (has_branch_smpl (event))
I guess this would be 'has_branch_stack' instead of 'has_branch_smpl'. 'has_branch_smpl' has not been defined any where but getting called here.
Quoted 152 lines
arch/arm/kernel/perf_event.c +2
-0+return -EOPNOTSUPP ; +if (armpmu->map_event (event) == -ENOENT )return -ENOENT ;arch/mips/kernel/perf_event_mipsxx.c +4
-0@@ -606,6 +606,10 @@ static int mipspmu_event_init(struct perf_event *event) {int err =0 ; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_RAW :case PERF_TYPE_HARDWARE :arch/powerpc/kernel/perf_event.c +4
-0@@ -1078,6 +1078,10 @@ static int power_pmu_event_init(struct perf_event *event)if (!ppmu)return -ENOENT ; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_HARDWARE : ev = event->attr.config;arch/sh/kernel/perf_event.c +4
-0@@ -310,6 +310,10 @@ static int sh_pmu_event_init(struct perf_event *event) {int err; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event->attr.type) {case PERF_TYPE_RAW :case PERF_TYPE_HW_CACHE :arch/sparc/kernel/perf_event.c +4
-0@@ -1105,6 +1105,10 @@ static int sparc_pmu_event_init(struct perf_event *event)if (atomic_read (&nmi_active) <0 )return -ENODEV ; +/* does not support taken branch sampling */ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (attr->type) {case PERF_TYPE_HARDWARE :if (attr->config >= sparc_pmu->max_events)arch/x86/kernel/cpu/perf_event_amd.c +3
-0@@ -138,6 +138,9 @@ static int amd_pmu_hw_config(struct perf_event *event)if (ret)return ret; +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +if (event->attr.exclude_host && event->attr.exclude_guest)/* * When HO == GO == 1 the hardware treats that as GO == HO == 0 kernel/events/core.c +24
-0@@ -5000,6 +5000,12 @@ static int perf_swevent_init(struct perf_event *event)if (event->attr.type !=PERF_TYPE_SOFTWARE )return -ENOENT ; +/* +* no branch sampling for software events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +switch (event_id) {case PERF_COUNT_SW_CPU_CLOCK :case PERF_COUNT_SW_TASK_CLOCK :@@ -5110,6 +5116,12 @@ static int perf_tp_event_init(struct perf_event *event)if (event->attr.type !=PERF_TYPE_TRACEPOINT )return -ENOENT ; +/* +* no branch sampling for tracepoint events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; + err =perf_trace_init (event);if (err)return err;@@ -5335,6 +5347,12 @@ static int cpu_clock_event_init(struct perf_event *event)if (event->attr.config !=PERF_COUNT_SW_CPU_CLOCK )return -ENOENT ; +/* +* no branch sampling for software events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +perf_swevent_init_hrtimer (event);return 0 ;@@ -5409,6 +5427,12 @@ static int task_clock_event_init(struct perf_event *event)if (event->attr.config !=PERF_COUNT_SW_TASK_CLOCK )return -ENOENT ; +/* +* no branch sampling for software events +*/ +if (has_branch_stack (event)) +return -EOPNOTSUPP ; +perf_swevent_init_hrtimer (event);return 0 ;kernel/events/hw_breakpoint.c +6
-0@@ -581,6 +581,12 @@ static int hw_breakpoint_event_init(struct perf_event *bp)if (bp->attr.type !=PERF_TYPE_BREAKPOINT )return -ENOENT ; +/* +* no branch sampling for breakpoint events +*/ +if (has_branch_stack (bp)) +return -EOPNOTSUPP ; + err =register_perf_hw_breakpoint (bp);if (err)return err;
Signature · 3 lines
Linux Technology Centre IBM Systems and Technology Group Bangalore India
Re: [PATCH 09/13] perf_events: disable PERF_SAMPLE_BRANCH_* when not supported (v3)
Quoted 43 lines · Anshuman Khandual
Quoted 42 lines · Stephane Eranian
PERF_SAMPLE_BRANCH_* is disabled for:
- SW events (sw counters, tracepoints)
- HW breakpoints
- ALL but Intel X86 architecture
- AMD64 processorsSigned-off-by Stephane Eranian <[email protected]>---
arch/alpha/kernel/perf_event.c | 4 ++++arch/arm/kernel/perf_event.c| 4 ++++arch/mips/kernel/perf_event_mipsxx.c| 4 ++++arch/powerpc/kernel/perf_event.c| 4 ++++arch/sh/kernel/perf_event.c| 4 ++++arch/sparc/kernel/perf_event.c| 4 ++++arch/x86/kernel/cpu/perf_event_amd.c| 3 +++kernel/events/core.c| 24 ++++++++++++++++++++++++kernel/events/hw_breakpoint.c| 6 ++++++9 files changed, 57 insertions(+), 0 deletions(-)arch/alpha/kernel/perf_event.c +4
-0@@ -685,6 +685,10 @@ static int alpha_pmu_event_init(struct perf_event *event) { int err; + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + switch (event->attr.type) {case
PERF_TYPE_RAW:
casePERF_TYPE_HARDWARE:arch/arm/kernel/perf_event.c +0
-0@@ -540,6 +540,10 @@ static int armpmu_event_init(struct perf_event *event) int err = 0; atomic_t *active_events = &armpmu->active_events;
Quoted 4 lines
arch/arm/kernel/perf_event.c static int armpmu_event_init(struct perf_event *event) · line 544
Quoted 2 lines
arch/arm/kernel/perf_event.c +2
-0+ /* does not support taken branch sampling */ + if (has_branch_smpl(event))I guess this would be '
has_branch_stack' instead of 'has_branch_smpl'. 'has_branch_smpl' has not been defined any where but getting called here.
Good catch. Will post a patch to fix that.
Quoted 159 lines
Quoted 142 lines
arch/arm/kernel/perf_event.c +2
-0+ return -EOPNOTSUPP; + if (armpmu->map_event(event) == -ENOENT) return -ENOENT;arch/mips/kernel/perf_event_mipsxx.c +4
-0@@ -606,6 +606,10 @@ static int mipspmu_event_init(struct perf_event *event) { int err = 0; + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + switch (event->attr.type) {case
PERF_TYPE_RAW:
casePERF_TYPE_HARDWARE:arch/powerpc/kernel/perf_event.c +4
-0@@ -1078,6 +1078,10 @@ static int power_pmu_event_init(struct perf_event *event) if (!ppmu) return -ENOENT; + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + switch (event->attr.type) {case
PERF_TYPE_HARDWARE:
ev =event->attr.config;arch/sh/kernel/perf_event.c +4
-0@@ -310,6 +310,10 @@ static int sh_pmu_event_init(struct perf_event *event) { int err; + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + switch (event->attr.type) {case
PERF_TYPE_RAW:
casePERF_TYPE_HW_CACHE:arch/sparc/kernel/perf_event.c +4
-0@@ -1105,6 +1105,10 @@ static int sparc_pmu_event_init(struct perf_event *event) if (atomic_read(&nmi_active) < 0) return -ENODEV; + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + switch (attr->type) {case
PERF_TYPE_HARDWARE:
if (attr->config>=sparc_pmu->max_events)arch/x86/kernel/cpu/perf_event_amd.c +3
-0@@ -138,6 +138,9 @@ static int amd_pmu_hw_config(struct perf_event *event) if (ret) return ret; + if (has_branch_stack(event)) + return -EOPNOTSUPP; + if (event->attr.exclude_host && event->attr.exclude_guest) /** When HO == GO == 1 the hardware treats that as GO == HO == 0 kernel/events/core.c +6
-0@@ -5000,6 +5000,12 @@ static int perf_swevent_init(struct perf_event *event) if (event->attr.type != PERF_TYPE_SOFTWARE) return -ENOENT; + /* + * no branch sampling for software events + */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + switch (event_id) {case
PERF_COUNT_SW_CPU_CLOCK:
casePERF_COUNT_SW_TASK_CLOCK:kernel/events/core.c +18
-0@@ -5110,6 +5116,12 @@ static int perf_tp_event_init(struct perf_event *event) if (event->attr.type != PERF_TYPE_TRACEPOINT) return -ENOENT; + /* + * no branch sampling for tracepoint events + */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + err = perf_trace_init(event); if (err) return err;@@ -5335,6 +5347,12 @@ static int cpu_clock_event_init(struct perf_event *event) if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK) return -ENOENT; + /* + * no branch sampling for software events + */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + perf_swevent_init_hrtimer(event); return 0;@@ -5409,6 +5427,12 @@ static int task_clock_event_init(struct perf_event *event) if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK) return -ENOENT; + /* + * no branch sampling for software events + */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + perf_swevent_init_hrtimer(event); return 0;kernel/events/hw_breakpoint.c +0
-0@@ -581,6 +581,12 @@ static int hw_breakpoint_event_init(struct perf_event *bp) if (bp->attr.type != PERF_TYPE_BREAKPOINT) return -ENOENT;kernel/events/hw_breakpoint.c static int hw_breakpoint_event_init(struct perf_event *bp) · line 592
Quoted 10 lines
kernel/events/hw_breakpoint.c +6
-0+ /* + * no branch sampling for breakpoint events + */ + if (has_branch_stack(bp)) + return -EOPNOTSUPP; + err = register_perf_hw_breakpoint(bp); if (err) return err;--
Linux Technology Centre
IBM Systems and Technology Group
Bangalore India
PATCH 10/13 perf_events: add hook to flush branch_stack on context switch (v3)
In reply to Stephane EranianWith branch stack sampling, it is possible to filter by priv levels. In system-wide mode, that means it is possible to capture only user level branches. The builtin SW LBR filter needs to disassemble code based on LBR captured addresses. For that, it needs to know the task the addresses are associated with. Because of context switches, the content of the branch stack buffer may contain addresses from different tasks.
We need a hook on context switch to either flush the branch stack or save it. This patch adds a new hook in struct pmu which is called during context switches. The hook is called only when necessary. That is when a system-wide context has, at least, one event which uses PERF_SAMPLE_BRANCH_STACK. The hook is never called for per-thread context.
In this version, the Intel X86 code simply flushes (reset) the LBR on context switches (fill with zeroes). Those zeroed branches are then filtered out by the SW filter.
--- arch/x86/kernel/cpu/perf_event.c | 21 +++++--- arch/x86/kernel/cpu/perf_event.h | 1 + arch/x86/kernel/cpu/perf_event_intel.c | 13 +++++ include/linux/perf_event.h | 9 +++- kernel/events/core.c | 85 ++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/perf_event.c +14 -7
@@ -1633,25 +1633,32 @@ static const struct attribute_group *x86_pmu_attr_groups[] = { NULL, }; +static void x86_pmu_flush_branch_stack (void ) +{ +if (x86_pmu.flush_branch_stack) + x86_pmu.flush_branch_stack (); +} +static struct pmu pmu = { - .pmu_enable = x86_pmu_enable, - .pmu_disable = x86_pmu_disable, + .pmu_enable = x86_pmu_enable, + .pmu_disable = x86_pmu_disable, .attr_groups = x86_pmu_attr_groups, .event_init = x86_pmu_event_init, - .add = x86_pmu_add, - .del = x86_pmu_del, - .start = x86_pmu_start, - .stop = x86_pmu_stop, - .read = x86_pmu_read, + .add = x86_pmu_add, + .del = x86_pmu_del, + .start = x86_pmu_start, + .stop = x86_pmu_stop, + .read = x86_pmu_read, .start_txn = x86_pmu_start_txn, .cancel_txn = x86_pmu_cancel_txn, .commit_txn = x86_pmu_commit_txn, .event_idx = x86_pmu_event_idx, + .flush_branch_stack = x86_pmu_flush_branch_stack, };void perf_update_user_clock (struct perf_event_mmap_page *userpg,u64 now)
arch/x86/kernel/cpu/perf_event.h +1 -0
@@ -322,6 +322,7 @@ struct x86_pmu {void (*cpu_starting)(int cpu);void (*cpu_dying)(int cpu);void (*cpu_dead)(int cpu); +void (*flush_branch_stack)(void );/* * Intel Arch Perfmon v2+
arch/x86/kernel/cpu/perf_event_intel.c +13 -0
@@ -1539,6 +1539,18 @@ static void intel_pmu_cpu_dying(int cpu)fini_debug_store_on_cpu (cpu); } +static void intel_pmu_flush_branch_stack (void ) +{ +/* +* Intel LBR does not tag entries with the +* PID of the current task, then we need to +* flush it on ctxsw +* For now, we simply reset it +*/ +if (x86_pmu.lbr_nr) +intel_pmu_lbr_reset (); +} +static __initconst const struct x86_pmu intel_pmu = { .name ="Intel" , .handle_irq = intel_pmu_handle_irq,
@@ -1566,6 +1578,7 @@ static __initconst const struct x86_pmu intel_pmu = { .cpu_starting = intel_pmu_cpu_starting, .cpu_dying = intel_pmu_cpu_dying, .guest_get_msrs = intel_guest_get_msrs, + .flush_branch_stack = intel_pmu_flush_branch_stack, };static __init void intel_clovertown_quirk (void )
include/linux/perf_event.h +8 -1
@@ -743,6 +743,11 @@ struct pmu {* if no implementation is provided it will default to: event->hw.idx + 1. */ int (*event_idx) (struct perf_event *event);/*optional */ + +/* +* flush branch stack on context-switches (needed in cpu-wide mode) +*/ +void (*flush_branch_stack) (void ); };/**
@@ -973,7 +978,8 @@ struct perf_event_context {u64 parent_gen;u64 generation;int pin_count; -int nr_cgroups;/* cgroup events present */ +int nr_cgroups;/* cgroup evts */ +int nr_branch_stack;/* branch_stack evt */ struct rcu_head rcu_head; };
@@ -1038,6 +1044,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,extern u64 perf_event_read_value (struct perf_event *event,u64 *enabled,u64 *running); +struct perf_sample_data {u64 type;
kernel/events/core.c +85 -0
127 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH 11/13 perf: add code to support PERF_SAMPLE_BRANCH_STACK (v3)
In reply to Stephane EranianFrom: Roberto Agostino Vitillo <[email protected]>
This patch adds:
- ability to parse samples with PERF_SAMPLE_BRANCH_STACK
- sort on branches
- build histograms on branches
--- tools/perf/perf.h | 17 ++ tools/perf/util/annotate.c | 2 +- tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 10 ++ tools/perf/util/hist.c | 93 +++++++++--- tools/perf/util/hist.h | 7 + tools/perf/util/session.c | 72 +++++++++ tools/perf/util/session.h | 4 + tools/perf/util/sort.c | 361 +++++++++++++++++++++++++++++++++----------- tools/perf/util/sort.h | 5 + tools/perf/util/symbol.h | 13 ++ 11 files changed, 474 insertions(+), 111 deletions(-)
tools/perf/perf.h +17 -0
@@ -180,6 +180,23 @@ struct ip_callchain {u64 ips[0 ]; }; +struct branch_flags { +u64 mispred:1 ; +u64 predicted:1 ; +u64 reserved:62 ; +}; + +struct branch_entry { +u64 from; +u64 to; +struct branch_flags flags; +}; + +struct branch_stack { +u64 nr; +struct branch_entry entries[0 ]; +}; +extern bool perf_host, perf_guest;extern const char perf_version_string[];
tools/perf/util/annotate.c +1 -1
@@ -64,7 +64,7 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,pr_debug3 ("%s: addr=%#" PRIx64"\n" , __func__, map->unmap_ip (map, addr)); -if (addr >= sym->end) +if (addr >= sym->end || addr < sym->start)return 0 ; offset = addr - sym->start;
tools/perf/util/event.h +1 -0
@@ -81,6 +81,7 @@ struct perf_sample {u32 raw_size;void *raw_data;struct ip_callchain *callchain; +struct branch_stack *branch_stack; };#define BUILD_ID_SIZE 20
tools/perf/util/evsel.c +10 -0
@@ -575,6 +575,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, data->raw_data = (void *) pdata; } +if (type &PERF_SAMPLE_BRANCH_STACK ) { +u64 sz; + + data->branch_stack = (struct branch_stack *)array; + array++;/* nr */ + + sz = data->branch_stack->nr *sizeof (struct branch_entry ); + sz /=sizeof (uint64_t ); + array += sz; + }return 0 ; }
tools/perf/util/hist.c +73 -20
128 lines not on this page · raw message
tools/perf/util/hist.h +7 -0
@@ -41,6 +41,7 @@ enum hist_column {HISTC_COMM ,HISTC_PARENT ,HISTC_CPU , +HISTC_MISPREDICT , HISTC_NR_COLS, /* Last entry */ };
@@ -72,6 +73,12 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, struct hists *hists);void hist_entry__free (struct hist_entry *); +struct hist_entry *__hists__add_branch_entry (struct hists *self, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info * bi, +u64 period); +void hists__output_resort (struct hists *self);void hists__output_resort_threaded (struct hists *hists);void hists__collapse_resort (struct hists *self);
tools/perf/util/session.c +72 -0
90 lines not on this page · raw message
tools/perf/util/session.h +4 -0
@@ -73,6 +73,10 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evselstruct ip_callchain *chain, struct symbol **parent); +struct branch_info *perf_session__resolve_bstack (struct machine *self, +struct thread *thread, +struct branch_stack *bs); +bool perf_session__has_traces (struct perf_session *self,const char *msg);void mem_bswap_64 (void *src,int byte_size);
tools/perf/util/sort.c +271 -90
435 lines not on this page · raw message
tools/perf/util/sort.h +5 -0
@@ -31,11 +31,14 @@ extern const char *parent_pattern;extern const char default_sort_order[];extern int sort__need_collapse;extern int sort__has_parent; +extern bool sort__branch_mode;extern char *field_sep;extern struct sort_entry sort_comm;extern struct sort_entry sort_dso;extern struct sort_entry sort_sym;extern struct sort_entry sort_parent; +extern struct sort_entry sort_lbr_dso; +extern struct sort_entry sort_lbr_sym;extern enum sort_type sort__first_dimension;/**
@@ -72,6 +75,7 @@ struct hist_entry {struct hist_entry *pair;struct rb_root sorted_chain; }; +struct branch_info *branch_info;struct callchain_root callchain[0 ]; };
@@ -82,6 +86,7 @@ enum sort_type {SORT_SYM ,SORT_PARENT ,SORT_CPU , + SORT_MISPREDICTED, };/*
tools/perf/util/symbol.h +13 -0
@@ -5,6 +5,7 @@#include <stdbool.h> #include <stdint.h> #include "map.h" +#include "../perf.h" #include <linux/list.h> #include <linux/rbtree.h> #include <stdio.h>
@@ -119,6 +120,18 @@ struct map_symbol {bool has_children; }; +struct addr_map_symbol { +struct map *map; +struct symbol *sym; +u64 addr; +}; + +struct branch_info { +struct addr_map_symbol from; +struct addr_map_symbol to; +struct branch_flags flags; +}; +struct addr_location {struct thread *thread;struct map *map;
Signature · 1 line
1.7.1
Re: [PATCH 11/13] perf: add code to support PERF_SAMPLE_BRANCH_STACK (v3)
Quoted 7 lines · Stephane Eranian
From: Roberto Agostino Vitillo<[email protected]>
This patch adds:
- ability to parse samples withPERF_SAMPLE_BRANCH_STACK
- sort on branches
- build histograms on branches
[..]
Quoted 9 lines
static struct sort_dimension sort_dimensions[] = {(quoted diff) +2
-6- { .name = "pid", .entry =&sort_thread, }, - { .name = "comm", .entry =&sort_comm, }, - { .name = "dso", .entry =&sort_dso, }, - { .name = "symbol", .entry =&sort_sym, }, - { .name = "parent", .entry =&sort_parent, }, - { .name = "cpu", .entry =&sort_cpu, }, + { .name = "pid", .entry =&sort_thread, }, + { .name = "comm", .entry =&sort_comm, },
Review
Quoted 10 lines
(quoted diff) +9
-0+ { .name = "dso", .entry =&sort_dso, }, + { .name = "dso_from", .entry =&sort_dso_from,.taken = true }, + { .name = "dso_to", .entry =&sort_dso_to, .taken = true }, + { .name = "symbol", .entry =&sort_sym, }, + { .name = "symbol_from",.entry =&sort_sym_from,.taken = true }, + { .name = "symbol_to", .entry =&sort_sym_to, .taken = true }, + { .name = "parent", .entry =&sort_parent, }, + { .name = "cpu", .entry =&sort_cpu, }, + { .name = "mispredict", .entry =&sort_mispredict, }, };
The new sort dimensions don't seem to show up in perf report -h. Could you please update the help text?
Also:
# perf script -h
-f, --fields <str> comma separated output fields prepend with
'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr
You probably want to add a field here, so I could:
perf record -b any_call,u -e cycles:u
perf script -f event,branch_stack
and examine raw (symbolized) samples like I can with
perf record -g
perf script -f event,ip,sym
-Arun
Re: [PATCH 11/13] perf: add code to support PERF_SAMPLE_BRANCH_STACK (v3)
Quoted 29 lines · Arun Sharma
Quoted 8 lines · Stephane Eranian
From: Roberto Agostino Vitillo<[email protected]>
This patch adds:
- ability to parse samples withPERF_SAMPLE_BRANCH_STACK
- sort on branches
- build histograms on branches[..]
Quoted 19 lines
static struct
sort_dimensionsort_dimensions[] = {
- { .name = "pid", .entry =&sort_thread, },
- { .name = "comm", .entry =&sort_comm, },
- { .name = "dso", .entry =&sort_dso, },
- { .name = "symbol", .entry =&sort_sym, },
- { .name = "parent", .entry =&sort_parent, },
- { .name = "cpu", .entry =&sort_cpu, },
+ { .name = "pid", .entry =&sort_thread, },
+ { .name = "comm", .entry =&sort_comm, },
+ { .name = "dso", .entry =&sort_dso, },
+ { .name = "dso_from", .entry =&sort_dso_from,.taken = true },
+ { .name = "dso_to", .entry =&sort_dso_to, .taken = true },
+ { .name = "symbol", .entry =&sort_sym, },
+ { .name = "symbol_from",.entry =&sort_sym_from,.taken = true },
+ { .name = "symbol_to", .entry =&sort_sym_to, .taken = true },
+ { .name = "parent", .entry =&sort_parent, },
+ { .name = "cpu", .entry =&sort_cpu, },
Quoted 7 lines
Quoted 2 lines
+ { .name = "mispredict", .entry =&sort_mispredict, }, };
The new sort dimensions don't seem to show up in perf report -h. Could you please update the help text?
Can do this with the understanding that those are only avail when you use branch sampling.
Quoted 10 lines
Also:
# perf script -h-f, --fields <str> comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields:
comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addrYou probably want to add a field here, so I could:
Quoted 8 lines
perf record -b any_call,u -e cycles:u
perf script -f event,branch_stackand examine raw (symbolized) samples like I can with
perf record -g
perf script -f event,ip,sym
Ok, I'll look into this. Looks like a useful command for automating processing.
Quoted 2 lines
-Arun
PATCH 12/13 perf: add support for sampling taken branch to perf record (v3)
In reply to Stephane EranianFrom: Roberto Agostino Vitillo <[email protected]>
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
Filters can be combined by passing a comma separated list to the option:
$ perf record -b any_call,u -e cycles:u branchy
--- tools/perf/Documentation/perf-record.txt | 18 ++++++++ tools/perf/builtin-record.c | 69 ++++++++++++++++++++++++++++++ tools/perf/perf.h | 1 + tools/perf/util/evsel.c | 4 ++ 4 files changed, 92 insertions(+), 0 deletions(-)
tools/perf/Documentation/perf-record.txt +18 -0
@@ -148,6 +148,24 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha corresponding events, i.e., they always refer to events defined earlier on the command line. +-b:: +--branch-stack:: +Enable taken branch stack sampling. Each sample captures a series of consecutive +taken branches. The number of branches captured with each sample depends on the +underlying hardware, the type of branches of interested and the executed code. +It is possible to filter the types of branches by enabling filters. The +following filters are defined: 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). At least one of any, any_call, any_ret, any_ind +must be provided. The privilege levels may be ommitted, in which case, the privilege +levels of the associated event is applied to the branch filter. When sampling on multiple +events, branch stack sampling is enabled for all the sampling events. The sampled branch +type is the same for all events. The privilege levels are adjusted based on those of +the associated event unless specified explicitly with this option. Note that taken +branch sampling may not be available on all processors. The various filters must +be specified as a comma separated list: -b any_ret,u,k + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1]
tools/perf/builtin-record.c +69 -0
81 lines not on this page · raw message
tools/perf/perf.h +1 -0
@@ -221,6 +221,7 @@ struct perf_record_opts {unsigned int freq;unsigned int mmap_pages;unsigned int user_freq; +int branch_stack;u64 default_interval;u64 user_interval;const char *cpu_list;
tools/perf/util/evsel.c +4 -0
@@ -126,6 +126,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) attr->watermark =0 ; attr->wakeup_events =1 ; } +if (opts->branch_stack) { + attr->sample_type |=PERF_SAMPLE_BRANCH_STACK ; + attr->branch_sample_type = opts->branch_stack; + } attr->mmap = track; attr->comm = track;
Signature · 1 line
1.7.1
PATCH 13/13 perf: add support for taken branch sampling to perf report (v3)
In reply to Stephane EranianFrom: Roberto Agostino Vitillo <[email protected]>
This patch adds support for taken branch sampling, i.e, the PERF_SAMPLE_BRANCH_STACK feature to perf report. In other words, to display histograms based on taken branches rather than executed instructions addresses.
The new option is called -b and it takes no argument. To generate meaningful output, the perf.data must have been obtained using perf record -b xxx ... where xxx is a branch filter option.
The output shows symbols, modules, sorted by 'who branches where' the most often. The percentages reported in the first column refer to the total number of branches captured and not the usual number of samples.
Here is a quick example.
Here branchy is simple test program which looks as follows:
void f2(void)
{}
void f3(void)
{}
void f1(unsigned long n)
{
if (n & 1UL)
f2();
else
f3();
}int main(void)
{
unsigned long i;
for (i=0; i < N; i++)
f1(i);
return 0;
}
Here is the output captured on Nehalem, if we are
only interested in user level function calls.
$ perf record -b any_call,u -e cycles:u branchy
$ perf report -b --sort=symbol
52.34% [.] main [.] f1
24.04% [.] f1 [.] f3
23.60% [.] f1 [.] f2
0.01% [k] _IO_new_file_xsputn [k] _IO_file_overflow
0.01% [k] _IO_vfprintf_internal [k] _IO_new_file_xsputn
0.01% [k] _IO_vfprintf_internal [k] strchrnul
0.01% [k] __printf [k] _IO_vfprintf_internal
0.01% [k] main [k] __printfAbout half (52%) of the call branches captured are from main() -> f1(). The second half (24%+23%) is split in two equal shares between f1() -> f2(), f1() ->f3(). The output is as expected given the code.
It should be noted, that using -b in perf record does not eliminate information in the perf.data file. Consequently, a typical profile can also be obtained by perf report by simply not using its -b option.
--- tools/perf/Documentation/perf-report.txt | 7 ++ tools/perf/builtin-report.c | 95 +++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 8 deletions(-)
tools/perf/Documentation/perf-report.txt +7 -0
@@ -153,6 +153,13 @@ OPTIONS information which may be very large and thus may clutter the display. It currently includes: cpu and numa topology of the host system. +-b:: +--branch-stack:: + Use the addresses of sampled taken branches instead of the instruction + address to build the histograms. To generate meaningful output, the + perf.data file must have been obtained using perf record -b xxx where + xxx is a branch filter option. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-annotate[1]
tools/perf/builtin-report.c +87 -8
129 lines not on this page · raw message
Signature · 1 line
1.7.1
Any comments on this patch set?
Quoted 234 lines · Stephane Eranian
This patchset adds an important and useful new feature to
perf_events: branch stack sampling. In other words, the ability to capture taken branches into each sample.Statistical sampling of taken branch should not be confused for branch tracing. Not all branches are necessarily captured
Sampling taken branches is important for basic block profiling, statistical call graph, function call counts. Many of those measurements can help drive a compiler optimizer.
The branch stack is a software abstraction which sits on top of the PMU hardware. As such, it is not available on all processors. For now, the patch provides the generic interface and the Intel X86 implementation where it leverages the Last Branch Record (LBR) feature (from Core2 to SandyBridge).
Branch stack sampling is supported for both per-thread and system-wide modes.
It is possible to filter the type and privilege level of branches to sample. The target of the branch is used to determine the privilege level.
For each branch, the source and destination are captured. On some hardware platforms, it may be possible to also extract the target prediction and, in that case, it is also exposed to end users.
The branch stack can record a variable number of taken branches per sample. Those branches are always consecutive in time. The number of branches captured depends on the filtering and the underlying hardware. On Intel Nehalem and later, up to 16 consecutive branches can be captured per sample.
Branch sampling is always coupled with an event. It can be any PMU event but it can't be a SW or tracepoint event.
Branch sampling is requested by setting a new
sample_typeflag called:PERF_SAMPLE_BRANCH_STACK.To support branch filtering, we introduce a new field to the
perf_event_attrstruct:branch_sample_type. We chose NOT to overload the config1, config2 field because those are related to the event encoding. Branch stack is a separate feature which is combined with the event.The
branch_sample_typeis a bitmask of possible filters.
The following filters are defined (more can be added):
-PERF_SAMPLE_BRANCH_ANY: any control flow change
-PERF_SAMPLE_BRANCH_USER: capture branches when target is at user level
-PERF_SAMPLE_BRANCH_KERNEL: capture branches when target is at user level
-PERF_SAMPLE_BRANCH_ANY_CALL: capture call branches (incl. syscalls)
-PERF_SAMPLE_BRANCH_ANY_RET: capture return branches (incl. syscall returns)
-PERF_SAMPLE_BRANCH_IND_CALL: capture indirect callsIt is possible to combine filters, e.g., IND_CALL|USER|KERNEL.
When the privilege level is not specified, the branch stack inherits that of the associated event.
Some processors may not offer hardware branch filtering, e.g., Intel Atom. Some may have HW filtering bugs (e.g., Nehalem). The Intel X86 implementation in this patchset also provides a SW branch filter which works on a best effort basis. It can compensate for the lack of LBR filtering. But first and foremost, it helps work around LBR filtering errata. The goal is to only capture the type of branches requested by the user.
It is possible to combine branch stack sampling with PEBS on Intel X86 processors. Depending on the
precise_samplingmode, there are certain filterting restrictions. When precise_sampling=1, then there are no filtering restrictions. Whenprecise_sampling> 1, then only ANY|USER|KERNEL filter can be used. This comes from the fact that the kernel uses LBR to compensate for the PEBS off-by-1 skid on the instruction pointer.To demonstrate how the
perf_eventbranch stack sampling interface works, the patchset also modifies perf record to capture taken branches. Similarly perf report is enhanced to display a histogram of taken branches.I would like to thank Roberto Vitillo @ LBL for his work on the perf tool for this.
Enough talking, let's take a simple example. Our trivial test program goes like this:
void f2(void)
{}
void f3(void)
{}
void f1(unsigned long n)
{
if (n & 1UL)
f2();
else
f3();
}
int main(void)
{
unsigned long i;for (i=0; i < N; i++)
f1(i);
return 0;
}$ perf record -b any branchy $ perf report -b # Events: 23K cycles # # Overhead Source Symbol Target Symbol # ........ ................ ................18.13% [.] f1 [.] main
18.10% [.] main [.] main
18.01% [.] main [.] f1
15.69% [.] f1 [.] f1
9.11% [.] f3 [.] f1
6.78% [.] f1 [.] f3
6.74% [.] f1 [.] f2
6.71% [.] f2 [.] f1Of the total number of branches captured, 18.13% were from
f1()->main().Let's make this clearer by filtering the user call branches only:
$ perf record -b any_call -e cycles:u branchy $ perf report -b # Events: 19K cycles # # Overhead Source Symbol Target Symbol # ........ ......................... ......................... # 52.50% [.] main [.] f1 23.99% [.] f1 [.] f3 23.48% [.] f1 [.] f2 0.03% [.] _IO_default_xsputn [.] _IO_new_file_overflow 0.01% [k] _start [k] __libc_start_mainNow it is more obvious. %52 of all the captured branches where calls from
main()->f1(). The rest is split 50/50 betweenf1()->f2()andf1()->f3()which is expected given thatf1()dispatches based on odd vs. even values of n which is constantly increasing.Here is a kernel example, where we want to sample indirect calls:
$ perf record -a -C 1 -b ind_call -e r1c4:k sleep 10 $ perf report -b # # Overhead Source Symbol Target Symbol # ........ .......................... .......................... # 36.36% [k] __delay [k] delay_tsc 9.09% [k] ktime_get [k] read_tsc 9.09% [k] getnstimeofday [k] read_tsc 9.09% [k] notifier_call_chain [k] tick_notify 4.55% [k] cpuidle_idle_call [k] intel_idle 4.55% [k] cpuidle_idle_call [k] menu_reflect 2.27% [k] handle_irq [k] handle_edge_irq 2.27% [k] ack_apic_edge [k] native_apic_mem_write 2.27% [k] hpet_interrupt_handler [k] hrtimer_interrupt 2.27% [k] __run_hrtimer [k] watchdog_timer_fn 2.27% [k] enqueue_task [k] enqueue_task_rt 2.27% [k] try_to_wake_up [k] select_task_rq_rt 2.27% [k] do_timer [k] read_tscDue to HW limitations, branch filtering may be approximate on Core, Atom processors. It is more accurate on Nehalem, Westmere and best on Sandy Bridge.
In version 2, we've updated the patch to tip/master (commit 5734857) and we've incoporated the feedback from v1 concerning anynous bitfield struct for
branch_stack_entryand the hanlding of i386 ABI binaries on 64-bit host in the instr decoder for the LBR SW filter.In version 3, we've updated to 3.2.0-tip. The Atom revision check has been put into its own patch. We fixed a browser issue with report report. We fixed all the style issues as well.
Signed-off-by Stephane Eranian <[email protected]>---
Roberto Agostino Vitillo (3):
perf: add code to supportPERF_SAMPLE_BRANCH_STACK
perf: add support for sampling taken branch to perf record
perf: add support for taken branch sampling to perf reportStephane Eranian (10):
perf_events: add generic taken branch sampling support (v3)
perf_events: add Intel LBR MSR definitions
perf_events: add Intel X86 LBR sharing logic
perf_events: sync branch stack sampling with X86precise_sampling
perf_events: add LBR mappings forPERF_SAMPLE_BRANCHfilters
perf_events: disable LBR support for older Intel Atom processors
perf_events: implementPERF_SAMPLE_BRANCHfor Intel X86
perf_events: add LBR software filter support for Intel X86
perf_events: disable PERF_SAMPLE_BRANCH_* when not supported
perf_events: add hook to flushbranch_stackon context switcharch/alpha/kernel/perf_event.c | 4 +
arch/arm/kernel/perf_event.c| 4 +arch/mips/kernel/perf_event_mipsxx.c| 4 +arch/powerpc/kernel/perf_event.c| 4 +arch/sh/kernel/perf_event.c| 4 +arch/sparc/kernel/perf_event.c| 4 +arch/x86/include/asm/msr-index.h | 7 + arch/x86/kernel/cpu/perf_event.c | 47 +++- arch/x86/kernel/cpu/perf_event.h | 19 +arch/x86/kernel/cpu/perf_event_amd.c | 3 +
arch/x86/kernel/cpu/perf_event_intel.c| 120 +++++--arch/x86/kernel/cpu/perf_event_intel_ds.c| 22 +-arch/x86/kernel/cpu/perf_event_intel_lbr.c| 525 ++++++++++++++++++++++++++--include/linux/perf_event.h| 78 ++++-kernel/events/core.c| 167 +++++++++kernel/events/hw_breakpoint.c| 6 +tools/perf/Documentation/perf-record.txt| 18 +tools/perf/Documentation/perf-report.txt| 7 +tools/perf/builtin-record.c| 69 ++++tools/perf/builtin-report.c| 95 +++++-tools/perf/perf.h| 18 +tools/perf/util/annotate.c| 2 +-tools/perf/util/event.h | 1 + tools/perf/util/evsel.c | 14 + tools/perf/util/hist.c | 93 ++++- tools/perf/util/hist.h | 7 +tools/perf/util/session.c | 72 ++++
tools/perf/util/session.h| 4 +tools/perf/util/sort.c| 361 ++++++++++++++-----tools/perf/util/sort.h| 5 +tools/perf/util/symbol.h| 13 +31 files changed, 1601 insertions(+), 196 deletions(-)
Quoted 2 lines · Stephane Eranian
Any comments on this patch set?
Queued it, thanks!
Quoted 5 lines · Peter Zijlstra
Quoted 2 lines · Stephane Eranian
Any comments on this patch set?
Queued it, thanks!
Great Thanks.
Now, we still need to make progress on:
- fixing throttling
- PEBS-LL
- IBS
- event scheduling
- LWP
Quoted 3 lines
Now, we still need to make progress on:
- fixing throttling
- PEBS-LL
Raw PEBS really too
Quoted 3 lines
- IBS
- event scheduling
- LWP
- Back-to-back events
-Andi
Signature · 1 line
[email protected] -- Speaking for myself only.
Quoted 4 lines · Peter Zijlstra
Quoted 2 lines · Stephane Eranian
Any comments on this patch set?
Queued it, thanks!
One thing that needs to happen with this branch sampling patch is that Arnaldo needs
to apply the patch I developed with dsahern@ that changes the magic number to something that can determine the endianess. I don't know what happened to this patch.
It's been over 6 months since I posted it and it's still not in the perf source tree.
The issue here is that with branch stack sampling, the size of perf_event_attr has
now changed (an extra u64). As such if this new perf tries to read an old perf.data
file, it is going to think it's using a different endianess, it'll swap the attr_size and still
find it different from its own version of the struct. That leads to:
incompatible file
format.
We need to separate endianess detection from attr_size. If attr_size in perf.data <
then sizeof(struct perf_event_attr), then just zero out the extra (unused) fields.
With that in place, this new perf will be able to read older perf.data files.
Hi,
The branch stack sampling patch exposes a flaw in the sampling buffer format as currently exported by the kernel.
In the current format, sample records (RECORD_SAMPLE) are NOT self-describing. That means that by looking at the fixed size header, it is not possible to determine which event caused the sample to be recorded and what's in the body of the variable length sample.
Such introspection is only possible once we know the event unique id (PERF_SAMPLE_ID). But to get the event ID, we need to parse the sample. But, given that a sample has a variable length, there is no predefined position for that ID in the sample. You have a chicken and egg problem here. There is no room left in the fixed size header to fit this in.
This works today with perf because perf applies the SAME sample_type to ALL events, i.e., all events have the same body layout. This is a limitation of the tool. The kernel API clearly allows more flexibility but it is hindered by
the problem I described above.
With branch sampling, this becomes more problematic because if you are sampling on many events, it may not be necessary nor useful to capture the branch sample stack for each event. With existing HW, the branch stack uses at most 264 bytes in a sample. You'd be consuming the buffer space much faster for nothing.
We need to solve this problem yet maintain backward compatibility with old version of tools.
The kernel sampling buffer format needs to evolve to have fixed size header that are more self-describing. The header somehow needs to contain the event ID or the sample_type for type=RECORD_SAMPLE. I would prefer the former because if we ever need more than 64-bits for sample_type, we would have the same problem again. Having the event ID, requires that it be generated systematically. That is not the case today.
That new buffer format could be requested, as a flag, when the event is created. That would ensure backward compatibility.
An alternative would be to find a way to encode the event ID at a known position somehow in the body of a RECORD_SAMPLE. But I don't see how that would be possible (given there is already the sample_id_all stuff).
Any comments?
Quoted 10 lines · Stephane Eranian
Hi,
The branch stack sampling patch exposes a flaw in the sampling buffer format as currently exported by the kernel.
In the current format, sample records (
RECORD_SAMPLE) are NOT self-describing. That means that by looking at the fixed size header, it is not possible to determine which event caused the sample to be recorded and what's in the body of the variable length sample.
Quoted 6 lines
Such introspection is only possible once we know the event unique id (
PERF_SAMPLE_ID). But to get the event ID, we need to parse the sample. But, given that a sample has a variable length, there is no predefined position for that ID in the sample. You have a chicken and egg problem here. There is no room left in the fixed size header to fit this in.
I brought this up last Fall as well. As I recall the response is to move each sample_type based stream into its own data file and then merge the data files while processing.
David
Quoted 19 lines · David Ahern
Quoted 10 lines · Stephane Eranian
Hi,
The branch stack sampling patch exposes a flaw in the sampling buffer format as currently exported by the kernel.
In the current format, sample records (
RECORD_SAMPLE) are NOT self-describing. That means that by looking at the fixed size header, it is not possible to determine which event caused the sample to be recorded and what's in the body of the variable length sample.Quoted 6 lines
Such introspection is only possible once we know the event unique id (
PERF_SAMPLE_ID). But to get the event ID, we need to parse the sample. But, given that a sample has a variable length, there is no predefined position for that ID in the sample. You have a chicken and egg problem here. There is no room left in the fixed size header to fit this in.
Quoted 3 lines
I brought this up last Fall as well. As I recall the response is to move each
sample_typebased stream into its own data file and then merge the data files while processing.
By data stream, you're talking about actual sampling buffer. Sampling on 10 events, means 10 sampling buffers. If you reach the rlimit on it, you need to decrease buffer size, and therefore you increase overhead.
Moreover, I don't think perf record is well equipped to handle this.
Quoted 19 lines · David Ahern
Quoted 10 lines · Stephane Eranian
Hi,
The branch stack sampling patch exposes a flaw in the sampling buffer format as currently exported by the kernel.
In the current format, sample records (
RECORD_SAMPLE) are NOT self-describing. That means that by looking at the fixed size header, it is not possible to determine which event caused the sample to be recorded and what's in the body of the variable length sample.Quoted 6 lines
Such introspection is only possible once we know the event unique id (
PERF_SAMPLE_ID). But to get the event ID, we need to parse the sample. But, given that a sample has a variable length, there is no predefined position for that ID in the sample. You have a chicken and egg problem here. There is no room left in the fixed size header to fit this in.
Quoted 4 lines
I brought this up last Fall as well. As I recall the response is to move each
sample_typebased stream into its own data file and then merge the data files while processing.
But then, if you merge the files as is, it does not buy you anything. You need to
add or overwrite some information in the headers. Unless, you rewrite the tool to
handle multiple inputs files.
Quoted 1 line
David
Peter Zijlstra
maintainerArnaldo,
Quoted 85 lines · Stephane Eranian
I would like to thank Roberto Vitillo @ LBL for his work on the perf tool for this.
Enough talking, let's take a simple example. Our trivial test program goes like this:
void f2(void)
{}
void f3(void)
{}
void f1(unsigned long n)
{
if (n & 1UL)f2(); else f3(); }int main(void)
{
unsigned long i;for (i=0; i < N; i++)
f1(i);
return 0;
}$ perf record -b any branchy $ perf report -b # Events: 23K cycles # # Overhead Source Symbol Target Symbol # ........ ................ ................18.13% [.] f1 [.] main 18.10% [.] main [.] main 18.01% [.] main [.] f1 15.69% [.] f1 [.] f1 9.11% [.] f3 [.] f1 6.78% [.] f1 [.] f3 6.74% [.] f1 [.] f2 6.71% [.] f2 [.] f1Of the total number of branches captured, 18.13% were from
f1()->main().Let's make this clearer by filtering the user call branches only:
$ perf record -b any_call -e cycles:u branchy $ perf report -b # Events: 19K cycles # # Overhead Source Symbol Target Symbol # ........ ......................... ......................... # 52.50% [.] main [.] f1 23.99% [.] f1 [.] f3 23.48% [.] f1 [.] f2 0.03% [.] _IO_default_xsputn [.] _IO_new_file_overflow 0.01% [k] _start [k] __libc_start_mainNow it is more obvious. %52 of all the captured branches where calls from
main()->f1(). The rest is split 50/50 betweenf1()->f2()andf1()->f3()which is expected given thatf1()dispatches based on odd vs. even values of n which is constantly increasing.Here is a kernel example, where we want to sample indirect calls:
$ perf record -a -C 1 -b ind_call -e r1c4:k sleep 10 $ perf report -b # # Overhead Source Symbol Target Symbol # ........ .......................... .......................... # 36.36% [k] __delay [k] delay_tsc 9.09% [k] ktime_get [k] read_tsc 9.09% [k] getnstimeofday [k] read_tsc 9.09% [k] notifier_call_chain [k] tick_notify 4.55% [k] cpuidle_idle_call [k] intel_idle 4.55% [k] cpuidle_idle_call [k] menu_reflect 2.27% [k] handle_irq [k] handle_edge_irq 2.27% [k] ack_apic_edge [k] native_apic_mem_write 2.27% [k] hpet_interrupt_handler [k] hrtimer_interrupt 2.27% [k] __run_hrtimer [k] watchdog_timer_fn 2.27% [k] enqueue_task [k] enqueue_task_rt 2.27% [k] try_to_wake_up [k] select_task_rq_rt 2.27% [k] do_timer [k] read_tsc
Quoted 3 lines
Due to HW limitations, branch filtering may be approximate on Core, Atom processors. It is more accurate on Nehalem, Westmere and best on Sandy Bridge.
Can I have you ACK on this userspace stuff (patches 11-13)?
Quoted 21 lines · Peter Zijlstra
Quoted 21 lines
Here is a kernel example, where we want to sample indirect calls:
$ perf record -a -C 1 -b ind_call -e r1c4:k sleep 10 $ perf report -b # # Overhead Source Symbol Target Symbol # ........ .......................... .......................... # 36.36% [k] __delay [k] delay_tsc 9.09% [k] ktime_get [k] read_tsc 9.09% [k] getnstimeofday [k] read_tsc 9.09% [k] notifier_call_chain [k] tick_notify 4.55% [k] cpuidle_idle_call [k] intel_idle 4.55% [k] cpuidle_idle_call [k] menu_reflect 2.27% [k] handle_irq [k] handle_edge_irq 2.27% [k] ack_apic_edge [k] native_apic_mem_write 2.27% [k] hpet_interrupt_handler [k] hrtimer_interrupt 2.27% [k] __run_hrtimer [k] watchdog_timer_fn 2.27% [k] enqueue_task [k] enqueue_task_rt 2.27% [k] try_to_wake_up [k] select_task_rq_rt 2.27% [k] do_timer [k] read_tsc
Quoted 5 lines
Quoted 3 lines
Due to HW limitations, branch filtering may be approximate on Core, Atom processors. It is more accurate on Nehalem, Westmere and best on Sandy Bridge.
Can I have you ACK on this userspace stuff (patches 11-13)?
While the current "Source -> Target" based UI works well for many cases, it'd be nice to have "-g -b any_call" to result in a callgraph like output, so for userspace programs compiled without frame pointers, we get a limited callgraph.
-Arun