mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
x86/paravirt: Trace contended_release on unlock
On PARAVIRT_SPINLOCKS=y kernels queued_spin_unlock() is dispatched through a static_call(). Those PARAVIRT_SPINLOCKS=y kernels are quite popular. Gating contended_release behind a static branch would leave a NOP on the unlock hot path even, when the tracepoint is disabled. Since the static_call() is already present, swap its target to a traced unlock, when the tracepoint is enabled instead. When contended_release tracepoint is disabled the target is the plain unlock (an inline store on native x86_64), so the unlock path is unchanged and the tracepoint is truly zero-cost. Provide two traced variants, native_queued_spin_unlock_traced() and pv_queued_spin_unlock_traced(), so each tail-calls its own base unlock directly rather than recursing through the now-traced static_call(). Teach pv_is_native_spin_unlock() that the traced native variant still counts as native. Only PARAVIRT_SPINLOCKS=y is affected. PARAVIRT_SPINLOCKS=n keeps the generic static-branch path. Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Dmitry Ilvokhin <d@ilvokhin.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Juergen Gross <jgross@suse.com> Link: https://patch.msgid.link/17fa67f9fa4cf93f1150725e89f5f916e41a9b6f.1785778551.git.d@ilvokhin.com
This commit is contained in:
parent
b359800c69
commit
087116fefb
|
|
@ -99,6 +99,8 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
|
|||
|
||||
void __init native_pv_lock_init(void);
|
||||
__visible void __native_queued_spin_unlock(struct qspinlock *lock);
|
||||
__visible void native_queued_spin_unlock_traced(struct qspinlock *lock);
|
||||
__visible void pv_queued_spin_unlock_traced(struct qspinlock *lock);
|
||||
bool pv_is_native_spin_unlock(void);
|
||||
__visible bool __native_vcpu_is_preempted(long cpu);
|
||||
bool pv_is_native_vcpu_is_preempted(void);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <trace/events/lock.h>
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key);
|
||||
|
||||
|
|
@ -30,10 +31,58 @@ EXPORT_STATIC_CALL_TRAMP(queued_spin_lock_slowpath);
|
|||
DEFINE_STATIC_CALL(queued_spin_unlock, __raw_callee_save___native_queued_spin_unlock);
|
||||
EXPORT_STATIC_CALL_TRAMP(queued_spin_unlock);
|
||||
|
||||
/*
|
||||
* Traced unlock variants, swapped in via static_call while the
|
||||
* contended_release tracepoint is enabled. Two of them, so each tail calls its
|
||||
* own base directly.
|
||||
*/
|
||||
__visible void native_queued_spin_unlock_traced(struct qspinlock *lock)
|
||||
{
|
||||
if (queued_spin_is_contended(lock))
|
||||
trace_call__contended_release(lock);
|
||||
native_queued_spin_unlock(lock);
|
||||
}
|
||||
PV_CALLEE_SAVE_REGS_THUNK(native_queued_spin_unlock_traced);
|
||||
|
||||
__visible void pv_queued_spin_unlock_traced(struct qspinlock *lock)
|
||||
{
|
||||
if (queued_spin_is_contended(lock))
|
||||
trace_call__contended_release(lock);
|
||||
__raw_callee_save___pv_queued_spin_unlock(lock);
|
||||
}
|
||||
PV_CALLEE_SAVE_REGS_THUNK(pv_queued_spin_unlock_traced);
|
||||
|
||||
bool pv_is_native_spin_unlock(void)
|
||||
{
|
||||
return static_call_query(queued_spin_unlock) ==
|
||||
__raw_callee_save___native_queued_spin_unlock;
|
||||
void *unlock = static_call_query(queued_spin_unlock);
|
||||
|
||||
return unlock == __raw_callee_save___native_queued_spin_unlock ||
|
||||
unlock == __raw_callee_save_native_queued_spin_unlock_traced;
|
||||
}
|
||||
|
||||
int arch_contended_release_trace_reg(void)
|
||||
{
|
||||
void *cur = static_call_query(queued_spin_unlock);
|
||||
|
||||
if (cur == __raw_callee_save___native_queued_spin_unlock)
|
||||
static_call_update(queued_spin_unlock,
|
||||
__raw_callee_save_native_queued_spin_unlock_traced);
|
||||
else if (cur == __raw_callee_save___pv_queued_spin_unlock)
|
||||
static_call_update(queued_spin_unlock,
|
||||
__raw_callee_save_pv_queued_spin_unlock_traced);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arch_contended_release_trace_unreg(void)
|
||||
{
|
||||
void *cur = static_call_query(queued_spin_unlock);
|
||||
|
||||
if (cur == __raw_callee_save_native_queued_spin_unlock_traced)
|
||||
static_call_update(queued_spin_unlock,
|
||||
__raw_callee_save___native_queued_spin_unlock);
|
||||
else if (cur == __raw_callee_save_pv_queued_spin_unlock_traced)
|
||||
static_call_update(queued_spin_unlock,
|
||||
__raw_callee_save___pv_queued_spin_unlock);
|
||||
}
|
||||
|
||||
__visible bool __native_vcpu_is_preempted(long cpu)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user