Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1314034 > unrolled thread
| Started by | Ding Tianhong <dingtianhong@huawei.com> |
|---|---|
| First post | 2016-01-21 10:40 +0100 |
| Last post | 2016-01-22 14:50 +0100 |
| Articles | 19 — 7 participants |
Back to article view | Back to linux.kernel
[PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Ding Tianhong <dingtianhong@huawei.com> - 2016-01-21 10:40 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Tim Chen <tim.c.chen@linux.intel.com> - 2016-01-21 22:30 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Davidlohr Bueso <dave@stgolabs.net> - 2016-01-22 03:50 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-01-22 04:20 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2016-01-22 03:50 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Waiman Long <waiman.long@hpe.com> - 2016-01-22 00:10 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Davidlohr Bueso <dave@stgolabs.net> - 2016-01-22 07:20 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Waiman Long <waiman.long@hpe.com> - 2016-01-22 14:40 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Davidlohr Bueso <dave@stgolabs.net> - 2016-01-22 17:50 +0100
[PATCH] locking/mutex: Allow next waiter lockless wakeup Davidlohr Bueso <dave@stgolabs.net> - 2016-01-25 03:30 +0100
Re: [PATCH] locking/mutex: Allow next waiter lockless wakeup Waiman Long <waiman.long@hpe.com> - 2016-01-26 00:10 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Peter Zijlstra <peterz@infradead.org> - 2016-01-22 10:00 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Jason Low <jason.low2@hp.com> - 2016-01-22 11:30 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Peter Zijlstra <peterz@infradead.org> - 2016-01-22 12:00 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Peter Zijlstra <peterz@infradead.org> - 2016-01-22 12:00 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Peter Zijlstra <peterz@infradead.org> - 2016-01-22 12:10 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Waiman Long <waiman.long@hpe.com> - 2016-01-22 15:10 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Ding Tianhong <dingtianhong@huawei.com> - 2016-01-24 09:10 +0100
Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. Waiman Long <waiman.long@hpe.com> - 2016-01-22 14:50 +0100
| From | Ding Tianhong <dingtianhong@huawei.com> |
|---|---|
| Date | 2016-01-21 10:40 +0100 |
| Subject | [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTjSG-3ll-15@gated-at.bofh.it> |
I build a script to create several process for ioctl loop calling,
the ioctl will calling the kernel function just like:
xx_ioctl {
...
rtnl_lock();
function();
rtnl_unlock();
...
}
The function may sleep several ms, but will not halt, at the same time
another user service may calling ifconfig to change the state of the
ethernet, and after several hours, the hung task thread report this problem:
========================================================================
149738.039038] INFO: task ifconfig:11890 blocked for more than 120 seconds.
[149738.040597] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[149738.042280] ifconfig D ffff88061ec13680 0 11890 11573 0x00000080
[149738.042284] ffff88052449bd40 0000000000000082 ffff88053a33f300 ffff88052449bfd8
[149738.042286] ffff88052449bfd8 ffff88052449bfd8 ffff88053a33f300 ffffffff819e6240
[149738.042288] ffffffff819e6244 ffff88053a33f300 00000000ffffffff ffffffff819e6248
[149738.042290] Call Trace:
[149738.042300] [<ffffffff8160d219>] schedule_preempt_disabled+0x29/0x70
[149738.042303] [<ffffffff8160af65>] __mutex_lock_slowpath+0xc5/0x1c0
[149738.042305] [<ffffffff8160a3cf>] mutex_lock+0x1f/0x2f
[149738.042309] [<ffffffff8150d945>] rtnl_lock+0x15/0x20
[149738.042311] [<ffffffff81514e3a>] dev_ioctl+0xda/0x590
[149738.042314] [<ffffffff816121cc>] ? __do_page_fault+0x21c/0x560
[149738.042318] [<ffffffff814e42c5>] sock_do_ioctl+0x45/0x50
[149738.042320] [<ffffffff814e49d0>] sock_ioctl+0x1f0/0x2c0
[149738.042324] [<ffffffff811dc9b5>] do_vfs_ioctl+0x2e5/0x4c0
[149738.042327] [<ffffffff811e6a00>] ? fget_light+0xa0/0xd0
================================ cut here ================================
I got the vmcore and found that the ifconfig is already in the wait_list of the
rtnl_lock for 120 second, but my process could get and release the rtnl_lock
normally several times in one second, so it means that my process jump the
queue and the ifconfig couldn't get the rtnl all the time, I check the mutex lock
slow path and found that the mutex may spin on owner ignore whether the wait list
is empty, it will cause the task in the wait list always be cut in line, so add
test for wait list in the mutex_can_spin_on_owner and avoid this problem.
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@us.ibm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Jason Low <jason.low2@hp.com>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: Waiman Long <Waiman.Long@hp.com>
---
kernel/locking/mutex.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 0551c21..596b341 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -256,7 +256,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
struct task_struct *owner;
int retval = 1;
- if (need_resched())
+ if (need_resched() || atomic_read(&lock->count) == -1)
return 0;
rcu_read_lock();
@@ -283,10 +283,11 @@ static inline bool mutex_try_to_acquire(struct mutex *lock)
/*
* Optimistic spinning.
*
- * We try to spin for acquisition when we find that the lock owner
- * is currently running on a (different) CPU and while we don't
- * need to reschedule. The rationale is that if the lock owner is
- * running, it is likely to release the lock soon.
+ * We try to spin for acquisition when we find that there are no
+ * pending waiters and the lock owner is currently running on a
+ * (different) CPU and while we don't need to reschedule. The
+ * rationale is that if the lock owner is running, it is likely
+ * to release the lock soon.
*
* Since this needs the lock owner, and this mutex implementation
* doesn't track the owner atomically in the lock field, we need to
--
2.5.0
[toc] | [next] | [standalone]
| From | Tim Chen <tim.c.chen@linux.intel.com> |
|---|---|
| Date | 2016-01-21 22:30 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTuXM-2zU-19@gated-at.bofh.it> |
| In reply to | #1314034 |
On Thu, 2016-01-21 at 17:29 +0800, Ding Tianhong wrote: > > diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c > index 0551c21..596b341 100644 > --- a/kernel/locking/mutex.c > +++ b/kernel/locking/mutex.c > @@ -256,7 +256,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock) > struct task_struct *owner; > int retval = 1; > > - if (need_resched()) > + if (need_resched() || atomic_read(&lock->count) == -1) > return 0; > One concern I have is this change will eliminate any optimistic spinning as long as there is a waiter. Is there a middle ground that we can allow only one spinner if there are waiters? In other words, we allow spinning when atomic_read(&lock->count) == -1 but there is no one on the osq lock that queue up the spinners (i.e. no other process doing optimistic spinning). This could allow a bit of spinning without starving out the waiters. Tim
[toc] | [prev] | [next] | [standalone]
| From | Davidlohr Bueso <dave@stgolabs.net> |
|---|---|
| Date | 2016-01-22 03:50 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTzXs-5Rs-21@gated-at.bofh.it> |
| In reply to | #1314543 |
On Thu, 21 Jan 2016, Paul E. McKenney wrote: >I did some testing, which exposed it to the 0day test robot, which >did note some performance differences. I was hoping that it would >clear up some instability from other patches, but no such luck. ;-) Oh, that explains why we got a performance regression report :) Thanks, Davidlohr
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-01-22 04:20 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTAqu-6pk-3@gated-at.bofh.it> |
| In reply to | #1314719 |
On Thu, Jan 21, 2016 at 06:48:54PM -0800, Davidlohr Bueso wrote: > On Thu, 21 Jan 2016, Paul E. McKenney wrote: > > >I did some testing, which exposed it to the 0day test robot, which > >did note some performance differences. I was hoping that it would > >clear up some instability from other patches, but no such luck. ;-) > > Oh, that explains why we got a performance regression report :) Plus I suspected that you wanted some extra email. ;-) Thanx, Paul
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-01-22 03:50 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTzXs-5Rs-23@gated-at.bofh.it> |
| In reply to | #1314543 |
On Thu, Jan 21, 2016 at 01:23:09PM -0800, Tim Chen wrote: > On Thu, 2016-01-21 at 17:29 +0800, Ding Tianhong wrote: > > > > > diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c > > index 0551c21..596b341 100644 > > --- a/kernel/locking/mutex.c > > +++ b/kernel/locking/mutex.c > > @@ -256,7 +256,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock) > > struct task_struct *owner; > > int retval = 1; > > > > - if (need_resched()) > > + if (need_resched() || atomic_read(&lock->count) == -1) > > return 0; > > > > One concern I have is this change will eliminate any optimistic spinning > as long as there is a waiter. Is there a middle ground that we > can allow only one spinner if there are waiters? > > In other words, we allow spinning when > atomic_read(&lock->count) == -1 but there is no one on the > osq lock that queue up the spinners (i.e. no other process doing > optimistic spinning). > > This could allow a bit of spinning without starving out the waiters. I did some testing, which exposed it to the 0day test robot, which did note some performance differences. I was hoping that it would clear up some instability from other patches, but no such luck. ;-) Thanx, Paul
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2016-01-22 00:10 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTwwA-3Hx-59@gated-at.bofh.it> |
| In reply to | #1314034 |
[Multipart message — attachments visible in raw view] — view raw
On 01/21/2016 04:29 AM, Ding Tianhong wrote:
> I build a script to create several process for ioctl loop calling,
> the ioctl will calling the kernel function just like:
> xx_ioctl {
> ...
> rtnl_lock();
> function();
> rtnl_unlock();
> ...
> }
> The function may sleep several ms, but will not halt, at the same time
> another user service may calling ifconfig to change the state of the
> ethernet, and after several hours, the hung task thread report this problem:
>
> ========================================================================
> 149738.039038] INFO: task ifconfig:11890 blocked for more than 120 seconds.
> [149738.040597] "echo 0> /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> [149738.042280] ifconfig D ffff88061ec13680 0 11890 11573 0x00000080
> [149738.042284] ffff88052449bd40 0000000000000082 ffff88053a33f300 ffff88052449bfd8
> [149738.042286] ffff88052449bfd8 ffff88052449bfd8 ffff88053a33f300 ffffffff819e6240
> [149738.042288] ffffffff819e6244 ffff88053a33f300 00000000ffffffff ffffffff819e6248
> [149738.042290] Call Trace:
> [149738.042300] [<ffffffff8160d219>] schedule_preempt_disabled+0x29/0x70
> [149738.042303] [<ffffffff8160af65>] __mutex_lock_slowpath+0xc5/0x1c0
> [149738.042305] [<ffffffff8160a3cf>] mutex_lock+0x1f/0x2f
> [149738.042309] [<ffffffff8150d945>] rtnl_lock+0x15/0x20
> [149738.042311] [<ffffffff81514e3a>] dev_ioctl+0xda/0x590
> [149738.042314] [<ffffffff816121cc>] ? __do_page_fault+0x21c/0x560
> [149738.042318] [<ffffffff814e42c5>] sock_do_ioctl+0x45/0x50
> [149738.042320] [<ffffffff814e49d0>] sock_ioctl+0x1f0/0x2c0
> [149738.042324] [<ffffffff811dc9b5>] do_vfs_ioctl+0x2e5/0x4c0
> [149738.042327] [<ffffffff811e6a00>] ? fget_light+0xa0/0xd0
>
> ================================ cut here ================================
>
> I got the vmcore and found that the ifconfig is already in the wait_list of the
> rtnl_lock for 120 second, but my process could get and release the rtnl_lock
> normally several times in one second, so it means that my process jump the
> queue and the ifconfig couldn't get the rtnl all the time, I check the mutex lock
> slow path and found that the mutex may spin on owner ignore whether the wait list
> is empty, it will cause the task in the wait list always be cut in line, so add
> test for wait list in the mutex_can_spin_on_owner and avoid this problem.
>
> Signed-off-by: Ding Tianhong<dingtianhong@huawei.com>
> Cc: Ingo Molnar<mingo@redhat.com>
> Cc: Peter Zijlstra<peterz@infradead.org>
> Cc: Davidlohr Bueso<dave@stgolabs.net>
> Cc: Linus Torvalds<torvalds@linux-foundation.org>
> Cc: Paul E. McKenney<paulmck@us.ibm.com>
> Cc: Thomas Gleixner<tglx@linutronix.de>
> Cc: Will Deacon<will.deacon@arm.com>
> Cc: Jason Low<jason.low2@hp.com>
> Cc: Tim Chen<tim.c.chen@linux.intel.com>
> Cc: Waiman Long<Waiman.Long@hp.com>
> ---
> kernel/locking/mutex.c | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
> index 0551c21..596b341 100644
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -256,7 +256,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
> struct task_struct *owner;
> int retval = 1;
>
> - if (need_resched())
> + if (need_resched() || atomic_read(&lock->count) == -1)
> return 0;
>
> rcu_read_lock();
> @@ -283,10 +283,11 @@ static inline bool mutex_try_to_acquire(struct mutex *lock)
> /*
> * Optimistic spinning.
> *
> - * We try to spin for acquisition when we find that the lock owner
> - * is currently running on a (different) CPU and while we don't
> - * need to reschedule. The rationale is that if the lock owner is
> - * running, it is likely to release the lock soon.
> + * We try to spin for acquisition when we find that there are no
> + * pending waiters and the lock owner is currently running on a
> + * (different) CPU and while we don't need to reschedule. The
> + * rationale is that if the lock owner is running, it is likely
> + * to release the lock soon.
> *
> * Since this needs the lock owner, and this mutex implementation
> * doesn't track the owner atomically in the lock field, we need to
This patch will largely defeat the performance benefit of optimistic
spinning. I have an alternative solution to this live-lock problem.
Would you mind trying out the attached patch to see if it can fix your
problem?
Cheers,
Longman
[toc] | [prev] | [next] | [standalone]
| From | Davidlohr Bueso <dave@stgolabs.net> |
|---|---|
| Date | 2016-01-22 07:20 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTDeG-8sR-3@gated-at.bofh.it> |
| In reply to | #1314630 |
On Thu, 21 Jan 2016, Waiman Long wrote: >On 01/21/2016 04:29 AM, Ding Tianhong wrote: >>I got the vmcore and found that the ifconfig is already in the wait_list of the >>rtnl_lock for 120 second, but my process could get and release the rtnl_lock >>normally several times in one second, so it means that my process jump the >>queue and the ifconfig couldn't get the rtnl all the time, I check the mutex lock >>slow path and found that the mutex may spin on owner ignore whether the wait list >>is empty, it will cause the task in the wait list always be cut in line, so add >>test for wait list in the mutex_can_spin_on_owner and avoid this problem. So this has been somewhat always known, at least in theory, until now. It's the cost of spinning without going through the wait-queue, unlike other locks. >> [...] >From: Waiman Long <Waiman.Long@hpe.com> >Date: Thu, 21 Jan 2016 17:53:14 -0500 >Subject: [PATCH] locking/mutex: Enable optimistic spinning of woken task in wait list > >Ding Tianhong reported a live-lock situation where a constant stream >of incoming optimistic spinners blocked a task in the wait list from >getting the mutex. > >This patch attempts to fix this live-lock condition by enabling the >a woken task in the wait list to enter optimistic spinning loop itself >with precedence over the ones in the OSQ. This should prevent the >live-lock >condition from happening. And one of the reasons why we never bothered 'fixing' things was the additional branching out in the slowpath (and lack of real issue, although this one being so damn pathological). I fear that your approach is one of those scenarios where the code ends up being bloated, albeit most of it is actually duplicated and can be refactored *sigh*. So now we'd spin, then sleep, then try spinning then sleep again... phew. Not to mention the performance implications, ie loosing the benefits of osq over waiter spinning in scenarios that would otherwise have more osq spinners as opposed to waiter spinners, or in setups where it is actually best to block instead of spinning. Thanks, Davidlohr
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2016-01-22 14:40 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTK6t-4Fl-1@gated-at.bofh.it> |
| In reply to | #1314767 |
On 01/22/2016 01:09 AM, Davidlohr Bueso wrote: > On Thu, 21 Jan 2016, Waiman Long wrote: > >> On 01/21/2016 04:29 AM, Ding Tianhong wrote: > >>> I got the vmcore and found that the ifconfig is already in the >>> wait_list of the >>> rtnl_lock for 120 second, but my process could get and release the >>> rtnl_lock >>> normally several times in one second, so it means that my process >>> jump the >>> queue and the ifconfig couldn't get the rtnl all the time, I check >>> the mutex lock >>> slow path and found that the mutex may spin on owner ignore whether >>> the wait list >>> is empty, it will cause the task in the wait list always be cut in >>> line, so add >>> test for wait list in the mutex_can_spin_on_owner and avoid this >>> problem. > > So this has been somewhat always known, at least in theory, until now. > It's the cost > of spinning without going through the wait-queue, unlike other locks. > >>> [...] > >> From: Waiman Long <Waiman.Long@hpe.com> >> Date: Thu, 21 Jan 2016 17:53:14 -0500 >> Subject: [PATCH] locking/mutex: Enable optimistic spinning of woken >> task in wait list >> >> Ding Tianhong reported a live-lock situation where a constant stream >> of incoming optimistic spinners blocked a task in the wait list from >> getting the mutex. >> >> This patch attempts to fix this live-lock condition by enabling the >> a woken task in the wait list to enter optimistic spinning loop itself >> with precedence over the ones in the OSQ. This should prevent the >> live-lock >> condition from happening. > > And one of the reasons why we never bothered 'fixing' things was the > additional > branching out in the slowpath (and lack of real issue, although this > one being so > damn pathological). I fear that your approach is one of those > scenarios where the > code ends up being bloated, albeit most of it is actually duplicated > and can be > refactored *sigh*. So now we'd spin, then sleep, then try spinning > then sleep again... > phew. Not to mention the performance implications, ie loosing the > benefits of osq > over waiter spinning in scenarios that would otherwise have more osq > spinners as > opposed to waiter spinners, or in setups where it is actually best to > block instead > of spinning. The patch that I sent out is just a proof of concept to make sure that it can fix that particular case. I do plan to refactor it if I decide to go ahead with an official one. Unlike the OSQ, there can be no more than one waiter spinner as the wakeup function is directed to only the first task in the wait list and the spinning won't happen until the task is first woken up. In the worst case scenario, there are only 2 spinners spinning on the lock and the owner field, one from OSQ and one from the wait list. That shouldn't put too much cacheline contention traffic to the system. Cheers, Longman
[toc] | [prev] | [next] | [standalone]
| From | Davidlohr Bueso <dave@stgolabs.net> |
|---|---|
| Date | 2016-01-22 17:50 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTN4m-6Dx-13@gated-at.bofh.it> |
| In reply to | #1314975 |
On Fri, 22 Jan 2016, Waiman Long wrote: >The patch that I sent out is just a proof of concept to make sure >that it can fix that particular case. I do plan to refactor it if I >decide to go ahead with an official one. Unlike the OSQ, there can be >no more than one waiter spinner as the wakeup function is directed to >only the first task in the wait list and the spinning won't happen >until the task is first woken up. In the worst case scenario, there >are only 2 spinners spinning on the lock and the owner field, one >from OSQ and one from the wait list. That shouldn't put too much >cacheline contention traffic to the system. Similarly, I guess we should also wakeup the next waiter in line after releasing the wait_lock via wake_q. This would allow the woken waiter a slightly better chance of finding the wait_lock free when continuing to take the mutex. Thanks, Davidlohr
[toc] | [prev] | [next] | [standalone]
| From | Davidlohr Bueso <dave@stgolabs.net> |
|---|---|
| Date | 2016-01-25 03:30 +0100 |
| Subject | [PATCH] locking/mutex: Allow next waiter lockless wakeup |
| Message-ID | <qUF4K-5sN-3@gated-at.bofh.it> |
| In reply to | #1315123 |
Make use of wake_q and enable the wakeup to occur after
releasing the wait_lock. This is similar to what we do
with rtmutex top waiter, slightly shortening the critical
region and allow other waiters to acquire the wait_lock
sooner. In low contention cases it can also help the
recently woken waiter to find the wait_lock available
(fastpath) when it continues execution.
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
---
kernel/locking/mutex.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 0551c21..e364b42 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -716,6 +716,7 @@ static inline void
__mutex_unlock_common_slowpath(struct mutex *lock, int nested)
{
unsigned long flags;
+ WAKE_Q(wake_q);
/*
* As a performance measurement, release the lock before doing other
@@ -743,11 +744,11 @@ __mutex_unlock_common_slowpath(struct mutex *lock, int nested)
struct mutex_waiter, list);
debug_mutex_wake_waiter(lock, waiter);
-
- wake_up_process(waiter->task);
+ wake_q_add(&wake_q, waiter->task);
}
spin_unlock_mutex(&lock->wait_lock, flags);
+ wake_up_q(&wake_q);
}
/*
--
2.1.4
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2016-01-26 00:10 +0100 |
| Subject | Re: [PATCH] locking/mutex: Allow next waiter lockless wakeup |
| Message-ID | <qUYqK-2KQ-7@gated-at.bofh.it> |
| In reply to | #1316172 |
On 01/24/2016 09:23 PM, Davidlohr Bueso wrote:
> Make use of wake_q and enable the wakeup to occur after
> releasing the wait_lock. This is similar to what we do
> with rtmutex top waiter, slightly shortening the critical
> region and allow other waiters to acquire the wait_lock
> sooner. In low contention cases it can also help the
> recently woken waiter to find the wait_lock available
> (fastpath) when it continues execution.
>
> Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
> ---
> kernel/locking/mutex.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
> index 0551c21..e364b42 100644
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -716,6 +716,7 @@ static inline void
> __mutex_unlock_common_slowpath(struct mutex *lock, int nested)
> {
> unsigned long flags;
> + WAKE_Q(wake_q);
>
> /*
> * As a performance measurement, release the lock before doing other
> @@ -743,11 +744,11 @@ __mutex_unlock_common_slowpath(struct mutex
> *lock, int nested)
> struct mutex_waiter, list);
>
> debug_mutex_wake_waiter(lock, waiter);
> -
> - wake_up_process(waiter->task);
> + wake_q_add(&wake_q, waiter->task);
> }
>
> spin_unlock_mutex(&lock->wait_lock, flags);
> + wake_up_q(&wake_q);
> }
>
> /*
This patch looks good to me.
Reviewed-by: Waiman Long <Waiman.Long@hpe.com>
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-01-22 10:00 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTFJv-1Dd-5@gated-at.bofh.it> |
| In reply to | #1314630 |
On Thu, Jan 21, 2016 at 06:02:34PM -0500, Waiman Long wrote: > This patch attempts to fix this live-lock condition by enabling the > a woken task in the wait list to enter optimistic spinning loop itself > with precedence over the ones in the OSQ. This should prevent the > live-lock > condition from happening. So I think having the top waiter going back in to contend on the OSQ is an excellent idea, but I'm not sure the wlh_spinning thing is important. The OSQ itself is FIFO fair, and the waiters retain the wait_list position. So having the top wait_list entry contending on the OSQ ensures we cannot starve (I think). Also, as Davidlohr said, we cannot copy/paste this much code.
[toc] | [prev] | [next] | [standalone]
| From | Jason Low <jason.low2@hp.com> |
|---|---|
| Date | 2016-01-22 11:30 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTH8B-2I1-3@gated-at.bofh.it> |
| In reply to | #1314832 |
On Fri, 2016-01-22 at 09:54 +0100, Peter Zijlstra wrote:
> On Thu, Jan 21, 2016 at 06:02:34PM -0500, Waiman Long wrote:
> > This patch attempts to fix this live-lock condition by enabling the
> > a woken task in the wait list to enter optimistic spinning loop itself
> > with precedence over the ones in the OSQ. This should prevent the
> > live-lock
> > condition from happening.
>
>
> So I think having the top waiter going back in to contend on the OSQ is
> an excellent idea, but I'm not sure the wlh_spinning thing is important.
>
> The OSQ itself is FIFO fair, and the waiters retain the wait_list
> position. So having the top wait_list entry contending on the OSQ
> ensures we cannot starve (I think).
Right, and we can also avoid needing to add that extra field to the
mutex structure. Before calling optimistic spinning, we do want to check
if the lock is available to avoid unnecessary OSQ overhead though.
So maybe the following would be sufficient:
---
kernel/locking/mutex.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 0551c21..ead0bd1 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -543,6 +543,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
lock_contended(&lock->dep_map, ip);
for (;;) {
+ bool acquired = false;
+
/*
* Lets try to take the lock again - this is needed even if
* we get here for the first time (shortly after failing to
@@ -577,7 +579,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
/* didn't get the lock, go to sleep: */
spin_unlock_mutex(&lock->wait_lock, flags);
schedule_preempt_disabled();
+
+ if (mutex_is_locked(lock))
+ acquired = mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx);
spin_lock_mutex(&lock->wait_lock, flags);
+ if (acquired)
+ break;
}
__set_task_state(task, TASK_RUNNING);
--
1.7.2.5
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-01-22 12:00 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTHBE-2UG-11@gated-at.bofh.it> |
| In reply to | #1314877 |
On Fri, Jan 22, 2016 at 02:20:19AM -0800, Jason Low wrote:
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -543,6 +543,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> lock_contended(&lock->dep_map, ip);
>
> for (;;) {
> + bool acquired = false;
> +
> /*
> * Lets try to take the lock again - this is needed even if
> * we get here for the first time (shortly after failing to
> @@ -577,7 +579,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> /* didn't get the lock, go to sleep: */
> spin_unlock_mutex(&lock->wait_lock, flags);
> schedule_preempt_disabled();
> +
> + if (mutex_is_locked(lock))
> + acquired = mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx);
> spin_lock_mutex(&lock->wait_lock, flags);
> + if (acquired)
> + break;
> }
> __set_task_state(task, TASK_RUNNING);
I think the problem here is that mutex_optimistic_spin() leaves the
mutex->count == 0, even though we have waiters (us at the very least).
But this should be easily fixed, since if we acquired, we should be the
one releasing, so there's no race.
So something like so:
if (acquired) {
atomic_set(&mutex->count, -1);
break;
}
Should deal with that -- we'll set it to 0 again a little further down
if the list ends up empty.
There might be other details, but this is the one that stood out.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-01-22 12:00 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTHBE-2UG-15@gated-at.bofh.it> |
| In reply to | #1314890 |
On Fri, Jan 22, 2016 at 11:53:12AM +0100, Peter Zijlstra wrote: > There might be other details, but this is the one that stood out. I think this also does the wrong thing for use_ww_ctx.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-01-22 12:10 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTHLj-3dT-1@gated-at.bofh.it> |
| In reply to | #1314891 |
On Fri, Jan 22, 2016 at 11:56:52AM +0100, Peter Zijlstra wrote:
> On Fri, Jan 22, 2016 at 11:53:12AM +0100, Peter Zijlstra wrote:
>
> > There might be other details, but this is the one that stood out.
>
> I think this also does the wrong thing for use_ww_ctx.
Something like so?
---
kernel/locking/mutex.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 0551c219c40e..070a0ac34aa7 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -512,6 +512,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
struct task_struct *task = current;
struct mutex_waiter waiter;
unsigned long flags;
+ bool acquired;
int ret;
preempt_disable();
@@ -543,6 +544,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
lock_contended(&lock->dep_map, ip);
for (;;) {
+ acquired = false;
/*
* Lets try to take the lock again - this is needed even if
* we get here for the first time (shortly after failing to
@@ -577,7 +579,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
/* didn't get the lock, go to sleep: */
spin_unlock_mutex(&lock->wait_lock, flags);
schedule_preempt_disabled();
+
+ if (mutex_is_locked(lock))
+ acquired = mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx);
+
spin_lock_mutex(&lock->wait_lock, flags);
+
+ if (acquired) {
+ atomic_set(&lock->count, -1);
+ break;
+ }
}
__set_task_state(task, TASK_RUNNING);
@@ -587,6 +598,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
atomic_set(&lock->count, 0);
debug_mutex_free_waiter(&waiter);
+ if (acquired)
+ goto unlock;
+
skip_wait:
/* got the lock - cleanup and rejoice! */
lock_acquired(&lock->dep_map, ip);
@@ -597,6 +611,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
ww_mutex_set_context_slowpath(ww, ww_ctx);
}
+unlock:
spin_unlock_mutex(&lock->wait_lock, flags);
preempt_enable();
return 0;
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2016-01-22 15:10 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTKzw-560-21@gated-at.bofh.it> |
| In reply to | #1314892 |
On 01/22/2016 06:06 AM, Peter Zijlstra wrote:
> On Fri, Jan 22, 2016 at 11:56:52AM +0100, Peter Zijlstra wrote:
>> On Fri, Jan 22, 2016 at 11:53:12AM +0100, Peter Zijlstra wrote:
>>
>>> There might be other details, but this is the one that stood out.
>> I think this also does the wrong thing for use_ww_ctx.
> Something like so?
I think that should work. My only minor concern is that putting the
waiter spinner at the end of the OSQ will take it longer to get the
lock, but that shouldn't be a big issue.
> ---
> kernel/locking/mutex.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
> index 0551c219c40e..070a0ac34aa7 100644
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -512,6 +512,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> struct task_struct *task = current;
> struct mutex_waiter waiter;
> unsigned long flags;
> + bool acquired;
> int ret;
>
> preempt_disable();
> @@ -543,6 +544,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> lock_contended(&lock->dep_map, ip);
>
> for (;;) {
> + acquired = false;
> /*
> * Lets try to take the lock again - this is needed even if
> * we get here for the first time (shortly after failing to
> @@ -577,7 +579,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> /* didn't get the lock, go to sleep: */
> spin_unlock_mutex(&lock->wait_lock, flags);
> schedule_preempt_disabled();
> +
> + if (mutex_is_locked(lock))
> + acquired = mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx);
> +
> spin_lock_mutex(&lock->wait_lock, flags);
> +
> + if (acquired) {
> + atomic_set(&lock->count, -1);
> + break;
> + }
> }
> __set_task_state(task, TASK_RUNNING);
>
> @@ -587,6 +598,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> atomic_set(&lock->count, 0);
> debug_mutex_free_waiter(&waiter);
>
> + if (acquired)
> + goto unlock;
> +
> skip_wait:
> /* got the lock - cleanup and rejoice! */
> lock_acquired(&lock->dep_map, ip);
> @@ -597,6 +611,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
> ww_mutex_set_context_slowpath(ww, ww_ctx);
> }
>
> +unlock:
> spin_unlock_mutex(&lock->wait_lock, flags);
> preempt_enable();
> return 0;
Cheers,
Longman
[toc] | [prev] | [next] | [standalone]
| From | Ding Tianhong <dingtianhong@huawei.com> |
|---|---|
| Date | 2016-01-24 09:10 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qUnUd-1Ui-1@gated-at.bofh.it> |
| In reply to | #1315009 |
On 2016/1/22 21:59, Waiman Long wrote:
> On 01/22/2016 06:06 AM, Peter Zijlstra wrote:
>> On Fri, Jan 22, 2016 at 11:56:52AM +0100, Peter Zijlstra wrote:
>>> On Fri, Jan 22, 2016 at 11:53:12AM +0100, Peter Zijlstra wrote:
>>>
>>>> There might be other details, but this is the one that stood out.
>>> I think this also does the wrong thing for use_ww_ctx.
>> Something like so?
>
> I think that should work. My only minor concern is that putting the waiter spinner at the end of the OSQ will take it longer to get the lock, but that shouldn't be a big issue.
>
>> ---
>> kernel/locking/mutex.c | 15 +++++++++++++++
>> 1 file changed, 15 insertions(+)
>>
>> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
>> index 0551c219c40e..070a0ac34aa7 100644
>> --- a/kernel/locking/mutex.c
>> +++ b/kernel/locking/mutex.c
>> @@ -512,6 +512,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>> struct task_struct *task = current;
>> struct mutex_waiter waiter;
>> unsigned long flags;
>> + bool acquired;
>> int ret;
>>
>> preempt_disable();
>> @@ -543,6 +544,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>> lock_contended(&lock->dep_map, ip);
>>
>> for (;;) {
>> + acquired = false;
>> /*
>> * Lets try to take the lock again - this is needed even if
>> * we get here for the first time (shortly after failing to
>> @@ -577,7 +579,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>> /* didn't get the lock, go to sleep: */
>> spin_unlock_mutex(&lock->wait_lock, flags);
>> schedule_preempt_disabled();
>> +
>> + if (mutex_is_locked(lock))
>> + acquired = mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx);
>> +
>> spin_lock_mutex(&lock->wait_lock, flags);
>> +
>> + if (acquired) {
>> + atomic_set(&lock->count, -1);
>> + break;
>> + }
>> }
>> __set_task_state(task, TASK_RUNNING);
>>
>> @@ -587,6 +598,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>> atomic_set(&lock->count, 0);
>> debug_mutex_free_waiter(&waiter);
>>
>> + if (acquired)
>> + goto unlock;
>> +
>> skip_wait:
>> /* got the lock - cleanup and rejoice! */
>> lock_acquired(&lock->dep_map, ip);
>> @@ -597,6 +611,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>> ww_mutex_set_context_slowpath(ww, ww_ctx);
>> }
>>
>> +unlock:
>> spin_unlock_mutex(&lock->wait_lock, flags);
>> preempt_enable();
>> return 0;
>
> Cheers,
> Longman
>
looks good to me, I will try this solution and report the result, thanks everyone.
Ding
> .
>
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2016-01-22 14:50 +0100 |
| Subject | Re: [PATCH RFC] locking/mutexes: don't spin on owner when wait list is not NULL. |
| Message-ID | <qTKg9-4IT-15@gated-at.bofh.it> |
| In reply to | #1314832 |
On 01/22/2016 03:54 AM, Peter Zijlstra wrote: > On Thu, Jan 21, 2016 at 06:02:34PM -0500, Waiman Long wrote: >> This patch attempts to fix this live-lock condition by enabling the >> a woken task in the wait list to enter optimistic spinning loop itself >> with precedence over the ones in the OSQ. This should prevent the >> live-lock >> condition from happening. > > So I think having the top waiter going back in to contend on the OSQ is > an excellent idea, but I'm not sure the wlh_spinning thing is important. Yes, that is optional. I put it there just to make it is more likely for the waiter spinner to get the lock. Without that, the chance will be 50/50 on average. I can certainly take that out. > The OSQ itself is FIFO fair, and the waiters retain the wait_list > position. So having the top wait_list entry contending on the OSQ > ensures we cannot starve (I think). > > Also, as Davidlohr said, we cannot copy/paste this much code. As I said in the previous mail, I do intend to refactor it before sending out the official patch. Cheers, Longman
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web