Repository navigation
Conversation
Every Count Sketch estimate collected its per-row estimates in a fresh Vec before taking the median, a heap allocation per query. The fast and regular paths, CountSketchWithL2Norm::estimate_with_hash, CountSketchFold::estimate and Vector2D::fast_query_median(_with_key) now collect them in a SmallVec of MATRIX_MAX_ROWS (20) f64s, so a sketch the ASAPv1 wire can carry never allocates on a query. Results are unchanged.
…2_squared The fixed-size matrices (QuickMatrix*, FixedMatrix) collect their per-row estimates in a [f64; ROWS] array; BitMatrix::fast_query_median and CountSketchWithL2Norm::l2_squared use the inline RowEstimates, so no Count Sketch median allocates for 20 rows or fewer.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every Count Sketch estimate collects its per-row estimates in a fresh
Vecand then takes the median, so each query pays a heap allocation and a free. On small shapes that is most of the gap between an estimate and an update. On main eb04e7f, 3×1024 with u64 keys costs 59 ns per fast-path estimate against 21 ns per update.What
The per-row estimates are collected on the stack:
RowEstimates(a crate-privateSmallVec<[f64; MATRIX_MAX_ROWS]>) for:Vector2D(fast_query_median,fast_query_median_with_key), which serves the CountSketch fast path;BitMatrix::fast_query_median;CountSketchWithL2Norm::estimate_with_hashandl2_squared;CountSketchFold::estimate.[f64; ROWS]array for the fixed-size matrices (QuickMatrixI32/I64/I128,FixedMatrix, inimpl_fixed_matrix!).No Count Sketch median allocates for 20 rows or fewer. Wider in-memory
Vector2DorBitMatrixmatrices spill as before. Results are unchanged; the median code is untouched.How
The collected
Vecs becomeRowEstimates, and the fixed-matrix macro fills a[f64; $rows]array.compute_median_inline_f64and the regular path's sort take the slice as before.Before / After
Benchmark: a local example, not committed. Release build, pinned to one core (
taskset -c 50),2^20keys per case, the two builds alternated over 7 rounds, median ns/op. The host was shared (load 40–60), so differences under ~5 ns are noise. The update rows are unchanged code. The regular-path update reads 7–9 ns slower in this table. A separate example that times only that update (3×1024, 5×2048, 7×2048) runs at the same speed on both builds (best of 7: 83.8 vs 84.0, 122.6 vs 122.7 and 160.6 vs 160.7 ns), and its disassembly is the same length on both. So the slowdown comes from how this all-in-one bench compiles (LTO inlines every case into one function), not from the library.Not in this PR (follow-ups)
MatrixHash::Rows(wasSmallVec<[u64; 8]>). Measured, and not a pure speedup. It growsMatrixHashfrom about 80 to about 176 bytes, and the packed layouts paid for it:The Rows layout saved only 4–10 ns, because the row hashing (9–15 xxh3 calls) dominates, not the allocation. A Rows path that hashes each row when it is read, instead of materializing the hashes inside
MatrixHash, would avoid both costs.Verification
cargo fmt --all -- --check-D warningswith--all-features, default features,octo-runtimeandexperimentalcargo test --all-features --locked(2,233 passed) andcargo test --locked(1,977 passed); the existing estimate, median and golden tests cover the unchanged resultsRUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features --locked