Skip to content

goodhistogram: add WithExactMinMax wrapper for exact extremes - #14

Merged
angles-n-daemons merged 4 commits into
mainfrom
bdillmann/exact-summary
Sep 9, 2026
Merged

angles-n-daemons merged 4 commits into
mainfrom
bdillmann/exact-summary

Conversation

@angles-n-daemons

Copy link
Copy Markdown
Contributor

Summary

Bucket-based quantile estimation can't recover the true extremes: q=1.0 clamps to the top occupied bucket's edge, and out-of-range observations lose their magnitude entirely. Callers who need a truthful min/max (e.g. "max latency") had no way to get one.

WithExactMinMax wraps a Histogram and additionally tracks exact min/max, completing an exact {count, sum, min, max} summary. The base already tracks sum and count exactly (matching Prometheus, which maintains an exact _sum/_count), so this only adds min/max.

Design

Additive and opt-in — no base API change:

  • Embeds *Histogram, so every existing method still works and the base recording path is untouched for callers who don't opt in.
  • Record updates min/max via load-then-CAS, which degrades to two relaxed loads once the extremes stabilize — cheap under contention (writes only while the extreme is climbing).
  • Min/Max span all observations, including out-of-range (underflow/overflow) and zero/negative values, mirroring the exact sum. Max may exceed hi and Min may be below lo — by design; that's precisely what bucket interpolation can't recover.
  • ExactSnapshot.ValueAtQuantile returns the exact min at q<=0 and max at q>=1 (possibly outside [lo, hi]); interior quantiles delegate to the base trapezoidal estimate. Merge composes via min-of-mins / max-of-maxes.

Empty vs. single-zero is disambiguated by the minVal <= maxVal sentinel invariant (MaxInt64/MinInt64 before any record), which are also identities for min/max so merges stay clean.

Scope / out of scope

  • Histogram, Windowed, and the Prometheus export are unchanged. Windowed histograms keep their existing bucket-derived extremes (exact windowed extremes would need a per-interval min/max ring, since the windowed view is derived by subtraction and a max isn't subtractable — a possible follow-up).

Tests

exact_minmax_test.go covers: exact summary incl. out-of-range/negative/zero values, empty and single-zero edge cases, quantile endpoints (exact min/max even outside range) for both single and batch paths, Merge (incl. empty operands), Reset, concurrent correctness (race-clean), and that the embedded base behavior (sum/count, Mean, Prometheus export) is intact.

angles-n-daemons and others added 2 commits August 25, 2026 17:02
Bucket-based quantile estimation cannot recover the true smallest and
largest observed values: q=1.0 clamps to the top occupied bucket's edge
and out-of-range observations lose their magnitude entirely. Callers who
need exact extremes (e.g. a truthful "max latency") had no way to get them.

WithExactMinMax wraps a Histogram and additionally tracks exact min/max,
completing an exact {count, sum, min, max} summary (the base already tracks
sum and count exactly, matching Prometheus). It is additive and opt-in:

  - Embeds *Histogram, so every existing method still works and the base
    recording path is untouched for callers who don't need extremes.
  - Record updates min/max via load-then-CAS, which degrades to two relaxed
    loads once the extremes stabilize — cheap under contention.
  - Min/Max span all observations, including out-of-range and zero/negative
    values, mirroring the exact sum. Max may exceed hi and Min may be below
    lo by design.
  - ExactSnapshot.ValueAtQuantile returns the exact min at q<=0 and max at
    q>=1 (which may fall outside [lo, hi]); interior quantiles delegate to
    the base trapezoidal estimate. Merge composes via min-of-mins /
    max-of-maxes.

The base Histogram, Windowed, and the Prometheus export are unchanged;
windowed histograms keep their existing bucket-derived extremes.

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
Comment thread exact_minmax.go Outdated
// (Underflow/Overflow) and zero/negative values, so Max may exceed hi and Min
// may be below lo.
type WithExactMinMax struct {
*Histogram

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be a non-pointer, so we don't force two allocations?

Also, does it have to be embedded? It would be better to export only the methods that make sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely, will change it too to only expose the appropriate subset of methods.

Comment thread exact_minmax.go Outdated
// ExactSnapshot is a Snapshot with exact extremes. Min and Max are meaningful
// only when TotalCount > 0.
type ExactSnapshot struct {
Snapshot

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not embed this. For example, we get a "sketchy" Sub() Snapshot method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, removing this

@angles-n-daemons
angles-n-daemons merged commit 9ae8112 into main Sep 9, 2026
3 checks passed
@angles-n-daemons
angles-n-daemons deleted the bdillmann/exact-summary branch September 9, 2026 21:17
@angles-n-daemons
angles-n-daemons restored the bdillmann/exact-summary branch September 9, 2026 21:17
@angles-n-daemons
angles-n-daemons deleted the bdillmann/exact-summary branch September 9, 2026 21:17
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.

2 participants