bench: refresh competitive table from single fresh-process run - #55
Conversation
Re-ran experiments/bench_competitive.py start-to-finish in a single clean Python session on main (commit 8a28af1, post v0.10.0 merge) after observing a 56% p50 delta on SnapIndex between the first multi-session measurement and a later standalone run. The refreshed table (this commit) sits within +/-5% of the previous numbers for every row except hnswlib, confirming that the spike was the first-run outlier we already corrected, not a systemic drift. All recall numbers are identical run-to-run (determinism tests hold). Also add a short Methodology note above the table so readers know the numbers came from one fresh process, and call out the expected run-to-run noise (<=5% p50 for most rows, ~10% for hnswlib). This is what lets the table survive a 're-run it and compare' review.
There was a problem hiding this comment.
Code Review
This pull request updates the benchmark data in docs/benchmarks.md and adds a methodology section describing the measurement process and expected variance. Review feedback suggests refining the reported noise variance for hnswlib to better reflect observed data and identifies several inconsistencies in the descriptive text where hardcoded benchmark values were not updated to match the new table data.
| Accelerate with its default thread count. Expected run-to-run noise | ||
| on this hardware is <=5% p50 for every row except hnswlib, which | ||
| hits +/-10% routinely. |
There was a problem hiding this comment.
The PR description mentions that hnswlib showed a +11% delta, which is described as being within its expected variance. However, the text here specifies +/-10%. It might be safer to adjust this to ~10-15% to more accurately reflect the observed noise levels on this hardware.
| Accelerate with its default thread count. Expected run-to-run noise | |
| on this hardware is <=5% p50 for every row except hnswlib, which | |
| hits +/-10% routinely. | |
| Accelerate with its default thread count. Expected run-to-run noise | |
| on this hardware is <=5% p50 for every row except hnswlib, which | |
| hits ~10-15% routinely. |
| on this hardware is <=5% p50 for every row except hnswlib, which | ||
| hits +/-10% routinely. | ||
|
|
||
| ### Reading the table |
There was a problem hiding this comment.
The benchmark table has been updated with fresh numbers, but the descriptive text in the following sections (### Reading the table, ### Positioning in plain language, and ### Caveats) still contains hardcoded values from the previous run.
For example:
- Line 84:
(336 vs 475 us)should be(325 vs 483 us). - Line 86:
355 usshould be359 us. - Line 90:
819 usshould be994 us. - Line 92:
13 msshould be13.9 ms. - Line 117:
(16 s vs 112 s)should be(17 s vs 110 s).
These should be updated to maintain consistency with the new table data.
There was a problem hiding this comment.
Pull request overview
Refreshes the published “competitive” benchmark table in the documentation using results from a single end-to-end rerun of experiments/bench_competitive.py, and clarifies measurement methodology/noise expectations to address previously observed run-to-run deltas.
Changes:
- Updated all rows in the competitive benchmark table (p50/p99/build/disk) with fresh-run numbers.
- Added a Methodology paragraph describing the single-run approach and expected noise envelope (notably for hnswlib).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| | sqlite-vec (brute-force cosine, exact) | **1.000** | 13891 | 18628 | 91.1 | 0.5 | | ||
| | hnswlib (M=32, ef_search=128) | 0.994 | 561 | 994 | 104.5 | 45 | | ||
| | **snapvec IVFPQ + fp16 rerank (M=192)** | **0.945** | **359** | 457 | 56.9 | 108 | | ||
| | FAISS IVFPQ (M=192) [matched-budget] | 0.906 | 483 | 584 | 12.7 | 17 | | ||
| | **snapvec IVFPQ no rerank (M=192)** | 0.895 | **325** | 376 | 12.6 | 110 | | ||
| | snapvec SnapIndex 4-bit scalar (full-scan) | 0.854 | 2676 | 3164 | 15.4 | 1.1 | | ||
| | snapvec SnapIndex 3-bit scalar (full-scan) | 0.736 | 2688 | 3013 | 11.7 | 0.8 | | ||
| | snapvec SnapIndex 2-bit scalar (full-scan) | 0.618 | 2726 | 4016 | 8.0 | 0.7 | | ||
| | FAISS IVFPQ (M=48) | 0.603 | 142 | 200 | 4.4 | 10 | | ||
| | snapvec IVFPQ no rerank (M=48) [matched-budget] | 0.549 | 267 | 350 | 4.3 | 33 | |
| **Methodology.** All numbers come from a single fresh-process run of | ||
| `experiments/bench_competitive.py` so backend-to-backend comparisons | ||
| are not contaminated by OS page-cache state inherited from earlier | ||
| runs. An earlier multi-session measurement showed a ~56% p50 delta | ||
| on SnapIndex between cold and warm runs; the single-run convention | ||
| above eliminates that. |
Two reviewers flagged that after updating the table values I left the narrative bullets (Reading the table, Positioning, Caveats) citing old p50/p99/build numbers. Align every number in the prose with the refreshed fresh-process run so the page is internally consistent: - M=192 matched-budget headline: 1.4x -> 1.5x, 336/475 -> 325/483 - IVFPQ+rerank bullet: 355 us -> 359 us - hnswlib p99: 819 us -> 994 us - sqlite-vec cite: 13 ms -> 13.9 ms (so the '~5x faster' claim matches) - FAISS fit gap: 7x vs 16/112 -> 6.5x vs 17/110 - FAISS M=48 latency bullet: 168 us -> 142 us Also refine two wording issues from the same review: - Methodology said 'single fresh-process run' but the bench actually runs four per-backend subprocesses under one orchestrator. Reword to 'single end-to-end invocation' and explain the subprocess layout so readers know why. - Expected hnswlib noise was noted as +/-10%; observed +11% delta in this run puts it closer to 10-15%. Update the envelope to match reality.
Summary
Jay flagged a 56% p50 delta on SnapIndex 4-bit between two earlier
measurements (4244 us vs 2727 us on the same config). Too big for
query noise. Re-ran the full `bench_competitive.py` start-to-finish
in one fresh Python session on main (post v0.10.0 merge, commit
`8a28af1`) to confirm the published table.
Findings
Run-to-run delta vs the previously published numbers:
Everything except hnswlib sits within 5%. hnswlib is at +11%, which
is within its measured run-to-run variance (noted explicitly in the
new Methodology paragraph).
What changes
fresh numbers (all 10 rows).
process, expected noise envelope per backend, the reason (no OS
page-cache contamination).
Recall
Unchanged. All backends are deterministic given seeds; recall@10
matches earlier run bit-for-bit.
Test plan