Skip to contentSkip to conversation

powerpc/perf: Adjust callchain based on DWARF debug info

PATCH In review Sukadev Bhattiprolu 2 participants 3 messages May 10, 2014 – May 13, 2014 perf events

lore
Share & tools
lore
#0 lore raw

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
                                     0x0

Callgraph 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
                          0x0

TODO: 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
index 744e629..512cc8d 100644
@@ -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
index 5a3c452..7e93877 100644
@@ -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
index 8ad97e9..81ecb90 100644
@@ -157,4 +157,16 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
 int 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
index a53cd0b..dce3bf0 100644
@@ -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
Acked-by on v1 1/1
#1 lore raw

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
                                     0x0

Callgraph 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
                          0x0

TODO: 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

[snip]

author Tested-by Maynard Johnson Acked-by Maynard Johnson
#2 lore raw

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
                                     0x0

Callgraph 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
                          0x0

TODO: 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
index 744e629..512cc8d 100644
@@ -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
index 5a3c452..7e93877 100644
@@ -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
index 8ad97e9..81ecb90 100644
@@ -157,4 +157,16 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
 int 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
index a53cd0b..dce3bf0 100644
@@ -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