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