Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 9073533

Browse files
author
Ralph Caraveo
committed
Remove locks from the hot-path in meter.go and add parallel benchmark
1 parent b08b742 commit 9073533

File tree

2 files changed

+41
-38
lines changed

2 files changed

+41
-38
lines changed

meter.go

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package metrics
22

33
import (
4+
"math"
45
"sync"
6+
"sync/atomic"
57
"time"
68
)
79

@@ -62,7 +64,7 @@ func NewRegisteredMeter(name string, r Registry) Meter {
6264
// MeterSnapshot is a read-only copy of another Meter.
6365
type MeterSnapshot struct {
6466
count int64
65-
rate1, rate5, rate15, rateMean float64
67+
rate1, rate5, rate15, rateMean uint64
6668
}
6769

6870
// Count returns the count of events at the time the snapshot was taken.
@@ -75,19 +77,19 @@ func (*MeterSnapshot) Mark(n int64) {
7577

7678
// Rate1 returns the one-minute moving average rate of events per second at the
7779
// time the snapshot was taken.
78-
func (m *MeterSnapshot) Rate1() float64 { return m.rate1 }
80+
func (m *MeterSnapshot) Rate1() float64 { return math.Float64frombits(m.rate1) }
7981

8082
// Rate5 returns the five-minute moving average rate of events per second at
8183
// the time the snapshot was taken.
82-
func (m *MeterSnapshot) Rate5() float64 { return m.rate5 }
84+
func (m *MeterSnapshot) Rate5() float64 { return math.Float64frombits(m.rate5) }
8385

8486
// Rate15 returns the fifteen-minute moving average rate of events per second
8587
// at the time the snapshot was taken.
86-
func (m *MeterSnapshot) Rate15() float64 { return m.rate15 }
88+
func (m *MeterSnapshot) Rate15() float64 { return math.Float64frombits(m.rate15) }
8789

8890
// RateMean returns the meter's mean rate of events per second at the time the
8991
// snapshot was taken.
90-
func (m *MeterSnapshot) RateMean() float64 { return m.rateMean }
92+
func (m *MeterSnapshot) RateMean() float64 { return math.Float64frombits(m.rateMean) }
9193

9294
// Snapshot returns the snapshot.
9395
func (m *MeterSnapshot) Snapshot() Meter { return m }
@@ -124,7 +126,8 @@ func (NilMeter) Stop() {}
124126

125127
// StandardMeter is the standard implementation of a Meter.
126128
type StandardMeter struct {
127-
lock sync.RWMutex
129+
// Only used on stop.
130+
lock sync.Mutex
128131
snapshot *MeterSnapshot
129132
a1, a5, a15 EWMA
130133
startTime time.Time
@@ -156,10 +159,7 @@ func (m *StandardMeter) Stop() {
156159

157160
// Count returns the number of events recorded.
158161
func (m *StandardMeter) Count() int64 {
159-
m.lock.RLock()
160-
count := m.snapshot.count
161-
m.lock.RUnlock()
162-
return count
162+
return atomic.LoadInt64(&m.snapshot.count)
163163
}
164164

165165
// Mark records the occurance of n events.
@@ -178,56 +178,49 @@ func (m *StandardMeter) Mark(n int64) {
178178

179179
// Rate1 returns the one-minute moving average rate of events per second.
180180
func (m *StandardMeter) Rate1() float64 {
181-
m.lock.RLock()
182-
rate1 := m.snapshot.rate1
183-
m.lock.RUnlock()
184-
return rate1
181+
return math.Float64frombits(atomic.LoadUint64(&m.snapshot.rate1))
185182
}
186183

187184
// Rate5 returns the five-minute moving average rate of events per second.
188185
func (m *StandardMeter) Rate5() float64 {
189-
m.lock.RLock()
190-
rate5 := m.snapshot.rate5
191-
m.lock.RUnlock()
192-
return rate5
186+
return math.Float64frombits(atomic.LoadUint64(&m.snapshot.rate5))
193187
}
194188

195189
// Rate15 returns the fifteen-minute moving average rate of events per second.
196190
func (m *StandardMeter) Rate15() float64 {
197-
m.lock.RLock()
198-
rate15 := m.snapshot.rate15
199-
m.lock.RUnlock()
200-
return rate15
191+
return math.Float64frombits(atomic.LoadUint64(&m.snapshot.rate15))
201192
}
202193

203194
// RateMean returns the meter's mean rate of events per second.
204195
func (m *StandardMeter) RateMean() float64 {
205-
m.lock.RLock()
206-
rateMean := m.snapshot.rateMean
207-
m.lock.RUnlock()
208-
return rateMean
196+
return math.Float64frombits(atomic.LoadUint64(&m.snapshot.rateMean))
209197
}
210198

211199
// Snapshot returns a read-only copy of the meter.
212200
func (m *StandardMeter) Snapshot() Meter {
213-
m.lock.RLock()
214-
snapshot := *m.snapshot
215-
m.lock.RUnlock()
216-
return &snapshot
201+
copiedSnapshot := MeterSnapshot{
202+
count: atomic.LoadInt64(&m.snapshot.count),
203+
rate1: atomic.LoadUint64(&m.snapshot.rate1),
204+
rate5: atomic.LoadUint64(&m.snapshot.rate5),
205+
rate15: atomic.LoadUint64(&m.snapshot.rate15),
206+
rateMean: atomic.LoadUint64(&m.snapshot.rateMean),
207+
}
208+
return &copiedSnapshot
217209
}
218210

219211
func (m *StandardMeter) updateSnapshot() {
220-
// should run with write lock held on m.lock
221-
snapshot := m.snapshot
222-
snapshot.rate1 = m.a1.Rate()
223-
snapshot.rate5 = m.a5.Rate()
224-
snapshot.rate15 = m.a15.Rate()
225-
snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds()
212+
rate1 := math.Float64bits(m.a1.Rate())
213+
rate5 := math.Float64bits(m.a5.Rate())
214+
rate15 := math.Float64bits(m.a15.Rate())
215+
rateMean := math.Float64bits(float64(m.Count()) / time.Since(m.startTime).Seconds())
216+
217+
atomic.StoreUint64(&m.snapshot.rate1, rate1)
218+
atomic.StoreUint64(&m.snapshot.rate5, rate5)
219+
atomic.StoreUint64(&m.snapshot.rate15, rate15)
220+
atomic.StoreUint64(&m.snapshot.rateMean, rateMean)
226221
}
227222

228223
func (m *StandardMeter) tick() {
229-
m.lock.Lock()
230-
defer m.lock.Unlock()
231224
m.a1.Tick()
232225
m.a5.Tick()
233226
m.a15.Tick()

meter_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ func BenchmarkMeter(b *testing.B) {
1313
}
1414
}
1515

16+
func BenchmarkMeterParallel(b *testing.B) {
17+
m := NewMeter()
18+
b.ResetTimer()
19+
b.RunParallel(func(pb *testing.PB) {
20+
for pb.Next() {
21+
m.Mark(1)
22+
}
23+
})
24+
}
25+
1626
func TestGetOrRegisterMeter(t *testing.T) {
1727
r := NewRegistry()
1828
NewRegisteredMeter("foo", r).Mark(47)

0 commit comments

Comments
 (0)