Re: Re:[PATCH] Speed up repeat() for larger counts - Mailing list pgsql-hackers

From Jan Nidzwetzki
Subject Re: Re:[PATCH] Speed up repeat() for larger counts
Date
Msg-id fc35e9a4-09c0-4220-8f6d-3cc371c980c3@planetscale.com
Whole thread
In response to [PATCH] Speed up repeat() for larger counts  ("ChenhuiMo" <chenhuimo.mch@qq.com>)
List 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




pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: Assert failure in try_nestloop_path()
Next
From: Andres Freund
Date:
Subject: Re: Make the transition state of avg(int2)/avg(int4)/sum(int2)/sum(int4) internal