From: Pan Xinhui <hidden> Date: 2016-05-25 08:21:27
cmpxchg_release is light-wight than cmpxchg, we can gain a better
performace then. On some arch like ppc, barrier impact the performace
too much.
Suggested-by: Boqun Feng <redacted>
Signed-off-by: Pan Xinhui <redacted>
---
kernel/locking/qspinlock_paravirt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Pan Xinhui <hidden> Date: 2016-05-25 08:21:35
pseries will use qspinlock by default.
Signed-off-by: Pan Xinhui <redacted>
---
arch/powerpc/platforms/pseries/Kconfig | 1 +
1 file changed, 1 insertion(+)
From: Pan Xinhui <hidden> Date: 2016-05-25 08:21:55
Base code to enable qspinlock on powerpc. this patch add some #ifdef
here and there. Although there is no paravirt related code, we can
successfully build a qspinlock kernel after apply this patch.
Signed-off-by: Pan Xinhui <redacted>
---
arch/powerpc/include/asm/qspinlock.h | 22 ++++++++++++++++++++++
arch/powerpc/include/asm/spinlock.h | 27 +++++++++++++++------------
arch/powerpc/include/asm/spinlock_types.h | 4 ++++
arch/powerpc/lib/locks.c | 4 ++++
4 files changed, 45 insertions(+), 12 deletions(-)
create mode 100644 arch/powerpc/include/asm/qspinlock.h
@@ -0,0 +1,22 @@+#ifndef _ASM_POWERPC_QSPINLOCK_H+#define _ASM_POWERPC_QSPINLOCK_H++#include<asm-generic/qspinlock_types.h>++#define SPIN_THRESHOLD (1 << 15)+#define queued_spin_unlock queued_spin_unlock++staticinlinevoidnative_queued_spin_unlock(structqspinlock*lock)+{+/* no load/store can be across the unlock()*/+smp_store_release((u8*)lock,0);+}++staticinlinevoidqueued_spin_unlock(structqspinlock*lock)+{+native_queued_spin_unlock(lock);+}++#include<asm-generic/qspinlock.h>++#endif /* _ASM_POWERPC_QSPINLOCK_H */
@@ -52,6 +52,20 @@#define SYNC_IO#endif+#if defined(CONFIG_PPC_SPLPAR)+/* We only yield to the hypervisor if we are in shared processor mode */+#define SHARED_PROCESSOR (lppaca_shared_proc(local_paca->lppaca_ptr))+externvoid__spin_yield(arch_spinlock_t*lock);+externvoid__rw_yield(arch_rwlock_t*lock);+#else /* SPLPAR */+#define __spin_yield(x) barrier()+#define __rw_yield(x) barrier()+#define SHARED_PROCESSOR 0+#endif++#ifdef CONFIG_QUEUED_SPINLOCKS+#include<asm/qspinlock.h>+#elsestatic__always_inlineintarch_spin_value_unlocked(arch_spinlock_tlock){returnlock.slock==0;
@@ -106,18 +120,6 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)*held.Conveniently,wehaveawordinthepacathatholdsthis*value.*/--#if defined(CONFIG_PPC_SPLPAR)-/* We only yield to the hypervisor if we are in shared processor mode */-#define SHARED_PROCESSOR (lppaca_shared_proc(local_paca->lppaca_ptr))-externvoid__spin_yield(arch_spinlock_t*lock);-externvoid__rw_yield(arch_rwlock_t*lock);-#else /* SPLPAR */-#define __spin_yield(x) barrier()-#define __rw_yield(x) barrier()-#define SHARED_PROCESSOR 0-#endif-staticinlinevoidarch_spin_lock(arch_spinlock_t*lock){CLEAR_IO_SYNC;
From: Pan Xinhui <hidden> Date: 2016-05-25 08:21:57
As we need let pv-qspinlock-kernel run on all environment which might
have no powervm, we should runtime choose which qspinlock version to
use.
The default pv-qspinlock use native version. pv_lock initialization
should be done in bootstage with irq disabled. And if there is PHYP,
restore pv_lock_ops callbacks to pv version.
Signed-off-by: Pan Xinhui <redacted>
---
arch/powerpc/include/asm/qspinlock.h | 17 ++++++++
arch/powerpc/include/asm/qspinlock_paravirt.h | 38 ++++++++++++++++++
.../powerpc/include/asm/qspinlock_paravirt_types.h | 13 +++++++
arch/powerpc/kernel/paravirt.c | 45 ++++++++++++++++++++++
arch/powerpc/platforms/pseries/setup.c | 5 +++
5 files changed, 118 insertions(+)
create mode 100644 arch/powerpc/include/asm/qspinlock_paravirt.h
create mode 100644 arch/powerpc/include/asm/qspinlock_paravirt_types.h
create mode 100644 arch/powerpc/kernel/paravirt.c
@@ -0,0 +1,38 @@+#ifndef CONFIG_PARAVIRT_SPINLOCKS+#error "do not include this file"+#endif++#ifndef _ASM_QSPINLOCK_PARAVIRT_H+#define _ASM_QSPINLOCK_PARAVIRT_H++#include<asm/qspinlock_paravirt_types.h>++externvoidpv_lock_init(void);+externvoidnative_queued_spin_lock_slowpath(structqspinlock*lock,u32val);+externvoid__pv_init_lock_hash(void);+externvoid__pv_queued_spin_lock_slowpath(structqspinlock*lock,u32val);+externvoid__pv_queued_spin_unlock(structqspinlock*lock);++staticinlinevoidpv_queued_spin_lock(structqspinlock*lock,u32val)+{+CLEAR_IO_SYNC;+pv_lock_op.lock(lock,val);+}++staticinlinevoidpv_queued_spin_unlock(structqspinlock*lock)+{+SYNC_IO;+pv_lock_op.unlock(lock);+}++staticinlinevoidpv_wait(u8*ptr,u8val,intlockcpu)+{+pv_lock_op.wait(ptr,val,lockcpu);+}++staticinlinevoidpv_kick(intcpu)+{+pv_lock_op.kick(cpu);+}++#endif
From: Pan Xinhui <hidden> Date: 2016-05-25 08:22:02
pv-qspinlock core has pv_wait/pv_kick which will give a better
performace by yielding and kicking cpu at some cases.
lets support them by adding two corresponding helper functions.
Signed-off-by: Pan Xinhui <redacted>
---
arch/powerpc/include/asm/spinlock.h | 4 ++++
arch/powerpc/lib/locks.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
@@ -56,9 +56,13 @@/* We only yield to the hypervisor if we are in shared processor mode */#define SHARED_PROCESSOR (lppaca_shared_proc(local_paca->lppaca_ptr))externvoid__spin_yield(arch_spinlock_t*lock);+externvoid__spin_yield_cpu(intcpu);+externvoid__spin_wake_cpu(intcpu);externvoid__rw_yield(arch_rwlock_t*lock);#else /* SPLPAR */#define __spin_yield(x) barrier()+#define __spin_yield_cpu(x) barrier()+#define __spin_wake_cpu(x) barrier()#define __rw_yield(x) barrier()#define SHARED_PROCESSOR 0#endif
@@ -23,6 +23,39 @@#include<asm/hvcall.h>#include<asm/smp.h>+void__spin_yield_cpu(intcpu)+{+unsignedintholder_cpu=cpu,yield_count;++if(cpu==-1){+plpar_hcall_norets(H_CONFER,-1,0);+return;+}+BUG_ON(holder_cpu>=nr_cpu_ids);+yield_count=be32_to_cpu(lppaca_of(holder_cpu).yield_count);+if((yield_count&1)==0){+/* if target cpu is running, confer slices to lpar*/+plpar_hcall_norets(H_CONFER,-1,0);+return;+}+plpar_hcall_norets(H_CONFER,+get_hard_smp_processor_id(holder_cpu),yield_count);+}+EXPORT_SYMBOL_GPL(__spin_yield_cpu);++void__spin_wake_cpu(intcpu)+{+unsignedintholder_cpu=cpu,yield_count;++BUG_ON(holder_cpu>=nr_cpu_ids);+yield_count=be32_to_cpu(lppaca_of(holder_cpu).yield_count);+if((yield_count&1)==0)+return;/* virtual cpu is currently running */+plpar_hcall_norets(H_PROD,+get_hard_smp_processor_id(holder_cpu));+}+EXPORT_SYMBOL_GPL(__spin_wake_cpu);+#ifndef CONFIG_QUEUED_SPINLOCKSvoid__spin_yield(arch_spinlock_t*lock){
@@ -128,3 +128,11 @@ config HV_PERF_CTRSsystems.24x7isavailableonPower8systems.Ifunsure,selectY.++configPARAVIRT_SPINLOCKS+bool"Paravirtialization support for qspinlock"+depends onPPC_SPLPAR&&QUEUED_SPINLOCKS+defaulty+help+Ifplatformsupportsvirtualization,forexamplePowerVM,thisoption+canletguesthaveabetterperformace.
From: Peter Zijlstra <peterz@infradead.org> Date: 2016-05-26 16:47:47
On Wed, May 25, 2016 at 04:18:08PM +0800, Pan Xinhui wrote:
quoted hunk
cmpxchg_release is light-wight than cmpxchg, we can gain a better
performace then. On some arch like ppc, barrier impact the performace
too much.
Suggested-by: Boqun Feng <redacted>
Signed-off-by: Pan Xinhui <redacted>
---
kernel/locking/qspinlock_paravirt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
This patch fails to explain _why_ it can be relaxed.
And seeing how this cmpxchg() can actually unlock the lock, I don't see
how this can possibly be correct. Maybe cmpxchg_release(), but relaxed
seems very wrong.
From: Peter Zijlstra <peterz@infradead.org> Date: 2016-05-26 16:51:12
On Wed, May 25, 2016 at 04:18:03PM +0800, Pan Xinhui wrote:
_____test________________spinlcok______________pv-qspinlcok_____
|futex hash | 556370 ops | 629634 ops |
|futex lock-pi | 362 ops | 367 ops |
scheduler test:
Test how many loops of schedule() can finish within 10 seconds on all cpus.
_____test________________spinlcok______________pv-qspinlcok_____
|schedule() loops| 322811921 | 311449290 |
kernel compiling test:
build a linux kernel image to see how long it took
_____test________________spinlcok______________pv-qspinlcok_____
| compiling takes| 22m | 22m |
s/spinlcok/spinlock/
Is 'spinlcok' the current test-and-set lock?
And what about regular qspinlock, in case of !SHARED_PROCESSOR?
How can a kernel build take 22 minutes with 32 CPUs? That's far too
long. My 40 CPU IVB-EP takes all of 50 seconds to build an
x86_64-defconfig from scratch.
From: Peter Zijlstra <peterz@infradead.org> Date: 2016-05-26 16:57:26
On Thu, May 26, 2016 at 06:47:29PM +0200, Peter Zijlstra wrote:
On Wed, May 25, 2016 at 04:18:08PM +0800, Pan Xinhui wrote:
quoted
cmpxchg_release is light-wight than cmpxchg, we can gain a better
performace then. On some arch like ppc, barrier impact the performace
too much.
Suggested-by: Boqun Feng <redacted>
Signed-off-by: Pan Xinhui <redacted>
---
kernel/locking/qspinlock_paravirt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
This patch fails to explain _why_ it can be relaxed.
And seeing how this cmpxchg() can actually unlock the lock, I don't see
how this can possibly be correct. Maybe cmpxchg_release(), but relaxed
seems very wrong.
Clearly I need to stop working for the day, I cannea read. You're doing
release, not relaxed.
Still Changelog needs improvement.
On Thu, May 26, 2016 at 06:47:29PM +0200, Peter Zijlstra wrote:
quoted
On Wed, May 25, 2016 at 04:18:08PM +0800, Pan Xinhui wrote:
quoted
cmpxchg_release is light-wight than cmpxchg, we can gain a better
performace then. On some arch like ppc, barrier impact the performace
too much.
Suggested-by: Boqun Feng <redacted>
Signed-off-by: Pan Xinhui <redacted>
---
kernel/locking/qspinlock_paravirt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
This patch fails to explain _why_ it can be relaxed.
And seeing how this cmpxchg() can actually unlock the lock, I don't see
how this can possibly be correct. Maybe cmpxchg_release(), but relaxed
seems very wrong.
Clearly I need to stop working for the day, I cannea read. You're doing
release, not relaxed.
On Wed, May 25, 2016 at 04:18:03PM +0800, Pan Xinhui wrote:
quoted
_____test________________spinlcok______________pv-qspinlcok_____
|futex hash | 556370 ops | 629634 ops |
|futex lock-pi | 362 ops | 367 ops |
scheduler test:
Test how many loops of schedule() can finish within 10 seconds on all cpus.
_____test________________spinlcok______________pv-qspinlcok_____
|schedule() loops| 322811921 | 311449290 |
kernel compiling test:
build a linux kernel image to see how long it took
_____test________________spinlcok______________pv-qspinlcok_____
| compiling takes| 22m | 22m |
s/spinlcok/spinlock/
Oh, foolish mistake...sorry
Is 'spinlcok' the current test-and-set lock?
Yes. I will describe it in a clear way in the next patchset.
And what about regular qspinlock, in case of !SHARED_PROCESSOR?
You mean the test results on powerNV?
yes, I make a kernel build with !SHARED_PROCESSOR.
and do perf tests and scheduler tests on same machine(32 cpus). performance is better than current spinlock
_____test________________spinlock________________qspinlock_____
|futex hash | 533060 ops | 541513 ops |
|futex lock-pi | 357 ops | 356 ops |
_____test________________spinlock________________qspinlock_____
|schedule() loops| 337691713 | 361935207 |
NOTE: I have updated the scheduler test tools, and the new performance test results show that both pv-spinlock and qspinlock is better than current spinlock.
I will also update the test result in my next patchset.
thanks
xinhui