From f8eed65dfb580f0971e2e6ead83135bfa3ddeb06 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 27 Dec 2003 20:58:58 +0000 Subject: [PATCH] Improve spinlock code for recent x86 processors: insert a PAUSE instruction in the s_lock() wait loop, and use test before test-and-set in TAS() macro to avoid unnecessary bus traffic. Patch from Manfred Spraul, reworked a bit by Tom. --- src/backend/storage/lmgr/s_lock.c | 6 +++++- src/include/storage/s_lock.h | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c index e5e372bb39..fac77aef0a 100644 --- a/src/backend/storage/lmgr/s_lock.c +++ b/src/backend/storage/lmgr/s_lock.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/s_lock.c,v 1.22 2003/12/23 22:15:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/s_lock.c,v 1.23 2003/12/27 20:58:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -88,6 +88,10 @@ s_lock(volatile slock_t *lock, const char *file, int line) while (TAS(lock)) { + /* CPU-specific delay each time through the loop */ + SPIN_DELAY(); + + /* Block the process every SPINS_PER_DELAY tries */ if (++spins > SPINS_PER_DELAY) { if (++delays > NUM_DELAYS) diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index e1851fb9ce..9ab24f93ae 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -24,6 +24,9 @@ * Tests if the lock is free. Returns TRUE if free, FALSE if locked. * This does *not* change the state of the lock. * + * void SPIN_DELAY(void) + * Delay operation to occur inside spinlock wait loop. + * * Note to implementors: there are default implementations for all these * macros at the bottom of the file. Check if your platform can use * these or needs to override them. @@ -63,7 +66,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.123 2003/12/23 22:15:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/storage/s_lock.h,v 1.124 2003/12/27 20:58:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -107,14 +110,28 @@ tas(volatile slock_t *lock) { register slock_t _res = 1; + /* Use a non-locking test before asserting the bus lock */ __asm__ __volatile__( + " cmpb $0,%1 \n" + " jne 1f \n" " lock \n" " xchgb %0,%1 \n" + "1: \n" : "=q"(_res), "=m"(*lock) : "0"(_res)); return (int) _res; } +#define SPIN_DELAY() spin_delay() + +static __inline__ void +spin_delay(void) +{ + __asm__ __volatile__( + " rep; nop \n" + : : : "memory"); +} + #endif /* __i386__ || __x86_64__ */ @@ -708,6 +725,10 @@ extern int tas_sema(volatile slock_t *lock); #define S_INIT_LOCK(lock) S_UNLOCK(lock) #endif /* S_INIT_LOCK */ +#if !defined(SPIN_DELAY) +#define SPIN_DELAY() ((void) 0) +#endif /* SPIN_DELAY */ + #if !defined(TAS) extern int tas(volatile slock_t *lock); /* in port/.../tas.s, or * s_lock.c */