| From: | Jan Nidzwetzki <jan(at)planetscale(dot)com> |
|---|---|
| To: | ChenhuiMo <chenhuimo(dot)mch(at)qq(dot)com>, pgsql-hackers <pgsql-hackers(at)postgresql(dot)org> |
| Cc: | "jeevan(dot)chalke" <jeevan(dot)chalke(at)enterprisedb(dot)com>, Heikki Linnakangas <hlinnaka(at)iki(dot)fi> |
| Subject: | Re: Re:[PATCH] Speed up repeat() for larger counts |
| Date: | 2026-09-04 13:51:06 |
| Message-ID: | fc35e9a4-09c0-4220-8f6d-3cc371c980c3@planetscale.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hello Chenhui,
On 03.09.26 17:20, ChenhuiMo wrote:
[...]
>
> I updated the benchmark so that the capped strategies also use memset() for
> single-byte inputs. In that path, the memset() calls are split according to
> the selected block size, with CHECK_FOR_INTERRUPTS() between chunks
Thanks for the updated benchmark. For comparison, here are my numbers:
# Debian 13.5 VM on an Apple M5 Max, 32MB of L2 cache / 24 MB of L3
# cache, 36 GB RAM, gcc 14.2.0 -O2
jan=# select * from repeat_bench();
source | repeats | output | master | doubling | nocap | cap512 | cap1k | cap2k | cap4k | cap8k | cap16k | cap32k | cap64k | cap128k | cap256k | cap512k | cap1m | cap2m | cap4m | cap8m | cap16m | fastest
--------+-----------+----------+----------+----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------------------------
32 B | 2 | 64 B | 3 ns | 0.93x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | 0.82x | master
32 B | 4 | 128 B | 5 ns | 1.31x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | 1.13x | doubling
32 B | 6 | 192 B | 7 ns | 1.59x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | 1.42x | doubling
32 B | 7 | 224 B | 7 ns | 1.67x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | 1.50x | doubling
32 B | 8 | 256 B | 7 ns | 1.56x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | 1.65x | cap2k (median: nocap)
32 B | 9 | 288 B | 8 ns | 1.71x | 1.57x | 1.56x | 1.57x | 1.57x | 1.57x | 1.56x | 1.57x | 1.57x | 1.57x | 1.56x | 1.57x | 1.56x | 1.56x | 1.57x | 1.57x | 1.57x | 1.57x | doubling
32 B | 12 | 384 B | 9 ns | 1.27x | 1.52x | 1.44x | 1.55x | 1.40x | 1.56x | 1.55x | 1.56x | 1.55x | 1.46x | 1.40x | 1.46x | 1.43x | 1.55x | 1.40x | 1.56x | 1.55x | 1.56x | cap16k (median: cap1k)
32 B | 16 | 512 B | 12 ns | 1.43x | 1.24x | 1.24x | 1.24x | 1.25x | 1.24x | 1.25x | 1.25x | 1.25x | 1.24x | 1.25x | 1.25x | 1.24x | 1.25x | 1.25x | 1.25x | 1.24x | 1.25x | doubling (median: cap4m)
32 B | 64 | 2 KB | 49 ns | 2.29x | 2.25x | 2.24x | 2.27x | 2.26x | 2.27x | 2.26x | 2.27x | 2.26x | 2.26x | 2.26x | 2.27x | 2.27x | 2.26x | 2.26x | 2.27x | 2.26x | 2.27x | doubling (median: cap16m)
32 B | 4096 | 128 KB | 2.7 us | 2.55x | 2.84x | 2.35x | 2.44x | 2.44x | 2.47x | 2.58x | 2.50x | 2.51x | 2.51x | 2.54x | 2.54x | 2.51x | 2.53x | 2.51x | 2.52x | 2.50x | 2.50x | nocap (median: cap8k)
1 B | 16777216 | 16 MB | 14.8 ms | 119.90x | 120.23x | 71.77x | 73.30x | 74.02x | 67.44x | 39.32x | 61.44x | 71.05x | 93.60x | 105.89x | 112.77x | 116.40x | 118.54x | 119.58x | 120.19x | 120.19x | 120.35x | cap16m
10 B | 1677721 | 16 MB | 1.5 ms | 5.84x | 5.86x | 6.60x | 6.66x | 6.62x | 5.07x | 6.14x | 7.72x | 9.60x | 10.65x | 5.95x | 6.02x | 6.05x | 5.89x | 5.86x | 5.84x | 5.85x | 5.86x | cap64k
100 B | 167772 | 16 MB | 316.4 us | 1.27x | 1.27x | 1.42x | 1.47x | 1.37x | 1.11x | 1.47x | 1.90x | 2.26x | 2.38x | 1.30x | 1.30x | 1.31x | 1.28x | 1.27x | 1.27x | 1.27x | 1.27x | cap64k
1 KB | 16384 | 16 MB | 258.5 us | 1.04x | 1.04x | 1.01x | 1.01x | 1.20x | 1.09x | 0.95x | 1.18x | 1.45x | 1.80x | 1.68x | 1.06x | 1.07x | 1.06x | 1.04x | 1.04x | 1.03x | 1.04x | cap64k
64 KB | 256 | 16 MB | 204.0 us | 0.82x | 0.82x | 1.00x | 1.00x | 1.01x | 1.01x | 1.01x | 1.02x | 1.02x | 1.01x | 1.35x | 0.84x | 0.84x | 0.83x | 0.82x | 0.82x | 0.82x | 0.82x | cap128k
1 MB | 16 | 16 MB | 249.3 us | 0.99x | 0.99x | 1.00x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 0.99x | 0.99x | 0.99x | 0.99x | cap4k (median: cap256k)
1 B | 268435456 | 256 MB | 272.1 ms | 137.59x | 137.80x | 62.59x | 62.03x | 63.57x | 62.09x | 31.27x | 33.47x | 47.84x | 67.43x | 89.15x | 108.70x | 127.66x | 134.98x | 136.54x | 137.14x | 137.42x | 137.55x | nocap (median: cap16m)
10 B | 26843545 | 256 MB | 23.5 ms | 5.65x | 5.66x | 5.74x | 5.77x | 5.64x | 5.21x | 4.19x | 2.95x | 4.26x | 6.20x | 5.29x | 5.72x | 5.94x | 5.86x | 5.84x | 5.84x | 5.74x | 5.73x | cap64k
100 B | 2684354 | 256 MB | 5.2 ms | 1.25x | 1.25x | 1.26x | 1.28x | 1.24x | 0.74x | 0.97x | 0.74x | 1.08x | 1.57x | 1.29x | 1.31x | 1.32x | 1.29x | 1.29x | 1.29x | 1.27x | 1.26x | cap64k
1 KB | 262144 | 256 MB | 4.5 ms | 1.08x | 1.09x | 1.06x | 1.05x | 1.11x | 1.04x | 0.73x | 0.53x | 0.72x | 1.05x | 1.39x | 1.11x | 1.14x | 1.15x | 1.12x | 1.13x | 1.13x | 1.12x | cap128k
64 KB | 4096 | 256 MB | 4.5 ms | 1.08x | 1.09x | 1.02x | 1.00x | 1.00x | 1.01x | 1.01x | 0.99x | 1.00x | 0.99x | 1.34x | 1.08x | 1.14x | 1.14x | 1.12x | 1.13x | 1.12x | 1.12x | cap128k
1 MB | 256 | 256 MB | 4.1 ms | 0.97x | 0.98x | 1.02x | 1.04x | 1.04x | 1.04x | 1.04x | 1.04x | 1.04x | 1.04x | 1.06x | 1.04x | 1.04x | 1.04x | 1.02x | 1.02x | 1.02x | 1.01x | cap128k (median: cap64k)
1 B | 1000 | 1000 B | 1.3 us | 166.38x | 157.59x | 153.17x | 157.57x | 156.83x | 156.83x | 157.57x | 157.57x | 157.57x | 157.59x | 157.57x | 157.57x | 156.83x | 157.57x | 157.59x | 156.83x | 156.83x | 156.83x | doubling
1 B | 1000000 | 976.6 KB | 870.5 us | 112.32x | 112.94x | 72.54x | 75.42x | 76.25x | 75.42x | 49.63x | 70.82x | 87.05x | 99.48x | 107.70x | 113.55x | 112.32x | 112.94x | 112.92x | 112.94x | 112.94x | 113.54x | cap256k (median: nocap)
(24 rows)
# Debian 13.5 on an Intel Pentium Silver J5005, 4 MB L2 cache, no L3
# cache, 16 GB RAM, gcc 14.2.0 -O2
jan=# select * from repeat_bench();
source | repeats | output | master | doubling | nocap | cap512 | cap1k | cap2k | cap4k | cap8k | cap16k | cap32k | cap64k | cap128k | cap256k | cap512k | cap1m | cap2m | cap4m | cap8m | cap16m | fastest
--------+-----------+----------+-----------+----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+-------------------------
32 B | 2 | 64 B | 13 ns | 1.06x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | 0.81x | doubling
32 B | 4 | 128 B | 22 ns | 1.15x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | 1.02x | doubling
32 B | 6 | 192 B | 31 ns | 1.19x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | 1.09x | doubling
32 B | 7 | 224 B | 36 ns | 1.39x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | 1.27x | doubling
32 B | 8 | 256 B | 42 ns | 1.57x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | 1.43x | doubling
32 B | 9 | 288 B | 47 ns | 1.46x | 1.36x | 1.35x | 1.35x | 1.35x | 1.35x | 1.35x | 1.36x | 1.36x | 1.35x | 1.35x | 1.35x | 1.36x | 1.36x | 1.36x | 1.36x | 1.36x | 1.36x | doubling
32 B | 12 | 384 B | 61 ns | 1.81x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | 1.68x | doubling
32 B | 16 | 512 B | 84 ns | 2.26x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | 2.06x | doubling
32 B | 64 | 2 KB | 316 ns | 3.77x | 3.56x | 3.29x | 3.57x | 3.56x | 3.55x | 3.55x | 3.56x | 3.55x | 3.56x | 3.55x | 3.55x | 3.55x | 3.55x | 3.55x | 3.55x | 3.55x | 3.55x | doubling
32 B | 4096 | 128 KB | 19.1 us | 2.06x | 2.06x | 2.65x | 2.83x | 2.97x | 2.80x | 2.86x | 2.57x | 2.10x | 2.06x | 2.07x | 2.07x | 2.07x | 2.06x | 2.06x | 2.07x | 2.06x | 2.07x | cap2k
1 B | 16777216 | 16 MB | 115.4 ms | 62.63x | 62.87x | 48.66x | 48.17x | 46.47x | 46.12x | 46.15x | 45.99x | 46.26x | 46.42x | 45.77x | 46.02x | 45.57x | 53.15x | 62.82x | 62.85x | 64.64x | 63.37x | cap8m (median: cap16m)
10 B | 1677721 | 16 MB | 12.8 ms | 4.69x | 4.84x | 5.81x | 5.43x | 5.56x | 5.51x | 5.50x | 5.44x | 5.29x | 5.29x | 5.28x | 5.29x | 5.31x | 6.08x | 6.31x | 4.92x | 4.92x | 4.87x | cap2m
100 B | 167772 | 16 MB | 2.2 ms | 0.82x | 0.85x | 1.01x | 0.98x | 0.91x | 0.93x | 0.93x | 0.90x | 0.90x | 0.89x | 0.89x | 0.90x | 0.90x | 1.01x | 1.03x | 0.86x | 0.85x | 0.85x | cap2m
1 KB | 16384 | 16 MB | 2.2 ms | 0.83x | 0.85x | 1.00x | 0.98x | 0.76x | 0.96x | 0.96x | 0.95x | 0.92x | 0.91x | 0.92x | 0.92x | 0.91x | 1.01x | 1.10x | 0.92x | 0.87x | 0.85x | cap2m
64 KB | 256 | 16 MB | 2.4 ms | 0.90x | 0.91x | 1.00x | 1.00x | 0.97x | 0.97x | 0.97x | 0.97x | 0.97x | 0.97x | 0.98x | 0.98x | 0.98x | 1.07x | 1.18x | 0.98x | 0.92x | 0.91x | cap2m
1 MB | 16 | 16 MB | 2.3 ms | 0.87x | 0.85x | 0.98x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.06x | 1.05x | 0.91x | 0.83x | 0.85x | cap1k (median: cap16k)
1 B | 268435456 | 256 MB | 1863.4 ms | 63.24x | 64.65x | 49.51x | 49.87x | 49.36x | 49.32x | 48.93x | 49.09x | 48.95x | 49.08x | 49.03x | 48.93x | 49.00x | 61.96x | 63.08x | 62.97x | 63.22x | 63.51x | nocap
10 B | 26843545 | 256 MB | 207.6 ms | 4.45x | 4.47x | 5.43x | 5.22x | 5.49x | 5.50x | 5.44x | 5.38x | 5.25x | 5.20x | 5.24x | 5.22x | 5.21x | 6.37x | 6.38x | 4.60x | 4.53x | 4.47x | cap2m (median: cap1m)
100 B | 2684354 | 256 MB | 38.7 ms | 0.82x | 0.83x | 1.01x | 0.97x | 1.02x | 1.02x | 1.01x | 0.98x | 0.98x | 0.97x | 0.98x | 0.98x | 0.97x | 1.18x | 1.16x | 0.85x | 0.84x | 0.83x | cap1m
1 KB | 262144 | 256 MB | 37.8 ms | 0.81x | 0.81x | 1.00x | 1.00x | 0.70x | 1.00x | 0.99x | 0.99x | 0.95x | 0.95x | 0.95x | 0.95x | 0.95x | 1.16x | 1.16x | 1.03x | 0.82x | 0.82x | cap2m (median: cap1m)
64 KB | 4096 | 256 MB | 39.1 ms | 0.83x | 0.84x | 1.00x | 0.99x | 0.99x | 0.99x | 0.99x | 0.99x | 0.99x | 0.99x | 0.99x | 0.98x | 0.98x | 1.20x | 1.20x | 1.00x | 0.84x | 0.85x | cap2m (median: cap1m)
1 MB | 256 | 256 MB | 32.6 ms | 0.70x | 0.69x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.01x | 1.00x | 0.82x | 0.71x | 0.71x | cap128k
1 B | 1000 | 1000 B | 6.8 us | 240.97x | 225.32x | 201.53x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | 225.38x | doubling
1 B | 1000000 | 976.6 KB | 6.8 ms | 134.42x | 134.55x | 124.58x | 126.56x | 132.95x | 128.51x | 131.56x | 133.10x | 133.85x | 134.27x | 134.37x | 134.51x | 134.58x | 134.53x | 134.55x | 134.57x | 134.52x | 134.54x | cap512k (median: nocap)
(24 rows)
To understand the different cap behavior on our systems better, could
you share the output of the following command from your systems?
ld.so --list-tunables | grep non_temporal
On my J5005, it looks as follows:
$ ld.so --list-tunables | grep non_temporal
glibc.cpu.x86_memset_non_temporal_threshold: 0x100000 (min: 0x4040, max: 0xffffffffffffffff)
glibc.cpu.x86_non_temporal_threshold: 0x100000 (min: 0x4040, max: 0xfffffffffffffff)
The preferred cap on the J5005 is the first one at or above this
threshold (0x100000 = 1 MB). Does this match the behavior on your
systems as well?
On ARM, this tunable isn't present.
> The corrected single-byte results do not change the overall conclusion. For
> multi-byte inputs, the preferred cap on this machine still varies noticeably
> with the total output size. In particular, the 16 MB cases tend to prefer
> relatively small caps, while the 256 MB cases consistently prefer cap16m.
>
> For the single-byte cases, splitting the memset() into capped chunks also does
> not seem to introduce a significant performance penalty. In some cases, the
> larger capped memset variants are even slightly faster than a single large
> memset().
Unfortunately, on the M5 Max it does. Comparing the worst chunked
variant (cap8k in all three cases) against nocap, which does the same
work in a single memset():
output cap8k nocap ratio
16 MB 39.32x 120.23x 3.1x
256 MB 31.27x 137.80x 4.4x
976.6 KB 49.63x 112.94x 2.3x
To move this patch forward, would you consider proposing the
single-byte memset() as a separate, smaller patch first? It is a large
win with no regression in the benchmarks we have executed. It is also
independent of the block size question. So, it could go in while the
doubling strategy needs more investigation. Also, the early return
for count == 0 || slen == 0 is a second change that could be committed
independently of the cap discussion.
Best regards
Jan
--
Jan Nidzwetzki
PlanetScale Postgres Core Team
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Fujii Masao | 2026-09-04 14:02:44 | Re: Stabilize 026_overwrite_contrecord test |
| Previous Message | Tom Lane | 2026-09-04 13:50:47 | Re: Assert failure in try_nestloop_path() |