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  }