diff --git a/BENCHMARKS.md b/BENCHMARKS.md index c4e1705..0bc5fe7 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -484,7 +484,52 @@ explain the slower windows. ## Concurrent reads -### Results (2026-09-26, tank) +### Results after the read fixes (2026-09-26, tank, `408f69e`) + +Same machine, files and commands as the first run below, re-run on an idle +tank (load average 1.60 at the start; the 1-minute figure rose to about 5 +during the clawhdf5 runs, mostly their own threads) after two fixes: +contiguous reads back their output with transparent huge pages and copy +hyperslabs run by run, and full chunked reads no longer queue behind a +one-thread rayon pool. h5py was re-run in the same session. + +Each read decoding on its calling thread (`--decode-threads 1`, like h5py): + +| layout | mode | threads | clawhdf5 MB/s (eff) | h5py threads MB/s (eff) | h5py processes MB/s (eff) | +|---|---|---:|---:|---:|---:| +| deflate | distinct | 1 | 606 (1.00) | 432 (1.00) | 421 (1.00) | +| deflate | distinct | 4 | 1816 (0.75) | 428 (0.25) | 1654 (0.98) | +| deflate | distinct | 8 | 2943 (0.61) | 428 (0.12) | 3042 (0.90) | +| deflate | distinct | 16 | 2142 (0.22) | 375 (0.05) | 3083 (0.46) | +| deflate | same | 1 | 154 (1.00) | 130 (1.00) | 129 (1.00) | +| deflate | same | 4 | 599 (0.98) | 129 (0.25) | 499 (0.97) | +| deflate | same | 16 | 1592 (0.65) | 128 (0.06) | 1399 (0.68) | +| contiguous | distinct | 1 | 13665 (1.00) | 9490 (1.00) | 8781 (1.00) | +| contiguous | distinct | 16 | 12674 (0.06) | 2285 (0.02) | 6942 (0.05) | +| contiguous | same | 1 | 31991 (1.00) | 5087 (1.00) | 5078 (1.00) | +| contiguous | same | 16 | 237151 (0.46) | 4304 (0.05) | 35772 (0.44) | + +With the default rayon pool: deflate `distinct` 2117 MB/s at 1 thread (4.9x +h5py), 3163 at 4, 2341 at 16 (0.76x h5py processes); deflate `same` 1439 MB/s +at 16; contiguous as above within a few percent. + +Before -> after for clawhdf5 (`--decode-threads 1` unless noted): +contiguous full read at 1 thread 2495 -> 13665 MB/s (0.25x -> 1.44x h5py); +contiguous 256 x 256 hyperslabs at 1 thread 624 -> 31991 MB/s (0.12x -> +6.3x); deflate full reads at 8 threads 887 -> 2943 MB/s; deflate +hyperslabs at 16 threads 1244 -> 1592 MB/s. + +Read with care: +- `contiguous same` reads 1024 slabs of one 64 MiB dataset over and over, so + it mostly measures copies out of the CPU's caches (the 7800X3D has 96 MiB + of L3); the per-call overhead is what differs (h5py's is about 50 us). +- At 16 threads every tool dropped in this run (h5py threads on contiguous + data from 8002 to 2285 MB/s, processes from 12846 to 6942), so the + 16-thread rows are noisier than the others. +- Still behind: full reads of chunked data at 16 threads (0.69x-0.76x h5py + processes). See `docs/known-issues.md`. + +### First run, before the read fixes (2026-09-26, tank, `91644d8`) Measured on tank (AMD Ryzen 7 7800X3D, 8 cores / 16 threads, 61 GiB, Linux 7.0) at commit `91644d8`, load average 1.84 when the run started (the diff --git a/docs/known-issues.md b/docs/known-issues.md index 63a5fa2..2657cdf 100644 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -40,11 +40,12 @@ tank with `concurrent_read` against h5py 3.16 / HDF5 2.0 (`BENCHMARKS.md`, worker (per-thread CPU time: one thread did all the decoding, the 16 readers almost none). Hyperslab reads touch one chunk each and never used the pool. Reads now decode on the calling thread when the pool has one - thread (`tests/single_thread_decode_pool.rs`). **Still open:** this - fixes only a one-thread pool. With the default pool, 16 reader threads - ran at about 2900 MB/s before and after the change, still short of 16 - h5py processes (4424 MB/s); with a small pool (2-4 threads) readers - outside it still wait on its workers. Datasets larger than the + thread (`tests/single_thread_decode_pool.rs`); re-measured at + `408f69e`, 8 threads went from 887 to 2943 MB/s (h5py processes: 3042). + **Still open:** at 16 threads full chunked reads reach 2142-2341 MB/s, + 0.69x-0.76x 16 h5py processes (3083 MB/s in the same run), with the + default pool as with a one-thread one; with a small pool (2-4 threads) + readers outside it still wait on its workers. Datasets larger than the cache's budget were already read without inserting into it, and skipping its lookups entirely gained only a few percent at 16 threads. Remaining per-read overhead, not yet addressed: each full `read_f32` of a chunked @@ -52,7 +53,9 @@ tank with `concurrent_read` against h5py 3.16 / HDF5 2.0 (`BENCHMARKS.md`, the `f32` copy of it, and a new buffer per decoded chunk). - Contiguous datasets read 4x slower than h5py on one thread (2.5 vs 9.8 GB/s full, 0.12x for 256 x 256 hyperslabs). - **Fixed 2026-09-26** (not yet re-measured for `BENCHMARKS.md`): full + **Fixed 2026-09-26** (re-measured on tank at `408f69e`: 13665 MB/s + full and 31991 MB/s for 256 x 256 hyperslabs on one thread, 1.44x and + 6.3x h5py; `BENCHMARKS.md`): full reads were dominated by 4 KiB page faults on the fresh output buffer, which is now backed by transparent huge pages as numpy's is; hyperslab reads copied the selection three times, element by element, and now copy