Skip to content

Commit 09ae2c8

Browse files
committed
bufmgr: Optimize & harmonize LockBufHdr(), LWLockWaitListLock()
The main optimization is for LockBufHdr() to delay initializing SpinDelayStatus, similar to what LWLockWaitListLock already did. The initialization is sufficiently expensive & buffer header lock acquisitions are sufficiently frequent, to make it worthwhile to instead have a fastpath (via a likely() branch) that does not initialize the SpinDelayStatus. While LWLockWaitListLock() already the aforementioned optimization, it did not use likely(), and inspection of the assembly shows that this indeed leads to worse code generation (also observed in a microbenchmark). Fix that by adding the likely(). While the LockBufHdr() improvement is a small gain on its own, it mainly is aimed at preventing a regression after a future commit, which requires additional locking to set hint bits. While touching both, also make the comments more similar to each other. Reviewed-by: Heikki Linnakangas <heikki.linnakangas@iki.fi> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff
1 parent 80f08a6 commit 09ae2c8

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6358,23 +6358,41 @@ rlocator_comparator(const void *p1, const void *p2)
63586358
uint32
63596359
LockBufHdr(BufferDesc *desc)
63606360
{
6361-
SpinDelayStatus delayStatus;
63626361
uint32 old_buf_state;
63636362

63646363
Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc)));
63656364

6366-
init_local_spin_delay(&delayStatus);
6367-
63686365
while (true)
63696366
{
6370-
/* set BM_LOCKED flag */
6367+
/*
6368+
* Always try once to acquire the lock directly, without setting up
6369+
* the spin-delay infrastructure. The work necessary for that shows up
6370+
* in profiles and is rarely necessary.
6371+
*/
63716372
old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED);
6372-
/* if it wasn't set before we're OK */
6373-
if (!(old_buf_state & BM_LOCKED))
6374-
break;
6375-
perform_spin_delay(&delayStatus);
6373+
if (likely(!(old_buf_state & BM_LOCKED)))
6374+
break; /* got lock */
6375+
6376+
/* and then spin without atomic operations until lock is released */
6377+
{
6378+
SpinDelayStatus delayStatus;
6379+
6380+
init_local_spin_delay(&delayStatus);
6381+
6382+
while (old_buf_state & BM_LOCKED)
6383+
{
6384+
perform_spin_delay(&delayStatus);
6385+
old_buf_state = pg_atomic_read_u32(&desc->state);
6386+
}
6387+
finish_spin_delay(&delayStatus);
6388+
}
6389+
6390+
/*
6391+
* Retry. The lock might obviously already be re-acquired by the time
6392+
* we're attempting to get it again.
6393+
*/
63766394
}
6377-
finish_spin_delay(&delayStatus);
6395+
63786396
return old_buf_state | BM_LOCKED;
63796397
}
63806398

src/backend/storage/lmgr/lwlock.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -870,9 +870,13 @@ LWLockWaitListLock(LWLock *lock)
870870

871871
while (true)
872872
{
873-
/* always try once to acquire lock directly */
873+
/*
874+
* Always try once to acquire the lock directly, without setting up
875+
* the spin-delay infrastructure. The work necessary for that shows up
876+
* in profiles and is rarely necessary.
877+
*/
874878
old_state = pg_atomic_fetch_or_u32(&lock->state, LW_FLAG_LOCKED);
875-
if (!(old_state & LW_FLAG_LOCKED))
879+
if (likely(!(old_state & LW_FLAG_LOCKED)))
876880
break; /* got lock */
877881

878882
/* and then spin without atomic operations until lock is released */

0 commit comments

Comments
 (0)