Skip to content

perf: chunked skip-scan in value_at_quantile (+63% read); supersedes #139#140

Open
fcostaoliveira wants to merge 1 commit into
HdrHistogram:mainfrom
fcostaoliveira:perf/chunked-scan
Open

perf: chunked skip-scan in value_at_quantile (+63% read); supersedes #139#140
fcostaoliveira wants to merge 1 commit into
HdrHistogram:mainfrom
fcostaoliveira:perf/chunked-scan

Conversation

@fcostaoliveira

Copy link
Copy Markdown

Summary

Replaces the value_at_quantile prefix-sum scan with a chunked skip-scan. The old loop added one
count 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 (base main vs this branch), 2 rounds:

metric base this branch Δ
value_at_percentile (Mq/s) 0.1739 0.2836 +62.9%
batch of 7 (7× singular, Mcalls basis) 24.8K 40.9K +64.8%
record (M ops/s) 348.9 348.6 flat

Percentile results byte-identical across base and patch (sink/bsink unchanged).

Tests

  • New white-box parity test comparing the chunked scan to a linear reference across all Counter
    widths
    (u8/u16/u32/u64) and a quantile sweep.
  • A dedicated tail-crossing test: a sig=0 histogram (sub_bucket_half_count == 1) is the only geometry
    whose counts.len() is not a multiple of 8, so it forces a crossing element into the remainder()
    tail loop. (For sig >= 1, sub_bucket_half_count is a power of two ≥ 16, so counts.len() is always
    a multiple of 8 and the tail is unreachable.)
  • cargo test, cargo fmt --check, cargo clippy all clean (zero new warnings); MSRV 1.64 / edition
    2018 unaffected (chunks_exact/remainder stabilized in 1.31); no new dependencies.

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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant