histogram.go 2.9 KB

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