ewma.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package metrics
  2. import (
  3. "math"
  4. )
  5. type EWMA interface {
  6. Clear()
  7. Rate() float64
  8. Tick()
  9. Update(int64)
  10. }
  11. type ewma struct {
  12. alpha float64
  13. in chan int64
  14. out chan float64
  15. reset, tick chan bool
  16. }
  17. func NewEWMA(alpha float64) EWMA {
  18. a := &ewma{
  19. alpha,
  20. make(chan int64),
  21. make(chan float64),
  22. make(chan bool), make(chan bool),
  23. }
  24. go a.arbiter()
  25. return a
  26. }
  27. func NewEWMA1() EWMA {
  28. return NewEWMA(1 - math.Exp(-5.0 / 60.0 / 1))
  29. }
  30. func NewEWMA5() EWMA {
  31. return NewEWMA(1 - math.Exp(-5.0 / 60.0 / 5))
  32. }
  33. func NewEWMA15() EWMA {
  34. return NewEWMA(1 - math.Exp(-5.0 / 60.0 / 15))
  35. }
  36. func (a *ewma) Clear() {
  37. a.reset <- true
  38. }
  39. func (a *ewma) Rate() float64 {
  40. return <-a.out * float64(1e9)
  41. }
  42. func (a *ewma) Tick() {
  43. a.tick <- true
  44. }
  45. func (a *ewma) Update(n int64) {
  46. a.in <- n
  47. }
  48. func (a *ewma) arbiter() {
  49. var uncounted int64
  50. var rate float64
  51. var initialized bool
  52. for {
  53. select {
  54. case n := <-a.in: uncounted += n
  55. case a.out <- rate:
  56. case <-a.reset:
  57. uncounted = 0
  58. rate = 0.0
  59. case <-a.tick:
  60. instantRate := float64(uncounted) / float64(5e9)
  61. if initialized {
  62. rate += a.alpha * (instantRate - rate)
  63. } else {
  64. initialized = true
  65. rate = instantRate
  66. }
  67. uncounted = 0
  68. }
  69. }
  70. }