mirror of
https://github.com/torvalds/linux.git
synced 2026-11-10 17:11:02 +01:00
perf riscv: Add perf_regs_load and enable the dwarf unwind test
riscv has no arch level perf test: tests/builtin-test.c only picks up arch_tests[] for x86, arm64 and powerpc64, tests/Build only builds the generic dwarf unwind test driver for x86, arm, arm64 and powerpc, and arch/riscv/tests/ did not exist. "Test dwarf unwind" was therefore never registered on riscv, even though DWARF is the only reliable way to walk a riscv user stack -- the arch callchain code walks frame pointers only -- and both unwinders already support riscv, elfutils libdw generically and libunwind through util/libunwind-arch/libunwind-riscv.c. Add perf_regs_load() and the arch unwind sample helper modelled on the arm64 ones, and wire riscv into the two gates. The x1..x31 slots of enum perf_event_riscv_regs match the hardware registers one to one, and PERF_REG_RISCV_PC is filled with ra so that unwinding starts at the caller. Reviewed-by: Ian Rogers <irogers@google.com> Signed-off-by: Chen Pei <cp0613@linux.alibaba.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
1622c9ae39
commit
0b26b346a8
|
|
@ -1 +1,2 @@
|
|||
perf-util-y += util/
|
||||
perf-test-y += tests/
|
||||
|
|
|
|||
9
tools/perf/arch/riscv/include/arch-tests.h
Normal file
9
tools/perf/arch/riscv/include/arch-tests.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef ARCH_TESTS_H
|
||||
#define ARCH_TESTS_H
|
||||
|
||||
struct test_suite;
|
||||
|
||||
extern struct test_suite *arch_tests[];
|
||||
|
||||
#endif
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
#include <linux/types.h>
|
||||
#include "../../../../arch/riscv/include/uapi/asm/perf_regs.h"
|
||||
|
||||
void perf_regs_load(u64 *regs);
|
||||
|
||||
#define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
|
||||
#define PERF_REGS_MAX PERF_REG_RISCV_MAX
|
||||
|
||||
|
|
|
|||
4
tools/perf/arch/riscv/tests/Build
Normal file
4
tools/perf/arch/riscv/tests/Build
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
perf-test-y += regs_load.o
|
||||
perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
|
||||
perf-test-y += arch-tests.o
|
||||
10
tools/perf/arch/riscv/tests/arch-tests.c
Normal file
10
tools/perf/arch/riscv/tests/arch-tests.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "tests/tests.h"
|
||||
#include "arch-tests.h"
|
||||
|
||||
struct test_suite *arch_tests[] = {
|
||||
#ifdef HAVE_DWARF_UNWIND_SUPPORT
|
||||
&suite__dwarf_unwind,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
64
tools/perf/arch/riscv/tests/dwarf-unwind.c
Normal file
64
tools/perf/arch/riscv/tests/dwarf-unwind.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <string.h>
|
||||
#include "perf_regs.h"
|
||||
#include "thread.h"
|
||||
#include "map.h"
|
||||
#include "maps.h"
|
||||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
|
||||
#define STACK_SIZE 8192
|
||||
|
||||
static int sample_ustack(struct perf_sample *sample,
|
||||
struct thread *thread, u64 *regs)
|
||||
{
|
||||
struct stack_dump *stack = &sample->user_stack;
|
||||
struct map *map;
|
||||
unsigned long sp;
|
||||
u64 stack_size, *buf;
|
||||
|
||||
buf = malloc(STACK_SIZE);
|
||||
if (!buf) {
|
||||
pr_debug("failed to allocate sample uregs data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp = (unsigned long) regs[PERF_REG_RISCV_SP];
|
||||
|
||||
map = maps__find(thread__maps(thread), (u64)sp);
|
||||
if (!map) {
|
||||
pr_debug("failed to get stack map\n");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
stack_size = map__end(map) - sp;
|
||||
map__put(map);
|
||||
stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
|
||||
|
||||
memcpy(buf, (void *) sp, stack_size);
|
||||
stack->data = (char *) buf;
|
||||
stack->size = stack_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test__arch_unwind_sample(struct perf_sample *sample,
|
||||
struct thread *thread)
|
||||
{
|
||||
struct regs_dump *regs = perf_sample__user_regs(sample);
|
||||
u64 *buf;
|
||||
|
||||
buf = calloc(PERF_REGS_MAX, sizeof(u64));
|
||||
if (!buf) {
|
||||
pr_debug("failed to allocate sample uregs data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
perf_regs_load(buf);
|
||||
regs->abi = PERF_SAMPLE_REGS_ABI;
|
||||
regs->regs = buf;
|
||||
regs->mask = PERF_REGS_MASK;
|
||||
|
||||
return sample_ustack(sample, thread, buf);
|
||||
}
|
||||
58
tools/perf/arch/riscv/tests/regs_load.S
Normal file
58
tools/perf/arch/riscv/tests/regs_load.S
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* Fill the u64 array 'regs' at the slots of enum perf_event_riscv_regs:
|
||||
* x1..x31 map one-to-one onto PERF_REG_RISCV_RA..PERF_REG_RISCV_T6, and the
|
||||
* stride stays 8 bytes on RV32 because the slots are u64 and the caller
|
||||
* zeroes them.
|
||||
*
|
||||
* PERF_REG_RISCV_PC is filled with ra, the return address of the call to
|
||||
* this function, so that unwinding starts at the caller rather than here.
|
||||
*/
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
#define REG_S sd
|
||||
#else
|
||||
#define REG_S sw
|
||||
#endif
|
||||
|
||||
#define STR_REG(r) REG_S x##r, 8 * r(a0)
|
||||
|
||||
.text
|
||||
.type perf_regs_load,%function
|
||||
SYM_FUNC_START(perf_regs_load)
|
||||
STR_REG(1)
|
||||
STR_REG(2)
|
||||
STR_REG(3)
|
||||
STR_REG(4)
|
||||
STR_REG(5)
|
||||
STR_REG(6)
|
||||
STR_REG(7)
|
||||
STR_REG(8)
|
||||
STR_REG(9)
|
||||
STR_REG(10)
|
||||
STR_REG(11)
|
||||
STR_REG(12)
|
||||
STR_REG(13)
|
||||
STR_REG(14)
|
||||
STR_REG(15)
|
||||
STR_REG(16)
|
||||
STR_REG(17)
|
||||
STR_REG(18)
|
||||
STR_REG(19)
|
||||
STR_REG(20)
|
||||
STR_REG(21)
|
||||
STR_REG(22)
|
||||
STR_REG(23)
|
||||
STR_REG(24)
|
||||
STR_REG(25)
|
||||
STR_REG(26)
|
||||
STR_REG(27)
|
||||
STR_REG(28)
|
||||
STR_REG(29)
|
||||
STR_REG(30)
|
||||
STR_REG(31)
|
||||
REG_S ra, 0(a0)
|
||||
ret
|
||||
SYM_FUNC_END(perf_regs_load)
|
||||
|
|
@ -73,7 +73,7 @@ perf-test-y += tool_pmu.o
|
|||
perf-test-y += subcmd-help.o
|
||||
perf-test-y += kallsyms-split.o
|
||||
|
||||
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc))
|
||||
ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc riscv))
|
||||
perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
|
||||
endif
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ static const char *workload_control;
|
|||
* dependent on the initialization, as such GCC with LTO complains of
|
||||
* conflicting definitions with a weak symbol.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
|
||||
defined(__powerpc64__) || defined(__riscv)
|
||||
extern struct test_suite *arch_tests[];
|
||||
#else
|
||||
static struct test_suite *arch_tests[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user