| From: | Alexandre Felipe <o(dot)alexandre(dot)felipe(at)gmail(dot)com> |
|---|---|
| To: | Andres Freund <andres(at)anarazel(dot)de> |
| Cc: | PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: Fwd: [patch] bufmgr Half state CAS |
| Date: | 2026-10-15 09:17:26 |
| Message-ID: | CAE8JnxP_Gbrv36r1VoVYJJrf41dKosm=nR0z41vXhHXFLfbGnQ@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On Wed, Oct 14, 2026 at 10:07 PM Andres Freund <andres(at)anarazel(dot)de> wrote:
> Hi,
>
Hi, I'm glad to see you here.
> On 2026-10-14 21:53:21 +0100, Alexandre Felipe wrote:
> > See attached, running on top of 10cc5aa96a6 I got
> >
> > clients base patched
> >
> > 1 3251.2 3221.3
> > 8 2592.2 3979.0 *+53.5%*
>
> Given how low the throughput is, you must be testing read/write pgbench. Is
> that right?
Each transaction here does 1000 index scans, maybe that is why it looks low.
The idea was to exercise reference/usage count, flags (low bits),
simultaneously with
buffer locking/unlocking (high bits). I tested a few different queries,
with negligible
difference, but in the script I posted above I include only the use case
where the
difference was visible.
enable_{seqscan,bitmapscan,memoize,material}=off
-- the entire table on a single buffer
CREATE TABLE hot(id int PRIMARY KEY, v int);
INSERT INTO hot SELECT g, g FROM generate_series(1, 10) g;
VACUUM ANALYZE hot;
Then each client runs, for 15 seconds, the following query
SELECT sum(s.v) FROM generate_series(1, 1000) g(i),
LATERAL (SELECT v FROM hot WHERE id = g.i % 10 + 1 OFFSET 0) s;
I know, so the index page and the heap page are not only hot, but are
probably
a L1 hit, and since we are not modifying them there is no contention in the
buffer
payload. But since we have to lock or pin the buffer there is contention on
the
buffer header status field, there is bouncing, I am attributing the
run-time difference
to the fact that pin/unpin in one CPU, while locking/unlocking.
If so, it's completely inconceivable that that lwock efficiency
> has that kind of impact at such low throughput & concurrency.
Even considering that I am running a query 1000 times per transaction?
> You're waiting
> for the disk, not a CAS retry.
Unlikely, I expect this to be two buffer hits, probably the entire pages
are in L1.
It'd be more likely that what you're measuring
> WAL file initialization overhead or such.
>
Unlikely, my queries are read-only.
There's no way that you'd ever see any meaningful benefits of something like
> this until you reach much much higher concurrency.
These might be a bit extreme, as they are numbers from an apple M2.
But I don't have other reasonable explanations.
The throughput initially increases adding clients, then it starts to
decrease
suggesting two competing effects at play. Concurrency, multiple backends
doing work independently, e.g. reading the buffer payload.
And some conflicts, not simply queued for a shared resource, but effectively
harming each other (maybe retrying?). The conflicting effect is present on
both base and patched but is reduced in the patched version. And this is
also reasonably explained because the patch doesn't eliminate CAS loops
entirely.
workload clients base patched change
index 1 3295.7 3277.9 -0.5%
index 2 5542.1 5504.5 -0.7%
index 3 6532.3 6640.0 +1.6%
index 4 6098.5 6580.9 +7.9%
index 5 3777.6 3997.1 +5.8%
index 6 3280.3 3916.2 +19.4%
index 7 2942.8 3914.8 +33.0%
index 8 2481.3 3966.5 +59.9%
The timeframe between
> reading the "old" value and the CAS is very short, it's pretty hard to
> steal
> the cacheline in that window and modify it.
As I mentioned above the entire page must be in L1, because they are not
modified
the cache line can be accessed in shared mode. The buffer header on the
other
had is likely to be a cache miss, because every time a backend accesses the
buffer
it will pin/unpin lock/unlock, and every change to the header invalidates
the cache,
so one backend invalidates the cache for 7 other backends in my test using
8 clients.
Under these conditions the time slice spent in the first CAS is high, in
the mean
time another backend might arrive and have to retry, once
I am including the script with the build steps, and queries that I
intentionally
omitted previously.
Regards,
Alexandre
| Attachment | Content-Type | Size |
|---|---|---|
| bench-half-state.sh | text/x-sh | 4.7 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | solai v | 2026-10-15 09:28:00 | Re: Add TOAST statistics columns to pg_stat_all_tables |
| Previous Message | Chao Li | 2026-10-15 09:09:28 | Avoid repeated scans of the output buffer in oidvectortypes() |