[PATCH] Reduce LWLockWaitListLock() cache-line contention with adaptive spin reads

Started by Min, Baohongabout 2 months ago3 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253171
psql -h localhost -U postgres

Built from patchset v1 (message #1), September 20, 2026 at 06:10 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253171_1 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253171_1 && git checkout t253171_1

Patchset v1 (message #1) is on t253171_1

Jump to latest
#1Min, Baohong
baohong.min@intel.com

Hi Hackers,

The attached patch reduces cache-line contention in LWLockWaitListLock()'s spin-wait loop on large x86_64 systems. It does not change the locking primitive; it only changes how often spinning waiters re-read the shared lock state adaptively according to the contention situation on the fly, plus a small tweak to the spin-delay floor.

Problem:
On large x86_64 machines (e.g.: Intel Xeon, 2 sockets), pgbench TPC-B throughput was limited at high core and high client counts. We observed excessive time spent in LWLockWaitListLock() under high concurrency due to contention on the lock semantic. Perf profiles
show this is due to excessive cache-line bouncing between different cores and sockets. We believe the better solution for this is to reduce contention adaptively. According to this idea, we drafted a patch and validated on server CPU as below.

Approach:
1. In LWLockWaitListLock(), re-read lock->state only once every
'spins_per_lock_read' spins instead of on every spin. The interval
is adaptive: it grows (up to 256) under heavy contention and
shrinks back toward 1 otherwise.
2. In s_lock.c, lower MIN_DELAY_USEC from 1000us to 100us, which
shortens the initial spin-delay back-off.

Benchmarks (pgbench, TPC-B-like, prepared protocol)
Intel Xeon, 60 cores, SMT-on, 2 sockets (240 vCPUs):

Clients Baseline Optimized Speedup
8 27878 28246 1.01
16 42851 44072 1.03
32 53893 54312 1.01
64 68807 72838 1.06
120 66825 74037 1.11
240 58585 75577 1.29
500 49208 74868 1.52
800 46982 74330 1.58
1000 44945 71436 1.59

Summary:
- Low client counts (<= core count): no measurable impact. Throughput is
unchanged within noise (1.01x-1.06x at 8-64 clients), so lightly loaded
systems are unaffected.
- High client counts (>= 120 clients): significant improvement. The patch
delivers 1.11x-1.59x at 120-1000 clients.

Thanks,
Baohong Min
Intel DCG Software

Authors: Min, Baohong <baohong.min@intel.com>
Jin, Jun < jun.i.jin@intel.com>
Kim, Andrew <andrew.kim@intel.com>

Attachments:

t253171_1
LWLockWaitListLock-adaptive-spin-reads-v1.patchapplication/octet-stream; name=LWLockWaitListLock-adaptive-spin-reads-v1.patchDownload+25-3
#2wenhui qiu
qiuwenhuifx@gmail.com
In reply to: Min, Baohong (#1)
Re: [PATCH] Reduce LWLockWaitListLock() cache-line contention with adaptive spin reads

Hi

Summary:

- Low client counts (<= core count): no measurable impact. Throughput is
unchanged within noise (1.01x-1.06x at 8-64 clients), so lightly

loaded

systems are unaffected.
- High client counts (>= 120 clients): significant improvement. The

patch

delivers 1.11x-1.59x at 120-1000 clients.

Thanks for working on this. The general approach looks reasonable and is
not specific to Intel CPUs. Reducing repeated reads of a contended cache
line lowers cache-coherency traffic and cache-line bouncing, so
high-core-count AMD and ARM systems should benefit as well. The adaptive
interval should also keep the impact small under low contention.

Please consider adding benchmark results from at least one non-Intel
platform. It would also be helpful to explain the choice of the threshold,
increment, and maximum interval. The MIN_DELAY_USEC change affects
spinlock behavior globally, so its relationship to this optimization should
be justified or evaluated in a separate patch.

Thanks

#3Okanovic, Haris
harisokn@amazon.com
In reply to: wenhui qiu (#2)
Re: [PATCH] Reduce LWLockWaitListLock() cache-line contention with adaptive spin reads

Hi Wenhui, Baohong,

Please consider adding benchmark results from at least one non-Intel
platform.

I benchmarked your v1 on AWS Graviton (Arm Neoverse N1/V1/V2/V3) on top
of postgres master f7cc6fd760: ran pgbench with 3 different workloads
over various machine sizes and client counts. I measured up to 59%
higher peak throughput on 192-core V3, up to 14% on 192-core V2, and no
change or regressions on small systems.

Result details can be found in these plots:
https://github.com/harisokanovic/harismisc/tree/master/postgres/pgsqlscaling/adaptiveSpinReads-bench-2026-09-18/

For context, I have also been trying to improve LWLockWaitListLock()
using futex-mutex, but so far this approach doesn't benchmark well on
x86_64 systems, and was conditioned on aarch64-only.

The futex-mutex variant:
/messages/by-id/DM6PR18MB29081469262A7BBCE85220B3A8112@DM6PR18MB2908.namprd18.prod.outlook.com

Regards,
Haris Okanovic
AWS Graviton