Skip to content

Commit

Permalink
s390/perf: add support for perf_regs and libdw
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
heicarst authored and Martin Schwidefsky committed Nov 16, 2017
1 parent c33eff6 commit f704ef4
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 1 deletion.
6 changes: 5 additions & 1 deletion tools/perf/Makefile.config
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
63 changes: 63 additions & 0 deletions tools/perf/arch/s390/include/perf_regs.h
Original file line number Diff line number Diff line change
@@ -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 */
1 change: 1 addition & 0 deletions tools/perf/arch/s390/util/Build
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions tools/perf/arch/s390/util/dwarf-regs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
40 changes: 40 additions & 0 deletions tools/perf/arch/s390/util/unwind-libdw.c
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit f704ef4

Please sign in to comment.