Re: [RFC] Implement Batched (group) ticket lock

2014-05-30 Thread Raghavendra K T

On 05/30/2014 04:15 AM, Waiman Long wrote:

On 05/28/2014 08:16 AM, Raghavendra K T wrote:

- we need an intelligent way to nullify the effect of batching for
baremetal
  (because extra cmpxchg is not required).


To do this, you will need to have 2 slightly different algorithms
depending on the paravirt_ticketlocks_enabled jump label.


Thanks for the hint Waiman.

[...]

+spin:
+for (;;) {
+inc.head = ACCESS_ONCE(lock->tickets.head);
+if (!(inc.head&  TICKET_LOCK_HEAD_INC)) {
+new.head = inc.head | TICKET_LOCK_HEAD_INC;
+if (cmpxchg(>tickets.head, inc.head, new.head)
+== inc.head)
+goto out;
+}
+cpu_relax();
+}
+


It had taken me some time to figure out the the LSB of inc.head is used
as a bit lock for the contending tasks in the spin loop. I would suggest
adding some comment here to make it easier to look at.


Agree. 'll add a comment.

[...]

+#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
+#define TICKET_LOCK_BATCH_MASK
(~(TICKET_BATCH<

I don't think TAIL_INC has anything to do with setting the BATCH_MASK.
It works here because TAIL_INC is 2. I think it is clearer to define it
as either "(~(TICKET_BATCH<

You are right.
Thanks for pointing out. Your expression is simple and clearer. 'll use
one of them.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-30 Thread Raghavendra K T

On 05/30/2014 04:15 AM, Waiman Long wrote:

On 05/28/2014 08:16 AM, Raghavendra K T wrote:

- we need an intelligent way to nullify the effect of batching for
baremetal
  (because extra cmpxchg is not required).


To do this, you will need to have 2 slightly different algorithms
depending on the paravirt_ticketlocks_enabled jump label.


Thanks for the hint Waiman.

[...]

+spin:
+for (;;) {
+inc.head = ACCESS_ONCE(lock-tickets.head);
+if (!(inc.head  TICKET_LOCK_HEAD_INC)) {
+new.head = inc.head | TICKET_LOCK_HEAD_INC;
+if (cmpxchg(lock-tickets.head, inc.head, new.head)
+== inc.head)
+goto out;
+}
+cpu_relax();
+}
+


It had taken me some time to figure out the the LSB of inc.head is used
as a bit lock for the contending tasks in the spin loop. I would suggest
adding some comment here to make it easier to look at.


Agree. 'll add a comment.

[...]

+#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
+#define TICKET_LOCK_BATCH_MASK
(~(TICKET_BATCHTICKET_LOCK_INC_SHIFT) + \
+  TICKET_LOCK_TAIL_INC - 1)


I don't think TAIL_INC has anything to do with setting the BATCH_MASK.
It works here because TAIL_INC is 2. I think it is clearer to define it
as either (~(TICKET_BATCHTICKET_LOCK_INC_SHIFT) + 1) or
(~((TICKET_BATCHTICKET_LOCK_INC_SHIFT) - 1)).


You are right.
Thanks for pointing out. Your expression is simple and clearer. 'll use
one of them.

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Waiman Long

On 05/28/2014 08:16 AM, Raghavendra K T wrote:


TODO:
- we need an intelligent way to nullify the effect of batching for baremetal
  (because extra cmpxchg is not required).


To do this, you will need to have 2 slightly different algorithms 
depending on the paravirt_ticketlocks_enabled jump label.




- My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem to
   show the impact of extra cmpxchg. but there should be effect of extra 
cmpxchg.


It will depend on the micro-benchmark and the test system used. I had 
seen the a test case that extra cmpxchg did not really impact 
performance on a Westmere system but had noticeable adverse impact on an 
IvyBridge system with the same micro-benchmark.



  Please provide your suggestion and comments.

diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 0f62f54..87685f1 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -81,23 +81,36 @@ static __always_inline int 
arch_spin_value_unlocked(arch_spinlock_t lock)
   */
  static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
  {
-   register struct __raw_tickets inc = { .tail = TICKET_LOCK_INC };
+   register struct __raw_tickets inc = { .tail = TICKET_LOCK_TAIL_INC };
+   struct __raw_tickets new;

inc = xadd(>tickets, inc);
-   if (likely(inc.head == inc.tail))
-   goto out;

inc.tail&= ~TICKET_SLOWPATH_FLAG;
for (;;) {
unsigned count = SPIN_THRESHOLD;

do {
-   if (ACCESS_ONCE(lock->tickets.head) == inc.tail)
-   goto out;
+   if ((inc.head&  TICKET_LOCK_BATCH_MASK) == (inc.tail&
+   TICKET_LOCK_BATCH_MASK))
+   goto spin;
cpu_relax();
+   inc.head = ACCESS_ONCE(lock->tickets.head);
} while (--count);
__ticket_lock_spinning(lock, inc.tail);
}
+spin:
+   for (;;) {
+   inc.head = ACCESS_ONCE(lock->tickets.head);
+   if (!(inc.head&  TICKET_LOCK_HEAD_INC)) {
+   new.head = inc.head | TICKET_LOCK_HEAD_INC;
+   if (cmpxchg(>tickets.head, inc.head, new.head)
+   == inc.head)
+   goto out;
+   }
+   cpu_relax();
+   }
+


It had taken me some time to figure out the the LSB of inc.head is used 
as a bit lock for the contending tasks in the spin loop. I would suggest 
adding some comment here to make it easier to look at.



diff --git a/arch/x86/include/asm/spinlock_types.h 
b/arch/x86/include/asm/spinlock_types.h
index 4f1bea1..b04c03d 100644
--- a/arch/x86/include/asm/spinlock_types.h
+++ b/arch/x86/include/asm/spinlock_types.h
@@ -3,15 +3,16 @@

  #include

+#define TICKET_LOCK_INC_SHIFT 1
+#define __TICKET_LOCK_TAIL_INC (1<

I don't think TAIL_INC has anything to do with setting the BATCH_MASK. 
It works here because TAIL_INC is 2. I think it is clearer to define it 
as either "(~(TICKET_BATCH<(~((TICKET_BATCH<

-Longman
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Raghavendra K T

On 05/29/2014 12:16 PM, Peter Zijlstra wrote:

On Wed, May 28, 2014 at 05:46:39PM +0530, Raghavendra K T wrote:

In virtualized environment there are mainly three problems
related to spinlocks that affect performance.
1. LHP (lock holder preemption)
2. Lock Waiter Preemption (LWP)
3. Starvation/fairness

  Though ticketlocks solve the fairness problem, it worsens LWP, LHP problems.
pv-ticketlocks tried to address this. But we can further improve at the
cost of relaxed fairness.


So I really hate the idea of having different locks for paravirt and
normal kernels.


Yes. I understand that queued lock for normal kernel and unfair version 
of queued spinlock for virtual guest would do better.


Since strict serialization of lockwaiters (in both ticketlock/queued 
spinlock) does not work well for virtualized guest, my idea was to
give an alternate idea which has bounded starvation and performs as good 
as unfair version to virtualized guest.




And we're looking to move to that queued lock for normal kernels.


Agree. and I have tested that too.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Raghavendra K T

On 05/29/2014 03:25 AM, Rik van Riel wrote:

On 05/28/2014 08:16 AM, Raghavendra K T wrote:

This patch looks very promising.


Thank you Rik.

[...]


- My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem to
   show the impact of extra cmpxchg. but there should be effect of extra 
cmpxchg.


Canceled out by better NUMA locality?


Yes perhaps. it was even slightly better.

[...]

- we can further add dynamically changing batch_size implementation 
(inspiration and
   hint by Paul McKenney) as necessary.


I could see a larger batch size being beneficial.

Currently the maximum wait time for a spinlock on a system
with N CPUs is N times the length of the largest critical
section.

Having the batch size set equal to the number of CPUs would only
double that, and better locality (CPUs local to the current
lock holder winning the spinlock operation) might speed things
up enough to cancel that part of that out again...


having batch size = number of cpus would definitely help contended cases
especially on larger machines (by my experience with testing on a 4
node 32 core machine). +ht case should make it even more
beneficial.

My only botheration was overhead in undercommit cases because of extra
cmpxchg.
So may be batch_size = total cpus / numa node be optimal?...

[...]

+#define TICKET_LOCK_INC_SHIFT 1
+#define __TICKET_LOCK_TAIL_INC (1<

For the !CONFIG_PARAVIRT case, TICKET_LOCK_INC_SHIFT used to be 0,
now you are making it one. Probably not an issue, since even people
who compile with 128 < CONFIG_NR_CPUS <= 256 will likely have their
spinlocks padded out to 32 or 64 bits anyway in most data structures.


Yes..

[...]

+#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
+#define TICKET_LOCK_BATCH_MASK (~(TICKET_BATCH<

I do not see the value in having TICKET_BATCH declared with a
hexadecimal number,


yes.. It had only helped me to make the idea readable to myself, I
could get rid of this if needed.

and it may be worth making sure the code

does not compile if someone tried a TICKET_BATCH value that
is not a power of 2.


I agree.  will have BUILD_BUG for not power of 2 in next version.
But yes it reminds me that I wanted to have TICKET_BATCH = 1 for
!CONFIG_PARAVIRT so that we continue to have original fair lock version.
Does that make sense? I left it after thinking about same kernel running
on host/guest which would anyway will have CONFIG_PARAVIRT on.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Peter Zijlstra
On Wed, May 28, 2014 at 05:46:39PM +0530, Raghavendra K T wrote:
> In virtualized environment there are mainly three problems
> related to spinlocks that affect performance.
> 1. LHP (lock holder preemption)
> 2. Lock Waiter Preemption (LWP)
> 3. Starvation/fairness
> 
>  Though ticketlocks solve the fairness problem, it worsens LWP, LHP problems.
> pv-ticketlocks tried to address this. But we can further improve at the
> cost of relaxed fairness.

So I really hate the idea of having different locks for paravirt and
normal kernels.

And we're looking to move to that queued lock for normal kernels.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Peter Zijlstra
On Wed, May 28, 2014 at 05:46:39PM +0530, Raghavendra K T wrote:
 In virtualized environment there are mainly three problems
 related to spinlocks that affect performance.
 1. LHP (lock holder preemption)
 2. Lock Waiter Preemption (LWP)
 3. Starvation/fairness
 
  Though ticketlocks solve the fairness problem, it worsens LWP, LHP problems.
 pv-ticketlocks tried to address this. But we can further improve at the
 cost of relaxed fairness.

So I really hate the idea of having different locks for paravirt and
normal kernels.

And we're looking to move to that queued lock for normal kernels.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Raghavendra K T

On 05/29/2014 03:25 AM, Rik van Riel wrote:

On 05/28/2014 08:16 AM, Raghavendra K T wrote:

This patch looks very promising.


Thank you Rik.

[...]


- My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem to
   show the impact of extra cmpxchg. but there should be effect of extra 
cmpxchg.


Canceled out by better NUMA locality?


Yes perhaps. it was even slightly better.

[...]

- we can further add dynamically changing batch_size implementation 
(inspiration and
   hint by Paul McKenney) as necessary.


I could see a larger batch size being beneficial.

Currently the maximum wait time for a spinlock on a system
with N CPUs is N times the length of the largest critical
section.

Having the batch size set equal to the number of CPUs would only
double that, and better locality (CPUs local to the current
lock holder winning the spinlock operation) might speed things
up enough to cancel that part of that out again...


having batch size = number of cpus would definitely help contended cases
especially on larger machines (by my experience with testing on a 4
node 32 core machine). +ht case should make it even more
beneficial.

My only botheration was overhead in undercommit cases because of extra
cmpxchg.
So may be batch_size = total cpus / numa node be optimal?...

[...]

+#define TICKET_LOCK_INC_SHIFT 1
+#define __TICKET_LOCK_TAIL_INC (1TICKET_LOCK_INC_SHIFT)
+
  #ifdef CONFIG_PARAVIRT_SPINLOCKS
-#define __TICKET_LOCK_INC  2
  #define TICKET_SLOWPATH_FLAG  ((__ticket_t)1)
  #else
-#define __TICKET_LOCK_INC  1
  #define TICKET_SLOWPATH_FLAG  ((__ticket_t)0)
  #endif


For the !CONFIG_PARAVIRT case, TICKET_LOCK_INC_SHIFT used to be 0,
now you are making it one. Probably not an issue, since even people
who compile with 128  CONFIG_NR_CPUS = 256 will likely have their
spinlocks padded out to 32 or 64 bits anyway in most data structures.


Yes..

[...]

+#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
+#define TICKET_LOCK_BATCH_MASK (~(TICKET_BATCHTICKET_LOCK_INC_SHIFT) + \
+ TICKET_LOCK_TAIL_INC - 1)


I do not see the value in having TICKET_BATCH declared with a
hexadecimal number,


yes.. It had only helped me to make the idea readable to myself, I
could get rid of this if needed.

and it may be worth making sure the code

does not compile if someone tried a TICKET_BATCH value that
is not a power of 2.


I agree.  will have BUILD_BUG for not power of 2 in next version.
But yes it reminds me that I wanted to have TICKET_BATCH = 1 for
!CONFIG_PARAVIRT so that we continue to have original fair lock version.
Does that make sense? I left it after thinking about same kernel running
on host/guest which would anyway will have CONFIG_PARAVIRT on.

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Raghavendra K T

On 05/29/2014 12:16 PM, Peter Zijlstra wrote:

On Wed, May 28, 2014 at 05:46:39PM +0530, Raghavendra K T wrote:

In virtualized environment there are mainly three problems
related to spinlocks that affect performance.
1. LHP (lock holder preemption)
2. Lock Waiter Preemption (LWP)
3. Starvation/fairness

  Though ticketlocks solve the fairness problem, it worsens LWP, LHP problems.
pv-ticketlocks tried to address this. But we can further improve at the
cost of relaxed fairness.


So I really hate the idea of having different locks for paravirt and
normal kernels.


Yes. I understand that queued lock for normal kernel and unfair version 
of queued spinlock for virtual guest would do better.


Since strict serialization of lockwaiters (in both ticketlock/queued 
spinlock) does not work well for virtualized guest, my idea was to
give an alternate idea which has bounded starvation and performs as good 
as unfair version to virtualized guest.




And we're looking to move to that queued lock for normal kernels.


Agree. and I have tested that too.

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-29 Thread Waiman Long

On 05/28/2014 08:16 AM, Raghavendra K T wrote:


TODO:
- we need an intelligent way to nullify the effect of batching for baremetal
  (because extra cmpxchg is not required).


To do this, you will need to have 2 slightly different algorithms 
depending on the paravirt_ticketlocks_enabled jump label.




- My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem to
   show the impact of extra cmpxchg. but there should be effect of extra 
cmpxchg.


It will depend on the micro-benchmark and the test system used. I had 
seen the a test case that extra cmpxchg did not really impact 
performance on a Westmere system but had noticeable adverse impact on an 
IvyBridge system with the same micro-benchmark.



  Please provide your suggestion and comments.

diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 0f62f54..87685f1 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -81,23 +81,36 @@ static __always_inline int 
arch_spin_value_unlocked(arch_spinlock_t lock)
   */
  static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
  {
-   register struct __raw_tickets inc = { .tail = TICKET_LOCK_INC };
+   register struct __raw_tickets inc = { .tail = TICKET_LOCK_TAIL_INC };
+   struct __raw_tickets new;

inc = xadd(lock-tickets, inc);
-   if (likely(inc.head == inc.tail))
-   goto out;

inc.tail= ~TICKET_SLOWPATH_FLAG;
for (;;) {
unsigned count = SPIN_THRESHOLD;

do {
-   if (ACCESS_ONCE(lock-tickets.head) == inc.tail)
-   goto out;
+   if ((inc.head  TICKET_LOCK_BATCH_MASK) == (inc.tail
+   TICKET_LOCK_BATCH_MASK))
+   goto spin;
cpu_relax();
+   inc.head = ACCESS_ONCE(lock-tickets.head);
} while (--count);
__ticket_lock_spinning(lock, inc.tail);
}
+spin:
+   for (;;) {
+   inc.head = ACCESS_ONCE(lock-tickets.head);
+   if (!(inc.head  TICKET_LOCK_HEAD_INC)) {
+   new.head = inc.head | TICKET_LOCK_HEAD_INC;
+   if (cmpxchg(lock-tickets.head, inc.head, new.head)
+   == inc.head)
+   goto out;
+   }
+   cpu_relax();
+   }
+


It had taken me some time to figure out the the LSB of inc.head is used 
as a bit lock for the contending tasks in the spin loop. I would suggest 
adding some comment here to make it easier to look at.



diff --git a/arch/x86/include/asm/spinlock_types.h 
b/arch/x86/include/asm/spinlock_types.h
index 4f1bea1..b04c03d 100644
--- a/arch/x86/include/asm/spinlock_types.h
+++ b/arch/x86/include/asm/spinlock_types.h
@@ -3,15 +3,16 @@

  #includelinux/types.h

+#define TICKET_LOCK_INC_SHIFT 1
+#define __TICKET_LOCK_TAIL_INC (1TICKET_LOCK_INC_SHIFT)
+
  #ifdef CONFIG_PARAVIRT_SPINLOCKS
-#define __TICKET_LOCK_INC  2
  #define TICKET_SLOWPATH_FLAG  ((__ticket_t)1)
  #else
-#define __TICKET_LOCK_INC  1
  #define TICKET_SLOWPATH_FLAG  ((__ticket_t)0)
  #endif

-#if (CONFIG_NR_CPUS  (256 / __TICKET_LOCK_INC))
+#if (CONFIG_NR_CPUS  (256 / __TICKET_LOCK_TAIL_INC))
  typedef u8  __ticket_t;
  typedef u16 __ticketpair_t;
  #else
@@ -19,7 +20,12 @@ typedef u16 __ticket_t;
  typedef u32 __ticketpair_t;
  #endif

-#define TICKET_LOCK_INC((__ticket_t)__TICKET_LOCK_INC)
+#define TICKET_LOCK_TAIL_INC ((__ticket_t)__TICKET_LOCK_TAIL_INC)
+
+#define TICKET_LOCK_HEAD_INC ((__ticket_t)1)
+#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
+#define TICKET_LOCK_BATCH_MASK (~(TICKET_BATCHTICKET_LOCK_INC_SHIFT) + \
+ TICKET_LOCK_TAIL_INC - 1)


I don't think TAIL_INC has anything to do with setting the BATCH_MASK. 
It works here because TAIL_INC is 2. I think it is clearer to define it 
as either (~(TICKET_BATCHTICKET_LOCK_INC_SHIFT) + 1) or 
(~((TICKET_BATCHTICKET_LOCK_INC_SHIFT) - 1)).


-Longman
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Rik van Riel
On 05/28/2014 06:19 PM, Linus Torvalds wrote:

> If somebody has a P4 still, that's likely the worst case by far.

I'm sure cmpxchg isn't the only thing making P4 the worst case :)

-- 
All rights reversed
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Thomas Gleixner
On Wed, 28 May 2014, Linus Torvalds wrote:
> 
> If somebody has a P4 still, that's likely the worst case by far.

I do, but I'm only using it during winter and only if the ia64 machine
does not provide sufficient heating. So you have to wait at least half
a year until I'm able to test it.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Linus Torvalds
On Wed, May 28, 2014 at 2:55 PM, Rik van Riel  wrote:
>
> Or maybe cmpxchg is cheap once you already own the cache line
> exclusively?

A locked cmpxchg ends up being anything between ~15-50 cycles
depending on microarchitecture if things are already exclusively in
the cache (with the P4 being an outlier, and all locked instructions
tend to take ~100+ cycles, but I can't say I can really find it in
myself to even care about netburst any more).

The most noticeable downside we've seen has been when we've used
"read-op-cmpxchg" as a _replacement_ for something like "lock [x]add",
when that "read+cmpxchg" has caused two cacheline ops (cacheline first
loaded shared by the read, then exclusive by the cmpxchg). That's bad.

But if preceded by a write (or, in this case, an xadd), that doesn't
happen. Still, those roughly 15-50 cycles can certainly be noticeable
(especially at the high end), but you need to have some load that
doesn't bounce the lock, and largely fit in the caches to see it. And
you probably want to test one of the older CPU's, I think Haswell is
the lower end (ie in the ~20 cycle range).

If somebody has a P4 still, that's likely the worst case by far.

  Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Rik van Riel
On 05/28/2014 08:16 AM, Raghavendra K T wrote:

This patch looks very promising.

> TODO:
> - we need an intelligent way to nullify the effect of batching for baremetal
>  (because extra cmpxchg is not required).

On (larger?) NUMA systems, the unfairness may be a nice performance
benefit, reducing cache line bouncing through the system, and it
could well outweigh the extra cmpxchg at times.

> - we may have to make batch size as kernel arg to solve above problem
>  (to run same kernel for host/guest). Increasing batch size also seem to help
>  virtualized guest more, so we will have flexibility of tuning depending on 
> vm size.
> 
> - My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem 
> to
>   show the impact of extra cmpxchg. but there should be effect of extra 
> cmpxchg.

Canceled out by better NUMA locality?

Or maybe cmpxchg is cheap once you already own the cache line
exclusively?

> - virtualized guest had slight impact on 1x cases of some benchmarks but we 
> have got
>  impressive performance for >1x cases. So overall, patch needs exhaustive 
> tesing.
> 
> - we can further add dynamically changing batch_size implementation 
> (inspiration and
>   hint by Paul McKenney) as necessary.

I could see a larger batch size being beneficial.

Currently the maximum wait time for a spinlock on a system
with N CPUs is N times the length of the largest critical
section.

Having the batch size set equal to the number of CPUs would only
double that, and better locality (CPUs local to the current
lock holder winning the spinlock operation) might speed things
up enough to cancel that part of that out again...

>  I have found that increasing  batch size gives excellent improvements for 
>  overcommitted guests. I understand that we need more exhaustive testing.
> 
>  Please provide your suggestion and comments.

I have only nitpicks so far...

> diff --git a/arch/x86/include/asm/spinlock_types.h 
> b/arch/x86/include/asm/spinlock_types.h
> index 4f1bea1..b04c03d 100644
> --- a/arch/x86/include/asm/spinlock_types.h
> +++ b/arch/x86/include/asm/spinlock_types.h
> @@ -3,15 +3,16 @@
>  
>  #include 
>  
> +#define TICKET_LOCK_INC_SHIFT 1
> +#define __TICKET_LOCK_TAIL_INC (1< +
>  #ifdef CONFIG_PARAVIRT_SPINLOCKS
> -#define __TICKET_LOCK_INC2
>  #define TICKET_SLOWPATH_FLAG ((__ticket_t)1)
>  #else
> -#define __TICKET_LOCK_INC1
>  #define TICKET_SLOWPATH_FLAG ((__ticket_t)0)
>  #endif

For the !CONFIG_PARAVIRT case, TICKET_LOCK_INC_SHIFT used to be 0,
now you are making it one. Probably not an issue, since even people
who compile with 128 < CONFIG_NR_CPUS <= 256 will likely have their
spinlocks padded out to 32 or 64 bits anyway in most data structures.

> -#if (CONFIG_NR_CPUS < (256 / __TICKET_LOCK_INC))
> +#if (CONFIG_NR_CPUS < (256 / __TICKET_LOCK_TAIL_INC))
>  typedef u8  __ticket_t;
>  typedef u16 __ticketpair_t;
>  #else
> @@ -19,7 +20,12 @@ typedef u16 __ticket_t;
>  typedef u32 __ticketpair_t;
>  #endif
>  
> -#define TICKET_LOCK_INC  ((__ticket_t)__TICKET_LOCK_INC)
> +#define TICKET_LOCK_TAIL_INC ((__ticket_t)__TICKET_LOCK_TAIL_INC)
> +
> +#define TICKET_LOCK_HEAD_INC ((__ticket_t)1)
> +#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
> +#define TICKET_LOCK_BATCH_MASK (~(TICKET_BATCH< +   TICKET_LOCK_TAIL_INC - 1)

I do not see the value in having TICKET_BATCH declared with a
hexadecimal number, and it may be worth making sure the code
does not compile if someone tried a TICKET_BATCH value that
is not a power of 2.

-- 
All rights reversed
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Raghavendra K T
In virtualized environment there are mainly three problems
related to spinlocks that affect performance.
1. LHP (lock holder preemption)
2. Lock Waiter Preemption (LWP)
3. Starvation/fairness

 Though ticketlocks solve the fairness problem, it worsens LWP, LHP problems.
pv-ticketlocks tried to address this. But we can further improve at the
cost of relaxed fairness.

In this patch, we form a batch of eligible lock holders and we serve the 
eligible
(to hold the lock) batches in FIFO, but the lock-waiters within eligible batch 
are served
in an unfair manner. This increases probability of any eligible lock-holder 
being
in running state (to an average of (batch_size/2)-1). It also provides needed
bounded starvation since any lock requester can not acquire more than batch_size
times repeatedly during contention. On the negetive side we would need an extra 
cmpxchg.

 The patch has the batch size of 4. (As we know increasing  batch size means we 
are
closer to unfair locks and batch size of 1 = ticketlock).

Result:
Test system: 32cpu 2node machine w/ 64GB each (16 pcpu machine +ht).
Guests:  8GB  16vcpu guests (average of 8 iterations)

 % Improvements with kvm guests (batch size = 4):
  ebizzy_0.5x   4.3
  ebizzy_1.0x   7.8
  ebizzy_1.5x  23.4
  ebizzy_2.0x  48.6

Baremetal:
ebizzy showed very high stdev, kernbench result was good but both of them did
not show much difference.

ebizzy: rec/sec higher is better
base50452
patched 50703

kernbench  time in sec (lesser is better)
base48.9 sec
patched 48.8 sec

Signed-off-by: Raghavendra K T 
---
 arch/x86/include/asm/spinlock.h   | 35 +--
 arch/x86/include/asm/spinlock_types.h | 14 ++
 arch/x86/kernel/kvm.c |  6 --
 3 files changed, 39 insertions(+), 16 deletions(-)

TODO:
- we need an intelligent way to nullify the effect of batching for baremetal
 (because extra cmpxchg is not required).

- we may have to make batch size as kernel arg to solve above problem
 (to run same kernel for host/guest). Increasing batch size also seem to help
 virtualized guest more, so we will have flexibility of tuning depending on vm 
size.

- My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem to
  show the impact of extra cmpxchg. but there should be effect of extra cmpxchg.

- virtualized guest had slight impact on 1x cases of some benchmarks but we 
have got
 impressive performance for >1x cases. So overall, patch needs exhaustive 
tesing.

- we can further add dynamically changing batch_size implementation 
(inspiration and
  hint by Paul McKenney) as necessary.
 
 I have found that increasing  batch size gives excellent improvements for 
 overcommitted guests. I understand that we need more exhaustive testing.

 Please provide your suggestion and comments.

diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 0f62f54..87685f1 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -81,23 +81,36 @@ static __always_inline int 
arch_spin_value_unlocked(arch_spinlock_t lock)
  */
 static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
 {
-   register struct __raw_tickets inc = { .tail = TICKET_LOCK_INC };
+   register struct __raw_tickets inc = { .tail = TICKET_LOCK_TAIL_INC };
+   struct __raw_tickets new;
 
inc = xadd(>tickets, inc);
-   if (likely(inc.head == inc.tail))
-   goto out;
 
inc.tail &= ~TICKET_SLOWPATH_FLAG;
for (;;) {
unsigned count = SPIN_THRESHOLD;
 
do {
-   if (ACCESS_ONCE(lock->tickets.head) == inc.tail)
-   goto out;
+   if ((inc.head & TICKET_LOCK_BATCH_MASK) == (inc.tail &
+   TICKET_LOCK_BATCH_MASK))
+   goto spin;
cpu_relax();
+   inc.head = ACCESS_ONCE(lock->tickets.head);
} while (--count);
__ticket_lock_spinning(lock, inc.tail);
}
+spin:
+   for (;;) {
+   inc.head = ACCESS_ONCE(lock->tickets.head);
+   if (!(inc.head & TICKET_LOCK_HEAD_INC)) {
+   new.head = inc.head | TICKET_LOCK_HEAD_INC;
+   if (cmpxchg(>tickets.head, inc.head, new.head)
+   == inc.head)
+   goto out;
+   }
+   cpu_relax();
+   }
+
 out:   barrier();  /* make sure nothing creeps before the lock is taken */
 }
 
@@ -109,7 +122,8 @@ static __always_inline int 
arch_spin_trylock(arch_spinlock_t *lock)
if (old.tickets.head != (old.tickets.tail & ~TICKET_SLOWPATH_FLAG))
return 0;
 
-   new.head_tail = old.head_tail + (TICKET_LOCK_INC << TICKET_SHIFT);
+   new.head_tail = old.head_tail + (TICKET_LOCK_TAIL_INC << 

Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Rik van Riel
On 05/28/2014 08:16 AM, Raghavendra K T wrote:

This patch looks very promising.

 TODO:
 - we need an intelligent way to nullify the effect of batching for baremetal
  (because extra cmpxchg is not required).

On (larger?) NUMA systems, the unfairness may be a nice performance
benefit, reducing cache line bouncing through the system, and it
could well outweigh the extra cmpxchg at times.

 - we may have to make batch size as kernel arg to solve above problem
  (to run same kernel for host/guest). Increasing batch size also seem to help
  virtualized guest more, so we will have flexibility of tuning depending on 
 vm size.
 
 - My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem 
 to
   show the impact of extra cmpxchg. but there should be effect of extra 
 cmpxchg.

Canceled out by better NUMA locality?

Or maybe cmpxchg is cheap once you already own the cache line
exclusively?

 - virtualized guest had slight impact on 1x cases of some benchmarks but we 
 have got
  impressive performance for 1x cases. So overall, patch needs exhaustive 
 tesing.
 
 - we can further add dynamically changing batch_size implementation 
 (inspiration and
   hint by Paul McKenney) as necessary.

I could see a larger batch size being beneficial.

Currently the maximum wait time for a spinlock on a system
with N CPUs is N times the length of the largest critical
section.

Having the batch size set equal to the number of CPUs would only
double that, and better locality (CPUs local to the current
lock holder winning the spinlock operation) might speed things
up enough to cancel that part of that out again...

  I have found that increasing  batch size gives excellent improvements for 
  overcommitted guests. I understand that we need more exhaustive testing.
 
  Please provide your suggestion and comments.

I have only nitpicks so far...

 diff --git a/arch/x86/include/asm/spinlock_types.h 
 b/arch/x86/include/asm/spinlock_types.h
 index 4f1bea1..b04c03d 100644
 --- a/arch/x86/include/asm/spinlock_types.h
 +++ b/arch/x86/include/asm/spinlock_types.h
 @@ -3,15 +3,16 @@
  
  #include linux/types.h
  
 +#define TICKET_LOCK_INC_SHIFT 1
 +#define __TICKET_LOCK_TAIL_INC (1TICKET_LOCK_INC_SHIFT)
 +
  #ifdef CONFIG_PARAVIRT_SPINLOCKS
 -#define __TICKET_LOCK_INC2
  #define TICKET_SLOWPATH_FLAG ((__ticket_t)1)
  #else
 -#define __TICKET_LOCK_INC1
  #define TICKET_SLOWPATH_FLAG ((__ticket_t)0)
  #endif

For the !CONFIG_PARAVIRT case, TICKET_LOCK_INC_SHIFT used to be 0,
now you are making it one. Probably not an issue, since even people
who compile with 128  CONFIG_NR_CPUS = 256 will likely have their
spinlocks padded out to 32 or 64 bits anyway in most data structures.

 -#if (CONFIG_NR_CPUS  (256 / __TICKET_LOCK_INC))
 +#if (CONFIG_NR_CPUS  (256 / __TICKET_LOCK_TAIL_INC))
  typedef u8  __ticket_t;
  typedef u16 __ticketpair_t;
  #else
 @@ -19,7 +20,12 @@ typedef u16 __ticket_t;
  typedef u32 __ticketpair_t;
  #endif
  
 -#define TICKET_LOCK_INC  ((__ticket_t)__TICKET_LOCK_INC)
 +#define TICKET_LOCK_TAIL_INC ((__ticket_t)__TICKET_LOCK_TAIL_INC)
 +
 +#define TICKET_LOCK_HEAD_INC ((__ticket_t)1)
 +#define TICKET_BATCH0x4 /* 4 waiters can contend simultaneously */
 +#define TICKET_LOCK_BATCH_MASK (~(TICKET_BATCHTICKET_LOCK_INC_SHIFT) + \
 +   TICKET_LOCK_TAIL_INC - 1)

I do not see the value in having TICKET_BATCH declared with a
hexadecimal number, and it may be worth making sure the code
does not compile if someone tried a TICKET_BATCH value that
is not a power of 2.

-- 
All rights reversed
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Linus Torvalds
On Wed, May 28, 2014 at 2:55 PM, Rik van Riel r...@redhat.com wrote:

 Or maybe cmpxchg is cheap once you already own the cache line
 exclusively?

A locked cmpxchg ends up being anything between ~15-50 cycles
depending on microarchitecture if things are already exclusively in
the cache (with the P4 being an outlier, and all locked instructions
tend to take ~100+ cycles, but I can't say I can really find it in
myself to even care about netburst any more).

The most noticeable downside we've seen has been when we've used
read-op-cmpxchg as a _replacement_ for something like lock [x]add,
when that read+cmpxchg has caused two cacheline ops (cacheline first
loaded shared by the read, then exclusive by the cmpxchg). That's bad.

But if preceded by a write (or, in this case, an xadd), that doesn't
happen. Still, those roughly 15-50 cycles can certainly be noticeable
(especially at the high end), but you need to have some load that
doesn't bounce the lock, and largely fit in the caches to see it. And
you probably want to test one of the older CPU's, I think Haswell is
the lower end (ie in the ~20 cycle range).

If somebody has a P4 still, that's likely the worst case by far.

  Linus
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Thomas Gleixner
On Wed, 28 May 2014, Linus Torvalds wrote:
 
 If somebody has a P4 still, that's likely the worst case by far.

I do, but I'm only using it during winter and only if the ia64 machine
does not provide sufficient heating. So you have to wait at least half
a year until I'm able to test it.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Rik van Riel
On 05/28/2014 06:19 PM, Linus Torvalds wrote:

 If somebody has a P4 still, that's likely the worst case by far.

I'm sure cmpxchg isn't the only thing making P4 the worst case :)

-- 
All rights reversed
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC] Implement Batched (group) ticket lock

2014-05-28 Thread Raghavendra K T
In virtualized environment there are mainly three problems
related to spinlocks that affect performance.
1. LHP (lock holder preemption)
2. Lock Waiter Preemption (LWP)
3. Starvation/fairness

 Though ticketlocks solve the fairness problem, it worsens LWP, LHP problems.
pv-ticketlocks tried to address this. But we can further improve at the
cost of relaxed fairness.

In this patch, we form a batch of eligible lock holders and we serve the 
eligible
(to hold the lock) batches in FIFO, but the lock-waiters within eligible batch 
are served
in an unfair manner. This increases probability of any eligible lock-holder 
being
in running state (to an average of (batch_size/2)-1). It also provides needed
bounded starvation since any lock requester can not acquire more than batch_size
times repeatedly during contention. On the negetive side we would need an extra 
cmpxchg.

 The patch has the batch size of 4. (As we know increasing  batch size means we 
are
closer to unfair locks and batch size of 1 = ticketlock).

Result:
Test system: 32cpu 2node machine w/ 64GB each (16 pcpu machine +ht).
Guests:  8GB  16vcpu guests (average of 8 iterations)

 % Improvements with kvm guests (batch size = 4):
  ebizzy_0.5x   4.3
  ebizzy_1.0x   7.8
  ebizzy_1.5x  23.4
  ebizzy_2.0x  48.6

Baremetal:
ebizzy showed very high stdev, kernbench result was good but both of them did
not show much difference.

ebizzy: rec/sec higher is better
base50452
patched 50703

kernbench  time in sec (lesser is better)
base48.9 sec
patched 48.8 sec

Signed-off-by: Raghavendra K T raghavendra...@linux.vnet.ibm.com
---
 arch/x86/include/asm/spinlock.h   | 35 +--
 arch/x86/include/asm/spinlock_types.h | 14 ++
 arch/x86/kernel/kvm.c |  6 --
 3 files changed, 39 insertions(+), 16 deletions(-)

TODO:
- we need an intelligent way to nullify the effect of batching for baremetal
 (because extra cmpxchg is not required).

- we may have to make batch size as kernel arg to solve above problem
 (to run same kernel for host/guest). Increasing batch size also seem to help
 virtualized guest more, so we will have flexibility of tuning depending on vm 
size.

- My kernbench/ebizzy test on baremetal (32 cpu +ht sandybridge) did not seem to
  show the impact of extra cmpxchg. but there should be effect of extra cmpxchg.

- virtualized guest had slight impact on 1x cases of some benchmarks but we 
have got
 impressive performance for 1x cases. So overall, patch needs exhaustive 
tesing.

- we can further add dynamically changing batch_size implementation 
(inspiration and
  hint by Paul McKenney) as necessary.
 
 I have found that increasing  batch size gives excellent improvements for 
 overcommitted guests. I understand that we need more exhaustive testing.

 Please provide your suggestion and comments.

diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 0f62f54..87685f1 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -81,23 +81,36 @@ static __always_inline int 
arch_spin_value_unlocked(arch_spinlock_t lock)
  */
 static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
 {
-   register struct __raw_tickets inc = { .tail = TICKET_LOCK_INC };
+   register struct __raw_tickets inc = { .tail = TICKET_LOCK_TAIL_INC };
+   struct __raw_tickets new;
 
inc = xadd(lock-tickets, inc);
-   if (likely(inc.head == inc.tail))
-   goto out;
 
inc.tail = ~TICKET_SLOWPATH_FLAG;
for (;;) {
unsigned count = SPIN_THRESHOLD;
 
do {
-   if (ACCESS_ONCE(lock-tickets.head) == inc.tail)
-   goto out;
+   if ((inc.head  TICKET_LOCK_BATCH_MASK) == (inc.tail 
+   TICKET_LOCK_BATCH_MASK))
+   goto spin;
cpu_relax();
+   inc.head = ACCESS_ONCE(lock-tickets.head);
} while (--count);
__ticket_lock_spinning(lock, inc.tail);
}
+spin:
+   for (;;) {
+   inc.head = ACCESS_ONCE(lock-tickets.head);
+   if (!(inc.head  TICKET_LOCK_HEAD_INC)) {
+   new.head = inc.head | TICKET_LOCK_HEAD_INC;
+   if (cmpxchg(lock-tickets.head, inc.head, new.head)
+   == inc.head)
+   goto out;
+   }
+   cpu_relax();
+   }
+
 out:   barrier();  /* make sure nothing creeps before the lock is taken */
 }
 
@@ -109,7 +122,8 @@ static __always_inline int 
arch_spin_trylock(arch_spinlock_t *lock)
if (old.tickets.head != (old.tickets.tail  ~TICKET_SLOWPATH_FLAG))
return 0;
 
-   new.head_tail = old.head_tail + (TICKET_LOCK_INC  TICKET_SHIFT);
+   new.head_tail =