perf: chunked skip-scan in value_at_quantile (+63% read); supersedes #139#140
Open
fcostaoliveira wants to merge 1 commit into
Open
perf: chunked skip-scan in value_at_quantile (+63% read); supersedes #139#140fcostaoliveira wants to merge 1 commit into
fcostaoliveira wants to merge 1 commit into
Conversation
Rather than add-and-branch on every counts[] element (a serial dependency chain), sum a fixed-size chunk at a time via chunks_exact(8) — a reduction with no early exit that autovectorizes — and skip the whole chunk while its subtotal cannot reach the target; only the crossing chunk is walked element by element. Counts are non-negative, so a chunk whose subtotal cannot reach the target contains no crossing element: results are identical to the linear scan for any input. Iterating chunks/elements also elides the per-element bounds check, superseding the plain-iterator change (HdrHistogram#139). gnr1 (Granite Rapids), single core: value_at_percentile 0.1741 -> 0.2786 Mq/s (+60%); the batch metric (7x singular on this crate) rides it to +65%; record path unchanged. Adds a white-box parity test (chunked vs a linear reference) across all Counter widths (u8/u16/u32/u64) and a sig=0 histogram that forces a crossing element into the tail loop (for sig >= 1, counts.len() is always a multiple of 8 so the tail is unreachable).
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.
Summary
Replaces the
value_at_quantileprefix-sum scan with a chunked skip-scan. The old loop added onecount and branched on the running total for every element — a serial dependency chain. This sums a
fixed-size chunk (
chunks_exact(8)) at a time — a reduction with no early exit that autovectorizes —and skips the whole chunk while its subtotal cannot reach the target; only the single crossing chunk is
walked element-by-element. Counts are non-negative, so a chunk whose subtotal cannot reach the target
contains no crossing element: the result is identical to the linear scan for any input. No
unsafe.Supersedes and closes #139 — the chunked scan iterates chunks/elements rather than indexing, so it
already elides the per-element bounds check that #139 targeted; this is a strict superset of that win.
Benchmark
gnr1(Intel Granite Rapids), single core,--release, same-session interleaved A/B (basemainvs this branch), 2 rounds:value_at_percentile(Mq/s)record(M ops/s)Percentile results byte-identical across base and patch (
sink/bsinkunchanged).Tests
Counterwidths (u8/u16/u32/u64) and a quantile sweep.
sig=0histogram (sub_bucket_half_count == 1) is the only geometrywhose
counts.len()is not a multiple of 8, so it forces a crossing element into theremainder()tail loop. (For
sig >= 1,sub_bucket_half_countis a power of two ≥ 16, socounts.len()is alwaysa multiple of 8 and the tail is unreachable.)
cargo test,cargo fmt --check,cargo clippyall clean (zero new warnings); MSRV 1.64 / edition2018 unaffected (
chunks_exact/remainderstabilized in 1.31); no new dependencies.