locking: contended_release tracepoint instrumentation
Subsystems (5)
v3 cover locking: contended_release tracepoint instrumentation
The existing contention_begin/contention_end tracepoints fire on the waiter side. The lock holder's identity and stack can be captured at contention_begin time (e.g. perf lock contention --lock-owner), but this reflects the holder's state when a waiter arrives, not when the lock is actually released.
This series adds a contended_release tracepoint that fires on the holder side when a lock with waiters is released. This provides:
- Hold time estimation: when the holder's own acquisition was contended, its contention_end (acquisition) and contended_release can be correlated to measure how long the lock was held under contention.
- The holder's stack at release time, which may differ from what perf lock contention --lock-owner captures if the holder does significant work between the waiter's arrival and the unlock.
The series is structured as follows:
1. Remove unnecessary linux/sched.h include from trace/events/lock.h.
2. Extract __percpu_up_read() out of the inline percpu_up_read() to avoid binary size increase from adding a tracepoint.
3. Add contended_release tracepoint and instrument sleepable locks:
mutex, rtmutex, semaphore, rwsem, percpu-rwsem, and rwbase_rt.
4. RFC. Extend contended_release to queued spinlocks and queued rwlocks.
v2 -> v3:
- Added new patch: extend contended_release tracepoint to queued spinlocks and queued rwlocks (marked as RFC, requesting feedback). This is prompted by Matthew Wilcox's suggestion to try to come up with generic instrumentation, instead of instrumenting each "special" lock manually. See [1] for the discussion.
- Reworked tracepoint placement to fire before the lock is released and before the waiter is woken where possible, for consistency with spinning locks where there is no explicit wake (inspired by Usama Arif's suggestion).
- Remove unnecessary linux/sched.h include from trace/events/lock.h.
RFC -> v2:
- Add trace_contended_release_enabled() guard before waiter checks that exist only for the tracepoint (Steven Rostedt).
- Rename __percpu_up_read_slowpath() to __percpu_up_read() (Peter Zijlstra).
- Add extern for __percpu_up_read() (Peter Zijlstra).
- Squashed tracepoint introduction and usage commits (Masami Hiramatsu).
v2: https://lore.kernel.org/all/[email protected]/
RFC: https://lore.kernel.org/all/[email protected]/
[1]: https://lore.kernel.org/all/[email protected]/
Dmitry Ilvokhin (4):
tracing/lock: Remove unnecessary linux/sched.h include locking/percpu-rwsem: Extract __percpu_up_read()
locking: Add contended_release tracepoint to sleepable locks
locking: Add contended_release tracepoint to spinning locks
include/asm-generic/qrwlock.h | 48 +++++++++++++++++++++++++++------ include/asm-generic/qspinlock.h | 25 +++++++++++++++-- include/linux/percpu-rwsem.h | 15 +++-------- include/trace/events/lock.h | 18 ++++++++++++- kernel/locking/mutex.c | 3 +++ kernel/locking/percpu-rwsem.c | 22 +++++++++++++++ kernel/locking/qrwlock.c | 16 +++++++++++ kernel/locking/qspinlock.c | 8 ++++++ kernel/locking/rtmutex.c | 1 + kernel/locking/rwbase_rt.c | 8 +++++- kernel/locking/rwsem.c | 9 +++++-- kernel/locking/semaphore.c | 4 ++- 12 files changed, 150 insertions(+), 27 deletions(-)
Signature · 1 line
2.52.0
PATCH v3 1/4 tracing/lock: Remove unnecessary linux/sched.h include
None of the trace events in lock.h reference anything from linux/sched.h. Remove the unnecessary include.
--- include/trace/events/lock.h | 1 - 1 file changed, 1 deletion(-)
include/trace/events/lock.h +0 -1
@@ -5,7 +5,6 @@#if !defined(_TRACE_LOCK_H) || defined(TRACE_HEADER_MULTI_READ )#define _TRACE_LOCK_H -#include <linux/sched.h> #include <linux/tracepoint.h> /* flags for lock:contention_begin */
Signature · 1 line
2.52.0
PATCH v3 2/4 locking/percpu-rwsem: Extract __percpu_up_read()
In reply to Dmitry IlvokhinMove the percpu_up_read() slowpath out of the inline function into a new __percpu_up_read() to avoid binary size increase from adding a tracepoint to an inlined function.
--- include/linux/percpu-rwsem.h | 15 +++------------ kernel/locking/percpu-rwsem.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 12 deletions(-)
include/linux/percpu-rwsem.h +3 -12
@@ -107,6 +107,8 @@ static inline bool percpu_down_read_trylock(struct percpu_rw_semaphore *sem)return ret; } +extern void __percpu_up_read (struct percpu_rw_semaphore *sem); +static inline void percpu_up_read (struct percpu_rw_semaphore *sem) {rwsem_release (&sem->dep_map, _RET_IP_);
@@ -118,18 +120,7 @@ static inline void percpu_up_read(struct percpu_rw_semaphore *sem)if (likely (rcu_sync_is_idle (&sem->rss))) {this_cpu_dec (*sem->read_count); }else { -/* -* slowpath; reader will only ever wake a single blocked -* writer. -*/ -smp_mb ();/* B matches C */ -/* -* In other words, if they see our decrement (presumably to -* aggregate zero, as that is the only time it matters) they -* will also see our critical section. -*/ -this_cpu_dec (*sem->read_count); -rcuwait_wake_up (&sem->writer); +__percpu_up_read (sem); }preempt_enable (); }
kernel/locking/percpu-rwsem.c +18 -0
@@ -288,3 +288,21 @@ void percpu_up_write(struct percpu_rw_semaphore *sem)rcu_sync_exit (&sem->rss); }EXPORT_SYMBOL_GPL (percpu_up_write); + +void __percpu_up_read (struct percpu_rw_semaphore *sem) +{ +lockdep_assert_preemption_disabled (); +/* +* slowpath; reader will only ever wake a single blocked +* writer. +*/ +smp_mb ();/* B matches C */ +/* +* In other words, if they see our decrement (presumably to +* aggregate zero, as that is the only time it matters) they +* will also see our critical section. +*/ +this_cpu_dec (*sem->read_count); +rcuwait_wake_up (&sem->writer); +} +EXPORT_SYMBOL_GPL (__percpu_up_read);
Signature · 1 line
2.52.0
PATCH v3 3/4 locking: Add contended_release tracepoint to sleepable locks
In reply to Dmitry IlvokhinAdd the contended_release trace event. This tracepoint fires on the holder side when a contended lock is released, complementing the existing contention_begin/contention_end tracepoints which fire on the waiter side.
This enables correlating lock hold time under contention with waiter events by lock address.
Add trace_contended_release() calls to the slowpath unlock paths of sleepable locks: mutex, rtmutex, semaphore, rwsem, percpu-rwsem, and RT-specific rwbase locks.
Where possible, trace_contended_release() fires before the lock is released and before the waiter is woken. For rwsem, semaphore, and rwbase_rt read unlock, the tracepoint fires after the release but before the wake, as contention is determined by the return value of the atomic release operation.
--- include/trace/events/lock.h | 17 +++++++++++++++++ kernel/locking/mutex.c | 3 +++ kernel/locking/percpu-rwsem.c | 4 ++++ kernel/locking/rtmutex.c | 1 + kernel/locking/rwbase_rt.c | 8 +++++++- kernel/locking/rwsem.c | 9 +++++++-- kernel/locking/semaphore.c | 4 +++- 7 files changed, 42 insertions(+), 4 deletions(-)
include/trace/events/lock.h +17 -0
@@ -137,6 +137,23 @@ TRACE_EVENT(contention_end,TP_printk ("%p (ret=%d)" , __entry->lock_addr, __entry->ret) ); +TRACE_EVENT (contended_release, + +TP_PROTO (void *lock), + +TP_ARGS (lock), + +TP_STRUCT__entry ( + __field(void *, lock_addr) + ), + +TP_fast_assign ( + __entry->lock_addr = lock; + ), + +TP_printk ("%p" , __entry->lock_addr) +); +#endif /* _TRACE_LOCK_H */ /* This part must be outside protection */
kernel/locking/mutex.c +3 -0
@@ -997,6 +997,9 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsignewake_q_add (&wake_q, next); } +if (trace_contended_release_enabled () && waiter) +trace_contended_release (lock); +if (owner &MUTEX_FLAG_HANDOFF )__mutex_handoff (lock, next);
kernel/locking/percpu-rwsem.c +4 -0
@@ -263,6 +263,9 @@ void percpu_up_write(struct percpu_rw_semaphore *sem) {rwsem_release (&sem->dep_map, _RET_IP_); +if (trace_contended_release_enabled () &&wq_has_sleeper (&sem->waiters)) +trace_contended_release (sem); +/* * Signal the writer is done, no fast path yet. *
@@ -292,6 +295,7 @@ EXPORT_SYMBOL_GPL(percpu_up_write);void __percpu_up_read (struct percpu_rw_semaphore *sem) {lockdep_assert_preemption_disabled (); +trace_contended_release (sem);/* * slowpath; reader will only ever wake a single blocked * writer.
kernel/locking/rtmutex.c +1 -0
@@ -1466,6 +1466,7 @@ static void __sched rt_mutex_slowunlock(struct rt_mutex_base *lock)raw_spin_lock_irqsave (&lock->wait_lock, flags); } +trace_contended_release (lock);/* * The wakeup next waiter path does not suffer from the above * race. See the comments there.
kernel/locking/rwbase_rt.c +7 -1
@@ -162,8 +162,10 @@ static void __sched __rwbase_read_unlock(struct rwbase_rt *rwb,* worst case which can happen is a spurious wakeup. */ owner =rt_mutex_owner (rtm); -if (owner) +if (owner) { +trace_contended_release (rwb);rt_mutex_wake_q_add_task (&wqh, owner, state); + }/* Pairs with the preempt_enable in rt_mutex_wake_up_q() */ preempt_disable ();
@@ -205,6 +207,8 @@ static inline void rwbase_write_unlock(struct rwbase_rt *rwb)unsigned long flags;raw_spin_lock_irqsave (&rtm->wait_lock, flags); +if (trace_contended_release_enabled () &&rt_mutex_has_waiters (rtm)) +trace_contended_release (rwb);__rwbase_write_unlock (rwb,WRITER_BIAS , flags); }
@@ -214,6 +218,8 @@ static inline void rwbase_write_downgrade(struct rwbase_rt *rwb)unsigned long flags;raw_spin_lock_irqsave (&rtm->wait_lock, flags); +if (trace_contended_release_enabled () &&rt_mutex_has_waiters (rtm)) +trace_contended_release (rwb);/* Release it and account current as reader */ __rwbase_write_unlock (rwb,WRITER_BIAS -1 , flags); }
kernel/locking/rwsem.c +7 -2
@@ -1390,6 +1390,7 @@ static inline void __up_read(struct rw_semaphore *sem)if (unlikely ((tmp & (RWSEM_LOCK_MASK |RWSEM_FLAG_WAITERS )) ==RWSEM_FLAG_WAITERS )) {clear_nonspinnable (sem); +trace_contended_release (sem);rwsem_wake (sem); }preempt_enable ();
@@ -1413,8 +1414,10 @@ static inline void __up_write(struct rw_semaphore *sem)preempt_disable ();rwsem_clear_owner (sem); tmp =atomic_long_fetch_add_release (-RWSEM_WRITER_LOCKED , &sem->count); -if (unlikely (tmp &RWSEM_FLAG_WAITERS )) +if (unlikely (tmp &RWSEM_FLAG_WAITERS )) { +trace_contended_release (sem);rwsem_wake (sem); + }preempt_enable (); }
@@ -1437,8 +1440,10 @@ static inline void __downgrade_write(struct rw_semaphore *sem) tmp =atomic_long_fetch_add_release ( -RWSEM_WRITER_LOCKED +RWSEM_READER_BIAS , &sem->count);rwsem_set_reader_owned (sem); -if (tmp &RWSEM_FLAG_WAITERS ) +if (tmp &RWSEM_FLAG_WAITERS ) { +trace_contended_release (sem);rwsem_downgrade_wake (sem); + }preempt_enable (); }
kernel/locking/semaphore.c +3 -1
@@ -231,8 +231,10 @@ void __sched up(struct semaphore *sem)else __up (sem, &wake_q);raw_spin_unlock_irqrestore (&sem->lock, flags); -if (!wake_q_empty (&wake_q)) +if (!wake_q_empty (&wake_q)) { +trace_contended_release (sem);wake_up_q (&wake_q); + } }EXPORT_SYMBOL (up);
Signature · 1 line
2.52.0
RFC PATCH v3 4/4 locking: Add contended_release tracepoint to spinning locks
In reply to Dmitry IlvokhinExtend the contended_release tracepoint to queued spinlocks and queued rwlocks.
When the tracepoint is disabled, the only addition to the hot path is a single NOP instruction (the static branch). When enabled, the contention check, trace call, and unlock are combined in an out-of-line function to minimize hot path impact, avoiding the compiler needing to preserve the lock pointer in a callee-saved register across the trace call.
Binary size impact (x86_64, defconfig):
uninlined unlock (common case): +983 bytes (+0.00%)
inlined unlock (worst case): +71554 bytes (+0.30%)
The inlined unlock case could not be achieved through Kconfig options on x86_64 as PREEMPT_BUILD unconditionally selects UNINLINE_SPIN_UNLOCK on x86_64. The UNINLINE_SPIN_UNLOCK guards were manually inverted to force inline the unlock path and estimate the worst case binary size increase.
--- include/asm-generic/qrwlock.h | 48 +++++++++++++++++++++++++++------ include/asm-generic/qspinlock.h | 25 +++++++++++++++-- kernel/locking/qrwlock.c | 16 +++++++++++ kernel/locking/qspinlock.c | 8 ++++++ 4 files changed, 87 insertions(+), 10 deletions(-)
include/asm-generic/qrwlock.h +40 -8
@@ -14,6 +14,7 @@#define __ASM_GENERIC_QRWLOCK_H#include <linux/atomic.h> +#include <linux/tracepoint-defs.h> #include <asm/barrier.h> #include <asm/processor.h>
@@ -35,6 +36,10 @@*/ extern void queued_read_lock_slowpath (struct qrwlock *lock);extern void queued_write_lock_slowpath (struct qrwlock *lock); +extern void queued_read_unlock_traced (struct qrwlock *lock); +extern void queued_write_unlock_traced (struct qrwlock *lock); + +DECLARE_TRACEPOINT (contended_release);/** * queued_read_trylock - try to acquire read lock of a queued rwlock
@@ -102,10 +107,16 @@ static inline void queued_write_lock(struct qrwlock *lock) }/** -* queued_read_unlock - release read lock of a queued rwlock +* queued_rwlock_is_contended - check if the lock is contended * @lock : Pointer to queued rwlock structure +* Return: 1 if lock contended, 0 otherwise */ -static inline void queued_read_unlock (struct qrwlock *lock) +static inline int queued_rwlock_is_contended (struct qrwlock *lock) +{ +return arch_spin_is_locked (&lock->wait_lock); +} + +static __always_inline void __queued_read_unlock(struct qrwlock *lock) {/* * Atomically decrement the reader count
@@ -114,22 +125,43 @@ static inline void queued_read_unlock(struct qrwlock *lock) }/** -* queued_write_unlock - release write lock of a queued rwlock +* queued_read_unlock - release read lock of a queued rwlock * @lock : Pointer to queued rwlock structure */ -static inline void queued_write_unlock (struct qrwlock *lock) +static inline void queued_read_unlock (struct qrwlock *lock) +{ +/* +* Trace and unlock are combined in the traced unlock variant so +* the compiler does not need to preserve the lock pointer across +* the function call, avoiding callee-saved register save/restore +* on the hot path. +*/ +if (tracepoint_enabled (contended_release)) { +queued_read_unlock_traced (lock); +return ; + } + +__queued_read_unlock (lock); +} + +static __always_inline void __queued_write_unlock(struct qrwlock *lock) {smp_store_release (&lock->wlocked,0 ); }/** -* queued_rwlock_is_contended - check if the lock is contended +* queued_write_unlock - release write lock of a queued rwlock * @lock : Pointer to queued rwlock structure -* Return: 1 if lock contended, 0 otherwise */ -static inline int queued_rwlock_is_contended (struct qrwlock *lock) +static inline void queued_write_unlock (struct qrwlock *lock) { -return arch_spin_is_locked (&lock->wait_lock); +/* See comment in queued_read_unlock(). */ +if (tracepoint_enabled (contended_release)) { +queued_write_unlock_traced (lock); +return ; + } + +__queued_write_unlock (lock); }/*
include/asm-generic/qspinlock.h +23 -2
@@ -41,6 +41,7 @@#include <asm-generic/qspinlock_types.h> #include <linux/atomic.h> +#include <linux/tracepoint-defs.h> #ifndef queued_spin_is_locked/**
@@ -116,6 +117,19 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock)#endif #ifndef queued_spin_unlock + +DECLARE_TRACEPOINT (contended_release); + +extern void queued_spin_unlock_traced (struct qspinlock *lock); + +static __always_inline void __queued_spin_unlock(struct qspinlock *lock) +{ +/* +* unlock() needs release semantics: +*/ +smp_store_release (&lock->locked,0 ); +} +/** * queued_spin_unlock - release a queued spinlock * @lock : Pointer to queued spinlock structure
@@ -123,9 +137,16 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock) static __always_inline void queued_spin_unlock(struct qspinlock *lock) {/* -* unlock() needs release semantics: +* Trace and unlock are combined in queued_spin_unlock_traced() +* so the compiler does not need to preserve the lock pointer +* across the function call, avoiding callee-saved register +* save/restore on the hot path. */ -smp_store_release (&lock->locked,0 ); +if (tracepoint_enabled (contended_release)) { +queued_spin_unlock_traced (lock); +return ; + } +__queued_spin_unlock (lock); }#endif
kernel/locking/qrwlock.c +16 -0
@@ -90,3 +90,19 @@ void __lockfunc queued_write_lock_slowpath(struct qrwlock *lock)trace_contention_end (lock,0 ); }EXPORT_SYMBOL (queued_write_lock_slowpath); + +void __lockfunc queued_read_unlock_traced(struct qrwlock *lock) +{ +if (queued_rwlock_is_contended (lock)) +trace_contended_release (lock); +__queued_read_unlock (lock); +} +EXPORT_SYMBOL (queued_read_unlock_traced); + +void __lockfunc queued_write_unlock_traced(struct qrwlock *lock) +{ +if (queued_rwlock_is_contended (lock)) +trace_contended_release (lock); +__queued_write_unlock (lock); +} +EXPORT_SYMBOL (queued_write_unlock_traced);
kernel/locking/qspinlock.c +8 -0
@@ -104,6 +104,14 @@ static __always_inline u32 __pv_wait_head_or_lock(struct qspinlock *lock,#define queued_spin_lock_slowpath native_queued_spin_lock_slowpath#endif +void __lockfunc queued_spin_unlock_traced(struct qspinlock *lock) +{ +if (queued_spin_is_contended (lock)) +trace_contended_release (lock); +__queued_spin_unlock (lock); +} +EXPORT_SYMBOL (queued_spin_unlock_traced); +#endif /* _GEN_PV_LOCK_SLOWPATH */ /**
Signature · 1 line
2.52.0
kernel test robot
build botRe: [RFC PATCH v3 4/4] locking: Add contended_release tracepoint to spinning locks
kernel test robot noticed the following build errors:
Hi Dmitry,
[This is a private test report for your RFC patch.] kernel test robot noticed the following build errors:
[auto build test ERROR on tip/locking/core]
[also build test ERROR on trace/for-next arnd-asm-generic/master linus/master v7.0-rc4 next-20260320] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dmitry-Ilvokhin/tracing-lock-Remove-unnecessary-linux-sched-h-include/20260320-145758 base: tip/locking/core patch link: https://lore.kernel.org/r/51aad0415b78c5a39f2029722118fa01eac77538.1773858853.git.d%40ilvokhin.com patch subject: [RFC PATCH v3 4/4] locking: Add contended_release tracepoint to spinning locks config: mips-allmodconfig (https://download.01.org/0day-ci/archive/20260322/[email protected]/config) compiler: mips-linux-gcc (GCC) 15.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260322/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All error/warnings (new ones prefixed by >>):
>> kernel/locking/qspinlock.c:107:17: warning: no previous prototype for 'queued_spin_unlock_traced' [-Wmissing-prototypes]
107 | void __lockfunc queued_spin_unlock_traced(struct qspinlock *lock)
| ^~~~~~~~~~~~~~~~~~~~~~~~~
kernel/locking/qspinlock.c: In function 'queued_spin_unlock_traced':
>> kernel/locking/qspinlock.c:111:9: error: implicit declaration of function '__queued_spin_unlock'; did you mean 'queued_spin_unlock'? [-Wimplicit-function-declaration]
111 | __queued_spin_unlock(lock);
| ^~~~~~~~~~~~~~~~~~~~
| queued_spin_unlockvim +111 kernel/locking/qspinlock.c
106
> 107 void __lockfunc queued_spin_unlock_traced(struct qspinlock *lock)
108 {
109 if (queued_spin_is_contended(lock))
110 trace_contended_release(lock);
> 111 __queued_spin_unlock(lock); 112 }
113 EXPORT_SYMBOL(queued_spin_unlock_traced);
114
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [RFC PATCH v3 4/4] locking: Add contended_release tracepoint to spinning locks
In reply to Dmitry Ilvokhinkernel test robot noticed the following build warnings:
Hi Dmitry,
[This is a private test report for your RFC patch.] kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/locking/core]
[also build test WARNING on trace/for-next arnd-asm-generic/master linus/master v7.0-rc4 next-20260320] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Dmitry-Ilvokhin/tracing-lock-Remove-unnecessary-linux-sched-h-include/20260320-145758 base: tip/locking/core patch link: https://lore.kernel.org/r/51aad0415b78c5a39f2029722118fa01eac77538.1773858853.git.d%40ilvokhin.com patch subject: [RFC PATCH v3 4/4] locking: Add contended_release tracepoint to spinning locks config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260322/[email protected]/config) compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261) rustc: rustc 1.88.0 (6b00bc388 2025-06-23) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260322/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
kernel/locking/qspinlock.c:111:2: error: call to undeclared function '__queued_spin_unlock'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
111 | __queued_spin_unlock(lock);
| ^
>> kernel/locking/qspinlock.c:107:17: warning: no previous prototype for function 'queued_spin_unlock_traced' [-Wmissing-prototypes]
107 | void __lockfunc queued_spin_unlock_traced(struct qspinlock *lock)
| ^
kernel/locking/qspinlock.c:107:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
107 | void __lockfunc queued_spin_unlock_traced(struct qspinlock *lock)
| ^
| static
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:98:11: warning: array index 3 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
98 | return (set->sig[3] | set->sig[2] |
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:98:25: warning: array index 2 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
98 | return (set->sig[3] | set->sig[2] |
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:99:4: warning: array index 1 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
99 | set->sig[1] | set->sig[0]) == 0;
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:101:11: warning: array index 1 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
101 | return (set->sig[1] | set->sig[0]) == 0;
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:114:11: warning: array index 3 is past the end of the array (that has type 'const unsigned long[1]') [-Warray-bounds]
114 | return (set1->sig[3] == set2->sig[3]) &&
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:114:27: warning: array index 3 is past the end of the array (that has type 'const unsigned long[1]') [-Warray-bounds]
114 | return (set1->sig[3] == set2->sig[3]) &&
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:115:5: warning: array index 2 is past the end of the array (that has type 'const unsigned long[1]') [-Warray-bounds]
115 | (set1->sig[2] == set2->sig[2]) &&
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^ In file included from kernel/locking/qspinlock.c:408:
In file included from kernel/locking/qspinlock_paravirt.h:7:
In file included from include/linux/memblock.h:12:
In file included from include/linux/mm.h:37:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:115:21: warning: array index 2 is past the end of the array (that has type 'const unsigned long[1]') [-Warray-bounds]
115 | (set1->sig[2] == set2->sig[2]) &&
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
vim +/queued_spin_unlock_traced +107 kernel/locking/qspinlock.c
106
> 107 void __lockfunc queued_spin_unlock_traced(struct qspinlock *lock)
108 {
109 if (queued_spin_is_contended(lock))
110 trace_contended_release(lock);
111 __queued_spin_unlock(lock);
112 }
113 EXPORT_SYMBOL(queued_spin_unlock_traced);
114
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Andrew Morton
maintainerQuoted 18 lines · On Wed, 18 Mar 2026 18:45:17 +0000 Dmitry Ilvokhin <[email protected]> wrote:
The existing contention_begin/contention_end tracepoints fire on the waiter side. The lock holder's identity and stack can be captured at
contention_begintime (e.g. perf lock contention --lock-owner), but this reflects the holder's state when a waiter arrives, not when the lock is actually released.This series adds a
contended_releasetracepoint that fires on the holder side when a lock with waiters is released. This provides:- Hold time estimation: when the holder's own acquisition was contended, its
contention_end(acquisition) andcontended_releasecan be correlated to measure how long the lock was held under contention.- The holder's stack at release time, which may differ from what perf lock contention --lock-owner captures if the holder does significant work between the waiter's arrival and the unlock.
Quoted 7 lines
The series is structured as follows:
1. Remove unnecessary
linux/sched.hinclude fromtrace/events/lock.h.
2. Extract__percpu_up_read()out of the inlinepercpu_up_read()to avoid binary size increase from adding a tracepoint.
3. Addcontended_releasetracepoint and instrument sleepable locks:
mutex, rtmutex, semaphore, rwsem, percpu-rwsem, andrwbase_rt.
AI review:
https://sashiko.dev/#/patchset/[email protected]
Quoted 22 lines · Andrew Morton
Quoted 20 lines · On Wed, 18 Mar 2026 18:45:17 +0000 Dmitry Ilvokhin <[email protected]> wrote:
The existing contention_begin/contention_end tracepoints fire on the waiter side. The lock holder's identity and stack can be captured at
contention_begintime (e.g. perf lock contention --lock-owner), but this reflects the holder's state when a waiter arrives, not when the lock is actually released.This series adds a
contended_releasetracepoint that fires on the holder side when a lock with waiters is released. This provides:- Hold time estimation: when the holder's own acquisition was contended, its
contention_end(acquisition) andcontended_releasecan be correlated to measure how long the lock was held under contention.- The holder's stack at release time, which may differ from what perf lock contention --lock-owner captures if the holder does significant work between the waiter's arrival and the unlock.
The series is structured as follows:
Quoted 8 lines
Quoted 5 lines
1. Remove unnecessary
linux/sched.hinclude fromtrace/events/lock.h.
2. Extract__percpu_up_read()out of the inlinepercpu_up_read()to avoid binary size increase from adding a tracepoint.
3. Addcontended_releasetracepoint and instrument sleepable locks:
mutex, rtmutex, semaphore, rwsem, percpu-rwsem, andrwbase_rt.AI review:
https://sashiko.dev/#/patchset/[email protected]
Thanks, Andrew, appreciate you sharing the link.
The AI review looks reasonable. I'll go through it and address the feedback in the next revision. The kernel test robot is also reporting failures on some configs, which seem related to the Sashiko comments.