Skip to content

Commit fd8961b

Browse files
committed
atomically increment exp histograms
1 parent 7ca3ccc commit fd8961b

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

sdk/metric/internal/aggregate/exponential_histogram.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,9 @@ func (p *expoHistogramDataPoint[N]) record(v N) {
9898
// If the new bin would make the counts larger than maxScale, we need to
9999
// downscale current measurements.
100100
scaleDelta := p.scaleChange(bin, bucket.startBin, len(bucket.counts))
101-
if scaleDelta <= 0 {
102-
bucket.record(bin)
101+
if scaleDelta <= 0 && !bucket.needsResize(bin) {
102+
// Fast path without requiring the full lock
103+
bucket.recordWithoutResize(bin)
103104
p.scaleMux.RUnlock()
104105
return
105106
}
@@ -110,18 +111,19 @@ func (p *expoHistogramDataPoint[N]) record(v N) {
110111
p.scaleMux.RUnlock()
111112
return
112113
}
113-
// Switch to a full Lock for downscaling
114+
// Switch to a full Lock for downscaling or resizing
114115
p.scaleMux.RUnlock()
115116
p.scaleMux.Lock()
116117
defer p.scaleMux.Unlock()
117-
// recompute the scaleDelta now that we hold the exclusive lock
118+
// recompute the scaleDelta now that we hold the full lock
118119
scaleDelta = p.scaleChange(bin, bucket.startBin, len(bucket.counts))
119120
// Downscale
120-
p.scale -= scaleDelta
121-
p.posBuckets.downscale(scaleDelta)
122-
p.negBuckets.downscale(scaleDelta)
121+
if scaleDelta > 0 {
122+
p.scale -= scaleDelta
123+
p.posBuckets.downscale(scaleDelta)
124+
p.negBuckets.downscale(scaleDelta)
125+
}
123126

124-
// TODO: is it worth switching back to a read-lock?
125127
bucket.record(p.getBin(absV))
126128
}
127129

@@ -202,6 +204,15 @@ type expoBuckets struct {
202204
counts []uint64
203205
}
204206

207+
func (b *expoBuckets) needsResize(bin int32) bool {
208+
endBin := int(b.startBin) + len(b.counts) - 1
209+
return len(b.counts) == 0 || bin < b.startBin || int(bin) > endBin
210+
}
211+
212+
func (b *expoBuckets) recordWithoutResize(bin int32) {
213+
atomic.AddUint64(&b.counts[bin-b.startBin], 1)
214+
}
215+
205216
// record increments the count for the given bin, and expands the buckets if needed.
206217
// Size changes must be done before calling this function.
207218
func (b *expoBuckets) record(bin int32) {
@@ -215,6 +226,7 @@ func (b *expoBuckets) record(bin int32) {
215226

216227
// if the new bin is inside the current range
217228
if bin >= b.startBin && int(bin) <= endBin {
229+
// No need to use atomics since we hold the RW lock.
218230
b.counts[bin-b.startBin]++
219231
return
220232
}

0 commit comments

Comments
 (0)