powerpc/perf: Adjust callchain based on DWARF debug info
PATCH 1/1 powerpc/perf: Adjust callchain based on DWARF debug info
[PATCH 1/1] 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.
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 DWARF debug information to ignore the unnecessary entries.
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.
Thanks to Ulrich Weigand for help with DWARF debug information.
Fix suggested by Anton Blanchard.
--- tools/perf/arch/powerpc/Makefile | 1 + tools/perf/arch/powerpc/util/adjust-callchain.c | 278 ++++++++++++++++++++++++ tools/perf/config/Makefile | 5 + tools/perf/util/callchain.h | 12 + tools/perf/util/machine.c | 16 +- 5 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 tools/perf/arch/powerpc/util/adjust-callchain.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/adjust-callchain.o
tools/perf/arch/powerpc/util/adjust-callchain.c new file +278 -0
278 lines not on this page · raw message
tools/perf/config/Makefile +5 -0
@@ -29,11 +29,16 @@ ifeq ($(ARCH),x86) endif NO_PERF_REGS := 0 endif + ifeq ($(ARCH),arm) NO_PERF_REGS := 0 LIBUNWIND_LIBS = -lunwind -lunwind-arm endif +ifeq ($(ARCH),powerpc) + CFLAGS += -DHAVE_ADJUST_CALLCHAIN +endif + ifeq ($(LIBUNWIND_LIBS),) NO_LIBUNWIND := 1 else
tools/perf/util/callchain.h +12 -0
@@ -157,4 +157,16 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentint hist_entry__append_callchain (struct hist_entry *he,struct perf_sample *sample);extern const char record_callchain_help[]; + +#ifdef HAVE_ADJUST_CALLCHAIN +extern int arch_adjust_callchain (struct machine *machine, +struct thread *thread,struct ip_callchain *chain); +#else +static inline int arch_adjust_callchain (struct machine *machine, +struct thread *thread,struct ip_callchain *chain) +{ +return -1 ; +} +#endif +#endif /* __PERF_CALLCHAIN_H */
tools/perf/util/machine.c +14 -2
@@ -1271,6 +1271,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);
@@ -1279,14 +1280,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_adjust_callchain (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.8.4.2
Sukadev Bhattiprolu <[email protected]> wrote on 05/09/2014 09:46:38 PM:
Quoted 8 lines
From: Sukadev Bhattiprolu <[email protected]>
To: Arnaldo Carvalho de Melo <[email protected]>,
Cc: [email protected], Anton Blanchard <[email protected]>, [email protected], Michael Ellerman <[email protected]>, Maynard Johnson/Rochester/IBM@IBMUS, [email protected]
Date: 05/09/2014 09:46 PM
Subject: [PATCH 1/1] powerpc/perf: Adjust callchain based on DWARF debug
info
Quoted 2 lines
[PATCH 1/1] powerpc/perf: Adjust callchain based on DWARF debug info
Reviewed and tested. Thanks, Suka.
-Maynard
Quoted 2 lines
When saving the callchain on Power, the kernel conservatively saves
excess
Quoted 87 lines
entries in the callchain. A few of these entries are needed in some cases but not others.
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 DWARF debug information to ignore the unnecessary entries.
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.Thanks to Ulrich Weigand for help with DWARF debug information.
Fix suggested by Anton Blanchard.
Reported-by Maynard Johnson <[email protected]>Signed-off-by Sukadev Bhattiprolu <[email protected]>--- tools/perf/arch/powerpc/Makefile | 1 + tools/perf/arch/powerpc/util/adjust-callchain.c | 278 +++++++++++++ +++++++++++ tools/perf/config/Makefile | 5 + tools/perf/util/callchain.h | 12 + tools/perf/util/machine.c | 16 +- 5 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 tools/perf/arch/powerpc/util/adjust-callchain.c
[snip]
Maynard Johnson [[email protected]] wrote:
| > [PATCH 1/1] powerpc/perf: Adjust callchain based on DWARF debug info | | Acked-by: Maynard Johnson <[email protected]> | | Reviewed and tested. Thanks, Suka.
Thanks Maynard. This updated patch also fixes whitespace damage.
From: Sukadev Bhattiprolu <[email protected]>
Date: Fri, 9 May 2014 19:00:35 -0500
Subject: [PATCH 1/1] 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.
--- tools/perf/arch/powerpc/Makefile | 1 + tools/perf/arch/powerpc/util/adjust-callchain.c | 276 ++++++++++++++++++++++++ tools/perf/config/Makefile | 5 + tools/perf/util/callchain.h | 12 ++ tools/perf/util/machine.c | 16 +- 5 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 tools/perf/arch/powerpc/util/adjust-callchain.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/adjust-callchain.o
tools/perf/arch/powerpc/util/adjust-callchain.c new file +276 -0
276 lines not on this page · raw message
tools/perf/config/Makefile +5 -0
@@ -29,11 +29,16 @@ ifeq ($(ARCH),x86) endif NO_PERF_REGS := 0 endif + ifeq ($(ARCH),arm) NO_PERF_REGS := 0 LIBUNWIND_LIBS = -lunwind -lunwind-arm endif +ifeq ($(ARCH),powerpc) + CFLAGS += -DHAVE_ADJUST_CALLCHAIN +endif + ifeq ($(LIBUNWIND_LIBS),) NO_LIBUNWIND := 1 else
tools/perf/util/callchain.h +12 -0
@@ -157,4 +157,16 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentint hist_entry__append_callchain (struct hist_entry *he,struct perf_sample *sample);extern const char record_callchain_help[]; + +#ifdef HAVE_ADJUST_CALLCHAIN +extern int arch_adjust_callchain (struct machine *machine, +struct thread *thread,struct ip_callchain *chain); +#else +static inline int arch_adjust_callchain (struct machine *machine, +struct thread *thread,struct ip_callchain *chain) +{ +return -1 ; +} +#endif +#endif /* __PERF_CALLCHAIN_H */
tools/perf/util/machine.c +14 -2
@@ -1271,6 +1271,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);
@@ -1279,14 +1280,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_adjust_callchain (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.8.4.2