histogram.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. if size > 0 {
  76. sort.Sort(values)
  77. for i, p := range ps {
  78. pos := p * float64(size + 1)
  79. if pos < 1.0 {
  80. scores[i] = float64(values[0])
  81. } else if pos >= float64(size) {
  82. scores[i] = float64(values[size - 1])
  83. } else {
  84. lower := float64(values[int(pos) - 1])
  85. upper := float64(values[int(pos)])
  86. scores[i] = lower + (pos - math.Floor(pos)) * (upper - lower)
  87. }
  88. }
  89. }
  90. return scores
  91. }
  92. func (h *histogram) StdDev() float64 {
  93. return math.Sqrt(h.Variance())
  94. }
  95. func (h *histogram) Sum() int64 {
  96. return (<-h.out).sum
  97. }
  98. func (h *histogram) Update(v int64) {
  99. h.in <- v
  100. }
  101. func (h *histogram) Variance() float64 {
  102. hv := <-h.out
  103. if 1 >= hv.count { return 0.0 }
  104. return hv.variance[1] / float64(hv.count - 1)
  105. }
  106. func (h *histogram) arbiter() {
  107. hv := newHistogramV()
  108. for {
  109. select {
  110. case v := <-h.in:
  111. h.s.Update(v)
  112. hv.count++
  113. if v < hv.min { hv.min = v }
  114. if v > hv.max { hv.max = v }
  115. hv.sum += v
  116. fv := float64(v)
  117. if -1.0 == hv.variance[0] {
  118. hv.variance[0] = fv
  119. hv.variance[1] = 0.0
  120. } else {
  121. m := hv.variance[0]
  122. s := hv.variance[1]
  123. hv.variance[0] = m + (fv - m) / float64(hv.count)
  124. hv.variance[1] = s + (fv - m) * (fv - hv.variance[0])
  125. }
  126. case h.out <- hv:
  127. case <- h.reset:
  128. h.s.Clear()
  129. hv = newHistogramV()
  130. }
  131. }
  132. }
  133. // Cribbed from the standard library's `sort` package.
  134. type Int64Slice []int64
  135. func (p Int64Slice) Len() int { return len(p) }
  136. func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] }
  137. func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }