Skip to content

goodhistogram: base error bound on true worst-case bucket error - #11

Merged
angles-n-daemons merged 3 commits into
mainfrom
bdillmann/error-bound-schema
Aug 18, 2026
Merged

goodhistogram: base error bound on true worst-case bucket error#11
angles-n-daemons merged 3 commits into
mainfrom
bdillmann/error-bound-schema

Conversation

@angles-n-daemons

Copy link
Copy Markdown
Contributor

Problem

goodhistogram's error bounding is inspired by DDSketch: the user specifies a relative error bound, and the coarsest Prometheus schema whose error fits is chosen. But the error formula it used, (γ-1)/(γ+1), is DDSketch's midpoint error — it only holds when a bucket is always reported by its midpoint, which is exactly what DDSketch does.

goodhistogram diverges here: it approximates quantiles using the shape of the observed distribution (trapezoidal interpolation), so a reported quantile can land anywhere in a bucket [b, γ·b], edges included. The true worst case is a value whose real location is the bucket start b reported at the end γ·b — a relative error of γ-1, roughly twice the midpoint figure.

So a histogram configured for, say, 10% error selected schema 2 (midpoint error 8.6%) while its reported quantiles could drift up to γ-1 = 18.9%, silently violating the configured bound. This is what users hit in #9, whose log shows pMax errors of +17.5% and +15.9% under a 10% ErrorBound — right at the schema-2 γ-1 ceiling.

Fix

As requested, this fixes the bound, not the quantile calculation. schemaRelativeError now returns γ-1 — the error the estimator can actually produce — so schema selection honors the bound quantiles really deliver. A given ErrorBound now picks a finer schema than before (10% → schema 3, not schema 2), trading a modest amount of memory for a guarantee that holds.

New resolution presets

Three full-range presets ([1, math.MaxInt64]) differentiated only by accuracy and memory:

Preset Schema Worst-case error Buckets Memory / histogram
CoarseParams 1 ~41.4% 126 ~1 KB
StandardParams 2 ~18.9% 252 ~2 KB
FineParams 3 ~9.05% 504 ~4 KB

Memory is the per-histogram counts array; the boundary/lookup tables live in a single shared, cached config, so allocating many histograms from one preset doesn't multiply that overhead.

Notes

  • README gains an Error bounds section explaining the γ-1 vs (γ-1)/(γ+1) distinction and a Resolution presets table.
  • Tests updated for the new schema selection (TestPickSchema, TestNewConfig, TestWindowedSchema) plus a new TestResolutionPresets locking in schema, bucket count, and bound for each preset.
  • Benchmarks are pinned to schema 2 via schemaRelativeError(benchSchema) so they stay comparable regardless of the bound arithmetic.

Related: #9

angles-n-daemons and others added 2 commits August 17, 2026 10:36
The relative error bound was selected using DDSketch's midpoint error,
(γ-1)/(γ+1). That figure only holds when a bucket is always reported by
its midpoint, which is what DDSketch does. goodhistogram instead uses
trapezoidal interpolation over the observed distribution, so a reported
quantile can land anywhere in a bucket [b, γ·b] — including the edges.
The true worst case is a value whose real location is the bucket start b
reported at the end γ·b, a relative error of γ-1, roughly twice the
midpoint figure.

The consequence was that a histogram configured for a given error bound
could report quantiles that visibly exceeded it: a 10% bound selected
schema 2 (midpoint error 8.6%) whose reported quantiles could drift up to
γ-1 = 18.9%, as seen in #9's pMax errors of +17.5%/+15.9%.

Change schemaRelativeError to return γ-1 so schema selection honors the
bound quantiles actually deliver. A given ErrorBound now selects a finer
schema than before (10% picks schema 3, not schema 2), trading a modest
amount of memory for a guarantee that holds.

Add three full-range resolution presets differentiated only by accuracy
and memory:

  - CoarseParams   schema 1  ~41.4% error  126 buckets  ~1 KB/histogram
  - StandardParams schema 2  ~18.9% error  252 buckets  ~2 KB/histogram
  - FineParams     schema 3  ~9.05% error  504 buckets  ~4 KB/histogram

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>

@alyshanjahani-crl alyshanjahani-crl left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM, the only review agent finding i think is worth calling out is:

withDefaults() (histogram.go:275) maps a zero ErrorBound to 0.10, and none of the existing latency/size presets set ErrorBound (HiResLatencyParams, IOLatencyParams, ResponseTimeParams, LongRunningParams, DataSizeParams, MemoryUsageParams). So this PR silently moves all of them — and every caller relying on the default — from schema 2 to schema 3, doubling their per-histogram memory.

But IIUC that is something you'd probably do in a PR in cockroach repo whenever you update the goodhistogram version?

@angles-n-daemons

Copy link
Copy Markdown
Contributor Author

yep, that's the plan!

@angles-n-daemons
angles-n-daemons merged commit 9e8b7af into main Aug 18, 2026
3 checks passed
@angles-n-daemons
angles-n-daemons deleted the bdillmann/error-bound-schema branch August 18, 2026 19:49
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