Performance on real data
AMD EPYC 9454: measured on older code
Measured at git v0.0.21a1-83-ga1a55ac (C sources sha256 5a0108f1b0c2, kernel-choice modules ce1cdafcbf56); this site was built from 6929bd75ab7a / 99941e0ecc68. The code changed since, so these numbers may no longer describe it. Re-run tools/bench_docs.py on that machine and commit its JSON.
Intel Xeon Gold 6248: measured on older code
Measured at git v0.0.21a1-83-ga1a55ac (C sources sha256 5a0108f1b0c2, kernel-choice modules ce1cdafcbf56); this site was built from 6929bd75ab7a / 99941e0ecc68. The code changed since, so these numbers may no longer describe it. Re-run tools/bench_docs.py on that machine and commit its JSON.
The two ID11 Eiger example files (sparse silicon, dense CeO2), each decoded on one core of each machine below, as bitshuffle-LZ4 in 8 kB blocks. 100 frames spread over each file were read into memory first (no file I/O is timed), then decoded in batches of 25 after one warmup batch; the best of 3 passes is shown. GB = 10^9 bytes. Compressed GB/s counts the bitshuffle-LZ4 bytes consumed, pixels GB/s the decompressed frame (pixels x bytes per pixel): their ratio is the compression ratio. Pipelines are the automatic choice on each machine, from the same build.
Both files share one approximate calibration, calib.poni (no spatial distortion), so the matrices are the same for every case: 75 um pixels, 0.139514 m distance, wavelength 2.84401e-11 m. Masked pixels: mask.h5 of the example data.
Machines
| machine | measured (UTC) | build | compiler | Python, numpy, pyFAI | data |
|---|---|---|---|---|---|
| AMD EPYC 9454 | 2026-10-14 17:28 | 0.0.22a1 v0.0.21a1-83-ga1a55ac |
gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 | 3.12.15, 2.5.3, 2026.9.0 | real_data_epyc-9454.json |
| Intel Xeon Gold 6248 | 2026-10-14 17:07 | 0.0.22a1 v0.0.21a1-83-ga1a55ac |
gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 | 3.12.15, 2.5.3, 2026.9.0 | real_data_xeon-gold-6248.json |
Frames per second
| data set | operation | AMD EPYC 9454 | Intel Xeon Gold 6248 |
|---|---|---|---|
| silicon | sparsify | 1770.2 | 820.4 |
| silicon | 1D | 1032.2 | 615.0 |
| silicon | 1D no-split | 1412.4 | 754.2 |
| silicon | 1D fine | 789.2 | 498.5 |
| silicon | 2D | 777.3 | 468.2 |
| silicon | 2D+rings | 1302.9 | 721.7 |
| ceo2 | sparsify | 437.7 | 186.9 |
| ceo2 | 1D | 108.1 | 47.9 |
| ceo2 | 1D no-split | 232.0 | 105.8 |
| ceo2 | 1D fine | 83.9 | 45.7 |
| ceo2 | 2D | 72.9 | 31.5 |
| ceo2 | 2D+rings | 330.8 | 153.2 |
Operations
| operation | what is timed |
|---|---|
| sparsify | chunk2sparse: decode, mask and threshold to (values, indices) |
| 1D | chunk2sparseCSC, pyFAI 1D bbox matrix (r_mm, one bin per pixel width) |
| 1D no-split | chunk2sparseCSC, pyFAI 1D no-split matrix: a histogram, every pixel in one bin with weight 1 (r_mm, one bin per pixel width) |
| 1D fine | chunk2sparseCSC, pyFAI 1D bbox matrix with 6000 bins (r_mm): a fine split, several bins per pixel |
| 2D | chunk2sparseCSC, pyFAI 2D bbox matrix (q_nm^-1, one radial bin per pixel width x 72 azimuthal bins) |
| 2D+rings | chunk2sparseCSC, 8 LaB6 ring windows x 72 azimuthal bins summed from the 2D matrix, the windows sized to hold ~8 % of the unmasked pixels |
silicon: sparse photon counting, uint16
silicon_lz4.h5, dataset /entry_0000/ESRF-ID11/eiger/data: 250 frames of 2162 x 2068 uint16; compression 59.8; 268834 masked pixels. Sparse cut 0: 0.5 % of the unmasked pixels are above it and go to the sparse output (mean over the timed frames).
| matrix | bins | entries | pixels with an entry | bins per pixel (mean, max) |
|---|---|---|---|---|
| 1D | 1542 | 9655790 | 100 % | 2.30, 3 |
| 1D no-split | 1542 | 4202182 | 100 % | 1.00, 1 |
| 1D fine | 6000 | 25427825 | 100 % | 6.05, 7 |
| 2D | 1542 x 72 | 9835464 | 100 % | 2.34, 88 |
| 2D+rings | 8 x 72 | 375415 | 8.8 % | 1.02, 2 |
| operation | machine | frames/s | compressed GB/s | pixels GB/s |
|---|---|---|---|---|
| sparsify | AMD EPYC 9454 | 1770.2 | 0.265 | 15.83 |
| sparsify | Intel Xeon Gold 6248 | 820.4 | 0.123 | 7.34 |
| 1D | AMD EPYC 9454 | 1032.2 | 0.154 | 9.23 |
| 1D | Intel Xeon Gold 6248 | 615.0 | 0.092 | 5.50 |
| 1D no-split | AMD EPYC 9454 | 1412.4 | 0.211 | 12.63 |
| 1D no-split | Intel Xeon Gold 6248 | 754.2 | 0.113 | 6.74 |
| 1D fine | AMD EPYC 9454 | 789.2 | 0.118 | 7.06 |
| 1D fine | Intel Xeon Gold 6248 | 498.5 | 0.075 | 4.46 |
| 2D | AMD EPYC 9454 | 777.3 | 0.116 | 6.95 |
| 2D | Intel Xeon Gold 6248 | 468.2 | 0.070 | 4.19 |
| 2D+rings | AMD EPYC 9454 | 1302.9 | 0.195 | 11.65 |
| 2D+rings | Intel Xeon Gold 6248 | 721.7 | 0.108 | 6.45 |
ceo2: dense powder rings, uint32
ceo2_lz4.h5, dataset /entry_0000/ESRF-ID11/eiger/data: 72 frames of 2162 x 2068 uint32; compression 4.6; 268834 masked pixels. Sparse cut 150: 1.3 % of the unmasked pixels are above it and go to the sparse output (mean over the timed frames).
| matrix | bins | entries | pixels with an entry | bins per pixel (mean, max) |
|---|---|---|---|---|
| 1D | 1542 | 9655790 | 100 % | 2.30, 3 |
| 1D no-split | 1542 | 4202182 | 100 % | 1.00, 1 |
| 1D fine | 6000 | 25427825 | 100 % | 6.05, 7 |
| 2D | 1542 x 72 | 9835464 | 100 % | 2.34, 88 |
| 2D+rings | 8 x 72 | 375415 | 8.8 % | 1.02, 2 |
| operation | machine | frames/s | compressed GB/s | pixels GB/s |
|---|---|---|---|---|
| sparsify | AMD EPYC 9454 | 437.7 | 1.720 | 7.83 |
| sparsify | Intel Xeon Gold 6248 | 186.9 | 0.735 | 3.34 |
| 1D | AMD EPYC 9454 | 108.1 | 0.425 | 1.93 |
| 1D | Intel Xeon Gold 6248 | 47.9 | 0.188 | 0.86 |
| 1D no-split | AMD EPYC 9454 | 232.0 | 0.912 | 4.15 |
| 1D no-split | Intel Xeon Gold 6248 | 105.8 | 0.416 | 1.89 |
| 1D fine | AMD EPYC 9454 | 83.9 | 0.330 | 1.50 |
| 1D fine | Intel Xeon Gold 6248 | 45.7 | 0.180 | 0.82 |
| 2D | AMD EPYC 9454 | 72.9 | 0.286 | 1.30 |
| 2D | Intel Xeon Gold 6248 | 31.5 | 0.124 | 0.56 |
| 2D+rings | AMD EPYC 9454 | 330.8 | 1.300 | 5.92 |
| 2D+rings | Intel Xeon Gold 6248 | 153.2 | 0.602 | 2.74 |
The conveyor on AMD EPYC 9454 + NVIDIA L40S
The conveyor (src/conveyor, threads) on 250 files of WAu5um_DT3 (ID11 Eiger 4M, uint16, scans 0001-0014 of /data/id11/nanoscope/blc12454/id11/WAu5um/WAu5um_DT3), 57.2 GB compressed, copied to /dev/shm first, so that the file system and the network are not timed; the results are dropped (a null sink). The same files for every point, in the order of the table; workers and their readers share 12 cores. The GPU points ran twice before the CPU points and twice after them. Operations: sparsify, the pixels above a cut of 1 (masked: the pixels at the dtype maximum of the first frame); 1d-nosplit, the same, and a pyFAI 1D no-split matrix (a histogram: one bin per pixel, weight 1). The matrices are built for that mask with the approximate geometry of tools/calib.poni: the work of an integration of this detector, not a calibrated pattern of these files. Measured 2026-10-14 17:12 UTC, build 0.0.22a1 v0.0.21a1-83-ga1a55ac; conveyor_epyc-9454-l40s.json.
| pass | decoder | operation | workers | frames/s | frames/s per CPU worker | compressed GB/s | worker cores | seconds |
|---|---|---|---|---|---|---|---|---|
| gpu1 | GPU | sparsify | 1 | 10064 | 2.30 | 1.0 | 24.8 | |
| gpu1 | GPU | sparsify | 2 | 14632 | 3.35 | 1.9 | 17.1 | |
| gpu1 | GPU | sparsify | 4 | 17090 | 3.91 | 3.6 | 14.6 | |
| gpu1 | GPU | 1d-nosplit | 1 | 7791 | 1.78 | 1.0 | 32.1 | |
| gpu1 | GPU | 1d-nosplit | 2 | 11097 | 2.54 | 1.9 | 22.5 | |
| gpu1 | GPU | 1d-nosplit | 4 | 11265 | 2.58 | 3.7 | 22.2 | |
| gpu2 | GPU | sparsify | 1 | 10070 | 2.30 | 1.0 | 24.8 | |
| gpu2 | GPU | sparsify | 2 | 14645 | 3.35 | 1.9 | 17.1 | |
| gpu2 | GPU | sparsify | 4 | 16958 | 3.88 | 3.6 | 14.7 | |
| gpu2 | GPU | 1d-nosplit | 1 | 7748 | 1.77 | 1.0 | 32.3 | |
| gpu2 | GPU | 1d-nosplit | 2 | 11012 | 2.52 | 1.9 | 22.7 | |
| gpu2 | GPU | 1d-nosplit | 4 | 11196 | 2.56 | 3.7 | 22.3 | |
| cpu | CPU | sparsify | 4 | 3975 | 994 | 0.91 | 4.0 | 62.9 |
| cpu | CPU | sparsify | 8 | 7640 | 955 | 1.75 | 7.7 | 32.7 |
| cpu | CPU | sparsify | 12 | 11228 | 936 | 2.57 | 11.2 | 22.3 |
| cpu | CPU | 1d-nosplit | 4 | 2840 | 710 | 0.65 | 4.0 | 88.0 |
| cpu | CPU | 1d-nosplit | 8 | 5339 | 667 | 1.22 | 7.7 | 46.8 |
| cpu | CPU | 1d-nosplit | 12 | 7730 | 644 | 1.77 | 11.2 | 32.3 |
| gpu3 | GPU | sparsify | 1 | 10057 | 2.30 | 1.0 | 24.9 | |
| gpu3 | GPU | sparsify | 2 | 14608 | 3.34 | 1.9 | 17.1 | |
| gpu3 | GPU | sparsify | 4 | 16947 | 3.88 | 3.6 | 14.8 | |
| gpu3 | GPU | 1d-nosplit | 1 | 7772 | 1.78 | 1.0 | 32.2 | |
| gpu3 | GPU | 1d-nosplit | 2 | 10988 | 2.51 | 1.9 | 22.8 | |
| gpu3 | GPU | 1d-nosplit | 4 | 11271 | 2.58 | 3.7 | 22.2 | |
| gpu4 | GPU | sparsify | 1 | 10014 | 2.29 | 1.0 | 25.0 | |
| gpu4 | GPU | sparsify | 2 | 14650 | 3.35 | 1.9 | 17.1 | |
| gpu4 | GPU | sparsify | 4 | 16930 | 3.87 | 3.6 | 14.8 | |
| gpu4 | GPU | 1d-nosplit | 1 | 7828 | 1.79 | 1.0 | 31.9 | |
| gpu4 | GPU | 1d-nosplit | 2 | 11053 | 2.53 | 1.9 | 22.6 | |
| gpu4 | GPU | 1d-nosplit | 4 | 11205 | 2.56 | 3.7 | 22.3 |
Written by tools/bench_docs.py and tools/bench_race.py; one JSON per machine in docs/bench/.
Generated by tools/generate_docs.py from bslz4_to_sparse 0.0.22a2 (git v0.0.22-13-g610ed27, sources sha256 6929bd75ab7a).