Message ID | 20210622094306.8336-2-lingshan.zhu@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [V7,01/18] perf/core: Use static_call to optimize perf_guest_info_callbacks | expand |
On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: > diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c > index 8f71dd72ef95..c71af4cfba9b 100644 > --- a/arch/x86/events/core.c > +++ b/arch/x86/events/core.c > @@ -90,6 +90,27 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases); > */ > DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs); > > +DEFINE_STATIC_CALL_RET0(x86_guest_state, *(perf_guest_cbs->state)); > +DEFINE_STATIC_CALL_RET0(x86_guest_get_ip, *(perf_guest_cbs->get_ip)); > +DEFINE_STATIC_CALL_RET0(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); > + > +void arch_perf_update_guest_cbs(void) > +{ > + static_call_update(x86_guest_state, (void *)&__static_call_return0); > + static_call_update(x86_guest_get_ip, (void *)&__static_call_return0); > + static_call_update(x86_guest_handle_intel_pt_intr, (void *)&__static_call_return0); > + > + if (perf_guest_cbs && perf_guest_cbs->state) > + static_call_update(x86_guest_state, perf_guest_cbs->state); > + > + if (perf_guest_cbs && perf_guest_cbs->get_ip) > + static_call_update(x86_guest_get_ip, perf_guest_cbs->get_ip); > + > + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) > + static_call_update(x86_guest_handle_intel_pt_intr, > + perf_guest_cbs->handle_intel_pt_intr); > +} Coding style wants { } on that last if().
On Fri, 2021-07-02 at 13:22 +0200, Peter Zijlstra wrote: > On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: > > diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c [] > > @@ -90,6 +90,27 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases); > > */ > > DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs); > > > > > > +DEFINE_STATIC_CALL_RET0(x86_guest_state, *(perf_guest_cbs->state)); > > +DEFINE_STATIC_CALL_RET0(x86_guest_get_ip, *(perf_guest_cbs->get_ip)); > > +DEFINE_STATIC_CALL_RET0(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); > > + > > +void arch_perf_update_guest_cbs(void) > > +{ > > + static_call_update(x86_guest_state, (void *)&__static_call_return0); > > + static_call_update(x86_guest_get_ip, (void *)&__static_call_return0); > > + static_call_update(x86_guest_handle_intel_pt_intr, (void *)&__static_call_return0); > > + > > + if (perf_guest_cbs && perf_guest_cbs->state) > > + static_call_update(x86_guest_state, perf_guest_cbs->state); > > + > > + if (perf_guest_cbs && perf_guest_cbs->get_ip) > > + static_call_update(x86_guest_get_ip, perf_guest_cbs->get_ip); > > + > > + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) > > + static_call_update(x86_guest_handle_intel_pt_intr, > > + perf_guest_cbs->handle_intel_pt_intr); > > +} > > Coding style wants { } on that last if(). That's just your personal preference. The coding-style document doesn't require that. It just says single statement. It's not the number of vertical lines or characters required for the statement. ---------------------------------- Do not unnecessarily use braces where a single statement will do. .. code-block:: c if (condition) action(); and .. code-block:: none if (condition) do_this(); else do_that(); This does not apply if only one branch of a conditional statement is a single statement; in the latter case use braces in both branches:
On Fri, Jul 02, 2021 at 09:00:22AM -0700, Joe Perches wrote: > On Fri, 2021-07-02 at 13:22 +0200, Peter Zijlstra wrote: > > On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: > > > diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c > [] > > > @@ -90,6 +90,27 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases); > > > */ > > > DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs); > > > > > > > > > +DEFINE_STATIC_CALL_RET0(x86_guest_state, *(perf_guest_cbs->state)); > > > +DEFINE_STATIC_CALL_RET0(x86_guest_get_ip, *(perf_guest_cbs->get_ip)); > > > +DEFINE_STATIC_CALL_RET0(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); > > > + > > > +void arch_perf_update_guest_cbs(void) > > > +{ > > > + static_call_update(x86_guest_state, (void *)&__static_call_return0); > > > + static_call_update(x86_guest_get_ip, (void *)&__static_call_return0); > > > + static_call_update(x86_guest_handle_intel_pt_intr, (void *)&__static_call_return0); > > > + > > > + if (perf_guest_cbs && perf_guest_cbs->state) > > > + static_call_update(x86_guest_state, perf_guest_cbs->state); > > > + > > > + if (perf_guest_cbs && perf_guest_cbs->get_ip) > > > + static_call_update(x86_guest_get_ip, perf_guest_cbs->get_ip); > > > + > > > + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) > > > + static_call_update(x86_guest_handle_intel_pt_intr, > > > + perf_guest_cbs->handle_intel_pt_intr); > > > +} > > > > Coding style wants { } on that last if(). > > That's just your personal preference. As a maintainer, those carry weight, also that's tip rules: https://lore.kernel.org/lkml/20181107171149.165693799@linutronix.de/
On Fri, Jul 02, 2021 at 09:00:22AM -0700, Joe Perches wrote: > On Fri, 2021-07-02 at 13:22 +0200, Peter Zijlstra wrote: > > On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: > > > diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c > [] > > > @@ -90,6 +90,27 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases); > > > */ > > > DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs); > > > > > > > > > +DEFINE_STATIC_CALL_RET0(x86_guest_state, *(perf_guest_cbs->state)); > > > +DEFINE_STATIC_CALL_RET0(x86_guest_get_ip, *(perf_guest_cbs->get_ip)); > > > +DEFINE_STATIC_CALL_RET0(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); > > > + > > > +void arch_perf_update_guest_cbs(void) > > > +{ > > > + static_call_update(x86_guest_state, (void *)&__static_call_return0); > > > + static_call_update(x86_guest_get_ip, (void *)&__static_call_return0); > > > + static_call_update(x86_guest_handle_intel_pt_intr, (void *)&__static_call_return0); > > > + > > > + if (perf_guest_cbs && perf_guest_cbs->state) > > > + static_call_update(x86_guest_state, perf_guest_cbs->state); > > > + > > > + if (perf_guest_cbs && perf_guest_cbs->get_ip) > > > + static_call_update(x86_guest_get_ip, perf_guest_cbs->get_ip); > > > + > > > + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) > > > + static_call_update(x86_guest_handle_intel_pt_intr, > > > + perf_guest_cbs->handle_intel_pt_intr); > > > +} > > > > Coding style wants { } on that last if(). > > That's just your personal preference. > > The coding-style document doesn't require that. > > It just says single statement. It's not the number of > vertical lines or characters required for the statement. > > ---------------------------------- > > Do not unnecessarily use braces where a single statement will do. > > .. code-block:: c > > if (condition) > action(); > > and > > .. code-block:: none > > if (condition) > do_this(); > else > do_that(); > > This does not apply if only one branch of a conditional statement is a single > statement; in the latter case use braces in both branches: Immediately after this, we say: | Also, use braces when a loop contains more than a single simple statement: | | .. code-block:: c | | while (condition) { | if (test) | do_something(); | } | ... and while that says "a loop", the principle is obviously supposed to apply to conditionals too; structurally they're no different. We should just fix the documentation to say "a loop or conditional", or something to that effect. Mark.
On Fri, 2021-07-02 at 18:19 +0200, Peter Zijlstra wrote: > On Fri, Jul 02, 2021 at 09:00:22AM -0700, Joe Perches wrote: > > On Fri, 2021-07-02 at 13:22 +0200, Peter Zijlstra wrote: > > > On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: > > > > diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c > > [] > > > > + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) > > > > + static_call_update(x86_guest_handle_intel_pt_intr, > > > > + perf_guest_cbs->handle_intel_pt_intr); > > > > +} > > > > > > Coding style wants { } on that last if(). > > > > That's just your personal preference. > > As a maintainer, those carry weight, also that's tip rules: > > https://lore.kernel.org/lkml/20181107171149.165693799@linutronix.de/ Right, definitely so. But merely referencing 'coding style' is ambiguous at best. btw: ASCII commonly refers to '{' and '}', the curly brackets, to be braces and '[' and ']', the square brackets, to be brackets. It might be clearer to use that terminology. belts and braces, etc... cheers, Joe ---------------- +Bracket rules +^^^^^^^^^^^^^ + +Brackets should be omitted only if the statement which follows 'if', 'for', +'while' etc. is truly a single line:: + + if (foo) + do_something(); + +The following is not considered to be a single line statement even +though C does not require brackets:: + + for (i = 0; i < end; i++) + if (foo[i]) + do_something(foo[i]); + +Adding brackets around the outer loop enhances the reading flow:: + + for (i = 0; i < end; i++) { + if (foo[i]) + do_something(foo[i]); + }
On Fri, 2021-07-02 at 17:38 +0100, Mark Rutland wrote: > On Fri, Jul 02, 2021 at 09:00:22AM -0700, Joe Perches wrote: > > On Fri, 2021-07-02 at 13:22 +0200, Peter Zijlstra wrote: > > > On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: [] > > > > + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) > > > > + static_call_update(x86_guest_handle_intel_pt_intr, > > > > + perf_guest_cbs->handle_intel_pt_intr); > > > > +} > > > > > > Coding style wants { } on that last if(). > > > > That's just your personal preference. > > > > The coding-style document doesn't require that. > > > > It just says single statement. It's not the number of > > vertical lines or characters required for the statement. > > > > ---------------------------------- > > > > Do not unnecessarily use braces where a single statement will do. > > > > .. code-block:: c > > > > if (condition) > > action(); > > > > and > > > > .. code-block:: none > > > > if (condition) > > do_this(); > > else > > do_that(); > > > > This does not apply if only one branch of a conditional statement is a single > > statement; in the latter case use braces in both branches: > > Immediately after this, we say: > > > Also, use braces when a loop contains more than a single simple statement: > > > > .. code-block:: c > > > > while (condition) { > > if (test) > > do_something(); > > } > > > > ... and while that says "a loop", the principle is obviously supposed to > apply to conditionals too; structurally they're no different. We should > just fix the documentation to say "a loop or conditional", or something > to that effect. <shrug> Maybe. I think there are _way_ too many existing obvious uses where the statement that follows a conditional is multi-line. if (foo) printk(fmt, args...); where the braces wouldn't add anything other than more vertical space. I don't much care one way or another other than Peter's somewhat ambiguous use of the phrase "coding style". checkpatch doesn't emit a message either way. ----------------------------------------- $ cat t_multiline.c // SPDX-License-Identifier: GPL-2.0-only void foo(void) { if (foo) { pr_info(fmt, args); } if (foo) pr_info(fmt, args); if (foo) pr_info(fmt, args); } $ ./scripts/checkpatch.pl -f --strict t_multiline.c total: 0 errors, 0 warnings, 0 checks, 16 lines checked t_multiline.c has no obvious style problems and is ready for submission. ----------------------------------------- cheers, Joe
On 7/2/2021 7:22 PM, Peter Zijlstra wrote: > On Tue, Jun 22, 2021 at 05:42:49PM +0800, Zhu Lingshan wrote: >> diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c >> index 8f71dd72ef95..c71af4cfba9b 100644 >> --- a/arch/x86/events/core.c >> +++ b/arch/x86/events/core.c >> @@ -90,6 +90,27 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases); >> */ >> DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs); >> >> +DEFINE_STATIC_CALL_RET0(x86_guest_state, *(perf_guest_cbs->state)); >> +DEFINE_STATIC_CALL_RET0(x86_guest_get_ip, *(perf_guest_cbs->get_ip)); >> +DEFINE_STATIC_CALL_RET0(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); >> + >> +void arch_perf_update_guest_cbs(void) >> +{ >> + static_call_update(x86_guest_state, (void *)&__static_call_return0); >> + static_call_update(x86_guest_get_ip, (void *)&__static_call_return0); >> + static_call_update(x86_guest_handle_intel_pt_intr, (void *)&__static_call_return0); >> + >> + if (perf_guest_cbs && perf_guest_cbs->state) >> + static_call_update(x86_guest_state, perf_guest_cbs->state); >> + >> + if (perf_guest_cbs && perf_guest_cbs->get_ip) >> + static_call_update(x86_guest_get_ip, perf_guest_cbs->get_ip); >> + >> + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) >> + static_call_update(x86_guest_handle_intel_pt_intr, >> + perf_guest_cbs->handle_intel_pt_intr); >> +} > Coding style wants { } on that last if(). will fix these coding style issues in V8 Thanks!
diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c index 3b69a76d341e..1ce30f86d6c7 100644 --- a/arch/arm/kernel/perf_callchain.c +++ b/arch/arm/kernel/perf_callchain.c @@ -64,7 +64,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs { struct frame_tail __user *tail; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (perf_guest_cbs && perf_guest_cbs->state()) { /* We don't support guest os callchain now */ return; } @@ -100,7 +100,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re { struct stackframe fr; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (perf_guest_cbs && perf_guest_cbs->state()) { /* We don't support guest os callchain now */ return; } @@ -111,8 +111,8 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re unsigned long perf_instruction_pointer(struct pt_regs *regs) { - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) - return perf_guest_cbs->get_guest_ip(); + if (perf_guest_cbs && perf_guest_cbs->state()) + return perf_guest_cbs->get_ip(); return instruction_pointer(regs); } @@ -120,9 +120,13 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) unsigned long perf_misc_flags(struct pt_regs *regs) { int misc = 0; + unsigned int state = 0; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - if (perf_guest_cbs->is_user_mode()) + if (perf_guest_cbs) + state = perf_guest_cbs->state(); + + if (perf_guest_cbs && state) { + if (state & PERF_GUEST_USER) misc |= PERF_RECORD_MISC_GUEST_USER; else misc |= PERF_RECORD_MISC_GUEST_KERNEL; diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c index 88ff471b0bce..5df2bd5d12ba 100644 --- a/arch/arm64/kernel/perf_callchain.c +++ b/arch/arm64/kernel/perf_callchain.c @@ -5,6 +5,7 @@ * Copyright (C) 2015 ARM Limited */ #include <linux/perf_event.h> +#include <linux/static_call.h> #include <linux/uaccess.h> #include <asm/pointer_auth.h> @@ -99,10 +100,25 @@ compat_user_backtrace(struct compat_frame_tail __user *tail, } #endif /* CONFIG_COMPAT */ +DEFINE_STATIC_CALL_RET0(arm64_guest_state, *(perf_guest_cbs->state)); +DEFINE_STATIC_CALL_RET0(arm64_guest_get_ip, *(perf_guest_cbs->get_ip)); + +void arch_perf_update_guest_cbs(void) +{ + static_call_update(arm64_guest_state, (void *)&__static_call_return0); + static_call_update(arm64_guest_get_ip, (void *)&__static_call_return0); + + if (perf_guest_cbs && perf_guest_cbs->state) + static_call_update(arm64_guest_state, perf_guest_cbs->state); + + if (perf_guest_cbs && perf_guest_cbs->get_ip) + static_call_update(arm64_guest_get_ip, perf_guest_cbs->get_ip); +} + void perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (static_call(arm64_guest_state)()) { /* We don't support guest os callchain now */ return; } @@ -149,7 +165,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, { struct stackframe frame; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (static_call(arm64_guest_state)()) { /* We don't support guest os callchain now */ return; } @@ -160,8 +176,8 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, unsigned long perf_instruction_pointer(struct pt_regs *regs) { - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) - return perf_guest_cbs->get_guest_ip(); + if (static_call(arm64_guest_state)()) + return static_call(arm64_guest_get_ip)(); return instruction_pointer(regs); } @@ -169,9 +185,10 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) unsigned long perf_misc_flags(struct pt_regs *regs) { int misc = 0; + unsigned int guest = static_call(arm64_guest_state)(); - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - if (perf_guest_cbs->is_user_mode()) + if (guest) { + if (guest & PERF_GUEST_USER) misc |= PERF_RECORD_MISC_GUEST_USER; else misc |= PERF_RECORD_MISC_GUEST_KERNEL; diff --git a/arch/arm64/kvm/perf.c b/arch/arm64/kvm/perf.c index 151c31fb9860..8a3387e58f42 100644 --- a/arch/arm64/kvm/perf.c +++ b/arch/arm64/kvm/perf.c @@ -13,21 +13,20 @@ DEFINE_STATIC_KEY_FALSE(kvm_arm_pmu_available); -static int kvm_is_in_guest(void) -{ - return kvm_get_running_vcpu() != NULL; -} - -static int kvm_is_user_mode(void) +static unsigned int kvm_guest_state(void) { struct kvm_vcpu *vcpu; + unsigned int state = 0; + + if (kvm_get_running_vcpu()) + state |= PERF_GUEST_ACTIVE; vcpu = kvm_get_running_vcpu(); - if (vcpu) - return !vcpu_mode_priv(vcpu); + if (vcpu && !vcpu_mode_priv(vcpu)) + state |= PERF_GUEST_USER; - return 0; + return state; } static unsigned long kvm_get_guest_ip(void) @@ -43,9 +42,8 @@ static unsigned long kvm_get_guest_ip(void) } static struct perf_guest_info_callbacks kvm_guest_cbs = { - .is_in_guest = kvm_is_in_guest, - .is_user_mode = kvm_is_user_mode, - .get_guest_ip = kvm_get_guest_ip, + .state = kvm_guest_state, + .get_ip = kvm_get_guest_ip, }; int kvm_perf_init(void) diff --git a/arch/csky/kernel/perf_callchain.c b/arch/csky/kernel/perf_callchain.c index ab55e98ee8f6..3e42239dd1b2 100644 --- a/arch/csky/kernel/perf_callchain.c +++ b/arch/csky/kernel/perf_callchain.c @@ -89,7 +89,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, unsigned long fp = 0; /* C-SKY does not support virtualization. */ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) + if (perf_guest_cbs && perf_guest_cbs->state()) return; fp = regs->regs[4]; @@ -113,7 +113,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct stackframe fr; /* C-SKY does not support virtualization. */ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (perf_guest_cbs && perf_guest_cbs->state()) { pr_warn("C-SKY does not support perf in guest mode!"); return; } diff --git a/arch/nds32/kernel/perf_event_cpu.c b/arch/nds32/kernel/perf_event_cpu.c index 0ce6f9f307e6..1dc32ba842ce 100644 --- a/arch/nds32/kernel/perf_event_cpu.c +++ b/arch/nds32/kernel/perf_event_cpu.c @@ -1371,7 +1371,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, leaf_fp = 0; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (perf_guest_cbs && perf_guest_cbs->state()) { /* We don't support guest os callchain now */ return; } @@ -1481,7 +1481,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, { struct stackframe fr; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (perf_guest_cbs && perf_guest_cbs->state()) { /* We don't support guest os callchain now */ return; } @@ -1494,8 +1494,8 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, unsigned long perf_instruction_pointer(struct pt_regs *regs) { /* However, NDS32 does not support virtualization */ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) - return perf_guest_cbs->get_guest_ip(); + if (perf_guest_cbs && perf_guest_cbs->state()) + return perf_guest_cbs->get_ip(); return instruction_pointer(regs); } @@ -1503,10 +1503,14 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) unsigned long perf_misc_flags(struct pt_regs *regs) { int misc = 0; + unsigned int state = 0; + + if (perf_guest_cbs) + state = perf_guest_cbs->state(); /* However, NDS32 does not support virtualization */ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - if (perf_guest_cbs->is_user_mode()) + if (perf_guest_cbs && state) { + if (state & PERF_GUEST_USER) misc |= PERF_RECORD_MISC_GUEST_USER; else misc |= PERF_RECORD_MISC_GUEST_KERNEL; diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c index 0bb1854dce83..ea63f70cae5d 100644 --- a/arch/riscv/kernel/perf_callchain.c +++ b/arch/riscv/kernel/perf_callchain.c @@ -59,7 +59,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, unsigned long fp = 0; /* RISC-V does not support perf in guest mode. */ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) + if (perf_guest_cbs && perf_guest_cbs->state()) return; fp = regs->s0; @@ -79,7 +79,7 @@ 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()) { + if (perf_guest_cbs && perf_guest_cbs->state()) { pr_warn("RISC-V does not support perf in guest mode!"); return; } diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 8f71dd72ef95..c71af4cfba9b 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -90,6 +90,27 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases); */ DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs); +DEFINE_STATIC_CALL_RET0(x86_guest_state, *(perf_guest_cbs->state)); +DEFINE_STATIC_CALL_RET0(x86_guest_get_ip, *(perf_guest_cbs->get_ip)); +DEFINE_STATIC_CALL_RET0(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); + +void arch_perf_update_guest_cbs(void) +{ + static_call_update(x86_guest_state, (void *)&__static_call_return0); + static_call_update(x86_guest_get_ip, (void *)&__static_call_return0); + static_call_update(x86_guest_handle_intel_pt_intr, (void *)&__static_call_return0); + + if (perf_guest_cbs && perf_guest_cbs->state) + static_call_update(x86_guest_state, perf_guest_cbs->state); + + if (perf_guest_cbs && perf_guest_cbs->get_ip) + static_call_update(x86_guest_get_ip, perf_guest_cbs->get_ip); + + if (perf_guest_cbs && perf_guest_cbs->handle_intel_pt_intr) + static_call_update(x86_guest_handle_intel_pt_intr, + perf_guest_cbs->handle_intel_pt_intr); +} + u64 __read_mostly hw_cache_event_ids [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] @@ -2738,7 +2759,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re struct unwind_state state; unsigned long addr; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (static_call(x86_guest_state)()) { /* TODO: We don't support guest os callchain now */ return; } @@ -2841,7 +2862,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs struct stack_frame frame; const struct stack_frame __user *fp; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (static_call(x86_guest_state)()) { /* TODO: We don't support guest os callchain now */ return; } @@ -2918,18 +2939,21 @@ static unsigned long code_segment_base(struct pt_regs *regs) unsigned long perf_instruction_pointer(struct pt_regs *regs) { - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) - return perf_guest_cbs->get_guest_ip(); + unsigned long ip = static_call(x86_guest_get_ip)(); + + if (likely(!ip)) + ip = regs->ip + code_segment_base(regs); - return regs->ip + code_segment_base(regs); + return ip; } unsigned long perf_misc_flags(struct pt_regs *regs) { + unsigned int guest = static_call(x86_guest_state)(); int misc = 0; - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - if (perf_guest_cbs->is_user_mode()) + if (guest) { + if (guest & PERF_GUEST_USER) misc |= PERF_RECORD_MISC_GUEST_USER; else misc |= PERF_RECORD_MISC_GUEST_KERNEL; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index e28892270c58..430f5743f3ca 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2780,6 +2780,8 @@ static void intel_pmu_reset(void) local_irq_restore(flags); } +DECLARE_STATIC_CALL(x86_guest_handle_intel_pt_intr, *(perf_guest_cbs->handle_intel_pt_intr)); + static int handle_pmi_common(struct pt_regs *regs, u64 status) { struct perf_sample_data data; @@ -2850,10 +2852,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) */ if (__test_and_clear_bit(GLOBAL_STATUS_TRACE_TOPAPMI_BIT, (unsigned long *)&status)) { handled++; - if (unlikely(perf_guest_cbs && perf_guest_cbs->is_in_guest() && - perf_guest_cbs->handle_intel_pt_intr)) - perf_guest_cbs->handle_intel_pt_intr(); - else + if (!static_call(x86_guest_handle_intel_pt_intr)()) intel_pt_interrupt(); } diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 9c7ced0e3171..f752fcf56d76 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1813,7 +1813,7 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu); int kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err); void __kvm_request_immediate_exit(struct kvm_vcpu *vcpu); -int kvm_is_in_guest(void); +unsigned int kvm_guest_state(void); void __user *__x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size); diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 827886c12c16..2dcbd1b30004 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -87,7 +87,7 @@ static void kvm_perf_overflow_intr(struct perf_event *perf_event, * woken up. So we should wake it, but this is impossible from * NMI context. Do it from irq work instead. */ - if (!kvm_is_in_guest()) + if (!kvm_guest_state()) irq_work_queue(&pmc_to_pmu(pmc)->irq_work); else kvm_make_request(KVM_REQ_PMI, pmc->vcpu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b594275d49b5..9cb1c02d348c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8035,44 +8035,47 @@ static void kvm_timer_init(void) DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); EXPORT_PER_CPU_SYMBOL_GPL(current_vcpu); -int kvm_is_in_guest(void) +unsigned int kvm_guest_state(void) { - return __this_cpu_read(current_vcpu) != NULL; -} - -static int kvm_is_user_mode(void) -{ - int user_mode = 3; + struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu); + unsigned int state = 0; - if (__this_cpu_read(current_vcpu)) - user_mode = static_call(kvm_x86_get_cpl)(__this_cpu_read(current_vcpu)); + if (vcpu) { + state |= PERF_GUEST_ACTIVE; + if (static_call(kvm_x86_get_cpl)(vcpu)) + state |= PERF_GUEST_USER; + } - return user_mode != 0; + return state; } -static unsigned long kvm_get_guest_ip(void) +static unsigned long kvm_guest_get_ip(void) { + struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu); unsigned long ip = 0; - if (__this_cpu_read(current_vcpu)) - ip = kvm_rip_read(__this_cpu_read(current_vcpu)); + if (vcpu) + ip = kvm_rip_read(vcpu); return ip; } -static void kvm_handle_intel_pt_intr(void) +static unsigned int kvm_handle_intel_pt_intr(void) { struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu); + if (!vcpu) + return 0; + kvm_make_request(KVM_REQ_PMI, vcpu); __set_bit(MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT, (unsigned long *)&vcpu->arch.pmu.global_status); + return 1; } static struct perf_guest_info_callbacks kvm_guest_cbs = { - .is_in_guest = kvm_is_in_guest, - .is_user_mode = kvm_is_user_mode, - .get_guest_ip = kvm_get_guest_ip, + .state = kvm_guest_state, + .get_ip = kvm_guest_get_ip, .handle_intel_pt_intr = kvm_handle_intel_pt_intr, }; diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index e13b0b49fcdf..7352cf002b87 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -413,34 +413,30 @@ int pmu_apic_update(uint32_t val) } /* perf callbacks */ -static int xen_is_in_guest(void) +static unsigned int xen_guest_state(void) { const struct xen_pmu_data *xenpmu_data = get_xenpmu_data(); + unsigned int state = 0; if (!xenpmu_data) { pr_warn_once("%s: pmudata not initialized\n", __func__); - return 0; + return state; } if (!xen_initial_domain() || (xenpmu_data->domain_id >= DOMID_SELF)) - return 0; - - return 1; -} + return state; -static int xen_is_user_mode(void) -{ - const struct xen_pmu_data *xenpmu_data = get_xenpmu_data(); + state |= PERF_GUEST_ACTIVE; - if (!xenpmu_data) { - pr_warn_once("%s: pmudata not initialized\n", __func__); - return 0; + if (xenpmu_data->pmu.pmu_flags & PMU_SAMPLE_PV) { + if (xenpmu_data->pmu.pmu_flags & PMU_SAMPLE_USER) + state |= PERF_GUEST_USER; + } else { + if (!!(xenpmu_data->pmu.r.regs.cpl & 3)) + state |= PERF_GUEST_USER; } - if (xenpmu_data->pmu.pmu_flags & PMU_SAMPLE_PV) - return (xenpmu_data->pmu.pmu_flags & PMU_SAMPLE_USER); - else - return !!(xenpmu_data->pmu.r.regs.cpl & 3); + return state; } static unsigned long xen_get_guest_ip(void) @@ -456,9 +452,8 @@ static unsigned long xen_get_guest_ip(void) } static struct perf_guest_info_callbacks xen_guest_cbs = { - .is_in_guest = xen_is_in_guest, - .is_user_mode = xen_is_user_mode, - .get_guest_ip = xen_get_guest_ip, + .state = xen_guest_state, + .get_ip = xen_get_guest_ip, }; /* Convert registers from Xen's format to Linux' */ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f5a6a2f069ed..8065e5f093f4 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -26,11 +26,13 @@ # include <asm/local64.h> #endif +#define PERF_GUEST_ACTIVE 0x01 +#define PERF_GUEST_USER 0x02 + struct perf_guest_info_callbacks { - int (*is_in_guest)(void); - int (*is_user_mode)(void); - unsigned long (*get_guest_ip)(void); - void (*handle_intel_pt_intr)(void); + unsigned int (*state)(void); + unsigned long (*get_ip)(void); + unsigned int (*handle_intel_pt_intr)(void); }; #ifdef CONFIG_HAVE_HW_BREAKPOINT @@ -1237,6 +1239,8 @@ extern void perf_event_bpf_event(struct bpf_prog *prog, u16 flags); extern struct perf_guest_info_callbacks *perf_guest_cbs; +extern void __weak arch_perf_update_guest_cbs(void); + extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); diff --git a/kernel/events/core.c b/kernel/events/core.c index 6fee4a7e88d7..101fa7d0bfda 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6479,9 +6479,18 @@ static void perf_pending_event(struct irq_work *entry) */ struct perf_guest_info_callbacks *perf_guest_cbs; +/* explicitly use __weak to fix duplicate symbol error */ +void __weak arch_perf_update_guest_cbs(void) +{ +} + int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) { + if (WARN_ON_ONCE(perf_guest_cbs)) + return -EBUSY; + perf_guest_cbs = cbs; + arch_perf_update_guest_cbs(); return 0; } EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks);