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  }