Skip to content

Commit 1c34305

Browse files
sean-jcPeter Zijlstra
authored andcommitted
perf: Add wrappers for invoking guest callbacks
Add helpers for the guest callbacks to prepare for burying the callbacks behind a Kconfig (it's a lot easier to provide a few stubs than to #ifdef piles of code), and also to prepare for converting the callbacks to static_call(). perf_instruction_pointer() in particular will have subtle semantics with static_call(), as the "no callbacks" case will return 0 if the callbacks are unregistered between querying guest state and getting the IP. Implement the change now to avoid a functional change when adding static_call() support, and because the new helper needs to return _something_ in this case. Signed-off-by: Sean Christopherson <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Paolo Bonzini <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b9f5621 commit 1c34305

File tree

4 files changed

+35
-25
lines changed

4 files changed

+35
-25
lines changed

arch/arm64/kernel/perf_callchain.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@ compat_user_backtrace(struct compat_frame_tail __user *tail,
102102
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
103103
struct pt_regs *regs)
104104
{
105-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
106-
107-
if (guest_cbs && guest_cbs->state()) {
105+
if (perf_guest_state()) {
108106
/* We don't support guest os callchain now */
109107
return;
110108
}
@@ -149,10 +147,9 @@ static bool callchain_trace(void *data, unsigned long pc)
149147
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
150148
struct pt_regs *regs)
151149
{
152-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
153150
struct stackframe frame;
154151

155-
if (guest_cbs && guest_cbs->state()) {
152+
if (perf_guest_state()) {
156153
/* We don't support guest os callchain now */
157154
return;
158155
}
@@ -163,18 +160,15 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
163160

164161
unsigned long perf_instruction_pointer(struct pt_regs *regs)
165162
{
166-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
167-
168-
if (guest_cbs && guest_cbs->state())
169-
return guest_cbs->get_ip();
163+
if (perf_guest_state())
164+
return perf_guest_get_ip();
170165

171166
return instruction_pointer(regs);
172167
}
173168

174169
unsigned long perf_misc_flags(struct pt_regs *regs)
175170
{
176-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
177-
unsigned int guest_state = guest_cbs ? guest_cbs->state() : 0;
171+
unsigned int guest_state = perf_guest_state();
178172
int misc = 0;
179173

180174
if (guest_state) {

arch/x86/events/core.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2768,11 +2768,10 @@ static bool perf_hw_regs(struct pt_regs *regs)
27682768
void
27692769
perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
27702770
{
2771-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
27722771
struct unwind_state state;
27732772
unsigned long addr;
27742773

2775-
if (guest_cbs && guest_cbs->state()) {
2774+
if (perf_guest_state()) {
27762775
/* TODO: We don't support guest os callchain now */
27772776
return;
27782777
}
@@ -2872,11 +2871,10 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry_ctx *ent
28722871
void
28732872
perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
28742873
{
2875-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
28762874
struct stack_frame frame;
28772875
const struct stack_frame __user *fp;
28782876

2879-
if (guest_cbs && guest_cbs->state()) {
2877+
if (perf_guest_state()) {
28802878
/* TODO: We don't support guest os callchain now */
28812879
return;
28822880
}
@@ -2953,18 +2951,15 @@ static unsigned long code_segment_base(struct pt_regs *regs)
29532951

29542952
unsigned long perf_instruction_pointer(struct pt_regs *regs)
29552953
{
2956-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
2957-
2958-
if (guest_cbs && guest_cbs->state())
2959-
return guest_cbs->get_ip();
2954+
if (perf_guest_state())
2955+
return perf_guest_get_ip();
29602956

29612957
return regs->ip + code_segment_base(regs);
29622958
}
29632959

29642960
unsigned long perf_misc_flags(struct pt_regs *regs)
29652961
{
2966-
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
2967-
unsigned int guest_state = guest_cbs ? guest_cbs->state() : 0;
2962+
unsigned int guest_state = perf_guest_state();
29682963
int misc = 0;
29692964

29702965
if (guest_state) {

arch/x86/events/intel/core.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,7 +2837,6 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
28372837
{
28382838
struct perf_sample_data data;
28392839
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2840-
struct perf_guest_info_callbacks *guest_cbs;
28412840
int bit;
28422841
int handled = 0;
28432842
u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl);
@@ -2904,9 +2903,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
29042903
*/
29052904
if (__test_and_clear_bit(GLOBAL_STATUS_TRACE_TOPAPMI_BIT, (unsigned long *)&status)) {
29062905
handled++;
2907-
2908-
guest_cbs = perf_get_guest_cbs();
2909-
if (likely(!guest_cbs || !guest_cbs->handle_intel_pt_intr()))
2906+
if (!perf_guest_handle_intel_pt_intr())
29102907
intel_pt_interrupt();
29112908
}
29122909

include/linux/perf_event.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,30 @@ static inline struct perf_guest_info_callbacks *perf_get_guest_cbs(void)
12541254
*/
12551255
return rcu_dereference(perf_guest_cbs);
12561256
}
1257+
static inline unsigned int perf_guest_state(void)
1258+
{
1259+
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
1260+
1261+
return guest_cbs ? guest_cbs->state() : 0;
1262+
}
1263+
static inline unsigned long perf_guest_get_ip(void)
1264+
{
1265+
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
1266+
1267+
/*
1268+
* Arbitrarily return '0' in the unlikely scenario that the callbacks
1269+
* are unregistered between checking guest state and getting the IP.
1270+
*/
1271+
return guest_cbs ? guest_cbs->get_ip() : 0;
1272+
}
1273+
static inline unsigned int perf_guest_handle_intel_pt_intr(void)
1274+
{
1275+
struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
1276+
1277+
if (guest_cbs && guest_cbs->handle_intel_pt_intr)
1278+
return guest_cbs->handle_intel_pt_intr();
1279+
return 0;
1280+
}
12571281
extern void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
12581282
extern void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
12591283

0 commit comments

Comments
 (0)