The first section was measured in October 2026 on a laptop. The others are historical measurements from the initial implementation (cloud container, 4 vCPU x86_64, files in the page cache, synthetic data, medians of several cold processes); they have not been rerun for the later oblique resampling, spectroscopy and exact 64-bit label paths and are not latency guarantees for those features.
Laptop, Intel i7-13800H (20 threads), files in the page cache, through the
protocol (open, load, the three centre slices; then the last volume and a
complete time course), medians of 3 cold processes, October 2026:
| File | Open | Three slices shown | Last volume | Complete time course |
|---|---|---|---|---|
4D 96×96×60×200 int16, 141 MB .nii.gz (synthetic, noisy) |
0.4 ms | 17 ms | 0.89 s (whole stream inflated once) | 0.89 s |
same, uncompressed 221 MB .nii |
0.3 ms | 10 ms | 9 ms | 9 ms |
same .nii.gz, taken as remote (NIFTI_PREVIEW_ASSUME_NETWORK=1) |
0.4 ms | 18 ms | 0.90 s | 0.90 s |
same .nii, taken as remote (read in 4 MiB blocks, never mapped) |
0.3 ms | 17 ms | 106 ms | 107 ms |
DICOM CT series, 140 files of 512×512 (Philips, dcm_qa_ct) |
7 ms (folder read) | 99 ms | – | – |
| DICOM enhanced MR, 176 frames of 256×256, one file | 10 ms | 58 ms | – | – |
| DICOM JPEG 2000 lossless, 1024×1024, 3 files | 8 ms | 99 ms | 8 ms | 8 ms |
| DICOM JPEG-LS lossless, 2140×1760 radiograph | 3 ms | 226 ms | – | – |
| DICOM JPEG lossless, 512×512 CT | 3 ms | 16 ms | – | – |
Frames of a DICOM image are decoded in parallel (up to 8 threads). Over a real
network the time is that of the transfer: the preview shows the progress and
the rate, and asks first above [network] confirm-above-mb.
Time from the construction of the viewer by Sushi to the moment the metadata,
then the three slices, are on screen (NIFTI_PREVIEW_DEBUG=1), GNOME Sushi 46
under Xvfb, Sushi already running:
| File | Metadata | Three slices |
|---|---|---|
1 mm T1, 256³ int16 with MRI-like noise, 18.5 MB .nii.gz |
15 ms | 167 ms |
same, uncompressed 33.6 MB .nii (read into memory) |
17 ms | 72 ms |
MNI-sized 182×218×182 float32, 10.5 MB .nii.gz |
13 ms | 110 ms |
4D 96×96×60×200 int16, 87 MB .nii.gz (volume 0 only) |
16 ms | 49 ms |
A real 1 mm MNI-space T1 (181×217×181 float32, 24 MB .nii.gz) previewed from the real
Nautilus 50 on Ubuntu 26.04: three slices after 171–250 ms; its segmentations
(uint8, 0.1–0.4 MB) after 55–95 ms. Clicking a label counts its voxels in about 5 ms.
The integration test also measures the 160×192×160 test phantom on each Sushi version: three slices after 74 ms (Sushi 46), 94 ms (Sushi 50) and 80 ms (Sushi 51). Scrolling costs about 1 ms of backend time per slice, far below a 16 ms frame.
nifti-preview bench FILE (one process per file, medians of 5):
| File | Header | Decompress | Statistics | 3 slices | Ready | Per slice | Peak RSS |
|---|---|---|---|---|---|---|---|
T1 256³ int16, 18.5 MB .nii.gz |
0.1 ms | 115 ms | 35 ms | 3.5 ms | 151 ms | 0.84 ms | 53 MB |
T1 256³ int16, smooth, 5.6 MB .nii.gz |
0.1 ms | 46 ms | 30 ms | 2.4 ms | 79 ms | 0.82 ms | 49 MB |
same, NIfTI-2 .nii.gz |
0.1 ms | 50 ms | 36 ms | 2.4 ms | 89 ms | 0.97 ms | 49 MB |
same, uncompressed .nii |
0.03 ms | – (read into memory) | 33 ms | 2.7 ms | 36 ms | 0.81 ms | 49 MB |
182×218×182 float32, 10.5 MB .nii.gz |
0.1 ms | 74 ms | 26 ms | 1.5 ms | 103 ms | 0.57 ms | 43 MB |
4D 96×96×60×200 int16, 87 MB .nii.gz |
0.1 ms | 4.7 ms | 17 ms | 0.3 ms | 22 ms | 0.06 ms | 13 MB |
Process start-up is 1.5 ms. Decompression (libdeflate, single-threaded,
≈ 300 MB/s of output here) dominates for .nii.gz; standard gzip cannot be
decompressed in parallel. For the 4D file only volume 0 (1.1 MB of voxel data) is
inflated; decompressing the whole 221 MB stream takes 1.4 s with zlib.
The first version of the backend used Python, nibabel and numpy. Same stages, same files (ADR 0001):
| File | Python + nibabel ready | Rust ready | Peak RSS Python / Rust |
|---|---|---|---|
T1 256³, 18.5 MB .nii.gz |
≈ 580 ms | 151 ms | 144 / 53 MB |
T1 256³ .nii |
≈ 305 ms | 36 ms | 142 / 49 MB |
4D 87 MB .nii.gz |
≈ 287 ms | 22 ms | 67 / 13 MB |
Python’s start-up alone (interpreter + import numpy, nibabel) is about 200 ms;
indexed_gzip does not help a 3D preview (233 ms vs 234 ms of decompression),
because three orthogonal slices touch the whole volume.
cd backend && cargo build --release
python3 -m venv /tmp/venv && /tmp/venv/bin/pip install -e ../reference
/tmp/venv/bin/nifti-preview-ref make-fixtures /tmp/fixtures # test phantoms
target/release/nifti-preview bench /tmp/fixtures/*.nii*