linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] riscv: Add perf callchain support
@ 2019-04-11  7:53 Mao Han
  2019-04-11  7:53 ` [PATCH 1/3] " Mao Han
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Mao Han @ 2019-04-11  7:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mao Han, Palmer Dabbelt, Guo Ren

Hi,

This patch set add perf callchain(FP/DWARF) support for RISC-V.
It comes from the csky version callchain support with some
slight modifications. The patchset base on Linux 5.1-rc4:
15ade5d2e7775667cf191cf2f94327a4889f8b9d

CC: Palmer Dabbelt <palmer@sifive.com>
CC: Guo Ren <guoren@kernel.org>

Mao Han (3):
  riscv: Add perf callchain support
  riscv: Add support for perf registers sampling
  riscv: Add support for libdw

 arch/riscv/Kconfig                            |   2 +
 arch/riscv/include/uapi/asm/perf_regs.h       |  42 +++++++++
 arch/riscv/kernel/Makefile                    |   4 +-
 arch/riscv/kernel/perf_callchain.c            | 122 ++++++++++++++++++++++++++
 arch/riscv/kernel/perf_regs.c                 |  44 ++++++++++
 tools/arch/riscv/include/uapi/asm/perf_regs.h |  42 +++++++++
 tools/perf/Makefile.config                    |   6 +-
 tools/perf/arch/riscv/Build                   |   1 +
 tools/perf/arch/riscv/Makefile                |   3 +
 tools/perf/arch/riscv/include/perf_regs.h     |  96 ++++++++++++++++++++
 tools/perf/arch/riscv/util/Build              |   2 +
 tools/perf/arch/riscv/util/dwarf-regs.c       |  70 +++++++++++++++
 tools/perf/arch/riscv/util/unwind-libdw.c     |  57 ++++++++++++
 13 files changed, 489 insertions(+), 2 deletions(-)
 create mode 100644 arch/riscv/include/uapi/asm/perf_regs.h
 create mode 100644 arch/riscv/kernel/perf_callchain.c
 create mode 100644 arch/riscv/kernel/perf_regs.c
 create mode 100644 tools/arch/riscv/include/uapi/asm/perf_regs.h
 create mode 100644 tools/perf/arch/riscv/Build
 create mode 100644 tools/perf/arch/riscv/Makefile
 create mode 100644 tools/perf/arch/riscv/include/perf_regs.h
 create mode 100644 tools/perf/arch/riscv/util/Build
 create mode 100644 tools/perf/arch/riscv/util/dwarf-regs.c
 create mode 100644 tools/perf/arch/riscv/util/unwind-libdw.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/3] riscv: Add perf callchain support
  2019-04-11  7:53 [PATCH 0/3] riscv: Add perf callchain support Mao Han
@ 2019-04-11  7:53 ` Mao Han
  2019-04-11 14:24   ` Christoph Hellwig
  2019-04-25 21:11   ` Palmer Dabbelt
  2019-04-11  7:53 ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 14+ messages in thread
From: Mao Han @ 2019-04-11  7:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mao Han, Palmer Dabbelt

This patch add support for perf callchain sampling on riscv platform.
The return address of leaf function is retrieved from pt_regs as
it is not saved in the outmost frame.

Signed-off-by: Mao Han <han_mao@c-sky.com>

CC: Palmer Dabbelt <palmer@sifive.com>
---
 arch/riscv/kernel/Makefile         |   3 +-
 arch/riscv/kernel/perf_callchain.c | 122 +++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/kernel/perf_callchain.c

diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 5985681..dd2ba44 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_MODULE_SECTIONS)	+= module-sections.o
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= mcount-dyn.o
 
-obj-$(CONFIG_PERF_EVENTS)      += perf_event.o
+obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o
+obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
 
 clean:
diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
new file mode 100644
index 0000000..eb3ddbb
--- /dev/null
+++ b/arch/riscv/kernel/perf_callchain.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/perf_event.h>
+#include <linux/uaccess.h>
+
+/* Kernel callchain */
+struct stackframe {
+	unsigned long fp;
+	unsigned long ra;
+};
+
+static int unwind_frame_kernel(struct stackframe *frame)
+{
+	int graph = 0;
+
+	/* 0x3 means misalignment */
+	if (!kstack_end((void *)frame->fp) &&
+	    !((unsigned long)frame->fp & 0x3) &&
+	    ((unsigned long)frame->fp >= TASK_SIZE)) {
+		frame->ra = ((struct stackframe *)frame->fp - 1)->ra;
+		frame->fp = ((struct stackframe *)frame->fp - 1)->fp;
+		/* make sure CONFIG_FUNCTION_GRAPH_TRACER is turned on */
+		if (__kernel_text_address(frame->ra))
+			frame->ra = ftrace_graph_ret_addr(NULL, &graph,
+							frame->ra, NULL);
+		return 0;
+	} else {
+		return -EPERM;
+	}
+}
+
+static void notrace walk_stackframe(struct stackframe *fr,
+			struct perf_callchain_entry_ctx *entry)
+{
+	while (1) {
+		int ret;
+
+		perf_callchain_store(entry, fr->ra);
+
+		ret = unwind_frame_kernel(fr);
+		if (ret < 0)
+			break;
+	}
+}
+
+/*
+ * Get the return address for a single stackframe and return a pointer to the
+ * next frame tail.
+ */
+static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
+			unsigned long fp, unsigned long reg_ra)
+{
+	struct stackframe buftail;
+	unsigned long ra = 0;
+	unsigned long *user_frame_tail = (unsigned long *)(fp - sizeof(struct stackframe));
+
+	/* Check accessibility of one struct frame_tail beyond */
+	if (!access_ok(user_frame_tail, sizeof(buftail)))
+		return 0;
+	if (__copy_from_user_inatomic(&buftail, user_frame_tail,
+				      sizeof(buftail)))
+		return 0;
+
+	if (reg_ra != 0)
+		ra = reg_ra;
+	else
+		ra = buftail.ra;
+
+	fp = buftail.fp;
+	perf_callchain_store(entry, ra);
+
+	return fp;
+}
+
+/*
+ * This will be called when the target is in user mode
+ * This function will only be called when we use
+ * "PERF_SAMPLE_CALLCHAIN" in
+ * kernel/events/core.c:perf_prepare_sample()
+ *
+ * How to trigger perf_callchain_[user/kernel] :
+ * $ perf record -e cpu-clock --call-graph fp ./program
+ * $ perf report --call-graph
+ *
+ * On RISC-V platform, the program being sampled and the C library
+ * need to be compiled with * -mbacktrace, otherwise the user
+ * stack will not contain function frame.
+ */
+void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
+			 struct pt_regs *regs)
+{
+	unsigned long fp = 0;
+
+	/* RISC-V does not support virtualization. */
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+		return;
+
+	fp = regs->s0;
+	perf_callchain_store(entry, regs->sepc);
+
+	fp = user_backtrace(entry, fp, regs->ra);
+	while ((entry->nr < entry->max_stack) &&
+		fp && !((unsigned long)fp & 0x3))
+		fp = user_backtrace(entry, fp, 0);
+}
+
+void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
+			   struct pt_regs *regs)
+{
+	struct stackframe fr;
+
+	/* RISC-V does not support virtualization. */
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+		pr_warn("RISC-V does not support perf in guest mode!");
+		return;
+	}
+
+	fr.fp = regs->s0;
+	fr.ra = regs->ra;
+	walk_stackframe(&fr, entry);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/3] riscv: Add support for perf registers sampling
  2019-04-11  7:53 [PATCH 0/3] riscv: Add perf callchain support Mao Han
  2019-04-11  7:53 ` [PATCH 1/3] " Mao Han
@ 2019-04-11  7:53 ` Mao Han
  2019-04-25 21:11   ` Palmer Dabbelt
  2019-04-11  7:53 ` [PATCH 3/3] riscv: Add support for libdw Mao Han
  2019-04-11 14:14 ` [PATCH 0/3] riscv: Add perf callchain support Christoph Hellwig
  3 siblings, 1 reply; 14+ messages in thread
From: Mao Han @ 2019-04-11  7:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mao Han, Palmer Dabbelt

This patch implements the perf registers sampling and validation API
for riscv arch. The valid registers and their register ID are defined in
perf_regs.h. Perf tool can backtrace in userspace with unwind library
and the registers/user stack dump support.

Signed-off-by: Mao Han <han_mao@c-sky.com>

CC: Palmer Dabbelt <palmer@sifive.com>
---
 arch/riscv/Kconfig                      |  2 ++
 arch/riscv/include/uapi/asm/perf_regs.h | 42 +++++++++++++++++++++++++++++++
 arch/riscv/kernel/Makefile              |  1 +
 arch/riscv/kernel/perf_regs.c           | 44 +++++++++++++++++++++++++++++++++
 4 files changed, 89 insertions(+)
 create mode 100644 arch/riscv/include/uapi/asm/perf_regs.h
 create mode 100644 arch/riscv/kernel/perf_regs.c

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index eb56c82..effd157 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -33,6 +33,8 @@ config RISCV
 	select HAVE_DMA_CONTIGUOUS
 	select HAVE_FUTEX_CMPXCHG if FUTEX
 	select HAVE_PERF_EVENTS
+	select HAVE_PERF_REGS
+	select HAVE_PERF_USER_STACK_DUMP
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_DOMAIN
 	select RISCV_ISA_A if SMP
diff --git a/arch/riscv/include/uapi/asm/perf_regs.h b/arch/riscv/include/uapi/asm/perf_regs.h
new file mode 100644
index 0000000..ce48987
--- /dev/null
+++ b/arch/riscv/include/uapi/asm/perf_regs.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef _ASM_RISCV_PERF_REGS_H
+#define _ASM_RISCV_PERF_REGS_H
+
+enum perf_event_riscv_regs {
+	PERF_REG_RISCV_PC,
+	PERF_REG_RISCV_RA,
+	PERF_REG_RISCV_SP,
+	PERF_REG_RISCV_GP,
+	PERF_REG_RISCV_TP,
+	PERF_REG_RISCV_T0,
+	PERF_REG_RISCV_T1,
+	PERF_REG_RISCV_T2,
+	PERF_REG_RISCV_S0,
+	PERF_REG_RISCV_S1,
+	PERF_REG_RISCV_A0,
+	PERF_REG_RISCV_A1,
+	PERF_REG_RISCV_A2,
+	PERF_REG_RISCV_A3,
+	PERF_REG_RISCV_A4,
+	PERF_REG_RISCV_A5,
+	PERF_REG_RISCV_A6,
+	PERF_REG_RISCV_A7,
+	PERF_REG_RISCV_S2,
+	PERF_REG_RISCV_S3,
+	PERF_REG_RISCV_S4,
+	PERF_REG_RISCV_S5,
+	PERF_REG_RISCV_S6,
+	PERF_REG_RISCV_S7,
+	PERF_REG_RISCV_S8,
+	PERF_REG_RISCV_S9,
+	PERF_REG_RISCV_S10,
+	PERF_REG_RISCV_S11,
+	PERF_REG_RISCV_T3,
+	PERF_REG_RISCV_T4,
+	PERF_REG_RISCV_T5,
+	PERF_REG_RISCV_T6,
+	PERF_REG_RISCV_MAX,
+};
+#endif /* _ASM_RISCV_PERF_REGS_H */
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index dd2ba44..024badc 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -39,5 +39,6 @@ obj-$(CONFIG_DYNAMIC_FTRACE)	+= mcount-dyn.o
 
 obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
+obj-$(CONFIG_HAVE_PERF_REGS)	+= perf_regs.o
 
 clean:
diff --git a/arch/riscv/kernel/perf_regs.c b/arch/riscv/kernel/perf_regs.c
new file mode 100644
index 0000000..03d7ac3
--- /dev/null
+++ b/arch/riscv/kernel/perf_regs.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/bug.h>
+#include <asm/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+	if (WARN_ON_ONCE((u32)idx >= PERF_REG_RISCV_MAX))
+		return 0;
+
+	return ((long *)regs)[idx];
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_RISCV_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+	if (!mask || mask & REG_RESERVED)
+		return -EINVAL;
+
+	return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+#if __riscv_xlen == 64
+	return PERF_SAMPLE_REGS_ABI_64;
+#else
+	return PERF_SAMPLE_REGS_ABI_32;
+#endif
+}
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+			struct pt_regs *regs,
+			struct pt_regs *regs_user_copy)
+{
+	regs_user->regs = task_pt_regs(current);
+	regs_user->abi = perf_reg_abi(current);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/3] riscv: Add support for libdw
  2019-04-11  7:53 [PATCH 0/3] riscv: Add perf callchain support Mao Han
  2019-04-11  7:53 ` [PATCH 1/3] " Mao Han
  2019-04-11  7:53 ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
@ 2019-04-11  7:53 ` Mao Han
  2019-04-25 21:11   ` Palmer Dabbelt
  2019-04-11 14:14 ` [PATCH 0/3] riscv: Add perf callchain support Christoph Hellwig
  3 siblings, 1 reply; 14+ messages in thread
From: Mao Han @ 2019-04-11  7:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mao Han, Palmer Dabbelt

This patch add support for DWARF register mappings and libdw registers
initialization, which is used by perf callchain analyzing when
--call-graph=dwarf is given.

Signed-off-by: Mao Han <han_mao@c-sky.com>

CC: Palmer Dabbelt <palmer@sifive.com>
---
 tools/arch/riscv/include/uapi/asm/perf_regs.h | 42 ++++++++++++
 tools/perf/Makefile.config                    |  6 +-
 tools/perf/arch/riscv/Build                   |  1 +
 tools/perf/arch/riscv/Makefile                |  3 +
 tools/perf/arch/riscv/include/perf_regs.h     | 96 +++++++++++++++++++++++++++
 tools/perf/arch/riscv/util/Build              |  2 +
 tools/perf/arch/riscv/util/dwarf-regs.c       | 70 +++++++++++++++++++
 tools/perf/arch/riscv/util/unwind-libdw.c     | 57 ++++++++++++++++
 8 files changed, 276 insertions(+), 1 deletion(-)
 create mode 100644 tools/arch/riscv/include/uapi/asm/perf_regs.h
 create mode 100644 tools/perf/arch/riscv/Build
 create mode 100644 tools/perf/arch/riscv/Makefile
 create mode 100644 tools/perf/arch/riscv/include/perf_regs.h
 create mode 100644 tools/perf/arch/riscv/util/Build
 create mode 100644 tools/perf/arch/riscv/util/dwarf-regs.c
 create mode 100644 tools/perf/arch/riscv/util/unwind-libdw.c

diff --git a/tools/arch/riscv/include/uapi/asm/perf_regs.h b/tools/arch/riscv/include/uapi/asm/perf_regs.h
new file mode 100644
index 0000000..ce48987
--- /dev/null
+++ b/tools/arch/riscv/include/uapi/asm/perf_regs.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef _ASM_RISCV_PERF_REGS_H
+#define _ASM_RISCV_PERF_REGS_H
+
+enum perf_event_riscv_regs {
+	PERF_REG_RISCV_PC,
+	PERF_REG_RISCV_RA,
+	PERF_REG_RISCV_SP,
+	PERF_REG_RISCV_GP,
+	PERF_REG_RISCV_TP,
+	PERF_REG_RISCV_T0,
+	PERF_REG_RISCV_T1,
+	PERF_REG_RISCV_T2,
+	PERF_REG_RISCV_S0,
+	PERF_REG_RISCV_S1,
+	PERF_REG_RISCV_A0,
+	PERF_REG_RISCV_A1,
+	PERF_REG_RISCV_A2,
+	PERF_REG_RISCV_A3,
+	PERF_REG_RISCV_A4,
+	PERF_REG_RISCV_A5,
+	PERF_REG_RISCV_A6,
+	PERF_REG_RISCV_A7,
+	PERF_REG_RISCV_S2,
+	PERF_REG_RISCV_S3,
+	PERF_REG_RISCV_S4,
+	PERF_REG_RISCV_S5,
+	PERF_REG_RISCV_S6,
+	PERF_REG_RISCV_S7,
+	PERF_REG_RISCV_S8,
+	PERF_REG_RISCV_S9,
+	PERF_REG_RISCV_S10,
+	PERF_REG_RISCV_S11,
+	PERF_REG_RISCV_T3,
+	PERF_REG_RISCV_T4,
+	PERF_REG_RISCV_T5,
+	PERF_REG_RISCV_T6,
+	PERF_REG_RISCV_MAX,
+};
+#endif /* _ASM_RISCV_PERF_REGS_H */
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index fe3f97e..8f2e6d3 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -59,6 +59,10 @@ ifeq ($(SRCARCH),arm64)
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
 
+ifeq ($(SRCARCH),riscv)
+  NO_PERF_REGS := 0
+endif
+
 ifeq ($(ARCH),s390)
   NO_PERF_REGS := 0
   NO_SYSCALL_TABLE := 0
@@ -77,7 +81,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 arm64 powerpc s390))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 riscv))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
diff --git a/tools/perf/arch/riscv/Build b/tools/perf/arch/riscv/Build
new file mode 100644
index 0000000..e4e5f33
--- /dev/null
+++ b/tools/perf/arch/riscv/Build
@@ -0,0 +1 @@
+perf-y += util/
diff --git a/tools/perf/arch/riscv/Makefile b/tools/perf/arch/riscv/Makefile
new file mode 100644
index 0000000..7fbca17
--- /dev/null
+++ b/tools/perf/arch/riscv/Makefile
@@ -0,0 +1,3 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+endif
diff --git a/tools/perf/arch/riscv/include/perf_regs.h b/tools/perf/arch/riscv/include/perf_regs.h
new file mode 100644
index 0000000..6051eff
--- /dev/null
+++ b/tools/perf/arch/riscv/include/perf_regs.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include <asm/perf_regs.h>
+
+#define PERF_REGS_MASK	((1ULL << PERF_REG_RISCV_MAX) - 1)
+#define PERF_REGS_MAX	PERF_REG_RISCV_MAX
+#if __riscv_xlen == 64
+#define PERF_SAMPLE_REGS_ABI    PERF_SAMPLE_REGS_ABI_64
+#else
+#define PERF_SAMPLE_REGS_ABI	PERF_SAMPLE_REGS_ABI_32
+#endif
+
+#define PERF_REG_IP	PERF_REG_RISCV_PC
+#define PERF_REG_SP	PERF_REG_RISCV_SP
+
+static inline const char *perf_reg_name(int id)
+{
+	switch (id) {
+	case PERF_REG_RISCV_PC:
+		return "pc";
+	case PERF_REG_RISCV_RA:
+		return "ra";
+	case PERF_REG_RISCV_SP:
+		return "sp";
+	case PERF_REG_RISCV_GP:
+		return "gp";
+	case PERF_REG_RISCV_TP:
+		return "tp";
+	case PERF_REG_RISCV_T0:
+		return "t0";
+	case PERF_REG_RISCV_T1:
+		return "t1";
+	case PERF_REG_RISCV_T2:
+		return "t2";
+	case PERF_REG_RISCV_S0:
+		return "s0";
+	case PERF_REG_RISCV_S1:
+		return "s1";
+	case PERF_REG_RISCV_A0:
+		return "a0";
+	case PERF_REG_RISCV_A1:
+		return "a1";
+	case PERF_REG_RISCV_A2:
+		return "a2";
+	case PERF_REG_RISCV_A3:
+		return "a3";
+	case PERF_REG_RISCV_A4:
+		return "a4";
+	case PERF_REG_RISCV_A5:
+		return "a5";
+	case PERF_REG_RISCV_A6:
+		return "a6";
+	case PERF_REG_RISCV_A7:
+		return "a7";
+	case PERF_REG_RISCV_S2:
+		return "s2";
+	case PERF_REG_RISCV_S3:
+		return "s3";
+	case PERF_REG_RISCV_S4:
+		return "s4";
+	case PERF_REG_RISCV_S5:
+		return "s5";
+	case PERF_REG_RISCV_S6:
+		return "s6";
+	case PERF_REG_RISCV_S7:
+		return "s7";
+	case PERF_REG_RISCV_S8:
+		return "s8";
+	case PERF_REG_RISCV_S9:
+		return "s9";
+	case PERF_REG_RISCV_S10:
+		return "s10";
+	case PERF_REG_RISCV_S11:
+		return "s11";
+	case PERF_REG_RISCV_T3:
+		return "t3";
+	case PERF_REG_RISCV_T4:
+		return "t4";
+	case PERF_REG_RISCV_T5:
+		return "t5";
+	case PERF_REG_RISCV_T6:
+		return "t6";
+	default:
+		return NULL;
+	}
+
+	return NULL;
+}
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
new file mode 100644
index 0000000..1160bb2
--- /dev/null
+++ b/tools/perf/arch/riscv/util/Build
@@ -0,0 +1,2 @@
+perf-$(CONFIG_DWARF) += dwarf-regs.o
+perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/riscv/util/dwarf-regs.c b/tools/perf/arch/riscv/util/dwarf-regs.c
new file mode 100644
index 0000000..a55f352
--- /dev/null
+++ b/tools/perf/arch/riscv/util/dwarf-regs.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+// Mapping of DWARF debug register numbers into register names.
+
+#include <stddef.h>
+#include <errno.h> /* for EINVAL */
+#include <string.h> /* for strcmp */
+#include <dwarf-regs.h>
+
+struct pt_regs_dwarfnum {
+	const char *name;
+	unsigned int dwarfnum;
+};
+
+#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
+#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
+
+struct pt_regs_dwarfnum riscv_dwarf_regs_table[] = {
+	REG_DWARFNUM_NAME("%zero", 0),
+	REG_DWARFNUM_NAME("%ra", 1),
+	REG_DWARFNUM_NAME("%sp", 2),
+	REG_DWARFNUM_NAME("%gp", 3),
+	REG_DWARFNUM_NAME("%tp", 4),
+	REG_DWARFNUM_NAME("%t0", 5),
+	REG_DWARFNUM_NAME("%t1", 6),
+	REG_DWARFNUM_NAME("%t2", 7),
+	REG_DWARFNUM_NAME("%s0", 8),
+	REG_DWARFNUM_NAME("%s1", 9),
+	REG_DWARFNUM_NAME("%a0", 10),
+	REG_DWARFNUM_NAME("%a1", 11),
+	REG_DWARFNUM_NAME("%a2", 12),
+	REG_DWARFNUM_NAME("%a3", 13),
+	REG_DWARFNUM_NAME("%a4", 14),
+	REG_DWARFNUM_NAME("%a5", 15),
+	REG_DWARFNUM_NAME("%a6", 16),
+	REG_DWARFNUM_NAME("%a7", 17),
+	REG_DWARFNUM_NAME("%s2", 18),
+	REG_DWARFNUM_NAME("%s3", 19),
+	REG_DWARFNUM_NAME("%s4", 20),
+	REG_DWARFNUM_NAME("%s5", 21),
+	REG_DWARFNUM_NAME("%s6", 22),
+	REG_DWARFNUM_NAME("%s7", 23),
+	REG_DWARFNUM_NAME("%s8", 24),
+	REG_DWARFNUM_NAME("%s9", 25),
+	REG_DWARFNUM_NAME("%s10", 26),
+	REG_DWARFNUM_NAME("%s11", 27),
+	REG_DWARFNUM_NAME("%t3", 28),
+	REG_DWARFNUM_NAME("%t4", 29),
+	REG_DWARFNUM_NAME("%t5", 30),
+	REG_DWARFNUM_NAME("%t6", 31),
+	REG_DWARFNUM_END,
+};
+
+#define RISCV_MAX_REGS ((sizeof(riscv_dwarf_regs_table) / \
+		 sizeof(riscv_dwarf_regs_table[0])) - 1)
+
+const char *get_arch_regstr(unsigned int n)
+{
+	return (n < RISCV_MAX_REGS) ? riscv_dwarf_regs_table[n].name : NULL;
+}
+
+int regs_query_register_offset(const char *name)
+{
+	const struct pt_regs_dwarfnum *roff;
+
+	for (roff = riscv_dwarf_regs_table; roff->name != NULL; roff++)
+		if (!strcmp(roff->name, name))
+			return roff->dwarfnum;
+	return -EINVAL;
+}
diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/arch/riscv/util/unwind-libdw.c
new file mode 100644
index 0000000..ed7a17b
--- /dev/null
+++ b/tools/perf/arch/riscv/util/unwind-libdw.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
+
+#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[32];
+
+#define REG(r) ({						\
+	Dwarf_Word val = 0;					\
+	perf_reg_value(&val, user_regs, PERF_REG_RISCV_##r);	\
+	val;							\
+})
+
+	dwarf_regs[0]  = 0;
+	dwarf_regs[1]  = REG(RA);
+	dwarf_regs[2]  = REG(SP);
+	dwarf_regs[3]  = REG(GP);
+	dwarf_regs[4]  = REG(TP);
+	dwarf_regs[5]  = REG(T0);
+	dwarf_regs[6]  = REG(T1);
+	dwarf_regs[7]  = REG(T2);
+	dwarf_regs[8]  = REG(S0);
+	dwarf_regs[9]  = REG(S1);
+	dwarf_regs[10] = REG(A0);
+	dwarf_regs[11] = REG(A1);
+	dwarf_regs[12] = REG(A2);
+	dwarf_regs[13] = REG(A3);
+	dwarf_regs[14] = REG(A4);
+	dwarf_regs[15] = REG(A5);
+	dwarf_regs[16] = REG(A6);
+	dwarf_regs[17] = REG(A7);
+	dwarf_regs[18] = REG(S2);
+	dwarf_regs[19] = REG(S3);
+	dwarf_regs[20] = REG(S4);
+	dwarf_regs[21] = REG(S5);
+	dwarf_regs[22] = REG(S6);
+	dwarf_regs[23] = REG(S7);
+	dwarf_regs[24] = REG(S8);
+	dwarf_regs[25] = REG(S9);
+	dwarf_regs[26] = REG(S10);
+	dwarf_regs[27] = REG(S11);
+	dwarf_regs[28] = REG(T3);
+	dwarf_regs[29] = REG(T4);
+	dwarf_regs[30] = REG(T5);
+	dwarf_regs[31] = REG(T6);
+	dwfl_thread_state_register_pc(thread, REG(PC));
+
+	return dwfl_thread_state_registers(thread, 0, PERF_REG_RISCV_MAX,
+					   dwarf_regs);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/3] riscv: Add perf callchain support
  2019-04-11  7:53 [PATCH 0/3] riscv: Add perf callchain support Mao Han
                   ` (2 preceding siblings ...)
  2019-04-11  7:53 ` [PATCH 3/3] riscv: Add support for libdw Mao Han
@ 2019-04-11 14:14 ` Christoph Hellwig
  2019-04-12  9:38   ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
  3 siblings, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2019-04-11 14:14 UTC (permalink / raw)
  To: Mao Han; +Cc: linux-kernel, Palmer Dabbelt, Guo Ren

Please also send all riscv patches to the
linux-riscv@lists.infradead.org list.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] riscv: Add perf callchain support
  2019-04-11  7:53 ` [PATCH 1/3] " Mao Han
@ 2019-04-11 14:24   ` Christoph Hellwig
  2019-04-25 21:11   ` Palmer Dabbelt
  1 sibling, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2019-04-11 14:24 UTC (permalink / raw)
  To: Mao Han; +Cc: linux-kernel, Palmer Dabbelt

> --- /dev/null
> +++ b/arch/riscv/kernel/perf_callchain.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.

Please use normal /* */ Style comment for everything but the SPDX
tags.

> +static int unwind_frame_kernel(struct stackframe *frame)
> +{
> +	int graph = 0;
> +
> +	/* 0x3 means misalignment */
> +	if (!kstack_end((void *)frame->fp) &&
> +	    !((unsigned long)frame->fp & 0x3) &&
> +	    ((unsigned long)frame->fp >= TASK_SIZE)) {
> +		frame->ra = ((struct stackframe *)frame->fp - 1)->ra;
> +		frame->fp = ((struct stackframe *)frame->fp - 1)->fp;
> +		/* make sure CONFIG_FUNCTION_GRAPH_TRACER is turned on */
> +		if (__kernel_text_address(frame->ra))
> +			frame->ra = ftrace_graph_ret_addr(NULL, &graph,
> +							frame->ra, NULL);
> +		return 0;
> +	} else {
> +		return -EPERM;
> +	}

Please do early exists for all the error conditions.  Also no casts
are needed for using ->fp as a scalar value, and we should probably
just do a struct copy instead of copying both values individually.

The function should look something like:

static int unwind_frame_kernel(struct stackframe *frame)
{
	if (!kstack_end((void *)frame->fp))
		return -EPERM;
	if ((frame->fp & 0x3 || frame->fp >= TASK_SIZE)
		return -EPERM;

	*frame = *((struct stackframe *)frame->fp - 1);
	if (__kernel_text_address(frame->ra)) {
		int graph = 0;

		frame->ra = ftrace_graph_ret_addr(NULL, &graph, frame->ra,
				NULL);
	}
	return 0;
}

> +static void notrace walk_stackframe(struct stackframe *fr,
> +			struct perf_callchain_entry_ctx *entry)
> +{
> +	while (1) {
> +		int ret;
> +
> +		perf_callchain_store(entry, fr->ra);
> +
> +		ret = unwind_frame_kernel(fr);
> +		if (ret < 0)
> +			break;
> +	}
> +}

Why not:

	do {
		perf_callchain_store(entry, fr->ra);
	} while (unwind_frame_kernel(fr) >= 0);

> +/*
> + * Get the return address for a single stackframe and return a pointer to the
> + * next frame tail.
> + */
> +static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
> +			unsigned long fp, unsigned long reg_ra)
> +{
> +	struct stackframe buftail;
> +	unsigned long ra = 0;
> +	unsigned long *user_frame_tail = (unsigned long *)(fp - sizeof(struct stackframe));

Overly long line.

> +	fp = user_backtrace(entry, fp, regs->ra);
> +	while ((entry->nr < entry->max_stack) &&
> +		fp && !((unsigned long)fp & 0x3))
> +		fp = user_backtrace(entry, fp, 0);

Please don't indent the condition continuation and the loop body
by the same amount.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] riscv: Add support for perf registers sampling
  2019-04-11 14:14 ` [PATCH 0/3] riscv: Add perf callchain support Christoph Hellwig
@ 2019-04-12  9:38   ` Mao Han
  2019-04-13  8:01     ` Christoph Hellwig
  0 siblings, 1 reply; 14+ messages in thread
From: Mao Han @ 2019-04-12  9:38 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-kernel, guoren

On Thu, Apr 11, 2019 at 07:24:32AM -0700, Christoph Hellwig wrote:
> > --- /dev/null
> > +++ b/arch/riscv/kernel/perf_callchain.c
> > @@ -0,0 +1,122 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> 
> Please use normal /* */ Style comment for everything but the SPDX
> tags.
>
OK
 
> Please do early exists for all the error conditions.  Also no casts
> are needed for using ->fp as a scalar value, and we should probably
> just do a struct copy instead of copying both values individually.
> 
> The function should look something like:
> 
> static int unwind_frame_kernel(struct stackframe *frame)
> {
> 	if (!kstack_end((void *)frame->fp))
> 		return -EPERM;
> 	if ((frame->fp & 0x3 || frame->fp >= TASK_SIZE)
> 		return -EPERM;
> 
> 	*frame = *((struct stackframe *)frame->fp - 1);
> 	if (__kernel_text_address(frame->ra)) {
> 		int graph = 0;
> 
> 		frame->ra = ftrace_graph_ret_addr(NULL, &graph, frame->ra,
> 				NULL);
> 	}
> 	return 0;
> }
>
Thanks for suggestion. It looks much better with the modification.

> 
> Why not:
> 
> 	do {
> 		perf_callchain_store(entry, fr->ra);
> 	} while (unwind_frame_kernel(fr) >= 0);
> 
Yes, it's much simpler.

> > +/*
> > + * Get the return address for a single stackframe and return a pointer to the
> > + * next frame tail.
> > + */
> > +static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
> > +			unsigned long fp, unsigned long reg_ra)
> > +{
> > +	struct stackframe buftail;
> > +	unsigned long ra = 0;
> > +	unsigned long *user_frame_tail = (unsigned long *)(fp - sizeof(struct stackframe));
> 
> Overly long line.
Will fix the style.

> 
> > +	fp = user_backtrace(entry, fp, regs->ra);
> > +	while ((entry->nr < entry->max_stack) &&
> > +		fp && !((unsigned long)fp & 0x3))
> > +		fp = user_backtrace(entry, fp, 0);
> 
> Please don't indent the condition continuation and the loop body
> by the same amount.

Like this?
	while ((entry->nr < entry->max_stack) &&
					fp && !((unsigned long)fp & 0x3))
		fp = user_backtrace(entry, fp, 0);

Thanks,
Mao Han

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] riscv: Add support for perf registers sampling
  2019-04-12  9:38   ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
@ 2019-04-13  8:01     ` Christoph Hellwig
  0 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2019-04-13  8:01 UTC (permalink / raw)
  To: Mao Han; +Cc: Christoph Hellwig, linux-kernel, guoren

On Fri, Apr 12, 2019 at 05:38:53PM +0800, Mao Han wrote:
> > 
> > > +	fp = user_backtrace(entry, fp, regs->ra);
> > > +	while ((entry->nr < entry->max_stack) &&
> > > +		fp && !((unsigned long)fp & 0x3))
> > > +		fp = user_backtrace(entry, fp, 0);
> > 
> > Please don't indent the condition continuation and the loop body
> > by the same amount.
> 
> Like this?
> 	while ((entry->nr < entry->max_stack) &&
> 					fp && !((unsigned long)fp & 0x3))
> 		fp = user_backtrace(entry, fp, 0);

We tend to either use indentations to the same level as the condition,
or two tabs indents.  But I also noticed that we shouldn't even need
the cast here as fp already is unsigned long, so it should all fit on
one line anyway:

	while (fp && !(fp & 0x3) && entry->nr < entry->max_stack)
		fp = user_backtrace(entry, fp, 0);

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] riscv: Add perf callchain support
  2019-04-11  7:53 ` [PATCH 1/3] " Mao Han
  2019-04-11 14:24   ` Christoph Hellwig
@ 2019-04-25 21:11   ` Palmer Dabbelt
  2019-04-29  8:39     ` Mao Han
  1 sibling, 1 reply; 14+ messages in thread
From: Palmer Dabbelt @ 2019-04-25 21:11 UTC (permalink / raw)
  To: han_mao; +Cc: linux-kernel, han_mao

On Thu, 11 Apr 2019 00:53:48 PDT (-0700), han_mao@c-sky.com wrote:
> This patch add support for perf callchain sampling on riscv platform.
> The return address of leaf function is retrieved from pt_regs as
> it is not saved in the outmost frame.
>
> Signed-off-by: Mao Han <han_mao@c-sky.com>
>
> CC: Palmer Dabbelt <palmer@sifive.com>
> ---
>  arch/riscv/kernel/Makefile         |   3 +-
>  arch/riscv/kernel/perf_callchain.c | 122 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 124 insertions(+), 1 deletion(-)
>  create mode 100644 arch/riscv/kernel/perf_callchain.c
>
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index 5985681..dd2ba44 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_MODULE_SECTIONS)	+= module-sections.o
>  obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o ftrace.o
>  obj-$(CONFIG_DYNAMIC_FTRACE)	+= mcount-dyn.o
>
> -obj-$(CONFIG_PERF_EVENTS)      += perf_event.o
> +obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o
> +obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
>
>  clean:
> diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
> new file mode 100644
> index 0000000..eb3ddbb
> --- /dev/null
> +++ b/arch/riscv/kernel/perf_callchain.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +
> +#include <linux/perf_event.h>
> +#include <linux/uaccess.h>
> +
> +/* Kernel callchain */
> +struct stackframe {
> +	unsigned long fp;
> +	unsigned long ra;
> +};
> +
> +static int unwind_frame_kernel(struct stackframe *frame)
> +{
> +	int graph = 0;
> +
> +	/* 0x3 means misalignment */
> +	if (!kstack_end((void *)frame->fp) &&
> +	    !((unsigned long)frame->fp & 0x3) &&
> +	    ((unsigned long)frame->fp >= TASK_SIZE)) {
> +		frame->ra = ((struct stackframe *)frame->fp - 1)->ra;
> +		frame->fp = ((struct stackframe *)frame->fp - 1)->fp;

It looks like this depends on having a frame pointer?  In that case, shouldn't
we add some Kconfig logic to make CONFIG_PERF_EVENTS select
-fno-omit-frame-pointer?  Frame pointers aren't enabled by default on RISC-V
and therefor are unlikely to exist at all.

> +		/* make sure CONFIG_FUNCTION_GRAPH_TRACER is turned on */

Should that also be mandated by a Kconfig?

> +		if (__kernel_text_address(frame->ra))
> +			frame->ra = ftrace_graph_ret_addr(NULL, &graph,
> +							frame->ra, NULL);
> +		return 0;
> +	} else {
> +		return -EPERM;
> +	}
> +}
> +
> +static void notrace walk_stackframe(struct stackframe *fr,
> +			struct perf_callchain_entry_ctx *entry)
> +{
> +	while (1) {
> +		int ret;
> +
> +		perf_callchain_store(entry, fr->ra);
> +
> +		ret = unwind_frame_kernel(fr);
> +		if (ret < 0)
> +			break;
> +	}
> +}
> +
> +/*
> + * Get the return address for a single stackframe and return a pointer to the
> + * next frame tail.
> + */
> +static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry,
> +			unsigned long fp, unsigned long reg_ra)
> +{
> +	struct stackframe buftail;
> +	unsigned long ra = 0;
> +	unsigned long *user_frame_tail = (unsigned long *)(fp - sizeof(struct stackframe));
> +
> +	/* Check accessibility of one struct frame_tail beyond */
> +	if (!access_ok(user_frame_tail, sizeof(buftail)))
> +		return 0;
> +	if (__copy_from_user_inatomic(&buftail, user_frame_tail,
> +				      sizeof(buftail)))
> +		return 0;
> +
> +	if (reg_ra != 0)
> +		ra = reg_ra;
> +	else
> +		ra = buftail.ra;
> +
> +	fp = buftail.fp;
> +	perf_callchain_store(entry, ra);
> +
> +	return fp;
> +}
> +
> +/*
> + * This will be called when the target is in user mode
> + * This function will only be called when we use
> + * "PERF_SAMPLE_CALLCHAIN" in
> + * kernel/events/core.c:perf_prepare_sample()
> + *
> + * How to trigger perf_callchain_[user/kernel] :
> + * $ perf record -e cpu-clock --call-graph fp ./program
> + * $ perf report --call-graph
> + *
> + * On RISC-V platform, the program being sampled and the C library
> + * need to be compiled with * -mbacktrace, otherwise the user

What is "-mbacktrace"?  I don't remember that ever being a RISC-V GCC option,
and my compiler doesn't undersand it.  It understands "-fbacktrace" but that
doesn't produce a frame pointer.

> + * stack will not contain function frame.
> + */
> +void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
> +			 struct pt_regs *regs)
> +{
> +	unsigned long fp = 0;
> +
> +	/* RISC-V does not support virtualization. */
> +	if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
> +		return;
> +
> +	fp = regs->s0;
> +	perf_callchain_store(entry, regs->sepc);
> +
> +	fp = user_backtrace(entry, fp, regs->ra);
> +	while ((entry->nr < entry->max_stack) &&
> +		fp && !((unsigned long)fp & 0x3))
> +		fp = user_backtrace(entry, fp, 0);
> +}
> +
> +void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
> +			   struct pt_regs *regs)
> +{
> +	struct stackframe fr;
> +
> +	/* RISC-V does not support virtualization. */
> +	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
> +		pr_warn("RISC-V does not support perf in guest mode!");
> +		return;
> +	}
> +
> +	fr.fp = regs->s0;
> +	fr.ra = regs->ra;
> +	walk_stackframe(&fr, entry);
> +}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] riscv: Add support for perf registers sampling
  2019-04-11  7:53 ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
@ 2019-04-25 21:11   ` Palmer Dabbelt
  2019-04-29  8:42     ` Mao Han
  0 siblings, 1 reply; 14+ messages in thread
From: Palmer Dabbelt @ 2019-04-25 21:11 UTC (permalink / raw)
  To: han_mao; +Cc: linux-kernel, han_mao

On Thu, 11 Apr 2019 00:53:49 PDT (-0700), han_mao@c-sky.com wrote:
> This patch implements the perf registers sampling and validation API
> for riscv arch. The valid registers and their register ID are defined in
> perf_regs.h. Perf tool can backtrace in userspace with unwind library
> and the registers/user stack dump support.
>
> Signed-off-by: Mao Han <han_mao@c-sky.com>
>
> CC: Palmer Dabbelt <palmer@sifive.com>
> ---
>  arch/riscv/Kconfig                      |  2 ++
>  arch/riscv/include/uapi/asm/perf_regs.h | 42 +++++++++++++++++++++++++++++++
>  arch/riscv/kernel/Makefile              |  1 +
>  arch/riscv/kernel/perf_regs.c           | 44 +++++++++++++++++++++++++++++++++
>  4 files changed, 89 insertions(+)
>  create mode 100644 arch/riscv/include/uapi/asm/perf_regs.h
>  create mode 100644 arch/riscv/kernel/perf_regs.c
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index eb56c82..effd157 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -33,6 +33,8 @@ config RISCV
>  	select HAVE_DMA_CONTIGUOUS
>  	select HAVE_FUTEX_CMPXCHG if FUTEX
>  	select HAVE_PERF_EVENTS
> +	select HAVE_PERF_REGS
> +	select HAVE_PERF_USER_STACK_DUMP
>  	select HAVE_SYSCALL_TRACEPOINTS
>  	select IRQ_DOMAIN
>  	select RISCV_ISA_A if SMP
> diff --git a/arch/riscv/include/uapi/asm/perf_regs.h b/arch/riscv/include/uapi/asm/perf_regs.h
> new file mode 100644
> index 0000000..ce48987
> --- /dev/null
> +++ b/arch/riscv/include/uapi/asm/perf_regs.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +
> +#ifndef _ASM_RISCV_PERF_REGS_H
> +#define _ASM_RISCV_PERF_REGS_H
> +
> +enum perf_event_riscv_regs {
> +	PERF_REG_RISCV_PC,
> +	PERF_REG_RISCV_RA,
> +	PERF_REG_RISCV_SP,
> +	PERF_REG_RISCV_GP,
> +	PERF_REG_RISCV_TP,
> +	PERF_REG_RISCV_T0,
> +	PERF_REG_RISCV_T1,
> +	PERF_REG_RISCV_T2,
> +	PERF_REG_RISCV_S0,
> +	PERF_REG_RISCV_S1,
> +	PERF_REG_RISCV_A0,
> +	PERF_REG_RISCV_A1,
> +	PERF_REG_RISCV_A2,
> +	PERF_REG_RISCV_A3,
> +	PERF_REG_RISCV_A4,
> +	PERF_REG_RISCV_A5,
> +	PERF_REG_RISCV_A6,
> +	PERF_REG_RISCV_A7,
> +	PERF_REG_RISCV_S2,
> +	PERF_REG_RISCV_S3,
> +	PERF_REG_RISCV_S4,
> +	PERF_REG_RISCV_S5,
> +	PERF_REG_RISCV_S6,
> +	PERF_REG_RISCV_S7,
> +	PERF_REG_RISCV_S8,
> +	PERF_REG_RISCV_S9,
> +	PERF_REG_RISCV_S10,
> +	PERF_REG_RISCV_S11,
> +	PERF_REG_RISCV_T3,
> +	PERF_REG_RISCV_T4,
> +	PERF_REG_RISCV_T5,
> +	PERF_REG_RISCV_T6,
> +	PERF_REG_RISCV_MAX,
> +};

Is it expected this eventually supports floating-point and vector registers?
If so, how do we make this extensible?

> +#endif /* _ASM_RISCV_PERF_REGS_H */
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index dd2ba44..024badc 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -39,5 +39,6 @@ obj-$(CONFIG_DYNAMIC_FTRACE)	+= mcount-dyn.o
>
>  obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o
>  obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
> +obj-$(CONFIG_HAVE_PERF_REGS)	+= perf_regs.o
>
>  clean:
> diff --git a/arch/riscv/kernel/perf_regs.c b/arch/riscv/kernel/perf_regs.c
> new file mode 100644
> index 0000000..03d7ac3
> --- /dev/null
> +++ b/arch/riscv/kernel/perf_regs.c
> @@ -0,0 +1,44 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/perf_event.h>
> +#include <linux/bug.h>
> +#include <asm/perf_regs.h>
> +#include <asm/ptrace.h>
> +
> +u64 perf_reg_value(struct pt_regs *regs, int idx)
> +{
> +	if (WARN_ON_ONCE((u32)idx >= PERF_REG_RISCV_MAX))
> +		return 0;
> +
> +	return ((long *)regs)[idx];
> +}
> +
> +#define REG_RESERVED (~((1ULL << PERF_REG_RISCV_MAX) - 1))
> +
> +int perf_reg_validate(u64 mask)
> +{
> +	if (!mask || mask & REG_RESERVED)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +u64 perf_reg_abi(struct task_struct *task)
> +{
> +#if __riscv_xlen == 64
> +	return PERF_SAMPLE_REGS_ABI_64;
> +#else
> +	return PERF_SAMPLE_REGS_ABI_32;
> +#endif
> +}
> +
> +void perf_get_regs_user(struct perf_regs *regs_user,
> +			struct pt_regs *regs,
> +			struct pt_regs *regs_user_copy)
> +{
> +	regs_user->regs = task_pt_regs(current);
> +	regs_user->abi = perf_reg_abi(current);
> +}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] riscv: Add support for libdw
  2019-04-11  7:53 ` [PATCH 3/3] riscv: Add support for libdw Mao Han
@ 2019-04-25 21:11   ` Palmer Dabbelt
  2019-04-29  8:45     ` Mao Han
  0 siblings, 1 reply; 14+ messages in thread
From: Palmer Dabbelt @ 2019-04-25 21:11 UTC (permalink / raw)
  To: han_mao; +Cc: linux-kernel, han_mao

On Thu, 11 Apr 2019 00:53:50 PDT (-0700), han_mao@c-sky.com wrote:
> This patch add support for DWARF register mappings and libdw registers
> initialization, which is used by perf callchain analyzing when
> --call-graph=dwarf is given.

Is there any way to make this the only backtracer?  It's the only one that's
likely to be useful on RISC-V without recompiling everything with
-fno-omit-frame-pointer, which has a major performance hit.

> Signed-off-by: Mao Han <han_mao@c-sky.com>
>
> CC: Palmer Dabbelt <palmer@sifive.com>
> ---
>  tools/arch/riscv/include/uapi/asm/perf_regs.h | 42 ++++++++++++
>  tools/perf/Makefile.config                    |  6 +-
>  tools/perf/arch/riscv/Build                   |  1 +
>  tools/perf/arch/riscv/Makefile                |  3 +
>  tools/perf/arch/riscv/include/perf_regs.h     | 96 +++++++++++++++++++++++++++
>  tools/perf/arch/riscv/util/Build              |  2 +
>  tools/perf/arch/riscv/util/dwarf-regs.c       | 70 +++++++++++++++++++
>  tools/perf/arch/riscv/util/unwind-libdw.c     | 57 ++++++++++++++++
>  8 files changed, 276 insertions(+), 1 deletion(-)
>  create mode 100644 tools/arch/riscv/include/uapi/asm/perf_regs.h
>  create mode 100644 tools/perf/arch/riscv/Build
>  create mode 100644 tools/perf/arch/riscv/Makefile
>  create mode 100644 tools/perf/arch/riscv/include/perf_regs.h
>  create mode 100644 tools/perf/arch/riscv/util/Build
>  create mode 100644 tools/perf/arch/riscv/util/dwarf-regs.c
>  create mode 100644 tools/perf/arch/riscv/util/unwind-libdw.c
>
> diff --git a/tools/arch/riscv/include/uapi/asm/perf_regs.h b/tools/arch/riscv/include/uapi/asm/perf_regs.h
> new file mode 100644
> index 0000000..ce48987
> --- /dev/null
> +++ b/tools/arch/riscv/include/uapi/asm/perf_regs.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +
> +#ifndef _ASM_RISCV_PERF_REGS_H
> +#define _ASM_RISCV_PERF_REGS_H
> +
> +enum perf_event_riscv_regs {
> +	PERF_REG_RISCV_PC,
> +	PERF_REG_RISCV_RA,
> +	PERF_REG_RISCV_SP,
> +	PERF_REG_RISCV_GP,
> +	PERF_REG_RISCV_TP,
> +	PERF_REG_RISCV_T0,
> +	PERF_REG_RISCV_T1,
> +	PERF_REG_RISCV_T2,
> +	PERF_REG_RISCV_S0,
> +	PERF_REG_RISCV_S1,
> +	PERF_REG_RISCV_A0,
> +	PERF_REG_RISCV_A1,
> +	PERF_REG_RISCV_A2,
> +	PERF_REG_RISCV_A3,
> +	PERF_REG_RISCV_A4,
> +	PERF_REG_RISCV_A5,
> +	PERF_REG_RISCV_A6,
> +	PERF_REG_RISCV_A7,
> +	PERF_REG_RISCV_S2,
> +	PERF_REG_RISCV_S3,
> +	PERF_REG_RISCV_S4,
> +	PERF_REG_RISCV_S5,
> +	PERF_REG_RISCV_S6,
> +	PERF_REG_RISCV_S7,
> +	PERF_REG_RISCV_S8,
> +	PERF_REG_RISCV_S9,
> +	PERF_REG_RISCV_S10,
> +	PERF_REG_RISCV_S11,
> +	PERF_REG_RISCV_T3,
> +	PERF_REG_RISCV_T4,
> +	PERF_REG_RISCV_T5,
> +	PERF_REG_RISCV_T6,
> +	PERF_REG_RISCV_MAX,
> +};
> +#endif /* _ASM_RISCV_PERF_REGS_H */
> diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
> index fe3f97e..8f2e6d3 100644
> --- a/tools/perf/Makefile.config
> +++ b/tools/perf/Makefile.config
> @@ -59,6 +59,10 @@ ifeq ($(SRCARCH),arm64)
>    LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
>  endif
>
> +ifeq ($(SRCARCH),riscv)
> +  NO_PERF_REGS := 0
> +endif
> +
>  ifeq ($(ARCH),s390)
>    NO_PERF_REGS := 0
>    NO_SYSCALL_TABLE := 0
> @@ -77,7 +81,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 arm64 powerpc s390))
> +ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 riscv))
>    NO_LIBDW_DWARF_UNWIND := 1
>  endif
>
> diff --git a/tools/perf/arch/riscv/Build b/tools/perf/arch/riscv/Build
> new file mode 100644
> index 0000000..e4e5f33
> --- /dev/null
> +++ b/tools/perf/arch/riscv/Build
> @@ -0,0 +1 @@
> +perf-y += util/
> diff --git a/tools/perf/arch/riscv/Makefile b/tools/perf/arch/riscv/Makefile
> new file mode 100644
> index 0000000..7fbca17
> --- /dev/null
> +++ b/tools/perf/arch/riscv/Makefile
> @@ -0,0 +1,3 @@
> +ifndef NO_DWARF
> +PERF_HAVE_DWARF_REGS := 1
> +endif
> diff --git a/tools/perf/arch/riscv/include/perf_regs.h b/tools/perf/arch/riscv/include/perf_regs.h
> new file mode 100644
> index 0000000..6051eff
> --- /dev/null
> +++ b/tools/perf/arch/riscv/include/perf_regs.h
> @@ -0,0 +1,96 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +
> +#ifndef ARCH_PERF_REGS_H
> +#define ARCH_PERF_REGS_H
> +
> +#include <stdlib.h>
> +#include <linux/types.h>
> +#include <asm/perf_regs.h>
> +
> +#define PERF_REGS_MASK	((1ULL << PERF_REG_RISCV_MAX) - 1)
> +#define PERF_REGS_MAX	PERF_REG_RISCV_MAX
> +#if __riscv_xlen == 64
> +#define PERF_SAMPLE_REGS_ABI    PERF_SAMPLE_REGS_ABI_64
> +#else
> +#define PERF_SAMPLE_REGS_ABI	PERF_SAMPLE_REGS_ABI_32
> +#endif
> +
> +#define PERF_REG_IP	PERF_REG_RISCV_PC
> +#define PERF_REG_SP	PERF_REG_RISCV_SP
> +
> +static inline const char *perf_reg_name(int id)
> +{
> +	switch (id) {
> +	case PERF_REG_RISCV_PC:
> +		return "pc";
> +	case PERF_REG_RISCV_RA:
> +		return "ra";
> +	case PERF_REG_RISCV_SP:
> +		return "sp";
> +	case PERF_REG_RISCV_GP:
> +		return "gp";
> +	case PERF_REG_RISCV_TP:
> +		return "tp";
> +	case PERF_REG_RISCV_T0:
> +		return "t0";
> +	case PERF_REG_RISCV_T1:
> +		return "t1";
> +	case PERF_REG_RISCV_T2:
> +		return "t2";
> +	case PERF_REG_RISCV_S0:
> +		return "s0";
> +	case PERF_REG_RISCV_S1:
> +		return "s1";
> +	case PERF_REG_RISCV_A0:
> +		return "a0";
> +	case PERF_REG_RISCV_A1:
> +		return "a1";
> +	case PERF_REG_RISCV_A2:
> +		return "a2";
> +	case PERF_REG_RISCV_A3:
> +		return "a3";
> +	case PERF_REG_RISCV_A4:
> +		return "a4";
> +	case PERF_REG_RISCV_A5:
> +		return "a5";
> +	case PERF_REG_RISCV_A6:
> +		return "a6";
> +	case PERF_REG_RISCV_A7:
> +		return "a7";
> +	case PERF_REG_RISCV_S2:
> +		return "s2";
> +	case PERF_REG_RISCV_S3:
> +		return "s3";
> +	case PERF_REG_RISCV_S4:
> +		return "s4";
> +	case PERF_REG_RISCV_S5:
> +		return "s5";
> +	case PERF_REG_RISCV_S6:
> +		return "s6";
> +	case PERF_REG_RISCV_S7:
> +		return "s7";
> +	case PERF_REG_RISCV_S8:
> +		return "s8";
> +	case PERF_REG_RISCV_S9:
> +		return "s9";
> +	case PERF_REG_RISCV_S10:
> +		return "s10";
> +	case PERF_REG_RISCV_S11:
> +		return "s11";
> +	case PERF_REG_RISCV_T3:
> +		return "t3";
> +	case PERF_REG_RISCV_T4:
> +		return "t4";
> +	case PERF_REG_RISCV_T5:
> +		return "t5";
> +	case PERF_REG_RISCV_T6:
> +		return "t6";
> +	default:
> +		return NULL;
> +	}
> +
> +	return NULL;
> +}
> +
> +#endif /* ARCH_PERF_REGS_H */
> diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
> new file mode 100644
> index 0000000..1160bb2
> --- /dev/null
> +++ b/tools/perf/arch/riscv/util/Build
> @@ -0,0 +1,2 @@
> +perf-$(CONFIG_DWARF) += dwarf-regs.o
> +perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
> diff --git a/tools/perf/arch/riscv/util/dwarf-regs.c b/tools/perf/arch/riscv/util/dwarf-regs.c
> new file mode 100644
> index 0000000..a55f352
> --- /dev/null
> +++ b/tools/perf/arch/riscv/util/dwarf-regs.c
> @@ -0,0 +1,70 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +// Mapping of DWARF debug register numbers into register names.
> +
> +#include <stddef.h>
> +#include <errno.h> /* for EINVAL */
> +#include <string.h> /* for strcmp */
> +#include <dwarf-regs.h>
> +
> +struct pt_regs_dwarfnum {
> +	const char *name;
> +	unsigned int dwarfnum;
> +};
> +
> +#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
> +#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
> +
> +struct pt_regs_dwarfnum riscv_dwarf_regs_table[] = {
> +	REG_DWARFNUM_NAME("%zero", 0),
> +	REG_DWARFNUM_NAME("%ra", 1),
> +	REG_DWARFNUM_NAME("%sp", 2),
> +	REG_DWARFNUM_NAME("%gp", 3),
> +	REG_DWARFNUM_NAME("%tp", 4),
> +	REG_DWARFNUM_NAME("%t0", 5),
> +	REG_DWARFNUM_NAME("%t1", 6),
> +	REG_DWARFNUM_NAME("%t2", 7),
> +	REG_DWARFNUM_NAME("%s0", 8),
> +	REG_DWARFNUM_NAME("%s1", 9),
> +	REG_DWARFNUM_NAME("%a0", 10),
> +	REG_DWARFNUM_NAME("%a1", 11),
> +	REG_DWARFNUM_NAME("%a2", 12),
> +	REG_DWARFNUM_NAME("%a3", 13),
> +	REG_DWARFNUM_NAME("%a4", 14),
> +	REG_DWARFNUM_NAME("%a5", 15),
> +	REG_DWARFNUM_NAME("%a6", 16),
> +	REG_DWARFNUM_NAME("%a7", 17),
> +	REG_DWARFNUM_NAME("%s2", 18),
> +	REG_DWARFNUM_NAME("%s3", 19),
> +	REG_DWARFNUM_NAME("%s4", 20),
> +	REG_DWARFNUM_NAME("%s5", 21),
> +	REG_DWARFNUM_NAME("%s6", 22),
> +	REG_DWARFNUM_NAME("%s7", 23),
> +	REG_DWARFNUM_NAME("%s8", 24),
> +	REG_DWARFNUM_NAME("%s9", 25),
> +	REG_DWARFNUM_NAME("%s10", 26),
> +	REG_DWARFNUM_NAME("%s11", 27),
> +	REG_DWARFNUM_NAME("%t3", 28),
> +	REG_DWARFNUM_NAME("%t4", 29),
> +	REG_DWARFNUM_NAME("%t5", 30),
> +	REG_DWARFNUM_NAME("%t6", 31),
> +	REG_DWARFNUM_END,
> +};
> +
> +#define RISCV_MAX_REGS ((sizeof(riscv_dwarf_regs_table) / \
> +		 sizeof(riscv_dwarf_regs_table[0])) - 1)
> +
> +const char *get_arch_regstr(unsigned int n)
> +{
> +	return (n < RISCV_MAX_REGS) ? riscv_dwarf_regs_table[n].name : NULL;
> +}
> +
> +int regs_query_register_offset(const char *name)
> +{
> +	const struct pt_regs_dwarfnum *roff;
> +
> +	for (roff = riscv_dwarf_regs_table; roff->name != NULL; roff++)
> +		if (!strcmp(roff->name, name))
> +			return roff->dwarfnum;
> +	return -EINVAL;
> +}
> diff --git a/tools/perf/arch/riscv/util/unwind-libdw.c b/tools/perf/arch/riscv/util/unwind-libdw.c
> new file mode 100644
> index 0000000..ed7a17b
> --- /dev/null
> +++ b/tools/perf/arch/riscv/util/unwind-libdw.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
> +
> +#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[32];
> +
> +#define REG(r) ({						\
> +	Dwarf_Word val = 0;					\
> +	perf_reg_value(&val, user_regs, PERF_REG_RISCV_##r);	\
> +	val;							\
> +})
> +
> +	dwarf_regs[0]  = 0;
> +	dwarf_regs[1]  = REG(RA);
> +	dwarf_regs[2]  = REG(SP);
> +	dwarf_regs[3]  = REG(GP);
> +	dwarf_regs[4]  = REG(TP);
> +	dwarf_regs[5]  = REG(T0);
> +	dwarf_regs[6]  = REG(T1);
> +	dwarf_regs[7]  = REG(T2);
> +	dwarf_regs[8]  = REG(S0);
> +	dwarf_regs[9]  = REG(S1);
> +	dwarf_regs[10] = REG(A0);
> +	dwarf_regs[11] = REG(A1);
> +	dwarf_regs[12] = REG(A2);
> +	dwarf_regs[13] = REG(A3);
> +	dwarf_regs[14] = REG(A4);
> +	dwarf_regs[15] = REG(A5);
> +	dwarf_regs[16] = REG(A6);
> +	dwarf_regs[17] = REG(A7);
> +	dwarf_regs[18] = REG(S2);
> +	dwarf_regs[19] = REG(S3);
> +	dwarf_regs[20] = REG(S4);
> +	dwarf_regs[21] = REG(S5);
> +	dwarf_regs[22] = REG(S6);
> +	dwarf_regs[23] = REG(S7);
> +	dwarf_regs[24] = REG(S8);
> +	dwarf_regs[25] = REG(S9);
> +	dwarf_regs[26] = REG(S10);
> +	dwarf_regs[27] = REG(S11);
> +	dwarf_regs[28] = REG(T3);
> +	dwarf_regs[29] = REG(T4);
> +	dwarf_regs[30] = REG(T5);
> +	dwarf_regs[31] = REG(T6);
> +	dwfl_thread_state_register_pc(thread, REG(PC));
> +
> +	return dwfl_thread_state_registers(thread, 0, PERF_REG_RISCV_MAX,
> +					   dwarf_regs);
> +}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/3] riscv: Add perf callchain support
  2019-04-25 21:11   ` Palmer Dabbelt
@ 2019-04-29  8:39     ` Mao Han
  0 siblings, 0 replies; 14+ messages in thread
From: Mao Han @ 2019-04-29  8:39 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: linux-riscv, guoren, linux-kernel

On Thu, Apr 25, 2019 at 02:11:00PM -0700, Palmer Dabbelt wrote:
> On Thu, 11 Apr 2019 00:53:48 PDT (-0700), han_mao@c-sky.com wrote:
> >+	if (!kstack_end((void *)frame->fp) &&
> >+	    !((unsigned long)frame->fp & 0x3) &&
> >+	    ((unsigned long)frame->fp >= TASK_SIZE)) {
> >+		frame->ra = ((struct stackframe *)frame->fp - 1)->ra;
> >+		frame->fp = ((struct stackframe *)frame->fp - 1)->fp;
> 
> It looks like this depends on having a frame pointer?  In that case, shouldn't
> we add some Kconfig logic to make CONFIG_PERF_EVENTS select
> -fno-omit-frame-pointer?  Frame pointers aren't enabled by default on RISC-V
> and therefor are unlikely to exist at all.
>

Yes, frame pointer is required for kernel backtrace, -fno-omit-frame-pointer
should be added if frame pointer is not enabled by default on RISC-V.
When I testing the callchain support with buildroot chunk
git://git.busybox.net/buildroot
cbf1d861fadb491eee6e3686019d8f67d7f4ad85
both kernel and user program have fp without adding any extra option,
so I thought frame pointer was enabled by default.

ffffffe0000009ee <kernel_init_freeable>:
ffffffe0000009ee:       711d                    addi    sp,sp,-96
ffffffe0000009f0:       ec86                    sd      ra,88(sp)
ffffffe0000009f2:       e8a2                    sd      s0,80(sp)
ffffffe0000009f4:       e4a6                    sd      s1,72(sp)

void test_3(void)
{
   10498:       fe010113                addi    sp,sp,-32
   1049c:       00113c23                sd      ra,24(sp)
   104a0:       00813823                sd      s0,16(sp)
   104a4:       02010413                addi    s0,sp,32

> >+		/* make sure CONFIG_FUNCTION_GRAPH_TRACER is turned on */
> 
> Should that also be mandated by a Kconfig?
>

Yes, it is required for ftrace_graph_ret_addr support.
It's already default for ARCH_RV64I in Kconfig.
 
> >+/*
> >+ * This will be called when the target is in user mode
> >+ * This function will only be called when we use
> >+ * "PERF_SAMPLE_CALLCHAIN" in
> >+ * kernel/events/core.c:perf_prepare_sample()
> >+ *
> >+ * How to trigger perf_callchain_[user/kernel] :
> >+ * $ perf record -e cpu-clock --call-graph fp ./program
> >+ * $ perf report --call-graph
> >+ *
> >+ * On RISC-V platform, the program being sampled and the C library
> >+ * need to be compiled with * -mbacktrace, otherwise the user
> 
> What is "-mbacktrace"?  I don't remember that ever being a RISC-V GCC option,
> and my compiler doesn't undersand it.  It understands "-fbacktrace" but that
> doesn't produce a frame pointer.
>

It's a csky specific option, I forget to modify the comment.
So it should be -fno-omit-frame-pointer here.

Thanks,
Mao Han

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/3] riscv: Add support for perf registers sampling
  2019-04-25 21:11   ` Palmer Dabbelt
@ 2019-04-29  8:42     ` Mao Han
  0 siblings, 0 replies; 14+ messages in thread
From: Mao Han @ 2019-04-29  8:42 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: linux-riscv, guoren, linux-kernel

On Thu, Apr 25, 2019 at 02:11:02PM -0700, Palmer Dabbelt wrote:
> On Thu, 11 Apr 2019 00:53:49 PDT (-0700), han_mao@c-sky.com wrote:
> >+	PERF_REG_RISCV_S10,
> >+	PERF_REG_RISCV_S11,
> >+	PERF_REG_RISCV_T3,
> >+	PERF_REG_RISCV_T4,
> >+	PERF_REG_RISCV_T5,
> >+	PERF_REG_RISCV_T6,
> >+	PERF_REG_RISCV_MAX,
> >+};
> 
> Is it expected this eventually supports floating-point and vector registers?
> If so, how do we make this extensible?
>

It seems none of current architecture put their fp/vfp registers into this
file, gpr is normally enough for backtrace and context restoration. I'm not
quite understand the problem of extensible. All modification to this file
should be synchronzied as the perf tool is released with the kernel.

Thanks,
Mao Han

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/3] riscv: Add support for libdw
  2019-04-25 21:11   ` Palmer Dabbelt
@ 2019-04-29  8:45     ` Mao Han
  0 siblings, 0 replies; 14+ messages in thread
From: Mao Han @ 2019-04-29  8:45 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: linux-riscv, guoren, linux-kernel

On Thu, Apr 25, 2019 at 02:11:04PM -0700, Palmer Dabbelt wrote:
> On Thu, 11 Apr 2019 00:53:50 PDT (-0700), han_mao@c-sky.com wrote:
> >This patch add support for DWARF register mappings and libdw registers
> >initialization, which is used by perf callchain analyzing when
> >--call-graph=dwarf is given.
> 
> Is there any way to make this the only backtracer?  It's the only one that's
> likely to be useful on RISC-V without recompiling everything with
> -fno-omit-frame-pointer, which has a major performance hit.
>

Frame pointer is the default record mode in record_callchain_opt.
Some generic modification seems required to change this, default to
use dwarf if riscv and show corresponding message in --help.

Thanks,
Mao Han 

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2019-04-29  8:45 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-11  7:53 [PATCH 0/3] riscv: Add perf callchain support Mao Han
2019-04-11  7:53 ` [PATCH 1/3] " Mao Han
2019-04-11 14:24   ` Christoph Hellwig
2019-04-25 21:11   ` Palmer Dabbelt
2019-04-29  8:39     ` Mao Han
2019-04-11  7:53 ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
2019-04-25 21:11   ` Palmer Dabbelt
2019-04-29  8:42     ` Mao Han
2019-04-11  7:53 ` [PATCH 3/3] riscv: Add support for libdw Mao Han
2019-04-25 21:11   ` Palmer Dabbelt
2019-04-29  8:45     ` Mao Han
2019-04-11 14:14 ` [PATCH 0/3] riscv: Add perf callchain support Christoph Hellwig
2019-04-12  9:38   ` [PATCH 2/3] riscv: Add support for perf registers sampling Mao Han
2019-04-13  8:01     ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).