Re: [PATCH] perf: libdw support for powerpc

From: Naveen N. Rao
Date: Thu May 18 2017 - 14:20:53 EST


Paolo Bonzini wrote:
The ARM and x86 architectures already use libdw, and it is useful to
have as much common code for the unwinder as possible. Porting PPC
to libdw only needs an architecture-specific hook to move the register
state from perf to libdw.

Thanks. Ravi has had a similar patch locally, but from what I understand, there are issues with libdw based unwinding on powerpc64. I gave this a quick test and I don't see the user-space call trace being unwinded properly with libdw.

With the same perf.data, with libunwind:

bswap 19286 134866.199717: 321955 cycles: c0000000000b5e60 [unknown] ([unknown])
b31bc pSeries_lpar_hpte_invalidate (/boot/vmlinux)
76f10 flush_hash_page (/boot/vmlinux)
7ddec hpte_need_flush (/boot/vmlinux)
2d9f64 ptep_clear_flush (/boot/vmlinux)
2c24dc wp_page_copy (/boot/vmlinux)
2c5c44 do_wp_page (/boot/vmlinux)
2cabcc __handle_mm_fault (/boot/vmlinux)
2cbbe8 handle_mm_fault (/boot/vmlinux)
71074 do_page_fault (/boot/vmlinux)
1b078 handle_page_fault (/boot/vmlinux)
9958 _dl_map_object_from_fd (/lib/powerpc64le-linux-gnu/ld-2.24.so)
e70c _dl_map_object (/lib/powerpc64le-linux-gnu/ld-2.24.so)
18da4 openaux (/lib/powerpc64le-linux-gnu/ld-2.24.so)
1c068 _dl_catch_error (/lib/powerpc64le-linux-gnu/ld-2.24.so)
19430 _dl_map_object_deps (/lib/powerpc64le-linux-gnu/ld-2.24.so)
41dc dl_main (/lib/powerpc64le-linux-gnu/ld-2.24.so)
29954 _dl_sysdep_start (/lib/powerpc64le-linux-gnu/ld-2.24.so)
1be0 _dl_start_final (/lib/powerpc64le-linux-gnu/ld-2.24.so)
6080 _dl_start (/lib/powerpc64le-linux-gnu/ld-2.24.so)
1398 _start (/lib/powerpc64le-linux-gnu/ld-2.24.so)

... and with libdw:

bswap 19286 134866.199717: 321955 cycles: c0000000000b5e60 [unknown] ([unknown])
b31bc pSeries_lpar_hpte_invalidate (/boot/vmlinux)
76f10 flush_hash_page (/boot/vmlinux)
7ddec hpte_need_flush (/boot/vmlinux)
2d9f64 ptep_clear_flush (/boot/vmlinux)
2c24dc wp_page_copy (/boot/vmlinux)
2c5c44 do_wp_page (/boot/vmlinux)
2cabcc __handle_mm_fault (/boot/vmlinux)
2cbbe8 handle_mm_fault (/boot/vmlinux)
71074 do_page_fault (/boot/vmlinux)
1b078 handle_page_fault (/boot/vmlinux)

Ravi is OOO currently can will have more to say on this once he is back next week.



Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
tools/perf/Makefile.config | 2 +-
tools/perf/arch/powerpc/util/Build | 2 +
tools/perf/arch/powerpc/util/unwind-libdw.c | 73 +++++++++++++++++++++++++++++
3 files changed, 76 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/arch/powerpc/util/unwind-libdw.c

diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index f67ae83..342c57c 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -61,7 +61,7 @@ endif
# Disable it on all other architectures in case libdw unwind
# support is detected in system. Add supported architectures
# to the check.
-ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
+ifneq ($(ARCH),$(filter $(ARCH),x86 arm powerpc))
NO_LIBDW_DWARF_UNWIND := 1
endif
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 90ad64b..2e65953 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -5,4 +5,6 @@ libperf-y += perf_regs.o
libperf-$(CONFIG_DWARF) += dwarf-regs.o
libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
+
libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/arch/powerpc/util/unwind-libdw.c
new file mode 100644
index 0000000..c61e1d8
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/unwind-libdw.c
@@ -0,0 +1,73 @@
+#include <elfutils/libdwfl.h>
+#include "../../util/util.h"
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"

As an aside, we also need to include "event.h", without which there are a few compile errors.


- Naveen

+
+/* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */
+static const int special_regs[3][2] = {
+ { 65, PERF_REG_POWERPC_LINK },
+ { 101, PERF_REG_POWERPC_XER },
+ { 109, PERF_REG_POWERPC_CTR },
+};
+
+bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
+{
+ struct unwind_info *ui = arg;
+ struct regs_dump *user_regs = &ui->sample->user_regs;
+ Dwarf_Word dwarf_regs[32], dwarf_nip;
+ size_t i;
+
+#define REG(r) ({ \
+ Dwarf_Word val = 0; \
+ perf_reg_value(&val, user_regs, PERF_REG_POWERPC_##r); \
+ val; \
+})
+
+ dwarf_regs[0] = REG(R0);
+ dwarf_regs[1] = REG(R1);
+ dwarf_regs[2] = REG(R2);
+ dwarf_regs[3] = REG(R3);
+ dwarf_regs[4] = REG(R4);
+ dwarf_regs[5] = REG(R5);
+ dwarf_regs[6] = REG(R6);
+ dwarf_regs[7] = REG(R7);
+ dwarf_regs[8] = REG(R8);
+ dwarf_regs[9] = REG(R9);
+ dwarf_regs[10] = REG(R10);
+ dwarf_regs[11] = REG(R11);
+ dwarf_regs[12] = REG(R12);
+ dwarf_regs[13] = REG(R13);
+ dwarf_regs[14] = REG(R14);
+ dwarf_regs[15] = REG(R15);
+ dwarf_regs[16] = REG(R16);
+ dwarf_regs[17] = REG(R17);
+ dwarf_regs[18] = REG(R18);
+ dwarf_regs[19] = REG(R19);
+ dwarf_regs[20] = REG(R20);
+ dwarf_regs[21] = REG(R21);
+ dwarf_regs[22] = REG(R22);
+ dwarf_regs[23] = REG(R23);
+ dwarf_regs[24] = REG(R24);
+ dwarf_regs[25] = REG(R25);
+ dwarf_regs[26] = REG(R26);
+ dwarf_regs[27] = REG(R27);
+ dwarf_regs[28] = REG(R28);
+ dwarf_regs[29] = REG(R29);
+ dwarf_regs[30] = REG(R30);
+ dwarf_regs[31] = REG(R31);
+ if (!dwfl_thread_state_registers(thread, 0, 32, dwarf_regs))
+ return false;
+
+ dwarf_nip = REG(NIP);
+ dwfl_thread_state_register_pc(thread, dwarf_nip);
+ for (i = 0; i < ARRAY_SIZE(special_regs); i++) {
+ Dwarf_Word val = 0;
+ perf_reg_value(&val, user_regs, special_regs[i][1]);
+ if (!dwfl_thread_state_registers(thread,
+ special_regs[i][0], 1,
+ &val))
+ return false;
+ }
+
+ return true;
+}
--
1.8.3.1