github.com/calmw/ethereum@v0.1.1/metrics/meter.go (about) 1 package metrics 2 3 import ( 4 "sync" 5 "sync/atomic" 6 "time" 7 ) 8 9 // Meters count events to produce exponentially-weighted moving average rates 10 // at one-, five-, and fifteen-minutes and a mean rate. 11 type Meter interface { 12 Count() int64 13 Mark(int64) 14 Rate1() float64 15 Rate5() float64 16 Rate15() float64 17 RateMean() float64 18 Snapshot() Meter 19 Stop() 20 } 21 22 // GetOrRegisterMeter returns an existing Meter or constructs and registers a 23 // new StandardMeter. 24 // Be sure to unregister the meter from the registry once it is of no use to 25 // allow for garbage collection. 26 func GetOrRegisterMeter(name string, r Registry) Meter { 27 if nil == r { 28 r = DefaultRegistry 29 } 30 return r.GetOrRegister(name, NewMeter).(Meter) 31 } 32 33 // GetOrRegisterMeterForced returns an existing Meter or constructs and registers a 34 // new StandardMeter no matter the global switch is enabled or not. 35 // Be sure to unregister the meter from the registry once it is of no use to 36 // allow for garbage collection. 37 func GetOrRegisterMeterForced(name string, r Registry) Meter { 38 if nil == r { 39 r = DefaultRegistry 40 } 41 return r.GetOrRegister(name, NewMeterForced).(Meter) 42 } 43 44 // NewMeter constructs a new StandardMeter and launches a goroutine. 45 // Be sure to call Stop() once the meter is of no use to allow for garbage collection. 46 func NewMeter() Meter { 47 if !Enabled { 48 return NilMeter{} 49 } 50 m := newStandardMeter() 51 arbiter.Lock() 52 defer arbiter.Unlock() 53 arbiter.meters[m] = struct{}{} 54 if !arbiter.started { 55 arbiter.started = true 56 go arbiter.tick() 57 } 58 return m 59 } 60 61 // NewMeterForced constructs a new StandardMeter and launches a goroutine no matter 62 // the global switch is enabled or not. 63 // Be sure to call Stop() once the meter is of no use to allow for garbage collection. 64 func NewMeterForced() Meter { 65 m := newStandardMeter() 66 arbiter.Lock() 67 defer arbiter.Unlock() 68 arbiter.meters[m] = struct{}{} 69 if !arbiter.started { 70 arbiter.started = true 71 go arbiter.tick() 72 } 73 return m 74 } 75 76 // NewRegisteredMeter constructs and registers a new StandardMeter 77 // and launches a goroutine. 78 // Be sure to unregister the meter from the registry once it is of no use to 79 // allow for garbage collection. 80 func NewRegisteredMeter(name string, r Registry) Meter { 81 c := NewMeter() 82 if nil == r { 83 r = DefaultRegistry 84 } 85 r.Register(name, c) 86 return c 87 } 88 89 // NewRegisteredMeterForced constructs and registers a new StandardMeter 90 // and launches a goroutine no matter the global switch is enabled or not. 91 // Be sure to unregister the meter from the registry once it is of no use to 92 // allow for garbage collection. 93 func NewRegisteredMeterForced(name string, r Registry) Meter { 94 c := NewMeterForced() 95 if nil == r { 96 r = DefaultRegistry 97 } 98 r.Register(name, c) 99 return c 100 } 101 102 // MeterSnapshot is a read-only copy of another Meter. 103 type MeterSnapshot struct { 104 temp atomic.Int64 105 count int64 106 rate1, rate5, rate15, rateMean float64 107 } 108 109 // Count returns the count of events at the time the snapshot was taken. 110 func (m *MeterSnapshot) Count() int64 { return m.count } 111 112 // Mark panics. 113 func (*MeterSnapshot) Mark(n int64) { 114 panic("Mark called on a MeterSnapshot") 115 } 116 117 // Rate1 returns the one-minute moving average rate of events per second at the 118 // time the snapshot was taken. 119 func (m *MeterSnapshot) Rate1() float64 { return m.rate1 } 120 121 // Rate5 returns the five-minute moving average rate of events per second at 122 // the time the snapshot was taken. 123 func (m *MeterSnapshot) Rate5() float64 { return m.rate5 } 124 125 // Rate15 returns the fifteen-minute moving average rate of events per second 126 // at the time the snapshot was taken. 127 func (m *MeterSnapshot) Rate15() float64 { return m.rate15 } 128 129 // RateMean returns the meter's mean rate of events per second at the time the 130 // snapshot was taken. 131 func (m *MeterSnapshot) RateMean() float64 { return m.rateMean } 132 133 // Snapshot returns the snapshot. 134 func (m *MeterSnapshot) Snapshot() Meter { return m } 135 136 // Stop is a no-op. 137 func (m *MeterSnapshot) Stop() {} 138 139 // NilMeter is a no-op Meter. 140 type NilMeter struct{} 141 142 // Count is a no-op. 143 func (NilMeter) Count() int64 { return 0 } 144 145 // Mark is a no-op. 146 func (NilMeter) Mark(n int64) {} 147 148 // Rate1 is a no-op. 149 func (NilMeter) Rate1() float64 { return 0.0 } 150 151 // Rate5 is a no-op. 152 func (NilMeter) Rate5() float64 { return 0.0 } 153 154 // Rate15 is a no-op. 155 func (NilMeter) Rate15() float64 { return 0.0 } 156 157 // RateMean is a no-op. 158 func (NilMeter) RateMean() float64 { return 0.0 } 159 160 // Snapshot is a no-op. 161 func (NilMeter) Snapshot() Meter { return NilMeter{} } 162 163 // Stop is a no-op. 164 func (NilMeter) Stop() {} 165 166 // StandardMeter is the standard implementation of a Meter. 167 type StandardMeter struct { 168 lock sync.RWMutex 169 snapshot *MeterSnapshot 170 a1, a5, a15 EWMA 171 startTime time.Time 172 stopped atomic.Bool 173 } 174 175 func newStandardMeter() *StandardMeter { 176 return &StandardMeter{ 177 snapshot: &MeterSnapshot{}, 178 a1: NewEWMA1(), 179 a5: NewEWMA5(), 180 a15: NewEWMA15(), 181 startTime: time.Now(), 182 } 183 } 184 185 // Stop stops the meter, Mark() will be a no-op if you use it after being stopped. 186 func (m *StandardMeter) Stop() { 187 stopped := m.stopped.Swap(true) 188 if !stopped { 189 arbiter.Lock() 190 delete(arbiter.meters, m) 191 arbiter.Unlock() 192 } 193 } 194 195 // Count returns the number of events recorded. 196 // It updates the meter to be as accurate as possible 197 func (m *StandardMeter) Count() int64 { 198 m.lock.Lock() 199 defer m.lock.Unlock() 200 m.updateMeter() 201 return m.snapshot.count 202 } 203 204 // Mark records the occurrence of n events. 205 func (m *StandardMeter) Mark(n int64) { 206 m.snapshot.temp.Add(n) 207 } 208 209 // Rate1 returns the one-minute moving average rate of events per second. 210 func (m *StandardMeter) Rate1() float64 { 211 m.lock.RLock() 212 defer m.lock.RUnlock() 213 return m.snapshot.rate1 214 } 215 216 // Rate5 returns the five-minute moving average rate of events per second. 217 func (m *StandardMeter) Rate5() float64 { 218 m.lock.RLock() 219 defer m.lock.RUnlock() 220 return m.snapshot.rate5 221 } 222 223 // Rate15 returns the fifteen-minute moving average rate of events per second. 224 func (m *StandardMeter) Rate15() float64 { 225 m.lock.RLock() 226 defer m.lock.RUnlock() 227 return m.snapshot.rate15 228 } 229 230 // RateMean returns the meter's mean rate of events per second. 231 func (m *StandardMeter) RateMean() float64 { 232 m.lock.RLock() 233 defer m.lock.RUnlock() 234 return m.snapshot.rateMean 235 } 236 237 // Snapshot returns a read-only copy of the meter. 238 func (m *StandardMeter) Snapshot() Meter { 239 m.lock.RLock() 240 snapshot := MeterSnapshot{ 241 count: m.snapshot.count, 242 rate1: m.snapshot.rate1, 243 rate5: m.snapshot.rate5, 244 rate15: m.snapshot.rate15, 245 rateMean: m.snapshot.rateMean, 246 } 247 snapshot.temp.Store(m.snapshot.temp.Load()) 248 m.lock.RUnlock() 249 return &snapshot 250 } 251 252 func (m *StandardMeter) updateSnapshot() { 253 // should run with write lock held on m.lock 254 snapshot := m.snapshot 255 snapshot.rate1 = m.a1.Rate() 256 snapshot.rate5 = m.a5.Rate() 257 snapshot.rate15 = m.a15.Rate() 258 snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds() 259 } 260 261 func (m *StandardMeter) updateMeter() { 262 // should only run with write lock held on m.lock 263 n := m.snapshot.temp.Swap(0) 264 m.snapshot.count += n 265 m.a1.Update(n) 266 m.a5.Update(n) 267 m.a15.Update(n) 268 } 269 270 func (m *StandardMeter) tick() { 271 m.lock.Lock() 272 defer m.lock.Unlock() 273 m.updateMeter() 274 m.a1.Tick() 275 m.a5.Tick() 276 m.a15.Tick() 277 m.updateSnapshot() 278 } 279 280 // meterArbiter ticks meters every 5s from a single goroutine. 281 // meters are references in a set for future stopping. 282 type meterArbiter struct { 283 sync.RWMutex 284 started bool 285 meters map[*StandardMeter]struct{} 286 ticker *time.Ticker 287 } 288 289 var arbiter = meterArbiter{ticker: time.NewTicker(5 * time.Second), meters: make(map[*StandardMeter]struct{})} 290 291 // Ticks meters on the scheduled interval 292 func (ma *meterArbiter) tick() { 293 for range ma.ticker.C { 294 ma.tickMeters() 295 } 296 } 297 298 func (ma *meterArbiter) tickMeters() { 299 ma.RLock() 300 defer ma.RUnlock() 301 for meter := range ma.meters { 302 meter.tick() 303 } 304 }