-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch add support for perf callchain sampling on riscv platforms. 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: Paul Walmsley <paul.walmsley@sifive.com> Cc: Greentime Hu <green.hu@gmail.com> Cc: Palmer Dabbelt <palmer@sifive.com> Cc: linux-riscv <linux-riscv@lists.infradead.org> Cc: Christoph Hellwig <hch@lst.de> Cc: Guo Ren <guoren@kernel.org> Tested-by: Greentime Hu <greentime.hu@sifive.com> [paul.walmsley@sifive.com: fixed some 'checkpatch.pl --strict' issues; fixed patch description spelling] Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
- Loading branch information
Mao Han
authored and
Paul Walmsley
committed
Sep 4, 2019
1 parent
909548d
commit dbeb90b
Showing
4 changed files
with
101 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// 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; | ||
}; | ||
|
||
/* | ||
* 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; | ||
if (ra != 0) | ||
perf_callchain_store(entry, ra); | ||
else | ||
return 0; | ||
|
||
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 -fno-omit-frame-pointer, 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 perf in guest mode. */ | ||
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 (fp && !(fp & 0x3) && entry->nr < entry->max_stack) | ||
fp = user_backtrace(entry, fp, 0); | ||
} | ||
|
||
bool fill_callchain(unsigned long pc, void *entry) | ||
{ | ||
return perf_callchain_store(entry, pc); | ||
} | ||
|
||
void notrace walk_stackframe(struct task_struct *task, | ||
struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg); | ||
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, | ||
struct pt_regs *regs) | ||
{ | ||
/* RISC-V does not support perf in guest mode. */ | ||
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { | ||
pr_warn("RISC-V does not support perf in guest mode!"); | ||
return; | ||
} | ||
|
||
walk_stackframe(NULL, regs, fill_callchain, entry); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters