ewma.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package metrics
  2. import (
  3. "math"
  4. "sync"
  5. "sync/atomic"
  6. )
  7. // EWMAs continuously calculate an exponentially-weighted moving average
  8. // based on an outside source of clock ticks.
  9. type EWMA interface {
  10. Rate() float64
  11. Snapshot() EWMA
  12. Tick()
  13. Update(int64)
  14. }
  15. // NewEWMA constructs a new EWMA with the given alpha.
  16. func NewEWMA(alpha float64) EWMA {
  17. if UseNilMetrics {
  18. return NilEWMA{}
  19. }
  20. return &StandardEWMA{alpha: alpha}
  21. }
  22. // NewEWMA1 constructs a new EWMA for a one-minute moving average.
  23. func NewEWMA1() EWMA {
  24. return NewEWMA(1 - math.Exp(-5.0/60.0/1))
  25. }
  26. // NewEWMA5 constructs a new EWMA for a five-minute moving average.
  27. func NewEWMA5() EWMA {
  28. return NewEWMA(1 - math.Exp(-5.0/60.0/5))
  29. }
  30. // NewEWMA15 constructs a new EWMA for a fifteen-minute moving average.
  31. func NewEWMA15() EWMA {
  32. return NewEWMA(1 - math.Exp(-5.0/60.0/15))
  33. }
  34. // No-op EWMA.
  35. type NilEWMA struct{}
  36. // Rate is a no-op.
  37. func (NilEWMA) Rate() float64 { return 0.0 }
  38. // No-op.
  39. func (NilEWMA) Tick() {}
  40. // Update is a no-op.
  41. func (NilEWMA) Update(n int64) {}
  42. // StandardEWMA is the standard implementation of an EWMA and tracks the number
  43. // of uncounted events and processes them on each tick. It uses the
  44. // sync/atomic package to manage uncounted events.
  45. type StandardEWMA struct {
  46. alpha float64
  47. init bool
  48. mutex sync.Mutex
  49. rate float64
  50. uncounted int64
  51. }
  52. // Rate returns the moving average rate of events per second.
  53. func (a *StandardEWMA) Rate() float64 {
  54. a.mutex.Lock()
  55. defer a.mutex.Unlock()
  56. return a.rate * float64(1e9)
  57. }
  58. // Tick the clock to update the moving average.
  59. func (a *StandardEWMA) Tick() {
  60. count := atomic.LoadInt64(&a.uncounted)
  61. atomic.AddInt64(&a.uncounted, -count)
  62. instantRate := float64(count) / float64(5e9)
  63. a.mutex.Lock()
  64. defer a.mutex.Unlock()
  65. if a.init {
  66. a.rate += a.alpha * (instantRate - a.rate)
  67. } else {
  68. a.init = true
  69. a.rate = instantRate
  70. }
  71. }
  72. // Update adds n uncounted events.
  73. func (a *StandardEWMA) Update(n int64) {
  74. atomic.AddInt64(&a.uncounted, n)
  75. }