diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 0b0bb4fb8f42506f032918ea55469fceda3a0e66..aeacaf102aaee4a8a64374e7e6b3dee3918acd48 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.29 2005/08/20 23:26:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.30 2005/09/16 00:30:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,12 +38,32 @@ typedef struct LWLock /* tail is undefined when head is NULL */ } LWLock; +/* + * All the LWLock structs are allocated as an array in shared memory. + * (LWLockIds are indexes into the array.) We force the array stride to + * be a power of 2, which saves a few cycles in indexing, but more + * importantly also ensures that individual LWLocks don't cross cache line + * boundaries. This reduces cache contention problems, especially on AMD + * Opterons. (Of course, we have to also ensure that the array start + * address is suitably aligned.) + * + * LWLock is between 16 and 32 bytes on all known platforms, so these two + * cases are sufficient. + */ +#define LWLOCK_PADDED_SIZE (sizeof(LWLock) <= 16 ? 16 : 32) + +typedef union LWLockPadded +{ + LWLock lock; + char pad[LWLOCK_PADDED_SIZE]; +} LWLockPadded; + /* * This points to the array of LWLocks in shared memory. Backends inherit - * the pointer by fork from the postmaster. LWLockIds are indexes into - * the array. + * the pointer by fork from the postmaster (except in the EXEC_BACKEND case, + * where we have special measures to pass it down). */ -NON_EXEC_STATIC LWLock *LWLockArray = NULL; +NON_EXEC_STATIC LWLockPadded *LWLockArray = NULL; /* shared counter for dynamic allocation of LWLockIds */ static int *LWLockCounter; @@ -135,10 +155,11 @@ LWLockShmemSize(void) Size size; int numLocks = NumLWLocks(); - /* Allocate the LWLocks plus space for shared allocation counter. */ - size = mul_size(numLocks, sizeof(LWLock)); + /* Space for the LWLock array. */ + size = mul_size(numLocks, sizeof(LWLockPadded)); - size = add_size(size, 2 * sizeof(int)); + /* Space for shared allocation counter, plus room for alignment. */ + size = add_size(size, 2 * sizeof(int) + LWLOCK_PADDED_SIZE); return size; } @@ -152,23 +173,29 @@ CreateLWLocks(void) { int numLocks = NumLWLocks(); Size spaceLocks = LWLockShmemSize(); - LWLock *lock; + LWLockPadded *lock; + char *ptr; int id; /* Allocate space */ - LWLockArray = (LWLock *) ShmemAlloc(spaceLocks); + ptr = (char *) ShmemAlloc(spaceLocks); + + /* Ensure desired alignment of LWLock array */ + ptr += LWLOCK_PADDED_SIZE - ((unsigned long) ptr) % LWLOCK_PADDED_SIZE; + + LWLockArray = (LWLockPadded *) ptr; /* * Initialize all LWLocks to "unlocked" state */ for (id = 0, lock = LWLockArray; id < numLocks; id++, lock++) { - SpinLockInit(&lock->mutex); - lock->releaseOK = true; - lock->exclusive = 0; - lock->shared = 0; - lock->head = NULL; - lock->tail = NULL; + SpinLockInit(&lock->lock.mutex); + lock->lock.releaseOK = true; + lock->lock.exclusive = 0; + lock->lock.shared = 0; + lock->lock.head = NULL; + lock->lock.tail = NULL; } /* @@ -206,7 +233,7 @@ LWLockAssign(void) void LWLockAcquire(LWLockId lockid, LWLockMode mode) { - volatile LWLock *lock = LWLockArray + lockid; + volatile LWLock *lock = &(LWLockArray[lockid].lock); PGPROC *proc = MyProc; bool retry = false; int extraWaits = 0; @@ -358,7 +385,7 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) bool LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode) { - volatile LWLock *lock = LWLockArray + lockid; + volatile LWLock *lock = &(LWLockArray[lockid].lock); bool mustwait; PRINT_LWDEBUG("LWLockConditionalAcquire", lockid, lock); @@ -423,7 +450,7 @@ LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode) void LWLockRelease(LWLockId lockid) { - volatile LWLock *lock = LWLockArray + lockid; + volatile LWLock *lock = &(LWLockArray[lockid].lock); PGPROC *head; PGPROC *proc; int i;