]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
s390/perf: add support for perf_regs and libdw
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Tue, 19 Jan 2016 10:23:38 +0000 (11:23 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 16 Nov 2017 14:06:12 +0000 (15:06 +0100)
With support for perf_regs and libdw, you can record and report
call graphs for user space programs. Simply invoke perf with
the --call-graph=dwarf command line option.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
[brueckner: added dwfl_thread_state_register_pc() call]
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-and-tested-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
tools/perf/Makefile.config
tools/perf/arch/s390/include/perf_regs.h [new file with mode: 0644]
tools/perf/arch/s390/util/Build
tools/perf/arch/s390/util/dwarf-regs.c
tools/perf/arch/s390/util/unwind-libdw.c [new file with mode: 0644]

index 63f534a0902f29e5682570d70751ccb6035d13bb..ed65e82f034efe0e76cef718fdb8a9bd07511edb 100644 (file)
@@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64)
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
 
+ifeq ($(ARCH),s390)
+  NO_PERF_REGS := 0
+endif
+
 ifeq ($(NO_PERF_REGS),0)
   $(call detected,CONFIG_PERF_REGS)
 endif
@@ -61,7 +65,7 @@ endif
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
 # to the check.
-ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h
new file mode 100644 (file)
index 0000000..ac4b8c8
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include <../../../../arch/s390/include/uapi/asm/perf_regs.h>
+
+void perf_regs_load(u64 *regs);
+
+#define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_S390_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
+
+#define PERF_REG_IP PERF_REG_S390_PC
+#define PERF_REG_SP PERF_REG_S390_R15
+
+static inline const char *perf_reg_name(int id)
+{
+       switch (id) {
+       case PERF_REG_S390_R0:
+               return "R0";
+       case PERF_REG_S390_R1:
+               return "R1";
+       case PERF_REG_S390_R2:
+               return "R2";
+       case PERF_REG_S390_R3:
+               return "R3";
+       case PERF_REG_S390_R4:
+               return "R4";
+       case PERF_REG_S390_R5:
+               return "R5";
+       case PERF_REG_S390_R6:
+               return "R6";
+       case PERF_REG_S390_R7:
+               return "R7";
+       case PERF_REG_S390_R8:
+               return "R8";
+       case PERF_REG_S390_R9:
+               return "R9";
+       case PERF_REG_S390_R10:
+               return "R10";
+       case PERF_REG_S390_R11:
+               return "R11";
+       case PERF_REG_S390_R12:
+               return "R12";
+       case PERF_REG_S390_R13:
+               return "R13";
+       case PERF_REG_S390_R14:
+               return "R14";
+       case PERF_REG_S390_R15:
+               return "R15";
+       case PERF_REG_S390_MASK:
+               return "MASK";
+       case PERF_REG_S390_PC:
+               return "PC";
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
index 397084382b235113da23b798889d2d056d8c88b2..4a233683c6848115f8619253aaa1109a92522f54 100644 (file)
@@ -2,6 +2,7 @@ libperf-y += header.o
 libperf-y += kvm-stat.o
 
 libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 
 libperf-y += machine.o
 
index 0dff5b2ed1e5093d3d8df16210061415630a1f95..0cd7cba5d6ee384d4db935650dc80b85ad854077 100644 (file)
@@ -19,5 +19,9 @@ static const char *gpr_names[NUM_GPRS] = {
 
 const char *get_arch_regstr(unsigned int n)
 {
+       if (n == 64)
+               return "mask";
+       if (n == 65)
+               return "pc";
        return (n >= NUM_GPRS) ? NULL : gpr_names[n];
 }
diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c
new file mode 100644 (file)
index 0000000..281bbb8
--- /dev/null
@@ -0,0 +1,40 @@
+#include <elfutils/libdwfl.h>
+#include "../../util/unwind-libdw.h"
+#include "../../util/perf_regs.h"
+#include "../../util/event.h"
+
+
+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[PERF_REG_S390_MAX];
+
+#define REG(r) ({                                              \
+       Dwarf_Word val = 0;                                     \
+       perf_reg_value(&val, user_regs, PERF_REG_S390_##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(MASK);
+       dwarf_regs[17] = REG(PC);
+
+       dwfl_thread_state_register_pc(thread, dwarf_regs[17]);
+       return dwfl_thread_state_registers(thread, 0, 16, dwarf_regs);
+}