]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
riscv: perf: add guest vs host distinction
authorQuan Zhou <zhouquan@iscas.ac.cn>
Tue, 15 Oct 2024 02:58:24 +0000 (10:58 +0800)
committerAnup Patel <anup@brainfault.org>
Mon, 28 Oct 2024 11:11:12 +0000 (16:41 +0530)
Introduce basic guest support in perf, enabling it to distinguish
between PMU interrupts in the host or guest, and collect
fundamental information.

Signed-off-by: Quan Zhou <zhouquan@iscas.ac.cn>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Link: https://lore.kernel.org/r/a67d527dc1b11493fe11f7f53584772fdd983744.1728957131.git.zhouquan@iscas.ac.cn
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/include/asm/perf_event.h
arch/riscv/kernel/perf_callchain.c

index 665bbc9b2f840a5272eb493d799f21dab73dfd25..38926b4a902d3c813d85108913870d77a8f2751a 100644 (file)
@@ -8,7 +8,11 @@
 #ifndef _ASM_RISCV_PERF_EVENT_H
 #define _ASM_RISCV_PERF_EVENT_H
 
+#ifdef CONFIG_PERF_EVENTS
 #include <linux/perf_event.h>
+extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
+extern unsigned long perf_misc_flags(struct pt_regs *regs);
+#define perf_misc_flags(regs) perf_misc_flags(regs)
 #define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs
 
 #define perf_arch_fetch_caller_regs(regs, __ip) { \
@@ -17,4 +21,6 @@
        (regs)->sp = current_stack_pointer; \
        (regs)->status = SR_PP; \
 }
+#endif
+
 #endif /* _ASM_RISCV_PERF_EVENT_H */
index c7468af77c663ab30d5728476e882d0882d1afa5..c2c81a80f81640fc58ad5f96dd1a569aa567a301 100644 (file)
@@ -28,11 +28,49 @@ static bool fill_callchain(void *entry, unsigned long pc)
 void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
                         struct pt_regs *regs)
 {
+       if (perf_guest_state()) {
+               /* TODO: We don't support guest os callchain now */
+               return;
+       }
+
        arch_stack_walk_user(fill_callchain, entry, regs);
 }
 
 void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
                           struct pt_regs *regs)
 {
+       if (perf_guest_state()) {
+               /* TODO: We don't support guest os callchain now */
+               return;
+       }
+
        walk_stackframe(NULL, regs, fill_callchain, entry);
 }
+
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+       if (perf_guest_state())
+               return perf_guest_get_ip();
+
+       return instruction_pointer(regs);
+}
+
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+       unsigned int guest_state = perf_guest_state();
+       unsigned long misc = 0;
+
+       if (guest_state) {
+               if (guest_state & PERF_GUEST_USER)
+                       misc |= PERF_RECORD_MISC_GUEST_USER;
+               else
+                       misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+       } else {
+               if (user_mode(regs))
+                       misc |= PERF_RECORD_MISC_USER;
+               else
+                       misc |= PERF_RECORD_MISC_KERNEL;
+       }
+
+       return misc;
+}