github.com/luckypickle/go-ethereum-vet@v1.14.2/metrics/meter.go (about)

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