histogram.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package metrics
  2. import (
  3. "math"
  4. "sort"
  5. )
  6. type Histogram interface {
  7. Clear()
  8. Count() int64
  9. Max() int64
  10. Mean() float64
  11. Min() int64
  12. Percentile(float64) float64
  13. Percentiles([]float64) []float64
  14. StdDev() float64
  15. Update(int64)
  16. Variance() float64
  17. }
  18. type histogram struct {
  19. s Sample
  20. in chan int64
  21. out chan histogramV
  22. reset chan bool
  23. }
  24. type histogramV struct {
  25. count, sum, min, max int64
  26. variance [2]float64
  27. }
  28. func NewHistogram(s Sample) Histogram {
  29. h := &histogram{
  30. s,
  31. make(chan int64),
  32. make(chan histogramV),
  33. make(chan bool),
  34. }
  35. go h.arbiter()
  36. return h
  37. }
  38. func newHistogramV() histogramV {
  39. return histogramV{
  40. 0, 0, math.MaxInt64, math.MinInt64,
  41. [2]float64{-1.0, 0.0},
  42. }
  43. }
  44. func (h *histogram) Clear() {
  45. h.reset <- true
  46. }
  47. func (h *histogram) Count() int64 {
  48. return (<-h.out).count
  49. }
  50. func (h *histogram) Max() int64 {
  51. hv := <-h.out
  52. if 0 < hv.count { return hv.max }
  53. return 0
  54. }
  55. func (h *histogram) Mean() float64 {
  56. hv := <-h.out
  57. if 0 < hv.count {
  58. return float64(hv.sum) / float64(hv.count)
  59. }
  60. return 0
  61. }
  62. func (h *histogram) Min() int64 {
  63. hv := <-h.out
  64. if 0 < hv.count { return hv.min }
  65. return 0
  66. }
  67. func (h *histogram) Percentile(p float64) float64 {
  68. return h.Percentiles([]float64{p})[0]
  69. }
  70. func (h *histogram) Percentiles(ps []float64) []float64 {
  71. scores := make([]float64, len(ps))
  72. values := Int64Slice(h.s.Values())
  73. size := len(values)
  74. if size > 0 {
  75. sort.Sort(values)
  76. for i, p := range ps {
  77. pos := p * float64(size + 1)
  78. if pos < 1.0 {
  79. scores[i] = float64(values[0])
  80. } else if pos >= float64(size) {
  81. scores[i] = float64(values[size - 1])
  82. } else {
  83. lower := float64(values[int(pos) - 1])
  84. upper := float64(values[int(pos)])
  85. scores[i] = lower + (pos - math.Floor(pos)) * (upper - lower)
  86. }
  87. }
  88. }
  89. return scores
  90. }
  91. func (h *histogram) StdDev() float64 {
  92. return math.Sqrt(h.Variance())
  93. }
  94. func (h *histogram) Update(v int64) {
  95. h.in <- v
  96. }
  97. func (h *histogram) Variance() float64 {
  98. hv := <-h.out
  99. if 1 >= hv.count { return 0.0 }
  100. return hv.variance[1] / float64(hv.count - 1)
  101. }
  102. func (h *histogram) arbiter() {
  103. hv := newHistogramV()
  104. for {
  105. select {
  106. case v := <-h.in:
  107. h.s.Update(v)
  108. hv.count++
  109. if v < hv.min { hv.min = v }
  110. if v > hv.max { hv.max = v }
  111. hv.sum += v
  112. fv := float64(v)
  113. if -1.0 == hv.variance[0] {
  114. hv.variance[0] = fv
  115. hv.variance[1] = 0.0
  116. } else {
  117. m := hv.variance[0]
  118. s := hv.variance[1]
  119. hv.variance[0] = m + (fv - m) / float64(hv.count)
  120. hv.variance[1] = s + (fv - m) * (fv - hv.variance[0])
  121. }
  122. case h.out <- hv:
  123. case <- h.reset:
  124. h.s.Clear()
  125. hv = newHistogramV()
  126. }
  127. }
  128. }
  129. // Cribbed from the standard library's `sort` package.
  130. type Int64Slice []int64
  131. func (p Int64Slice) Len() int { return len(p) }
  132. func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] }
  133. func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }