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



Reply via email to