From 66e2fec92776fc7a55d61e4916a156b60d73b8dc Mon Sep 17 00:00:00 2001 From: Alexandre Felipe Date: Mon, 24 Aug 2026 21:44:30 +0100 Subject: [PATCH 5/5] Inline attempt and fold acquire loop By inlining LWLockAttemptLock we may reduce the amount of fetched code. The previous code was always breaking the loop running a small common code at the bottom of the function likely on a different cache line (if not two). Might improve prefetching, or even terminate the function before fetching one more cache line. Using queued and !queued we can reuse the inline LWLock call at the cost of one one queued = false; and an if(!queued) in the uncontended path. op | avg | min | q1 | med | q3 | max | std -------------+-------+------+-------+-------+-------+-------+------ spin-lock | 14.26 | 7.81 | 12.37 | 15.63 | 16.28 | 21.16 | 3.13 LWLock-ex | 6.21 | 5.53 | 6.18 | 6.19 | 6.19 | 14.98 | 0.37 LWLock-sh | 6.22 | 5.53 | 6.18 | 6.19 | 6.19 | 8.46 | 0.25 LWLock-X | 9.02 | 7.81 | 8.79 | 9.12 | 9.44 | 12.37 | 0.49 lw-ex-mode | 8.99 | 7.81 | 8.79 | 9.11 | 9.12 | 13.02 | 0.49 lw-ex-last | 5.80 | 5.53 | 5.54 | 5.86 | 5.86 | 8.46 | 0.28 lw-sh-mode | 9.02 | 7.81 | 8.79 | 9.11 | 9.12 | 13.67 | 0.52 lw-sh-last | 5.85 | 5.21 | 5.54 | 5.86 | 5.86 | 49.48 | 1.41 LWLock-cond | 6.07 | 5.20 | 5.86 | 5.86 | 6.19 | 18.88 | 0.71 nop | 0.86 | 0.32 | 0.66 | 0.98 | 0.98 | 1.63 | 0.17 --- src/backend/storage/lmgr/lwlock.c | 61 ++++++++++++++++--------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 00b589f158e..ab7ec3bd767 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -760,7 +760,7 @@ GetLWLockIdentifier(uint32 classId, uint16 eventId) * * Returns true if the lock isn't free and we need to wait. */ -static bool +static pg_always_inline bool LWLockAttemptLock(LWLock *lock, LWLockMode mode) { uint32 old_state; @@ -1152,6 +1152,7 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode) PGPROC *proc = MyProc; bool result = true; int extraWaits = 0; + bool queued; #ifdef LWLOCK_STATS lwlock_stats *lwstats; @@ -1216,8 +1217,30 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode) if (!mustwait) { - LOG_LWDEBUG("LWLockAcquire", lock, "immediately acquired lock"); - break; /* got the lock */ + if (TRACE_POSTGRESQL_LWLOCK_ACQUIRE_ENABLED()) + TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), mode); + + /* Add lock to list of locks held by this backend */ + held_lwlocks[num_held_lwlocks++] = lock; + + /* + * Fix the process wait semaphore's count for any absorbed wakeups. + */ + while (extraWaits-- > 0) + PGSemaphoreUnlock(proc->sem); + + if(!queued) + { + LOG_LWDEBUG("LWLockAcquire", lock, "immediately acquired lock"); + return result; + } + else + { + LOG_LWDEBUG("LWLockAcquire", lock, "acquired, undoing queue"); + + LWLockDequeueSelf(lock); + return result; + } } /* @@ -1230,20 +1253,11 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode) * other locker will see our queue entries when releasing since they * existed before we checked for the lock. */ - - /* add to the queue */ - LWLockQueueSelf(lock, mode); - - /* we're now guaranteed to be woken up if necessary */ - mustwait = LWLockAttemptLock(lock, mode); - - /* ok, grabbed the lock the second time round, need to undo queueing */ - if (!mustwait) + if(!queued) { - LOG_LWDEBUG("LWLockAcquire", lock, "acquired, undoing queue"); - - LWLockDequeueSelf(lock); - break; + /* add to the queue */ + LWLockQueueSelf(lock, mode); + continue; } /* @@ -1287,26 +1301,13 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode) if (TRACE_POSTGRESQL_LWLOCK_WAIT_DONE_ENABLED()) TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), mode); LWLockReportWaitEnd(); - + queued = false; LOG_LWDEBUG("LWLockAcquire", lock, "awakened"); /* Now loop back and try to acquire lock again. */ result = false; } - if (TRACE_POSTGRESQL_LWLOCK_ACQUIRE_ENABLED()) - TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), mode); - - /* Add lock to list of locks held by this backend */ - held_lwlocks[num_held_lwlocks++] = lock; - - /* - * Fix the process wait semaphore's count for any absorbed wakeups. - */ - while (extraWaits-- > 0) - PGSemaphoreUnlock(proc->sem); - - return result; } bool LWLockAcquireX(LWLock *lock, LWLockMode mode) { -- 2.53.0