ewma.go 1018 B

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. package metrics
  2. import (
  3. "math"
  4. "sync/atomic"
  5. )
  6. type EWMA interface {
  7. Rate() float64
  8. Tick()
  9. Update(int64)
  10. }
  11. type ewma struct {
  12. alpha float64
  13. uncounted int64
  14. rate float64
  15. initialized bool
  16. tick chan bool
  17. }
  18. func NewEWMA(alpha float64) EWMA {
  19. a := &ewma{alpha, 0, 0.0, false, make(chan bool)}
  20. go a.ticker()
  21. return a
  22. }
  23. func NewEWMA1() EWMA {
  24. return NewEWMA(1 - math.Exp(-5.0 / 60.0 / 1))
  25. }
  26. func NewEWMA5() EWMA {
  27. return NewEWMA(1 - math.Exp(-5.0 / 60.0 / 5))
  28. }
  29. func NewEWMA15() EWMA {
  30. return NewEWMA(1 - math.Exp(-5.0 / 60.0 / 15))
  31. }
  32. func (a *ewma) Rate() float64 {
  33. return a.rate * float64(1e9)
  34. }
  35. func (a *ewma) Tick() {
  36. a.tick <- true
  37. }
  38. func (a *ewma) Update(n int64) {
  39. atomic.AddInt64(&a.uncounted, n)
  40. }
  41. func (a *ewma) ticker() {
  42. for <-a.tick {
  43. count := a.uncounted
  44. atomic.AddInt64(&a.uncounted, -count)
  45. instantRate := float64(count) / float64(5e9)
  46. if a.initialized {
  47. a.rate += a.alpha * (instantRate - a.rate)
  48. } else {
  49. a.initialized = true
  50. a.rate = instantRate
  51. }
  52. }
  53. }