Skip to content

Commit ee042be

Browse files
namhyungPeter Zijlstra
authored andcommitted
locking: Apply contention tracepoints in the slow path
Adding the lock contention tracepoints in various lock function slow paths. Note that each arch can define spinlock differently, I only added it only to the generic qspinlock for now. Signed-off-by: Namhyung Kim <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Tested-by: Hyeonggon Yoo <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 16edd9b commit ee042be

File tree

8 files changed

+63
-1
lines changed

8 files changed

+63
-1
lines changed

kernel/locking/mutex.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
644644
}
645645

646646
set_current_state(state);
647+
trace_contention_begin(lock, 0);
647648
for (;;) {
648649
bool first;
649650

@@ -710,6 +711,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
710711
skip_wait:
711712
/* got the lock - cleanup and rejoice! */
712713
lock_acquired(&lock->dep_map, ip);
714+
trace_contention_end(lock, 0);
713715

714716
if (ww_ctx)
715717
ww_mutex_lock_acquired(ww, ww_ctx);
@@ -721,6 +723,7 @@ __mutex_lock_common(struct mutex *lock, unsigned int state, unsigned int subclas
721723
err:
722724
__set_current_state(TASK_RUNNING);
723725
__mutex_remove_waiter(lock, &waiter);
726+
trace_contention_end(lock, ret);
724727
err_early_kill:
725728
raw_spin_unlock(&lock->wait_lock);
726729
debug_mutex_free_waiter(&waiter);

kernel/locking/percpu-rwsem.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/sched/task.h>
1010
#include <linux/sched/debug.h>
1111
#include <linux/errno.h>
12+
#include <trace/events/lock.h>
1213

1314
int __percpu_init_rwsem(struct percpu_rw_semaphore *sem,
1415
const char *name, struct lock_class_key *key)
@@ -171,9 +172,11 @@ bool __sched __percpu_down_read(struct percpu_rw_semaphore *sem, bool try)
171172
if (try)
172173
return false;
173174

175+
trace_contention_begin(sem, LCB_F_PERCPU | LCB_F_READ);
174176
preempt_enable();
175177
percpu_rwsem_wait(sem, /* .reader = */ true);
176178
preempt_disable();
179+
trace_contention_end(sem, 0);
177180

178181
return true;
179182
}
@@ -216,6 +219,7 @@ void __sched percpu_down_write(struct percpu_rw_semaphore *sem)
216219
{
217220
might_sleep();
218221
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
222+
trace_contention_begin(sem, LCB_F_PERCPU | LCB_F_WRITE);
219223

220224
/* Notify readers to take the slow path. */
221225
rcu_sync_enter(&sem->rss);
@@ -237,6 +241,7 @@ void __sched percpu_down_write(struct percpu_rw_semaphore *sem)
237241

238242
/* Wait for all active readers to complete. */
239243
rcuwait_wait_event(&sem->writer, readers_active_check(sem), TASK_UNINTERRUPTIBLE);
244+
trace_contention_end(sem, 0);
240245
}
241246
EXPORT_SYMBOL_GPL(percpu_down_write);
242247

kernel/locking/qrwlock.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/percpu.h>
1313
#include <linux/hardirq.h>
1414
#include <linux/spinlock.h>
15+
#include <trace/events/lock.h>
1516

1617
/**
1718
* queued_read_lock_slowpath - acquire read lock of a queue rwlock
@@ -34,6 +35,8 @@ void queued_read_lock_slowpath(struct qrwlock *lock)
3435
}
3536
atomic_sub(_QR_BIAS, &lock->cnts);
3637

38+
trace_contention_begin(lock, LCB_F_SPIN | LCB_F_READ);
39+
3740
/*
3841
* Put the reader into the wait queue
3942
*/
@@ -51,6 +54,8 @@ void queued_read_lock_slowpath(struct qrwlock *lock)
5154
* Signal the next one in queue to become queue head
5255
*/
5356
arch_spin_unlock(&lock->wait_lock);
57+
58+
trace_contention_end(lock, 0);
5459
}
5560
EXPORT_SYMBOL(queued_read_lock_slowpath);
5661

@@ -62,6 +67,8 @@ void queued_write_lock_slowpath(struct qrwlock *lock)
6267
{
6368
int cnts;
6469

70+
trace_contention_begin(lock, LCB_F_SPIN | LCB_F_WRITE);
71+
6572
/* Put the writer into the wait queue */
6673
arch_spin_lock(&lock->wait_lock);
6774

@@ -79,5 +86,7 @@ void queued_write_lock_slowpath(struct qrwlock *lock)
7986
} while (!atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, _QW_LOCKED));
8087
unlock:
8188
arch_spin_unlock(&lock->wait_lock);
89+
90+
trace_contention_end(lock, 0);
8291
}
8392
EXPORT_SYMBOL(queued_write_lock_slowpath);

kernel/locking/qspinlock.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/prefetch.h>
2323
#include <asm/byteorder.h>
2424
#include <asm/qspinlock.h>
25+
#include <trace/events/lock.h>
2526

2627
/*
2728
* Include queued spinlock statistics code
@@ -401,6 +402,8 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
401402
idx = node->count++;
402403
tail = encode_tail(smp_processor_id(), idx);
403404

405+
trace_contention_begin(lock, LCB_F_SPIN);
406+
404407
/*
405408
* 4 nodes are allocated based on the assumption that there will
406409
* not be nested NMIs taking spinlocks. That may not be true in
@@ -554,6 +557,8 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
554557
pv_kick_node(lock, next);
555558

556559
release:
560+
trace_contention_end(lock, 0);
561+
557562
/*
558563
* release the node
559564
*/

kernel/locking/rtmutex.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <linux/sched/wake_q.h>
2525
#include <linux/ww_mutex.h>
2626

27+
#include <trace/events/lock.h>
28+
2729
#include "rtmutex_common.h"
2830

2931
#ifndef WW_RT
@@ -1579,6 +1581,8 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
15791581

15801582
set_current_state(state);
15811583

1584+
trace_contention_begin(lock, LCB_F_RT);
1585+
15821586
ret = task_blocks_on_rt_mutex(lock, waiter, current, ww_ctx, chwalk);
15831587
if (likely(!ret))
15841588
ret = rt_mutex_slowlock_block(lock, ww_ctx, state, NULL, waiter);
@@ -1601,6 +1605,9 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
16011605
* unconditionally. We might have to fix that up.
16021606
*/
16031607
fixup_rt_mutex_waiters(lock);
1608+
1609+
trace_contention_end(lock, ret);
1610+
16041611
return ret;
16051612
}
16061613

@@ -1683,6 +1690,8 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock)
16831690
/* Save current state and set state to TASK_RTLOCK_WAIT */
16841691
current_save_and_set_rtlock_wait_state();
16851692

1693+
trace_contention_begin(lock, LCB_F_RT);
1694+
16861695
task_blocks_on_rt_mutex(lock, &waiter, current, NULL, RT_MUTEX_MIN_CHAINWALK);
16871696

16881697
for (;;) {
@@ -1712,6 +1721,8 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock)
17121721
*/
17131722
fixup_rt_mutex_waiters(lock);
17141723
debug_rt_mutex_free_waiter(&waiter);
1724+
1725+
trace_contention_end(lock, 0);
17151726
}
17161727

17171728
static __always_inline void __sched rtlock_slowlock(struct rt_mutex_base *lock)

kernel/locking/rwbase_rt.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
112112
* Reader2 to call up_read(), which might be unbound.
113113
*/
114114

115+
trace_contention_begin(rwb, LCB_F_RT | LCB_F_READ);
116+
115117
/*
116118
* For rwlocks this returns 0 unconditionally, so the below
117119
* !ret conditionals are optimized out.
@@ -130,6 +132,8 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
130132
raw_spin_unlock_irq(&rtm->wait_lock);
131133
if (!ret)
132134
rwbase_rtmutex_unlock(rtm);
135+
136+
trace_contention_end(rwb, ret);
133137
return ret;
134138
}
135139

@@ -247,11 +251,13 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
247251
goto out_unlock;
248252

249253
rwbase_set_and_save_current_state(state);
254+
trace_contention_begin(rwb, LCB_F_RT | LCB_F_WRITE);
250255
for (;;) {
251256
/* Optimized out for rwlocks */
252257
if (rwbase_signal_pending_state(state, current)) {
253258
rwbase_restore_current_state();
254259
__rwbase_write_unlock(rwb, 0, flags);
260+
trace_contention_end(rwb, -EINTR);
255261
return -EINTR;
256262
}
257263

@@ -265,6 +271,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
265271
set_current_state(state);
266272
}
267273
rwbase_restore_current_state();
274+
trace_contention_end(rwb, 0);
268275

269276
out_unlock:
270277
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);

kernel/locking/rwsem.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/export.h>
2828
#include <linux/rwsem.h>
2929
#include <linux/atomic.h>
30+
#include <trace/events/lock.h>
3031

3132
#ifndef CONFIG_PREEMPT_RT
3233
#include "lock_events.h"
@@ -1056,6 +1057,8 @@ rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int stat
10561057
if (!wake_q_empty(&wake_q))
10571058
wake_up_q(&wake_q);
10581059

1060+
trace_contention_begin(sem, LCB_F_READ);
1061+
10591062
/* wait to be given the lock */
10601063
for (;;) {
10611064
set_current_state(state);
@@ -1077,12 +1080,14 @@ rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int stat
10771080

10781081
__set_current_state(TASK_RUNNING);
10791082
lockevent_inc(rwsem_rlock);
1083+
trace_contention_end(sem, 0);
10801084
return sem;
10811085

10821086
out_nolock:
10831087
rwsem_del_wake_waiter(sem, &waiter, &wake_q);
10841088
__set_current_state(TASK_RUNNING);
10851089
lockevent_inc(rwsem_rlock_fail);
1090+
trace_contention_end(sem, -EINTR);
10861091
return ERR_PTR(-EINTR);
10871092
}
10881093

@@ -1132,6 +1137,8 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
11321137

11331138
/* wait until we successfully acquire the lock */
11341139
set_current_state(state);
1140+
trace_contention_begin(sem, LCB_F_WRITE);
1141+
11351142
for (;;) {
11361143
if (rwsem_try_write_lock(sem, &waiter)) {
11371144
/* rwsem_try_write_lock() implies ACQUIRE on success */
@@ -1171,13 +1178,15 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
11711178
__set_current_state(TASK_RUNNING);
11721179
raw_spin_unlock_irq(&sem->wait_lock);
11731180
lockevent_inc(rwsem_wlock);
1181+
trace_contention_end(sem, 0);
11741182
return sem;
11751183

11761184
out_nolock:
11771185
__set_current_state(TASK_RUNNING);
11781186
raw_spin_lock_irq(&sem->wait_lock);
11791187
rwsem_del_wake_waiter(sem, &waiter, &wake_q);
11801188
lockevent_inc(rwsem_wlock_fail);
1189+
trace_contention_end(sem, -EINTR);
11811190
return ERR_PTR(-EINTR);
11821191
}
11831192

kernel/locking/semaphore.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/semaphore.h>
3333
#include <linux/spinlock.h>
3434
#include <linux/ftrace.h>
35+
#include <trace/events/lock.h>
3536

3637
static noinline void __down(struct semaphore *sem);
3738
static noinline int __down_interruptible(struct semaphore *sem);
@@ -205,7 +206,7 @@ struct semaphore_waiter {
205206
* constant, and thus optimised away by the compiler. Likewise the
206207
* 'timeout' parameter for the cases without timeouts.
207208
*/
208-
static inline int __sched __down_common(struct semaphore *sem, long state,
209+
static inline int __sched ___down_common(struct semaphore *sem, long state,
209210
long timeout)
210211
{
211212
struct semaphore_waiter waiter;
@@ -236,6 +237,18 @@ static inline int __sched __down_common(struct semaphore *sem, long state,
236237
return -EINTR;
237238
}
238239

240+
static inline int __sched __down_common(struct semaphore *sem, long state,
241+
long timeout)
242+
{
243+
int ret;
244+
245+
trace_contention_begin(sem, 0);
246+
ret = ___down_common(sem, state, timeout);
247+
trace_contention_end(sem, ret);
248+
249+
return ret;
250+
}
251+
239252
static noinline void __sched __down(struct semaphore *sem)
240253
{
241254
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);

0 commit comments

Comments
 (0)