goodhistogram: add windowed histogram with Prometheus integration#4
Conversation
| } | ||
|
|
||
| // tick performs the actual baseline rotation. Must be called with w.mu held. | ||
| func (w *Windowed) tick() { |
There was a problem hiding this comment.
nit: Can we call this tickLocked just to make it clear that it is expected that a lock was already acquired?
There was a problem hiding this comment.
sure, doing this now
| w.prevBaseline = empty | ||
| w.curBaseline = empty | ||
| w.nextTick = time.Now().Add(w.interval) | ||
| w.mu.Unlock() |
There was a problem hiding this comment.
any reason why we dont defer this after taking the lock?
There was a problem hiding this comment.
no reason, changing this now
| labelNames []string | ||
|
|
||
| mu sync.RWMutex | ||
| histograms map[string]*labeledWindowed |
There was a problem hiding this comment.
nit: If a lock needs to be acquired to access it, i like to put it in an embeded struct, something like:
mu struct {
sync.RWMutex
histograms map[string]*labeledWindowed
}
that way, the histograms is accessed like w.mu.histograms, which makes it a little more clear that a lock needs to be acquired. Not gonna block on it, but just food for thought if you wanna make the change.
There was a problem hiding this comment.
yeah, i'll do that now
5748700 to
495e8da
Compare
8967ea7 to
4056c53
Compare
495e8da to
0b75663
Compare
4056c53 to
eb18b9c
Compare
0b75663 to
824c291
Compare
eb18b9c to
5732bff
Compare
824c291 to
765e86b
Compare
5732bff to
b3ed9f0
Compare
| type Windowed struct { | ||
| h *Histogram // cumulative — the only histogram, never swapped or reset | ||
|
|
||
| mu sync.Mutex |
There was a problem hiding this comment.
Sorry i missed this with the last review: can you do the same thing here that you did with windowedVec where the things that require locks are in the mutex struct?
There was a problem hiding this comment.
Good point, doing this now.
| cur := w.h.Snapshot() | ||
| w.mu.Lock() | ||
| base := w.prevBaseline |
There was a problem hiding this comment.
One thing claude pointed out:
Subtle race in WindowedSnapshot (worth fixing)
w.maybeTick()
cur := w.h.Snapshot() // T1
w.mu.Lock()
base := w.prevBaseline // T2
w.mu.Unlock()
return cur.Sub(&base)
If another goroutine calls Tick() while h.Snapshot() is running at T1, the new curBaseline may capture per-bucket counts that are higher than the corresponding counts in our
partially-snapshotted cur (snapshots are not atomic across buckets). If a second Tick() then runs before we read prevBaseline at T2, that newer snapshot becomes our base, and
cur.Sub(&base) underflows uint64 per-bucket counts and TotalCount. With frequent Tick()s this is reachable, and the test TestWindowedConcurrentRecordAndTick doesn't exercise
WindowedSnapshot (it does check it, but only via the cumulative side, not the diff side).
There was a problem hiding this comment.
Ah nice, yeah that seems to make sense. We'll change that now
Cumulative histograms are the right primitive for Prometheus scraping, but operators and dashboards need rolling-window quantiles to see recent behavior. Windowed maintains a single cumulative histogram with two baseline snapshots rotated on a configurable interval. The windowed view is computed by subtracting the older baseline from the current cumulative state, covering 1-2x the window duration. Recording cost is identical to a plain Histogram (~20ns, lock-free); the mutex only protects baseline rotation. WindowedCollector and WindowedVec provide Prometheus integration for single and labeled windowed histograms, following the same adapter pattern as PrometheusCollector and HistogramVec. Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
b3ed9f0 to
7e72115
Compare
796027d
into
bdillmann/prometheus-collector
Summary
Stacks on #2.
Cumulative histograms are the right primitive for Prometheus scraping, but operators and dashboards need rolling-window quantiles to see recent behavior.
Windowedmaintains a single cumulative histogram with two baseline snapshots rotated on a configurable interval. The windowed view is computed by subtracting the older baseline from the current cumulative state, covering 1-2x the window duration. Recording cost is identical to a plainHistogram(~20ns, lock-free); the mutex only protects baseline rotation.WindowedCollectorandWindowedVecprovide Prometheus integration for single and labeled windowed histograms, following the same adapter pattern asPrometheusCollectorandHistogramVec.