Re: [PATCH v4 00/18] perf: add support for sampling taken branches
From: Stephane Eranian
Date: Thu Feb 02 2012 - 08:23:14 EST
On Wed, Feb 1, 2012 at 9:41 AM, Anshuman Khandual
> On Saturday 28 January 2012 02:26 AM, Stephane Eranian wrote:
>> 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_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 Â Â: branches when target is at user level
>> - PERF_SAMPLE_BRANCH_KERNEL Â: branches when target is at kernel level
>> - PERF_SAMPLE_BRANCH_HV Â Â Â: branches when target is at hypervisor level
>> - PERF_SAMPLE_BRANCH_ANY_CALL: call branches (incl. syscalls)
>> - PERF_SAMPLE_BRANCH_ANY_RET : return branches (incl. syscall returns)
>> - PERF_SAMPLE_BRANCH_IND_CALL: 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
> Just wondering whether appending function call chain details to branch stack
> would add value from system performance event analysis perspective.
> perf record -g -b any_call,u -e branch-misses:k ls
Are you talking about using the content of branch_stack as a substitute
for PERF_SAMPLE_CALLCHAIN? You could, assuming you're sampling
only return branches (not call branches).
> 15.38% ls libc-2.11.1.so Âlibc-2.11.1.so Â[k] getenv Â Â Â Â Â Â Â[k] strncmp
> 15.38% ls libc-2.11.1.so Âlibc-2.11.1.so Â[k] __execvpe Â Â Â Â Â [k] strlen
> 15.38% ls libc-2.11.1.so Âlibc-2.11.1.so Â[k] __execvpe Â Â Â Â Â [k] memcpy
> 15.38% ls ld-2.11.1.so Â Âld-2.11.1.so Â Â[k] _dl_map_object_from_fd Â[k] mmap64
> Â7.69% ls libc-2.11.1.so Âlibc-2.11.1.so Â[k] __execvpe Â Â Â Â Â [k] __strchrnul
> Â7.69% ls libc-2.11.1.so Âlibc-2.11.1.so Â[k] __execvpe Â Â Â Â Â [k] __execve
> Â7.69% ls ld-2.11.1.so Â Âld-2.11.1.so Â Â[k] _dl_map_object_from_fd Â[k] _dl_setup_hash
> Â7.69% ls ld-2.11.1.so Â Âld-2.11.1.so Â Â[k] _dl_map_object_from_fd Â[k] close
> Â7.69% ls ld-2.11.1.so Â Âld-2.11.1.so Â Â[k] _dl_map_object_from_fd Â[k] memset
> From the example above, we can see
> (1) 15.38% Âls Âlibc-2.11.1.so libc-2.11.1.so [k] getenv [k] strncmp
> Â Â'[k] getenv ----> [k]' strncmp happened 15% time for the branch-misses
> Â Â event overflow.
No, that's not how you have to interpret the data. It's not 15.38% of the time.
It's 15.38% of all the captured branches.
One of the goals of this first perf report mode is to show how branch_stack can
be used to statistically capture cross-module (or cross-function)
calls. In other
words, who calls who and how often. This can be used by compilers to drive
inlining, for instance. The fact that on NHM/WSM/SNB, it is possible to capture
prediction is also interesting, especially for indirect calls.
> (2) But this lacks the information from the Âsource code program point of view
> Â Âlike what is the code path which eventually ended up in the branch (getenv
> Â Â----> strncmp) 15.38% of time for the event. There can be N number of
> Â Âfunction call chains which might lead to the branch (getenv ----> strncmp).
> Â ÂHaving a percentage distribution of the function callchians for every entry
> Â Âin the output (as above) would be a good idea. This would give complete
> Â Âinformation (though statistical sampling) on the source code control flow
> Â Âwhich would have lead to the PMU event.
Yes. I think what you are after is more like gprof or perf report -g, i.e., the
callgraph. You can use the branch_stack feature to collect a
without the need to frame-pointers or unwind info. You'd have to
filter on return
branches only, then you invert the edge. I think we could probably
reuse the existing
perf code to handle CALLCHAIN for this. We just haven't had a chance
to look at this
yet. But patches can be added later on.
> (3) <percentage of call_chain> <percentage of branch_chain> [EVENT]
> Â ÂThere may be situations where these chains are overlapping with each other
> Â Âto some extent.
> If we change to newt output format, we can display the relative percentages of call
> chains when we click on specific entry of branch chain similar to when we try to
> annotate a symbol in normal perf report newt output.
> Any thoughts ?
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/