diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2016-01-19 05:23:38 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2017-11-16 09:06:12 -0500 |
commit | f704ef44602fbf403e6722c7ed13f62d17e8cb20 (patch) | |
tree | 5addd8e06c1323a71b3e9caffa2d610d63a789ff /tools | |
parent | c33eff600584ed493adfb42e3f130a6335f97750 (diff) |
s390/perf: add support for perf_regs and libdw
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>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile.config | 6 | ||||
-rw-r--r-- | tools/perf/arch/s390/include/perf_regs.h | 63 | ||||
-rw-r--r-- | tools/perf/arch/s390/util/Build | 1 | ||||
-rw-r--r-- | tools/perf/arch/s390/util/dwarf-regs.c | 4 | ||||
-rw-r--r-- | tools/perf/arch/s390/util/unwind-libdw.c | 40 |
5 files changed, 113 insertions, 1 deletions
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 63f534a0902f..ed65e82f034e 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64) | |||
53 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 | 53 | LIBUNWIND_LIBS = -lunwind -lunwind-aarch64 |
54 | endif | 54 | endif |
55 | 55 | ||
56 | ifeq ($(ARCH),s390) | ||
57 | NO_PERF_REGS := 0 | ||
58 | endif | ||
59 | |||
56 | ifeq ($(NO_PERF_REGS),0) | 60 | ifeq ($(NO_PERF_REGS),0) |
57 | $(call detected,CONFIG_PERF_REGS) | 61 | $(call detected,CONFIG_PERF_REGS) |
58 | endif | 62 | endif |
@@ -61,7 +65,7 @@ endif | |||
61 | # Disable it on all other architectures in case libdw unwind | 65 | # Disable it on all other architectures in case libdw unwind |
62 | # support is detected in system. Add supported architectures | 66 | # support is detected in system. Add supported architectures |
63 | # to the check. | 67 | # to the check. |
64 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) | 68 | ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390)) |
65 | NO_LIBDW_DWARF_UNWIND := 1 | 69 | NO_LIBDW_DWARF_UNWIND := 1 |
66 | endif | 70 | endif |
67 | 71 | ||
diff --git a/tools/perf/arch/s390/include/perf_regs.h b/tools/perf/arch/s390/include/perf_regs.h new file mode 100644 index 000000000000..ac4b8c8c49e2 --- /dev/null +++ b/tools/perf/arch/s390/include/perf_regs.h | |||
@@ -0,0 +1,63 @@ | |||
1 | #ifndef ARCH_PERF_REGS_H | ||
2 | #define ARCH_PERF_REGS_H | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <../../../../arch/s390/include/uapi/asm/perf_regs.h> | ||
7 | |||
8 | void perf_regs_load(u64 *regs); | ||
9 | |||
10 | #define PERF_REGS_MASK ((1ULL << PERF_REG_S390_MAX) - 1) | ||
11 | #define PERF_REGS_MAX PERF_REG_S390_MAX | ||
12 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64 | ||
13 | |||
14 | #define PERF_REG_IP PERF_REG_S390_PC | ||
15 | #define PERF_REG_SP PERF_REG_S390_R15 | ||
16 | |||
17 | static inline const char *perf_reg_name(int id) | ||
18 | { | ||
19 | switch (id) { | ||
20 | case PERF_REG_S390_R0: | ||
21 | return "R0"; | ||
22 | case PERF_REG_S390_R1: | ||
23 | return "R1"; | ||
24 | case PERF_REG_S390_R2: | ||
25 | return "R2"; | ||
26 | case PERF_REG_S390_R3: | ||
27 | return "R3"; | ||
28 | case PERF_REG_S390_R4: | ||
29 | return "R4"; | ||
30 | case PERF_REG_S390_R5: | ||
31 | return "R5"; | ||
32 | case PERF_REG_S390_R6: | ||
33 | return "R6"; | ||
34 | case PERF_REG_S390_R7: | ||
35 | return "R7"; | ||
36 | case PERF_REG_S390_R8: | ||
37 | return "R8"; | ||
38 | case PERF_REG_S390_R9: | ||
39 | return "R9"; | ||
40 | case PERF_REG_S390_R10: | ||
41 | return "R10"; | ||
42 | case PERF_REG_S390_R11: | ||
43 | return "R11"; | ||
44 | case PERF_REG_S390_R12: | ||
45 | return "R12"; | ||
46 | case PERF_REG_S390_R13: | ||
47 | return "R13"; | ||
48 | case PERF_REG_S390_R14: | ||
49 | return "R14"; | ||
50 | case PERF_REG_S390_R15: | ||
51 | return "R15"; | ||
52 | case PERF_REG_S390_MASK: | ||
53 | return "MASK"; | ||
54 | case PERF_REG_S390_PC: | ||
55 | return "PC"; | ||
56 | default: | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | #endif /* ARCH_PERF_REGS_H */ | ||
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index 397084382b23..4a233683c684 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build | |||
@@ -2,6 +2,7 @@ libperf-y += header.o | |||
2 | libperf-y += kvm-stat.o | 2 | libperf-y += kvm-stat.o |
3 | 3 | ||
4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 4 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
5 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | ||
5 | 6 | ||
6 | libperf-y += machine.o | 7 | libperf-y += machine.o |
7 | 8 | ||
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c index 0dff5b2ed1e5..0cd7cba5d6ee 100644 --- a/tools/perf/arch/s390/util/dwarf-regs.c +++ b/tools/perf/arch/s390/util/dwarf-regs.c | |||
@@ -19,5 +19,9 @@ static const char *gpr_names[NUM_GPRS] = { | |||
19 | 19 | ||
20 | const char *get_arch_regstr(unsigned int n) | 20 | const char *get_arch_regstr(unsigned int n) |
21 | { | 21 | { |
22 | if (n == 64) | ||
23 | return "mask"; | ||
24 | if (n == 65) | ||
25 | return "pc"; | ||
22 | return (n >= NUM_GPRS) ? NULL : gpr_names[n]; | 26 | return (n >= NUM_GPRS) ? NULL : gpr_names[n]; |
23 | } | 27 | } |
diff --git a/tools/perf/arch/s390/util/unwind-libdw.c b/tools/perf/arch/s390/util/unwind-libdw.c new file mode 100644 index 000000000000..281bbb82402a --- /dev/null +++ b/tools/perf/arch/s390/util/unwind-libdw.c | |||
@@ -0,0 +1,40 @@ | |||
1 | #include <elfutils/libdwfl.h> | ||
2 | #include "../../util/unwind-libdw.h" | ||
3 | #include "../../util/perf_regs.h" | ||
4 | #include "../../util/event.h" | ||
5 | |||
6 | |||
7 | bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) | ||
8 | { | ||
9 | struct unwind_info *ui = arg; | ||
10 | struct regs_dump *user_regs = &ui->sample->user_regs; | ||
11 | Dwarf_Word dwarf_regs[PERF_REG_S390_MAX]; | ||
12 | |||
13 | #define REG(r) ({ \ | ||
14 | Dwarf_Word val = 0; \ | ||
15 | perf_reg_value(&val, user_regs, PERF_REG_S390_##r); \ | ||
16 | val; \ | ||
17 | }) | ||
18 | |||
19 | dwarf_regs[0] = REG(R0); | ||
20 | dwarf_regs[1] = REG(R1); | ||
21 | dwarf_regs[2] = REG(R2); | ||
22 | dwarf_regs[3] = REG(R3); | ||
23 | dwarf_regs[4] = REG(R4); | ||
24 | dwarf_regs[5] = REG(R5); | ||
25 | dwarf_regs[6] = REG(R6); | ||
26 | dwarf_regs[7] = REG(R7); | ||
27 | dwarf_regs[8] = REG(R8); | ||
28 | dwarf_regs[9] = REG(R9); | ||
29 | dwarf_regs[10] = REG(R10); | ||
30 | dwarf_regs[11] = REG(R11); | ||
31 | dwarf_regs[12] = REG(R12); | ||
32 | dwarf_regs[13] = REG(R13); | ||
33 | dwarf_regs[14] = REG(R14); | ||
34 | dwarf_regs[15] = REG(R15); | ||
35 | dwarf_regs[16] = REG(MASK); | ||
36 | dwarf_regs[17] = REG(PC); | ||
37 | |||
38 | dwfl_thread_state_register_pc(thread, dwarf_regs[17]); | ||
39 | return dwfl_thread_state_registers(thread, 0, 16, dwarf_regs); | ||
40 | } | ||