Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1250292 > unrolled thread
| Started by | ling.ma.program@gmail.com |
|---|---|
| First post | 2015-10-19 04:30 +0200 |
| Last post | 2015-10-21 07:50 +0200 |
| Articles | 20 on this page of 21 — 5 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback ling.ma.program@gmail.com - 2015-10-19 04:30 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ingo Molnar <mingo@kernel.org> - 2015-10-19 10:00 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Peter Zijlstra <peterz@infradead.org> - 2015-10-19 11:40 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ingo Molnar <mingo@kernel.org> - 2015-10-19 13:30 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Waiman Long <waiman.long@hpe.com> - 2015-10-19 19:30 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-20 05:00 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ingo Molnar <mingo@kernel.org> - 2015-10-20 10:50 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-21 07:30 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Peter Zijlstra <peterz@infradead.org> - 2015-10-20 11:20 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Peter Zijlstra <peterz@infradead.org> - 2015-10-19 11:40 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Waiman Long <waiman.long@hpe.com> - 2015-10-19 19:30 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-20 05:10 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Peter Zijlstra <peterz@infradead.org> - 2015-10-19 11:50 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-20 05:10 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-20 05:30 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Peter Zijlstra <peterz@infradead.org> - 2015-10-20 11:20 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-21 07:40 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Waiman Long <waiman.long@hpe.com> - 2015-10-19 19:20 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-20 05:20 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Waiman Long <waiman.long@hpe.com> - 2015-10-20 21:00 +0200
Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback Ling Ma <ling.ma.program@gmail.com> - 2015-10-21 07:50 +0200
Page 1 of 2 [1] 2 Next page →
| From | ling.ma.program@gmail.com |
|---|---|
| Date | 2015-10-19 04:30 +0200 |
| Subject | [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <ql8n0-7wA-19@gated-at.bofh.it> |
From: Ma Ling <ling.ml@alibaba-inc.com>
All load instructions can run speculatively but they have to follow
memory order rule in multiple cores as below:
_x = _y = 0
Processor 0 Processor 1
mov r1, [ _y] //M1 mov [ _x], 1 //M3
mov r2, [ _x] //M2 mov [ _y], 1 //M4
If r1 = 1, r2 must be 1
In order to guarantee above rule, although Processor 0 execute
M1 and M2 instruction out of order, they are kept in ROB,
when load buffer for _x in Processor 0 received the update
message from Processor 1, Processor 0 need to roll back
from M2 instruction, which will flush the whole pipeline,
the latency is over the penalty from branch prediction miss.
In this patch we use lock cmpxchg instruction to force load
instructions to be serialization, the destination operand
receives a write cycle without regard to the result of
the comparison, which can help us to reduce the penalty
from load instruction roll back.
Our experiment indicates the performance can be improved by 10%~15%
for 2 and 3 threads cases, the conflicts from lock cache line
spend them most of the time.
Thanks
Ling
Signed-off-by: Ma Ling <ling.ml@alibaba-inc.com>
---
kernel/locking/qspinlock.c | 43 ++++++++++++++++++-------------------------
1 files changed, 18 insertions(+), 25 deletions(-)
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index 87e9ce6..16421f2 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -332,25 +332,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
if (new == _Q_LOCKED_VAL)
return;
- /*
- * we're pending, wait for the owner to go away.
- *
- * *,1,1 -> *,1,0
+ /* we're waiting, and get lock owner
*
- * this wait loop must be a load-acquire such that we match the
- * store-release that clears the locked bit and create lock
- * sequentiality; this is because not all clear_pending_set_locked()
- * implementations imply full barriers.
+ * *,1,* -> *,0,1
*/
- while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_MASK)
+ while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending,
+ _Q_PENDING_VAL, _Q_LOCKED_VAL) != _Q_PENDING_VAL)
cpu_relax();
-
- /*
- * take ownership and clear the pending bit.
- *
- * *,1,0 -> *,0,1
- */
- clear_pending_set_locked(lock);
+
return;
/*
@@ -399,17 +388,21 @@ queue:
* we're at the head of the waitqueue, wait for the owner & pending to
* go away.
*
- * *,x,y -> *,0,0
- *
- * this wait loop must use a load-acquire such that we match the
- * store-release that clears the locked bit and create lock
- * sequentiality; this is because the set_locked() function below
- * does not imply a full barrier.
- *
+ * *,x,y -> *,0,1
*/
pv_wait_head(lock, node);
- while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK)
+ next = READ_ONCE(node->next);
+ while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending, 0,
+ _Q_LOCKED_VAL) != 0) {
+ next = READ_ONCE(node->next);
cpu_relax();
+ }
+
+ if (next)
+ goto next_node;
+
+ val = smp_load_acquire(&lock->val.counter);
+ tail = tail | _Q_LOCKED_VAL;
/*
* claim the lock:
@@ -423,7 +416,6 @@ queue:
*/
for (;;) {
if (val != tail) {
- set_locked(lock);
break;
}
old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
@@ -439,6 +431,7 @@ queue:
while (!(next = READ_ONCE(node->next)))
cpu_relax();
+next_node:
arch_mcs_spin_unlock_contended(&next->locked);
pv_kick_node(lock, next);
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2015-10-19 10:00 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qldwm-6s2-13@gated-at.bofh.it> |
| In reply to | #1250292 |
* ling.ma.program@gmail.com <ling.ma.program@gmail.com> wrote: > From: Ma Ling <ling.ml@alibaba-inc.com> > > All load instructions can run speculatively but they have to follow > memory order rule in multiple cores as below: > _x = _y = 0 > > Processor 0 Processor 1 > > mov r1, [ _y] //M1 mov [ _x], 1 //M3 > mov r2, [ _x] //M2 mov [ _y], 1 //M4 > > If r1 = 1, r2 must be 1 > > In order to guarantee above rule, although Processor 0 execute > M1 and M2 instruction out of order, they are kept in ROB, > when load buffer for _x in Processor 0 received the update > message from Processor 1, Processor 0 need to roll back > from M2 instruction, which will flush the whole pipeline, > the latency is over the penalty from branch prediction miss. > > In this patch we use lock cmpxchg instruction to force load > instructions to be serialization, the destination operand > receives a write cycle without regard to the result of > the comparison, which can help us to reduce the penalty > from load instruction roll back. > > Our experiment indicates the performance can be improved by 10%~15% > for 2 and 3 threads cases, the conflicts from lock cache line > spend them most of the time. So it would be nice to create a new user-space spinlock testing facility, via a new 'perf bench spinlock' feature or so. That way others can test and validate your results on different hardware as well. Thanks, Ingo -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2015-10-19 11:40 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlf59-lZ-21@gated-at.bofh.it> |
| In reply to | #1250414 |
On Mon, Oct 19, 2015 at 09:58:23AM +0200, Ingo Molnar wrote: > > * ling.ma.program@gmail.com <ling.ma.program@gmail.com> wrote: > > > From: Ma Ling <ling.ml@alibaba-inc.com> > > > > All load instructions can run speculatively but they have to follow > > memory order rule in multiple cores as below: > > _x = _y = 0 > > > > Processor 0 Processor 1 > > > > mov r1, [ _y] //M1 mov [ _x], 1 //M3 > > mov r2, [ _x] //M2 mov [ _y], 1 //M4 > > > > If r1 = 1, r2 must be 1 > > > > In order to guarantee above rule, although Processor 0 execute > > M1 and M2 instruction out of order, they are kept in ROB, > > when load buffer for _x in Processor 0 received the update > > message from Processor 1, Processor 0 need to roll back > > from M2 instruction, which will flush the whole pipeline, > > the latency is over the penalty from branch prediction miss. > > > > In this patch we use lock cmpxchg instruction to force load > > instructions to be serialization, the destination operand > > receives a write cycle without regard to the result of > > the comparison, which can help us to reduce the penalty > > from load instruction roll back. > > > > Our experiment indicates the performance can be improved by 10%~15% > > for 2 and 3 threads cases, the conflicts from lock cache line > > spend them most of the time. > > So it would be nice to create a new user-space spinlock testing facility, via a > new 'perf bench spinlock' feature or so. That way others can test and validate > your results on different hardware as well. So its trivial to lift this code into userspace -- in fact, I have that somewhere. The trouble is going to keep them in sync. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2015-10-19 13:30 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlgNA-2V1-9@gated-at.bofh.it> |
| In reply to | #1250509 |
* Peter Zijlstra <peterz@infradead.org> wrote: > On Mon, Oct 19, 2015 at 09:58:23AM +0200, Ingo Molnar wrote: > > > > * ling.ma.program@gmail.com <ling.ma.program@gmail.com> wrote: > > > > > From: Ma Ling <ling.ml@alibaba-inc.com> > > > > > > All load instructions can run speculatively but they have to follow > > > memory order rule in multiple cores as below: > > > _x = _y = 0 > > > > > > Processor 0 Processor 1 > > > > > > mov r1, [ _y] //M1 mov [ _x], 1 //M3 > > > mov r2, [ _x] //M2 mov [ _y], 1 //M4 > > > > > > If r1 = 1, r2 must be 1 > > > > > > In order to guarantee above rule, although Processor 0 execute > > > M1 and M2 instruction out of order, they are kept in ROB, > > > when load buffer for _x in Processor 0 received the update > > > message from Processor 1, Processor 0 need to roll back > > > from M2 instruction, which will flush the whole pipeline, > > > the latency is over the penalty from branch prediction miss. > > > > > > In this patch we use lock cmpxchg instruction to force load > > > instructions to be serialization, the destination operand > > > receives a write cycle without regard to the result of > > > the comparison, which can help us to reduce the penalty > > > from load instruction roll back. > > > > > > Our experiment indicates the performance can be improved by 10%~15% > > > for 2 and 3 threads cases, the conflicts from lock cache line > > > spend them most of the time. > > > > So it would be nice to create a new user-space spinlock testing facility, via a > > new 'perf bench spinlock' feature or so. That way others can test and validate > > your results on different hardware as well. > > So its trivial to lift this code into userspace -- in fact, I have that > somewhere. > > The trouble is going to keep them in sync. So we can just try this optimistically, and if it keeps breaking, we can use the technique perf uses to sync up the rbtree implementation: we copy the kernel version into tooling, but run diff against the kernel version and warn at tool build time that there's divergence. I.e. a non-build-fatal force that keeps things in sync. Thanks, Ingo -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2015-10-19 19:30 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlmpY-2H8-23@gated-at.bofh.it> |
| In reply to | #1250574 |
On 10/19/2015 07:24 AM, Ingo Molnar wrote: > * Peter Zijlstra<peterz@infradead.org> wrote: > >> On Mon, Oct 19, 2015 at 09:58:23AM +0200, Ingo Molnar wrote: >>> * ling.ma.program@gmail.com<ling.ma.program@gmail.com> wrote: >>> >>>> From: Ma Ling<ling.ml@alibaba-inc.com> >>>> >>>> All load instructions can run speculatively but they have to follow >>>> memory order rule in multiple cores as below: >>>> _x = _y = 0 >>>> >>>> Processor 0 Processor 1 >>>> >>>> mov r1, [ _y] //M1 mov [ _x], 1 //M3 >>>> mov r2, [ _x] //M2 mov [ _y], 1 //M4 >>>> >>>> If r1 = 1, r2 must be 1 >>>> >>>> In order to guarantee above rule, although Processor 0 execute >>>> M1 and M2 instruction out of order, they are kept in ROB, >>>> when load buffer for _x in Processor 0 received the update >>>> message from Processor 1, Processor 0 need to roll back >>>> from M2 instruction, which will flush the whole pipeline, >>>> the latency is over the penalty from branch prediction miss. >>>> >>>> In this patch we use lock cmpxchg instruction to force load >>>> instructions to be serialization, the destination operand >>>> receives a write cycle without regard to the result of >>>> the comparison, which can help us to reduce the penalty >>>> from load instruction roll back. >>>> >>>> Our experiment indicates the performance can be improved by 10%~15% >>>> for 2 and 3 threads cases, the conflicts from lock cache line >>>> spend them most of the time. >>> So it would be nice to create a new user-space spinlock testing facility, via a >>> new 'perf bench spinlock' feature or so. That way others can test and validate >>> your results on different hardware as well. >> So its trivial to lift this code into userspace -- in fact, I have that >> somewhere. >> >> The trouble is going to keep them in sync. > So we can just try this optimistically, and if it keeps breaking, we can use the > technique perf uses to sync up the rbtree implementation: we copy the kernel > version into tooling, but run diff against the kernel version and warn at tool > build time that there's divergence. > > I.e. a non-build-fatal force that keeps things in sync. > > Thanks, > > Ingo > It is on my to-do list. I just want to wrap up my latest PV qspinlock patch before embarking on this adventure. Cheers, Longman -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-20 05:00 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlvjz-7ng-7@gated-at.bofh.it> |
| In reply to | #1250414 |
[Multipart message — attachments visible in raw view] — view raw
> > So it would be nice to create a new user-space spinlock testing facility, via a > new 'perf bench spinlock' feature or so. That way others can test and validate > your results on different hardware as well. > Attached the spinlock test module . Queued spinlock will run very slowly in user space because process switch context, it is OK for spinlock-test implementation with kernel module ? Thanks Ling
[toc] | [prev] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2015-10-20 10:50 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlAMj-6Wk-35@gated-at.bofh.it> |
| In reply to | #1251274 |
* Ling Ma <ling.ma.program@gmail.com> wrote: > > So it would be nice to create a new user-space spinlock testing facility, via > > a new 'perf bench spinlock' feature or so. That way others can test and > > validate your results on different hardware as well. > > Attached the spinlock test module . Queued spinlock will run very slowly in user > space because process switch context, it is OK for spinlock-test implementation > with kernel module ? Not sure what you mean by 'because process switch context': if you pin the test tasks to individual CPUs and make sure there's nothing else running it should be equivalent to kernel-space execution. Thanks, Ingo -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-21 07:30 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlU8i-1IS-3@gated-at.bofh.it> |
| In reply to | #1251453 |
Ok, we will put the spinlock test into the perf bench. Thanks Ling 2015-10-20 16:48 GMT+08:00 Ingo Molnar <mingo@kernel.org>: > > * Ling Ma <ling.ma.program@gmail.com> wrote: > >> > So it would be nice to create a new user-space spinlock testing facility, via >> > a new 'perf bench spinlock' feature or so. That way others can test and >> > validate your results on different hardware as well. >> >> Attached the spinlock test module . Queued spinlock will run very slowly in user >> space because process switch context, it is OK for spinlock-test implementation >> with kernel module ? > > Not sure what you mean by 'because process switch context': if you pin the test > tasks to individual CPUs and make sure there's nothing else running it should be > equivalent to kernel-space execution. > > Thanks, > > Ingo -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2015-10-20 11:20 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlBfl-7L2-39@gated-at.bofh.it> |
| In reply to | #1251274 |
On Tue, Oct 20, 2015 at 10:57:53AM +0800, Ling Ma wrote: > > > > So it would be nice to create a new user-space spinlock testing facility, via a > > new 'perf bench spinlock' feature or so. That way others can test and validate > > your results on different hardware as well. > > > Attached the spinlock test module . Queued spinlock will run very > slowly in user space > because process switch context, it is OK for spinlock-test > implementation with kernel module ? Works just fine in userspace if you pin each thread to a cpu and ensure there's nothing else running on the system. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2015-10-19 11:40 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlf58-lZ-11@gated-at.bofh.it> |
| In reply to | #1250292 |
On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote:
> From: Ma Ling <ling.ml@alibaba-inc.com>
>
> All load instructions can run speculatively but they have to follow
> memory order rule in multiple cores as below:
> _x = _y = 0
>
> Processor 0 Processor 1
>
> mov r1, [ _y] //M1 mov [ _x], 1 //M3
> mov r2, [ _x] //M2 mov [ _y], 1 //M4
>
> If r1 = 1, r2 must be 1
>
> In order to guarantee above rule, although Processor 0 execute
> M1 and M2 instruction out of order, they are kept in ROB,
> when load buffer for _x in Processor 0 received the update
> message from Processor 1, Processor 0 need to roll back
> from M2 instruction, which will flush the whole pipeline,
> the latency is over the penalty from branch prediction miss.
>
> In this patch we use lock cmpxchg instruction to force load
> instructions to be serialization, the destination operand
> receives a write cycle without regard to the result of
> the comparison, which can help us to reduce the penalty
> from load instruction roll back.
>
> Our experiment indicates the performance can be improved by 10%~15%
> for 2 and 3 threads cases, the conflicts from lock cache line
> spend them most of the time.
On what hardware? Also, you forgot to Cc Waiman, who is a prime author
of this code. Excessive quoting for his benefit.
> Signed-off-by: Ma Ling <ling.ml@alibaba-inc.com>
> ---
> kernel/locking/qspinlock.c | 43 ++++++++++++++++++-------------------------
> 1 files changed, 18 insertions(+), 25 deletions(-)
>
> diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> index 87e9ce6..16421f2 100644
> --- a/kernel/locking/qspinlock.c
> +++ b/kernel/locking/qspinlock.c
> @@ -332,25 +332,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
> if (new == _Q_LOCKED_VAL)
> return;
>
> - /*
> - * we're pending, wait for the owner to go away.
> - *
> - * *,1,1 -> *,1,0
> + /* we're waiting, and get lock owner
That's incorrect coding style
> *
> - * this wait loop must be a load-acquire such that we match the
> - * store-release that clears the locked bit and create lock
> - * sequentiality; this is because not all clear_pending_set_locked()
> - * implementations imply full barriers.
> + * *,1,* -> *,0,1
> */
> - while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_MASK)
> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending,
> + _Q_PENDING_VAL, _Q_LOCKED_VAL) != _Q_PENDING_VAL)
That's both horrible coding style and painful, we should not spin-wait
with a cmpxchg instruction like that.
> cpu_relax();
> -
> - /*
> - * take ownership and clear the pending bit.
> - *
> - * *,1,0 -> *,0,1
> - */
> - clear_pending_set_locked(lock);
> +
> return;
>
> /*
> @@ -399,17 +388,21 @@ queue:
> * we're at the head of the waitqueue, wait for the owner & pending to
> * go away.
> *
> - * *,x,y -> *,0,0
> - *
> - * this wait loop must use a load-acquire such that we match the
> - * store-release that clears the locked bit and create lock
> - * sequentiality; this is because the set_locked() function below
> - * does not imply a full barrier.
> - *
> + * *,x,y -> *,0,1
> */
> pv_wait_head(lock, node);
> - while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK)
> + next = READ_ONCE(node->next);
> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending, 0,
> + _Q_LOCKED_VAL) != 0) {
idem
> + next = READ_ONCE(node->next);
> cpu_relax();
> + }
> +
> + if (next)
> + goto next_node;
> +
> + val = smp_load_acquire(&lock->val.counter);
> + tail = tail | _Q_LOCKED_VAL;
>
> /*
> * claim the lock:
> @@ -423,7 +416,6 @@ queue:
> */
> for (;;) {
> if (val != tail) {
> - set_locked(lock);
> break;
> }
> old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
> @@ -439,6 +431,7 @@ queue:
> while (!(next = READ_ONCE(node->next)))
> cpu_relax();
>
> +next_node:
> arch_mcs_spin_unlock_contended(&next->locked);
> pv_kick_node(lock, next);
>
> --
> 1.7.1
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2015-10-19 19:30 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlmpY-2H8-13@gated-at.bofh.it> |
| In reply to | #1250505 |
On 10/19/2015 05:33 AM, Peter Zijlstra wrote: > On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote: >> From: Ma Ling<ling.ml@alibaba-inc.com> >> >> All load instructions can run speculatively but they have to follow >> memory order rule in multiple cores as below: >> _x = _y = 0 >> >> Processor 0 Processor 1 >> >> mov r1, [ _y] //M1 mov [ _x], 1 //M3 >> mov r2, [ _x] //M2 mov [ _y], 1 //M4 >> >> If r1 = 1, r2 must be 1 >> >> In order to guarantee above rule, although Processor 0 execute >> M1 and M2 instruction out of order, they are kept in ROB, >> when load buffer for _x in Processor 0 received the update >> message from Processor 1, Processor 0 need to roll back >> from M2 instruction, which will flush the whole pipeline, >> the latency is over the penalty from branch prediction miss. >> >> In this patch we use lock cmpxchg instruction to force load >> instructions to be serialization, the destination operand >> receives a write cycle without regard to the result of >> the comparison, which can help us to reduce the penalty >> from load instruction roll back. >> >> Our experiment indicates the performance can be improved by 10%~15% >> for 2 and 3 threads cases, the conflicts from lock cache line >> spend them most of the time. > On what hardware? Also, you forgot to Cc Waiman, who is a prime author > of this code. Excessive quoting for his benefit. Thanks for letting me aware of this patch. I had commented on the patch in a separate mail. Cheers, Longman -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-20 05:10 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlvtf-7OS-5@gated-at.bofh.it> |
| In reply to | #1250505 |
2015-10-19 17:33 GMT+08:00 Peter Zijlstra <peterz@infradead.org>:
> On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote:
>> From: Ma Ling <ling.ml@alibaba-inc.com>
>>
>> All load instructions can run speculatively but they have to follow
>> memory order rule in multiple cores as below:
>> _x = _y = 0
>>
>> Processor 0 Processor 1
>>
>> mov r1, [ _y] //M1 mov [ _x], 1 //M3
>> mov r2, [ _x] //M2 mov [ _y], 1 //M4
>>
>> If r1 = 1, r2 must be 1
>>
>> In order to guarantee above rule, although Processor 0 execute
>> M1 and M2 instruction out of order, they are kept in ROB,
>> when load buffer for _x in Processor 0 received the update
>> message from Processor 1, Processor 0 need to roll back
>> from M2 instruction, which will flush the whole pipeline,
>> the latency is over the penalty from branch prediction miss.
>>
>> In this patch we use lock cmpxchg instruction to force load
>> instructions to be serialization, the destination operand
>> receives a write cycle without regard to the result of
>> the comparison, which can help us to reduce the penalty
>> from load instruction roll back.
>>
>> Our experiment indicates the performance can be improved by 10%~15%
>> for 2 and 3 threads cases, the conflicts from lock cache line
>> spend them most of the time.
>
> On what hardware? Also, you forgot to Cc Waiman, who is a prime author
> of this code. Excessive quoting for his benefit.
>
>> Signed-off-by: Ma Ling <ling.ml@alibaba-inc.com>
>> ---
>> kernel/locking/qspinlock.c | 43 ++++++++++++++++++-------------------------
>> 1 files changed, 18 insertions(+), 25 deletions(-)
>>
>> diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
>> index 87e9ce6..16421f2 100644
>> --- a/kernel/locking/qspinlock.c
>> +++ b/kernel/locking/qspinlock.c
>> @@ -332,25 +332,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
>> if (new == _Q_LOCKED_VAL)
>> return;
>>
>> - /*
>> - * we're pending, wait for the owner to go away.
>> - *
>> - * *,1,1 -> *,1,0
>> + /* we're waiting, and get lock owner
>
> That's incorrect coding style
Ok, I will fix, thx.
>
>> *
>> - * this wait loop must be a load-acquire such that we match the
>> - * store-release that clears the locked bit and create lock
>> - * sequentiality; this is because not all clear_pending_set_locked()
>> - * implementations imply full barriers.
>> + * *,1,* -> *,0,1
>> */
>> - while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_MASK)
>> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending,
>> + _Q_PENDING_VAL, _Q_LOCKED_VAL) != _Q_PENDING_VAL)
>
> That's both horrible coding style and painful, we should not spin-wait
> with a cmpxchg instruction like that.
Ok I will fix
>
>> cpu_relax();
>> -
>> - /*
>> - * take ownership and clear the pending bit.
>> - *
>> - * *,1,0 -> *,0,1
>> - */
>> - clear_pending_set_locked(lock);
>> +
>> return;
>>
>> /*
>> @@ -399,17 +388,21 @@ queue:
>> * we're at the head of the waitqueue, wait for the owner & pending to
>> * go away.
>> *
>> - * *,x,y -> *,0,0
>> - *
>> - * this wait loop must use a load-acquire such that we match the
>> - * store-release that clears the locked bit and create lock
>> - * sequentiality; this is because the set_locked() function below
>> - * does not imply a full barrier.
>> - *
>> + * *,x,y -> *,0,1
>> */
>> pv_wait_head(lock, node);
>> - while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK)
>> + next = READ_ONCE(node->next);
>> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending, 0,
>> + _Q_LOCKED_VAL) != 0) {
>
> idem
>
>> + next = READ_ONCE(node->next);
>> cpu_relax();
>> + }
>> +
>> + if (next)
>> + goto next_node;
>> +
>> + val = smp_load_acquire(&lock->val.counter);
>> + tail = tail | _Q_LOCKED_VAL;
>>
>> /*
>> * claim the lock:
>> @@ -423,7 +416,6 @@ queue:
>> */
>> for (;;) {
>> if (val != tail) {
>> - set_locked(lock);
>> break;
>> }
>> old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
>> @@ -439,6 +431,7 @@ queue:
>> while (!(next = READ_ONCE(node->next)))
>> cpu_relax();
>>
>> +next_node:
>> arch_mcs_spin_unlock_contended(&next->locked);
>> pv_kick_node(lock, next);
>>
>> --
>> 1.7.1
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2015-10-19 11:50 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlfeO-xB-19@gated-at.bofh.it> |
| In reply to | #1250292 |
On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote: > From: Ma Ling <ling.ml@alibaba-inc.com> > > All load instructions can run speculatively but they have to follow > memory order rule in multiple cores as below: > _x = _y = 0 > > Processor 0 Processor 1 > > mov r1, [ _y] //M1 mov [ _x], 1 //M3 > mov r2, [ _x] //M2 mov [ _y], 1 //M4 > > If r1 = 1, r2 must be 1 > > In order to guarantee above rule, although Processor 0 execute > M1 and M2 instruction out of order, they are kept in ROB, > when load buffer for _x in Processor 0 received the update > message from Processor 1, Processor 0 need to roll back > from M2 instruction, which will flush the whole pipeline, > the latency is over the penalty from branch prediction miss. > > In this patch we use lock cmpxchg instruction to force load "lock cmpxchg" makes me think you're working on x86. > instructions to be serialization, smp_rmb() does that, and that's 'free' on x86. Because x86 doesn't do read reordering. > the destination operand > receives a write cycle without regard to the result of > the comparison, which can help us to reduce the penalty > from load instruction roll back. And that makes me think I'm not understanding what you're getting at. If you need to force memory order, a "fence" (or smp_mb()) would still be cheaper than endlessly pulling the line into exclusive state for no reason, right? > Our experiment indicates the performance can be improved by 10%~15% > for 2 and 3 threads cases, the conflicts from lock cache line > spend them most of the time. That just doesn't parse, what? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-20 05:10 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlvtf-7OS-1@gated-at.bofh.it> |
| In reply to | #1250526 |
2015-10-19 17:46 GMT+08:00 Peter Zijlstra <peterz@infradead.org>: > On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote: >> From: Ma Ling <ling.ml@alibaba-inc.com> >> >> All load instructions can run speculatively but they have to follow >> memory order rule in multiple cores as below: >> _x = _y = 0 >> >> Processor 0 Processor 1 >> >> mov r1, [ _y] //M1 mov [ _x], 1 //M3 >> mov r2, [ _x] //M2 mov [ _y], 1 //M4 >> >> If r1 = 1, r2 must be 1 >> >> In order to guarantee above rule, although Processor 0 execute >> M1 and M2 instruction out of order, they are kept in ROB, >> when load buffer for _x in Processor 0 received the update >> message from Processor 1, Processor 0 need to roll back >> from M2 instruction, which will flush the whole pipeline, >> the latency is over the penalty from branch prediction miss. >> >> In this patch we use lock cmpxchg instruction to force load > > "lock cmpxchg" makes me think you're working on x86. > >> instructions to be serialization, > > smp_rmb() does that, and that's 'free' on x86. Because x86 doesn't do > read reordering. > >> the destination operand >> receives a write cycle without regard to the result of >> the comparison, which can help us to reduce the penalty >> from load instruction roll back. > > And that makes me think I'm not understanding what you're getting at. If > you need to force memory order, a "fence" (or smp_mb()) would still be > cheaper than endlessly pulling the line into exclusive state for no > reason, right? > >> Our experiment indicates the performance can be improved by 10%~15% >> for 2 and 3 threads cases, the conflicts from lock cache line >> spend them most of the time. > > That just doesn't parse, what? When the thread number is 2 or 3, only lock cache line will generate conflicts, and cost them the most of the time. Thanks Ling -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-20 05:30 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlvMC-8cU-3@gated-at.bofh.it> |
| In reply to | #1250526 |
2015-10-19 17:46 GMT+08:00 Peter Zijlstra <peterz@infradead.org>: > On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote: >> From: Ma Ling <ling.ml@alibaba-inc.com> >> >> All load instructions can run speculatively but they have to follow >> memory order rule in multiple cores as below: >> _x = _y = 0 >> >> Processor 0 Processor 1 >> >> mov r1, [ _y] //M1 mov [ _x], 1 //M3 >> mov r2, [ _x] //M2 mov [ _y], 1 //M4 >> >> If r1 = 1, r2 must be 1 >> >> In order to guarantee above rule, although Processor 0 execute >> M1 and M2 instruction out of order, they are kept in ROB, >> when load buffer for _x in Processor 0 received the update >> message from Processor 1, Processor 0 need to roll back >> from M2 instruction, which will flush the whole pipeline, >> the latency is over the penalty from branch prediction miss. >> >> In this patch we use lock cmpxchg instruction to force load > > "lock cmpxchg" makes me think you're working on x86. > >> instructions to be serialization, > > smp_rmb() does that, and that's 'free' on x86. Because x86 doesn't do > read reordering. > >> the destination operand >> receives a write cycle without regard to the result of >> the comparison, which can help us to reduce the penalty >> from load instruction roll back. > > And that makes me think I'm not understanding what you're getting at. If > you need to force memory order, a "fence" (or smp_mb()) would still be > cheaper than endlessly pulling the line into exclusive state for no > reason, right? Peter, we tested instruction lfence, but we hard to see any benefit, lfence only force load instruction , but load instruction still will rollback ,actually cmpxchg behavior is more like write operation, so we choose it. Thanks Ling > >> Our experiment indicates the performance can be improved by 10%~15% >> for 2 and 3 threads cases, the conflicts from lock cache line >> spend them most of the time. > > That just doesn't parse, what? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2015-10-20 11:20 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlBfm-7L2-49@gated-at.bofh.it> |
| In reply to | #1251280 |
On Tue, Oct 20, 2015 at 11:24:02AM +0800, Ling Ma wrote: > 2015-10-19 17:46 GMT+08:00 Peter Zijlstra <peterz@infradead.org>: > > On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote: > >> From: Ma Ling <ling.ml@alibaba-inc.com> > >> > >> All load instructions can run speculatively but they have to follow > >> memory order rule in multiple cores as below: > >> _x = _y = 0 > >> > >> Processor 0 Processor 1 > >> > >> mov r1, [ _y] //M1 mov [ _x], 1 //M3 > >> mov r2, [ _x] //M2 mov [ _y], 1 //M4 > >> > >> If r1 = 1, r2 must be 1 > >> > >> In order to guarantee above rule, although Processor 0 execute > >> M1 and M2 instruction out of order, they are kept in ROB, > >> when load buffer for _x in Processor 0 received the update > >> message from Processor 1, Processor 0 need to roll back > >> from M2 instruction, which will flush the whole pipeline, > >> the latency is over the penalty from branch prediction miss. > >> > >> In this patch we use lock cmpxchg instruction to force load > > > > "lock cmpxchg" makes me think you're working on x86. > > > >> instructions to be serialization, > > > > smp_rmb() does that, and that's 'free' on x86. Because x86 doesn't do > > read reordering. > > > >> the destination operand > >> receives a write cycle without regard to the result of > >> the comparison, which can help us to reduce the penalty > >> from load instruction roll back. > > > > And that makes me think I'm not understanding what you're getting at. If > > you need to force memory order, a "fence" (or smp_mb()) would still be > > cheaper than endlessly pulling the line into exclusive state for no > > reason, right? > > Peter, > > we tested instruction lfence, but we hard to see any benefit, lfence > only force load instruction , > but load instruction still will rollback ,actually cmpxchg behavior is > more like write operation, > so we choose it. But why? I'm just not getting this. Also LOCK CMPXCHG is 24 cycles when hot, that's almost as bad as a pipeline flush, and it can be many times worse when it needs to actually fetch memory from further than L1. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-21 07:40 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlUhX-1TW-1@gated-at.bofh.it> |
| In reply to | #1251492 |
2015-10-20 17:16 GMT+08:00 Peter Zijlstra <peterz@infradead.org>: > On Tue, Oct 20, 2015 at 11:24:02AM +0800, Ling Ma wrote: >> 2015-10-19 17:46 GMT+08:00 Peter Zijlstra <peterz@infradead.org>: >> > On Mon, Oct 19, 2015 at 10:27:22AM +0800, ling.ma.program@gmail.com wrote: >> >> From: Ma Ling <ling.ml@alibaba-inc.com> >> >> >> >> All load instructions can run speculatively but they have to follow >> >> memory order rule in multiple cores as below: >> >> _x = _y = 0 >> >> >> >> Processor 0 Processor 1 >> >> >> >> mov r1, [ _y] //M1 mov [ _x], 1 //M3 >> >> mov r2, [ _x] //M2 mov [ _y], 1 //M4 >> >> >> >> If r1 = 1, r2 must be 1 >> >> >> >> In order to guarantee above rule, although Processor 0 execute >> >> M1 and M2 instruction out of order, they are kept in ROB, >> >> when load buffer for _x in Processor 0 received the update >> >> message from Processor 1, Processor 0 need to roll back >> >> from M2 instruction, which will flush the whole pipeline, >> >> the latency is over the penalty from branch prediction miss. >> >> >> >> In this patch we use lock cmpxchg instruction to force load >> > >> > "lock cmpxchg" makes me think you're working on x86. >> > >> >> instructions to be serialization, >> > >> > smp_rmb() does that, and that's 'free' on x86. Because x86 doesn't do >> > read reordering. >> > >> >> the destination operand >> >> receives a write cycle without regard to the result of >> >> the comparison, which can help us to reduce the penalty >> >> from load instruction roll back. >> > >> > And that makes me think I'm not understanding what you're getting at. If >> > you need to force memory order, a "fence" (or smp_mb()) would still be >> > cheaper than endlessly pulling the line into exclusive state for no >> > reason, right? >> >> Peter, >> >> we tested instruction lfence, but we hard to see any benefit, lfence >> only force load instruction , >> but load instruction still will rollback ,actually cmpxchg behavior is >> more like write operation, >> so we choose it. > > But why? I'm just not getting this. > > Also LOCK CMPXCHG is 24 cycles when hot, that's almost as bad as > a pipeline flush, and it can be many times worse when it needs to > actually fetch memory from further than L1. We will clarify the root cause about this question soon. Thanks Ling -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2015-10-19 19:20 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlmgi-2vV-9@gated-at.bofh.it> |
| In reply to | #1250292 |
On 10/18/2015 10:27 PM, ling.ma.program@gmail.com wrote:
> From: Ma Ling<ling.ml@alibaba-inc.com>
>
> All load instructions can run speculatively but they have to follow
> memory order rule in multiple cores as below:
> _x = _y = 0
>
> Processor 0 Processor 1
>
> mov r1, [ _y] //M1 mov [ _x], 1 //M3
> mov r2, [ _x] //M2 mov [ _y], 1 //M4
>
> If r1 = 1, r2 must be 1
>
> In order to guarantee above rule, although Processor 0 execute
> M1 and M2 instruction out of order, they are kept in ROB,
> when load buffer for _x in Processor 0 received the update
> message from Processor 1, Processor 0 need to roll back
> from M2 instruction, which will flush the whole pipeline,
> the latency is over the penalty from branch prediction miss.
>
> In this patch we use lock cmpxchg instruction to force load
> instructions to be serialization, the destination operand
> receives a write cycle without regard to the result of
> the comparison, which can help us to reduce the penalty
> from load instruction roll back.
>
> Our experiment indicates the performance can be improved by 10%~15%
> for 2 and 3 threads cases, the conflicts from lock cache line
> spend them most of the time.
What kind of performance test were you running? With the right timing,
it is possible that you see some performance gain. However, if the lock
hold time is longer so that a fair number of cmpxchg instructions have
to be executed before it can get the lock, you may see a performance
degradation especially if the lock holder needs to access the lock
cacheline.
In general, we try to avoid this kind of cmpxchg loop unless we are sure
that at most a few iterations of the loop may happen.
>
> Thanks
> Ling
>
> Signed-off-by: Ma Ling<ling.ml@alibaba-inc.com>
> ---
> kernel/locking/qspinlock.c | 43 ++++++++++++++++++-------------------------
> 1 files changed, 18 insertions(+), 25 deletions(-)
>
> diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> index 87e9ce6..16421f2 100644
> --- a/kernel/locking/qspinlock.c
> +++ b/kernel/locking/qspinlock.c
> @@ -332,25 +332,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
> if (new == _Q_LOCKED_VAL)
> return;
>
> - /*
> - * we're pending, wait for the owner to go away.
> - *
> - * *,1,1 -> *,1,0
> + /* we're waiting, and get lock owner
> *
> - * this wait loop must be a load-acquire such that we match the
> - * store-release that clears the locked bit and create lock
> - * sequentiality; this is because not all clear_pending_set_locked()
> - * implementations imply full barriers.
> + * *,1,* -> *,0,1
> */
> - while ((val = smp_load_acquire(&lock->val.counter))& _Q_LOCKED_MASK)
> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending,
> + _Q_PENDING_VAL, _Q_LOCKED_VAL) != _Q_PENDING_VAL)
> cpu_relax();
> -
> - /*
> - * take ownership and clear the pending bit.
> - *
> - * *,1,0 -> *,0,1
> - */
> - clear_pending_set_locked(lock);
> +
> return;
>
> /*
> @@ -399,17 +388,21 @@ queue:
> * we're at the head of the waitqueue, wait for the owner& pending to
> * go away.
> *
> - * *,x,y -> *,0,0
> - *
> - * this wait loop must use a load-acquire such that we match the
> - * store-release that clears the locked bit and create lock
> - * sequentiality; this is because the set_locked() function below
> - * does not imply a full barrier.
> - *
> + * *,x,y -> *,0,1
> */
> pv_wait_head(lock, node);
> - while ((val = smp_load_acquire(&lock->val.counter))& _Q_LOCKED_PENDING_MASK)
> + next = READ_ONCE(node->next);
> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending, 0,
The locked_pending field isn't valid if _Q_PENDING_BITS != 8. So it
won't work if NR_CPUS is 16k or more.
> + _Q_LOCKED_VAL) != 0) {
> + next = READ_ONCE(node->next);
> cpu_relax();
> + }
> +
> + if (next)
> + goto next_node;
I did notice a slight performance benefit by reading the next pointer
early in light load cases myself. However, it is a very minor
improvement that I haven't actively pursued it.
> +
> + val = smp_load_acquire(&lock->val.counter);
> + tail = tail | _Q_LOCKED_VAL;
>
> /*
> * claim the lock:
> @@ -423,7 +416,6 @@ queue:
> */
> for (;;) {
> if (val != tail) {
> - set_locked(lock);
> break;
> }
> old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
> @@ -439,6 +431,7 @@ queue:
> while (!(next = READ_ONCE(node->next)))
> cpu_relax();
>
> +next_node:
> arch_mcs_spin_unlock_contended(&next->locked);
> pv_kick_node(lock, next);
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ling Ma <ling.ma.program@gmail.com> |
|---|---|
| Date | 2015-10-20 05:20 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlvCV-816-7@gated-at.bofh.it> |
| In reply to | #1250942 |
2015-10-20 1:18 GMT+08:00 Waiman Long <waiman.long@hpe.com>:
> On 10/18/2015 10:27 PM, ling.ma.program@gmail.com wrote:
>>
>> From: Ma Ling<ling.ml@alibaba-inc.com>
>>
>> All load instructions can run speculatively but they have to follow
>> memory order rule in multiple cores as below:
>> _x = _y = 0
>>
>> Processor 0 Processor 1
>>
>> mov r1, [ _y] //M1 mov [ _x], 1 //M3
>> mov r2, [ _x] //M2 mov [ _y], 1 //M4
>>
>> If r1 = 1, r2 must be 1
>>
>> In order to guarantee above rule, although Processor 0 execute
>> M1 and M2 instruction out of order, they are kept in ROB,
>> when load buffer for _x in Processor 0 received the update
>> message from Processor 1, Processor 0 need to roll back
>> from M2 instruction, which will flush the whole pipeline,
>> the latency is over the penalty from branch prediction miss.
>>
>> In this patch we use lock cmpxchg instruction to force load
>> instructions to be serialization, the destination operand
>> receives a write cycle without regard to the result of
>> the comparison, which can help us to reduce the penalty
>> from load instruction roll back.
>>
>> Our experiment indicates the performance can be improved by 10%~15%
>> for 2 and 3 threads cases, the conflicts from lock cache line
>> spend them most of the time.
>
>
> What kind of performance test were you running? With the right timing, it is
> possible that you see some performance gain. However, if the lock hold time
> is longer so that a fair number of cmpxchg instructions have to be executed
> before it can get the lock, you may see a performance degradation especially
> if the lock holder needs to access the lock cacheline.
>
> In general, we try to avoid this kind of cmpxchg loop unless we are sure
> that at most a few iterations of the loop may happen.
Waiman,
The machine is Haswell (2699 V3, COD off, HT on, 2 sockets)
(we have sent test module in separate email)
A. Data is located with lock in one cache line On 2 threads cases
(only write struct member data_a)
1. Load version test 5 times, the cost time is below:
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 103904620
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 104351876
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 118599784
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 103064024
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 103389696
Totally cost time is 533310000
2. Lock cmpxchg version test 5 times, the cost time is below:
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 67081220
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 97640708
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 96439612
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 66699296
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 96464800
Totally cost time is 424325636
Above data shows lock cmpxchg is better about average 25% (533310000/424325636)
B. Data is located with lock in different cache line On 2 threads
cases(only write struct member data_b)
1. Load version test 5 times, the cost time is below:
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 174266128
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 205053924
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 160165124
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 173241552
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 205765008
Totally cost time is 918491736
2. Lock cmpxchg version test 5 times, the cost time is below:
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 113410044
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 116293104
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 116064256
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 189320876
[root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c
all cost time is 123735352
Totally cost time is 658823632
Above data shows lock cmpxchg is better about average 39% (918491736/658823632)
>
>>
>> Thanks
>> Ling
>>
>> Signed-off-by: Ma Ling<ling.ml@alibaba-inc.com>
>> ---
>> kernel/locking/qspinlock.c | 43
>> ++++++++++++++++++-------------------------
>> 1 files changed, 18 insertions(+), 25 deletions(-)
>>
>> diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
>> index 87e9ce6..16421f2 100644
>> --- a/kernel/locking/qspinlock.c
>> +++ b/kernel/locking/qspinlock.c
>> @@ -332,25 +332,14 @@ void queued_spin_lock_slowpath(struct qspinlock
>> *lock, u32 val)
>> if (new == _Q_LOCKED_VAL)
>> return;
>>
>> - /*
>> - * we're pending, wait for the owner to go away.
>> - *
>> - * *,1,1 -> *,1,0
>> + /* we're waiting, and get lock owner
>> *
>> - * this wait loop must be a load-acquire such that we match the
>> - * store-release that clears the locked bit and create lock
>> - * sequentiality; this is because not all
>> clear_pending_set_locked()
>> - * implementations imply full barriers.
>> + * *,1,* -> *,0,1
>> */
>> - while ((val = smp_load_acquire(&lock->val.counter))&
>> _Q_LOCKED_MASK)
>> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending,
>> + _Q_PENDING_VAL, _Q_LOCKED_VAL) != _Q_PENDING_VAL)
>> cpu_relax();
>> -
>> - /*
>> - * take ownership and clear the pending bit.
>> - *
>> - * *,1,0 -> *,0,1
>> - */
>> - clear_pending_set_locked(lock);
>> +
>> return;
>>
>> /*
>> @@ -399,17 +388,21 @@ queue:
>> * we're at the head of the waitqueue, wait for the owner&
>> pending to
>> * go away.
>> *
>> - * *,x,y -> *,0,0
>> - *
>> - * this wait loop must use a load-acquire such that we match the
>> - * store-release that clears the locked bit and create lock
>> - * sequentiality; this is because the set_locked() function below
>> - * does not imply a full barrier.
>> - *
>> + * *,x,y -> *,0,1
>> */
>> pv_wait_head(lock, node);
>> - while ((val = smp_load_acquire(&lock->val.counter))&
>> _Q_LOCKED_PENDING_MASK)
>> + next = READ_ONCE(node->next);
>> + while (cmpxchg(&((struct __qspinlock *)lock)->locked_pending, 0,
>
>
> The locked_pending field isn't valid if _Q_PENDING_BITS != 8. So it won't
> work if NR_CPUS is 16k or more.
>
>> + _Q_LOCKED_VAL) != 0) {
>> + next = READ_ONCE(node->next);
>> cpu_relax();
>> + }
>> +
>> + if (next)
>> + goto next_node;
>
>
> I did notice a slight performance benefit by reading the next pointer early
> in light load cases myself. However, it is a very minor improvement that I
> haven't actively pursued it.
We use "next" to avoid smp_load_acquire(&lock->val.counter)
instruction rollback.
>
>> +
>> + val = smp_load_acquire(&lock->val.counter);
>> + tail = tail | _Q_LOCKED_VAL;
>>
>> /*
>> * claim the lock:
>> @@ -423,7 +416,6 @@ queue:
>> */
>> for (;;) {
>> if (val != tail) {
>> - set_locked(lock);
>> break;
>> }
>> old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
>> @@ -439,6 +431,7 @@ queue:
>> while (!(next = READ_ONCE(node->next)))
>> cpu_relax();
>>
>> +next_node:
>> arch_mcs_spin_unlock_contended(&next->locked);
>> pv_kick_node(lock, next);
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <waiman.long@hpe.com> |
|---|---|
| Date | 2015-10-20 21:00 +0200 |
| Subject | Re: [RFC PATCH] qspinlock: Improve performance by reducing load instruction rollback |
| Message-ID | <qlKiC-3V5-17@gated-at.bofh.it> |
| In reply to | #1251278 |
On 10/19/2015 11:12 PM, Ling Ma wrote: > 2015-10-20 1:18 GMT+08:00 Waiman Long<waiman.long@hpe.com>: >> On 10/18/2015 10:27 PM, ling.ma.program@gmail.com wrote: >>> From: Ma Ling<ling.ml@alibaba-inc.com> >>> >>> All load instructions can run speculatively but they have to follow >>> memory order rule in multiple cores as below: >>> _x = _y = 0 >>> >>> Processor 0 Processor 1 >>> >>> mov r1, [ _y] //M1 mov [ _x], 1 //M3 >>> mov r2, [ _x] //M2 mov [ _y], 1 //M4 >>> >>> If r1 = 1, r2 must be 1 >>> >>> In order to guarantee above rule, although Processor 0 execute >>> M1 and M2 instruction out of order, they are kept in ROB, >>> when load buffer for _x in Processor 0 received the update >>> message from Processor 1, Processor 0 need to roll back >>> from M2 instruction, which will flush the whole pipeline, >>> the latency is over the penalty from branch prediction miss. >>> >>> In this patch we use lock cmpxchg instruction to force load >>> instructions to be serialization, the destination operand >>> receives a write cycle without regard to the result of >>> the comparison, which can help us to reduce the penalty >>> from load instruction roll back. >>> >>> Our experiment indicates the performance can be improved by 10%~15% >>> for 2 and 3 threads cases, the conflicts from lock cache line >>> spend them most of the time. >> >> What kind of performance test were you running? With the right timing, it is >> possible that you see some performance gain. However, if the lock hold time >> is longer so that a fair number of cmpxchg instructions have to be executed >> before it can get the lock, you may see a performance degradation especially >> if the lock holder needs to access the lock cacheline. >> >> In general, we try to avoid this kind of cmpxchg loop unless we are sure >> that at most a few iterations of the loop may happen. > Waiman, > > The machine is Haswell (2699 V3, COD off, HT on, 2 sockets) > (we have sent test module in separate email) > > > > A. Data is located with lock in one cache line On 2 threads cases > (only write struct member data_a) > > 1. Load version test 5 times, the cost time is below: > > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 103904620 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 104351876 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 118599784 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 103064024 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 103389696 > > Totally cost time is 533310000 > > 2. Lock cmpxchg version test 5 times, the cost time is below: > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 67081220 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 97640708 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 96439612 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 66699296 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 96464800 > > > > Totally cost time is 424325636 > > > > Above data shows lock cmpxchg is better about average 25% (533310000/424325636) > > > > B. Data is located with lock in different cache line On 2 threads > cases(only write struct member data_b) > > > > 1. Load version test 5 times, the cost time is below: > > > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 174266128 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 205053924 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 160165124 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 173241552 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 205765008 > > Totally cost time is 918491736 > > > > 2. Lock cmpxchg version test 5 times, the cost time is below: > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 113410044 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 116293104 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 116064256 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 189320876 > > [root@localhost spinlock]# insmod dummy.ko; rmmod dummy;dmesg -c > > > > all cost time is 123735352 > > Totally cost time is 658823632 > > > > Above data shows lock cmpxchg is better about average 39% (918491736/658823632) > > I did see some performance improvement when I used your test program on a Haswell-EX system. It seems like the use of cmpxchg has forced the changed memory values to be visible to other processors earlier. I also ran your test on an older machine with Westmere-EX processors. This time, I didn't see any performance improvement. In fact, your change actually make it a tiny bit slower. So the benefit of your patch can be highly processor sensitive. As other architectures like ARM & AA64 are going to adopt qspinlock in the near future, we will also need to make sure that it won't cause a regression there. So I don't see your patch has a big chance of being merged upstream unless you can provide a real world workload that can benefit from your patch. Even then, proving that it won't cause regression in other processors or architectures can be tedious. Cheers, Longman -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web