The sparse range probe (#357) is overwhelmingly numpy-pass-bound: the branchless partition_point loop runs _depth iterations over the whole query block, each one a handful of full-array passes, and the cell_vk gather is the minority of the time.
Measured by splitting the lookup at N = 1e8: the cell_vk gather moves 2.4 GB across 16,384 scattered points in 0.26–0.28 ms and is only 13–16% of full lookup; the cell_id gather is 0.03 ms; full lookup is 1.68–2.03 ms. So the search loop is the other 84–87%, and it is overhead-bound, not memory-bound — it runs over a 16,384-element block that is L2-resident. (Multi-GB memory access was the stable part of that measurement, at a 1.02–1.09× min/max spread; all the variance sat in the search loop.)
A single-pass kernel over (region_ptr, cell_id) would do the whole search per query in registers instead of in _depth full-array numpy passes. Estimated headroom on the probe itself is 3–5×.
Deliberately NOT done in #357, on measurement rather than principle. The gate in tests/benchmarks/profiling/bench_svar2_range_lookup.py binds the probe at ≤ 2% of batch wall and it passes with margin:
- Worst row in the sweep (
N=1e8, n_q=8192, globally shuffled), canonical median of five runs: 1.48 ms = 0.86% of the 171 ms single-threaded spliced batch, and 1.68% of the same batch on 8 threads (88 ms).
- Realized chr22 operating point (
N=1e7, matching chr22's 18.0e6 entries): ~0.5% of the 171 ms batch — confirming the design spec's own "~0.5% of batch wall" claim — and ~0.95% at 8 threads.
So 3–5× on the probe buys roughly 0.35–0.4% of single-threaded batch wall today. The probe's share rises with thread count, because it is serial Python/numpy while the batch around it scales, which is why the 8-thread figure is carried here alongside the single-threaded one.
It becomes worth doing if the benchmark gate ever fails, if the read path gets fast enough elsewhere that 0.5% matters, or if thread counts climb far enough that the serial share dominates. The script prints a break-even batch wall (worst_ms / GATE) for exactly this purpose: 73.9 ms at the canonical figures — below that batch wall, the probe exceeds 2% and this issue is live.
Shape, if taken: a #[pyfunction] in src/ffi/mod.rs over a kernel in a domain module, registered in src/lib.rs's #[pymodule]. Note there is no dual-backend parity harness any more (_dispatch.py and docs/roadmaps/rust-migration.md were retired in 8f9d3c99), so parity needs a hand-written numpy oracle plus frozen .npz goldens under tests/parity/.
Found while implementing #357. The companion opportunity on the write path is the larger prize — see the genoray find_ranges_chunk issue.
The sparse range probe (#357) is overwhelmingly numpy-pass-bound: the branchless
partition_pointloop runs_depthiterations over the whole query block, each one a handful of full-array passes, and thecell_vkgather is the minority of the time.Measured by splitting the lookup at
N = 1e8: thecell_vkgather moves 2.4 GB across 16,384 scattered points in 0.26–0.28 ms and is only 13–16% of full lookup; thecell_idgather is 0.03 ms; full lookup is 1.68–2.03 ms. So the search loop is the other 84–87%, and it is overhead-bound, not memory-bound — it runs over a 16,384-element block that is L2-resident. (Multi-GB memory access was the stable part of that measurement, at a 1.02–1.09× min/max spread; all the variance sat in the search loop.)A single-pass kernel over
(region_ptr, cell_id)would do the whole search per query in registers instead of in_depthfull-array numpy passes. Estimated headroom on the probe itself is 3–5×.Deliberately NOT done in #357, on measurement rather than principle. The gate in
tests/benchmarks/profiling/bench_svar2_range_lookup.pybinds the probe at ≤ 2% of batch wall and it passes with margin:N=1e8,n_q=8192, globally shuffled), canonical median of five runs: 1.48 ms = 0.86% of the 171 ms single-threaded spliced batch, and 1.68% of the same batch on 8 threads (88 ms).N=1e7, matching chr22's 18.0e6 entries): ~0.5% of the 171 ms batch — confirming the design spec's own "~0.5% of batch wall" claim — and ~0.95% at 8 threads.So 3–5× on the probe buys roughly 0.35–0.4% of single-threaded batch wall today. The probe's share rises with thread count, because it is serial Python/numpy while the batch around it scales, which is why the 8-thread figure is carried here alongside the single-threaded one.
It becomes worth doing if the benchmark gate ever fails, if the read path gets fast enough elsewhere that 0.5% matters, or if thread counts climb far enough that the serial share dominates. The script prints a break-even batch wall (
worst_ms / GATE) for exactly this purpose: 73.9 ms at the canonical figures — below that batch wall, the probe exceeds 2% and this issue is live.Shape, if taken: a
#[pyfunction]insrc/ffi/mod.rsover a kernel in a domain module, registered insrc/lib.rs's#[pymodule]. Note there is no dual-backend parity harness any more (_dispatch.pyanddocs/roadmaps/rust-migration.mdwere retired in8f9d3c99), so parity needs a hand-written numpy oracle plus frozen.npzgoldens undertests/parity/.Found while implementing #357. The companion opportunity on the write path is the larger prize — see the genoray
find_ranges_chunkissue.