An alternative implementation of #31551, where the block is read into memory in chunks, resulting in more modest gains, is slightly more complicated, but uses less memory.
This is a follow-up to #31490 (first few commits duplicated here, hence a draft) and a precursor to #31144.
Currently, obfuscation operations are performed byte-by-byte during serialization. Buffering the reads allows batching these operations (implemented in #31144) and improves file access efficiency by reducing fread calls and associated locking overhead. Testing with various buffer sizes showed that 16 KiB provides the best performance.
For writes, buffering enables batched obfuscations directly on the internal buffer, avoiding the need to copy input spans for obfuscation. Xor key offsets are calculated based on the file position, and the batched obfuscation is applied before writing to disk.
BufferedFile
was avoided for both reads and writes due to its unrelated operations and potential deprecation.
2 full IBD runs against master for 870k blocks (seeded from real nodes) indicates a 6% total speedup.
0hyperfine --runs 2 --export-json /mnt/my_storage/ibd-xor-buffered.json --parameter-list COMMIT d73f37dda221835b5109ede1b84db2dc7c4b74a1,6853b2740851befffa3ca0b24d94212ed1e48d66 --prepare 'rm -rf /mnt/my_storage/BitcoinData/* && git checkout {COMMIT} && git clean -fxd && git reset --hard && cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_UTIL=OFF -DBUILD_TX=OFF -DBUILD_TESTS=OFF -DENABLE_WALLET=OFF -DINSTALL_MAN=OFF && cmake --build build -j$(nproc)' 'COMMIT={COMMIT} ./build/src/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=870000 -printtoconsole=0'
1
2Benchmark 1: COMMIT=d73f37dda221835b5109ede1b84db2dc7c4b74a1 ./build/src/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=870000 -printtoconsole=0
3 Time (mean ± σ): 40216.674 s ± 113.132 s [User: 51496.289 s, System: 3541.340 s]
4 Range (min … max): 40136.678 s … 40296.671 s 2 runs
5
6Benchmark 2: COMMIT=6853b2740851befffa3ca0b24d94212ed1e48d66 ./build/src/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=870000 -printtoconsole=0
7 Time (mean ± σ): 37964.015 s ± 624.115 s [User: 49086.037 s, System: 3375.072 s]
8 Range (min … max): 37522.699 s … 38405.331 s 2 runs
9
10Summary
11 COMMIT=6853b2740851befffa3ca0b24d94212ed1e48d66 ./build/src/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=870000 -printtoconsole=0 ran
12 1.06 ± 0.02 times faster than COMMIT=d73f37dda221835b5109ede1b84db2dc7c4b74a1 ./build/src/bitcoind -datadir=/mnt/my_storage/BitcoinData -stopatheight=870000 -printtoconsole=0
Microbenchmarks show a ~23%/290% speedup (the followup XOR batching improves this further):
cmake -B build -DBUILD_BENCH=ON -DCMAKE_BUILD_TYPE=Release && cmake –build build -j$(nproc) && build/src/bench/bench_bitcoin -filter=‘ReadBlockFromDiskBench|SaveBlockToDiskBench’ -min-time=10000
Before:
ns/op | op/s | err% | total | benchmark |
---|---|---|---|---|
2,288,264.16 | 437.01 | 0.2% | 11.00 | ReadBlockFromDiskBench |
5,260,934.43 | 190.08 | 1.2% | 11.08 | SaveBlockToDiskBench |
After optimization: Buffer serialization reads in UndoReadFromDisk and ReadBlockFromDisk
(23% faster read):
ns/op | op/s | err% | total | benchmark |
---|---|---|---|---|
1,847,259.64 | 541.34 | 0.2% | 11.03 | ReadBlockFromDiskBench |
After optimization: Buffer serialization writes in UndoWriteToDisk and WriteBlockToDisk
(290% faster write):
ns/op | op/s | err% | total | benchmark |
---|---|---|---|---|
1,804,208.61 | 554.26 | 1.4% | 10.89 | SaveBlockToDiskBench |