powerpc/perf: Adjust callchain based on DWARF debug info
PATCH v3 1/1 powerpc/perf: Adjust callchain based on DWARF debug info
powerpc/perf: Adjust callchain based on DWARF debug info
When saving the callchain on Power, the kernel conservatively saves excess entries in the callchain. A few of these entries are needed in some cases but not others. We should use the DWARF debug information to determine when the entries are needed.
Eg: the value in the link register (LR) is needed only when it holds the return address of a function. At other times it must be ignored.
If the unnecessary entries are not ignored, we end up with duplicate arcs in the call-graphs.
Use the DWARF debug information to determine if any callchain entries should be ignored when building call-graphs.
Callgraph before the patch:
14.67% 2234 sprintft libc-2.18.so [.] __random
|
--- __random
|
|--61.12%-- __random
| |
| |--97.15%-- rand
| | do_my_sprintf
| | main
| | generic_start_main.isra.0
| | __libc_start_main
| | 0x0
| |
| --2.85%-- do_my_sprintf
| main
| generic_start_main.isra.0
| __libc_start_main
| 0x0
|
--38.88%-- rand
|
|--94.01%-- rand
| do_my_sprintf
| main
| generic_start_main.isra.0
| __libc_start_main
| 0x0
|
--5.99%-- do_my_sprintf
main
generic_start_main.isra.0
__libc_start_main
0x0Callgraph after the patch:
14.67% 2234 sprintft libc-2.18.so [.] __random
|
--- __random
|
|--95.93%-- rand
| do_my_sprintf
| main
| generic_start_main.isra.0
| __libc_start_main
| 0x0
|
--4.07%-- do_my_sprintf
main
generic_start_main.isra.0
__libc_start_main
0x0TODO: For split-debug info objects like glibc, we can only determine
the call-frame-address only when both .eh_frame and .debug_info sections are available. We should be able to determin the CFA even without the .eh_frame section.
Fix suggested by Anton Blanchard.
Thanks to valuable input on DWARF debug information from Ulrich Weigand.
---
Changelog[v3]
[Jiri Olsa] Rename function to arch_skip_callchain_idx() to be
consistent with behavior.
[Jiri Olsa] Add '__maybe_unused' tags for unused parameters.
Changelog[v2]:
- Add missing dwfl_end()
- Fix merge conflicts due to some unwind code
tools/perf/arch/powerpc/Makefile | 1 + tools/perf/arch/powerpc/util/skip-callchain-idx.c | 266 +++++++++++++++++++++ tools/perf/config/Makefile | 4 + tools/perf/util/callchain.h | 13 + tools/perf/util/machine.c | 16 +- 5 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 tools/perf/arch/powerpc/util/skip-callchain-idx.c
tools/perf/arch/powerpc/Makefile +1 -0
@@ -3,3 +3,4 @@ PERF_HAVE_DWARF_REGS := 1 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o endif LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
tools/perf/arch/powerpc/util/skip-callchain-idx.c new file +266 -0
266 lines not on this page · raw message
tools/perf/config/Makefile +4 -0
@@ -48,6 +48,10 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm)) NO_LIBDW_DWARF_UNWIND := 1 endif +ifeq ($(ARCH),powerpc) + CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX +endif + ifeq ($(LIBUNWIND_LIBS),) NO_LIBUNWIND := 1 else
tools/perf/util/callchain.h +13 -0
@@ -165,4 +165,17 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sampextern const char record_callchain_help[];int parse_callchain_report_opt (const char *arg); + +#ifdef HAVE_SKIP_CALLCHAIN_IDX +extern int arch_skip_callchain_idx (struct machine *machine, +struct thread *thread,struct ip_callchain *chain); +#else +static inline int arch_skip_callchain_idx (struct machine *machine__maybe_unused , +struct thread *thread__maybe_unused , +struct ip_callchain *chain__maybe_unused ) +{ +return -1 ; +} +#endif +#endif /* __PERF_CALLCHAIN_H */
tools/perf/util/machine.c +14 -2
@@ -1290,6 +1290,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,int chain_nr =min (max_stack, (int )chain->nr);int i;int err; +int skip_slot;callchain_cursor_reset (&callchain_cursor);
@@ -1298,14 +1299,25 @@ static int machine__resolve_callchain_sample(struct machine *machine,return 0 ; } +/* +* Based on DWARF debug information, some architectures skip +* some of the callchain entries saved by the kernel. +*/ + skip_slot =arch_skip_callchain_idx (machine, thread, chain); +for (i =0 ; i < chain_nr; i++) {u64 ip;struct addr_location al; -if (callchain_param.order ==ORDER_CALLEE ) +if (callchain_param.order ==ORDER_CALLEE ) { +if (i == skip_slot) +continue ; ip = chain->ips[i]; -else + }else { +if ((int )(chain->nr - i -1 ) == skip_slot) +continue ; ip = chain->ips[chain->nr - i -1 ]; + }if (ip >=PERF_CONTEXT_MAX ) {switch (ip) {
Signature · 1 line
1.7.9.5