[benchmark/filtered-search prep] Make benchmarks stateful#995
[benchmark/filtered-search prep] Make benchmarks stateful#995hildebrandmw merged 4 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the benchmark framework to support stateful benchmarks by switching Benchmark/Regression APIs from type-level (static) methods to instance methods (&self) and updating the registry to register benchmark values (enabling future dynamic “search plugin” registration per benchmark instance).
Changes:
- Convert
BenchmarkandRegressiontrait methods (try_match,description,run,check) to take&self. - Update
Benchmarks::register/register_regressionto accept a benchmark instance by value and store it behind a type-erased wrapper. - Refactor benchmark implementations across
diskann-benchmarkanddiskann-benchmark-simdto remove the prior'static/dispatcher indirection patterns.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| diskann-benchmark/src/utils/mod.rs | Updates stub benchmark registration and trait method signatures to the new &self API. |
| diskann-benchmark/src/backend/index/spherical.rs | Refactors spherical index benchmarks to unit-like/stateful benchmarks and inlines prior dispatch indirection. |
| diskann-benchmark/src/backend/index/scalar.rs | Refactors scalar quantized index benchmarks to constructable/stateful benchmark instances. |
| diskann-benchmark/src/backend/index/product.rs | Refactors PQ index benchmark to a constructable/stateful benchmark instance. |
| diskann-benchmark/src/backend/index/benchmarks.rs | Removes BuildAndSearch/BuildAndDynamicRun indirection and moves logic directly into Benchmark::run(&self, ...). |
| diskann-benchmark/src/backend/filters/benchmark.rs | Converts metadata index benchmark into a stateful/unit-like benchmark and extracts run logic into a free function. |
| diskann-benchmark/src/backend/exhaustive/spherical.rs | Refactors exhaustive spherical benchmarks to unit-like/stateful benchmarks. |
| diskann-benchmark/src/backend/exhaustive/product.rs | Refactors exhaustive product benchmarks to unit-like/stateful benchmarks. |
| diskann-benchmark/src/backend/exhaustive/minmax.rs | Refactors exhaustive minmax benchmarks to unit-like/stateful benchmarks. |
| diskann-benchmark/src/backend/disk_index/benchmarks.rs | Refactors disk index benchmark/regression to stateful benchmarks and updates registration accordingly. |
| diskann-benchmark-simd/src/lib.rs | Updates SIMD regression benchmarks to be instance-based and adjusts kernel execution to pass arch at call time. |
| diskann-benchmark-runner/src/test/typed.rs | Updates typed test benchmarks/regressions to instance-based implementations (adds constructors). |
| diskann-benchmark-runner/src/test/mod.rs | Updates benchmark registration in test harness to pass benchmark instances. |
| diskann-benchmark-runner/src/test/dim.rs | Updates dim test benchmarks/regression to the new &self trait signatures. |
| diskann-benchmark-runner/src/registry.rs | Changes registry APIs to accept benchmark instances and stores them in the wrapper. |
| diskann-benchmark-runner/src/benchmark.rs | Changes core traits to &self methods and updates internal type-erased wrapper and regression plumbing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is ❌ Your patch status has failed because the patch coverage (79.55%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #995 +/- ##
==========================================
+ Coverage 89.48% 89.50% +0.02%
==========================================
Files 448 448
Lines 84095 84167 +72
==========================================
+ Hits 75250 75333 +83
+ Misses 8845 8834 -11
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
arkrishn94
left a comment
There was a problem hiding this comment.
Thanks Mark, looks good to me.
Bump version to 0.51.0 due to propagate changes to downstream consumers ## Breaking API changes (AI Generated) - **`ObjectPool` moved** (#975): now lives in `diskann-utils`. Update imports from `diskann::...::ObjectPool` → `diskann_utils::ObjectPool`. - **`AlignedSlice` removed** (#994): the `AlignedSlice` abstraction in `diskann-vector` is gone. Code that converted between vector representations through `AlignedSlice` should now use the `Poly` / `CastFromSlice` polymorphic interfaces directly (see `diskann-vector::conversion` and `diskann-quantization::alloc::poly`). Storage that previously held `AlignedSlice` values should hold `Poly<T, A>` instead. - **`AsThreadPool` generic removed** (#967): functions that previously took `pool: impl AsThreadPool` now take `pool: &RayonThreadPool`. Pass a borrow of an existing pool; remove the generic parameter from your call sites. - **`sgemm()` returns `Result`** (#997): in `diskann-linalg`, the new signature is: ```rust pub fn sgemm( atranspose: Transpose, btranspose: Transpose, m: usize, n: usize, k: usize, alpha: f32, a: &[f32], b: &[f32], beta: Option<f32>, c: &mut [f32], ) -> Result<(), SgemmError> ``` `SgemmError` has variants `InvalidMatrixDimensions { matrix_name, expected_rows, expected_cols, actual_len }` and `DimensionOverflow { matrix_name, rows, cols }`. Replace previous panic-on-bad-input assumptions with explicit handling. - **Benchmarks are stateful** (#995): the `Benchmark` impls in `diskann-benchmark` are no longer stateless unit structs. Each benchmark type now has a `::new()` constructor (often holding `PhantomData<T>` or plugin state), and registration uses an instance: ```rust // before benchmarks.register("name", MyBench); // after benchmarks.register("name", MyBench::<T>::new()); ``` If you wrote a custom benchmark, give it a `new()` and register an instance. Combined with #996, search-side benchmarks now compose `Plugins<Provider, Phase, Strategy>` and expose builder methods like `.search(plugin)` to register search plugins on the instance. - **`diskann-benchmark`: `async` → `graph-index`** (#1009): the benchmark category previously named `async` was renamed to `graph-index`. JSON config `type` values and example file names changed accordingly: - `async-build` → `graph-index-build` - `async-dynamic-run` → `graph-index-dynamic-run` - and the same prefix swap for `*-pq`, `*-sq`, `*-spherical-quantization`, etc. Update any benchmark config files, scripts, or CI that reference the old `async-*` names. - **`diskann-disk` buffer alignment decoupled from `block_size`** (#984): code that assumed I/O buffer alignment equals the disk block size should now configure alignment explicitly. ## Non-breaking - New cache-aware block-transposed Chamfer/MaxSim distance for f32/f16 (#863). - A/A benchmark documentation (#974); CI publish workflow improvements (#755, #1017); openssl bump (#973); `compute_closest_centers` allocation reduction (#980). - **`DistanceComputer` `'static` bound relaxed** (#1007) and **redundant `DistanceFunction` impls removed** (#1008) **Full Changelog**: v0.50.1...v0.51.0
A recurring problem with our current benchmark infrastructure is the
SearchPhaseenum (selecting what kind of search is conducted) does its job a little too well: every time a new variant is added, we need to either update all users ofSearchPhase(bloating compile times) or explicitly opt-out of a particular search phase, which is brittle especially with respect toBenchmark::try_matchconsistency.For example see:
This PR takes the first step towards systematically solving this problem by allowing benchmarks registered with
diskann_benchmark_runner::Benchmarksto have state ratherthan being purely type-level constructs. Stateful benchmarks can have "search plugins" dynamically registered at construction time. These plugins participate in
Benchmark::try_match,Benchmark::description, andBenchmark::run, allowing individual benchmarks to opt into new search-phase variants without requiring changes across allbenchmarks. See #996 as a follow-up implementing this idea
Suggested Reviewing Order
In
diskann-benchmark-runner:benchmark.rs: This is the main change. It simply changes theBenchmarkandRegressiontraits to receive by&self.registry.rs: Change the signatures ofBenchmarks::registerandBenchmarks::register_regressionto receive the benchmark type by-value.In
diskann-benchmark: The main changes involve cleaning up the'statichack and removing theBuildAndSearch/BuildAndDynamicRunindirection traits that are no longer necessary.In
diskann-benchmark-simd: Feel free to skip.