Skip to content

Commit f704ef4

Browse files
heicarstMartin Schwidefsky
authored andcommitted
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>
1 parent c33eff6 commit f704ef4

File tree

5 files changed

+113
-1
lines changed

5 files changed

+113
-1
lines changed

tools/perf/Makefile.config

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ ifeq ($(SRCARCH),arm64)
5353
LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
5454
endif
5555

56+
ifeq ($(ARCH),s390)
57+
NO_PERF_REGS := 0
58+
endif
59+
5660
ifeq ($(NO_PERF_REGS),0)
5761
$(call detected,CONFIG_PERF_REGS)
5862
endif
@@ -61,7 +65,7 @@ endif
6165
# Disable it on all other architectures in case libdw unwind
6266
# support is detected in system. Add supported architectures
6367
# to the check.
64-
ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc))
68+
ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc s390))
6569
NO_LIBDW_DWARF_UNWIND := 1
6670
endif
6771

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */

tools/perf/arch/s390/util/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ libperf-y += header.o
22
libperf-y += kvm-stat.o
33

44
libperf-$(CONFIG_DWARF) += dwarf-regs.o
5+
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
56

67
libperf-y += machine.o
78

tools/perf/arch/s390/util/dwarf-regs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@ static const char *gpr_names[NUM_GPRS] = {
1919

2020
const char *get_arch_regstr(unsigned int n)
2121
{
22+
if (n == 64)
23+
return "mask";
24+
if (n == 65)
25+
return "pc";
2226
return (n >= NUM_GPRS) ? NULL : gpr_names[n];
2327
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)