resetting_timer.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package metrics
  2. import (
  3. "math"
  4. "sort"
  5. "sync"
  6. "time"
  7. )
  8. // Initial slice capacity for the values stored in a ResettingTimer
  9. const InitialResettingTimerSliceCap = 10
  10. // ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
  11. type ResettingTimer interface {
  12. Values() []int64
  13. Snapshot() ResettingTimer
  14. Percentiles([]float64) []int64
  15. Mean() float64
  16. Time(func())
  17. Update(time.Duration)
  18. UpdateSince(time.Time)
  19. }
  20. // GetOrRegisterResettingTimer returns an existing ResettingTimer or constructs and registers a
  21. // new StandardResettingTimer.
  22. func GetOrRegisterResettingTimer(name string, r Registry) ResettingTimer {
  23. if nil == r {
  24. r = DefaultRegistry
  25. }
  26. return r.GetOrRegister(name, NewResettingTimer).(ResettingTimer)
  27. }
  28. // NewRegisteredResettingTimer constructs and registers a new StandardResettingTimer.
  29. func NewRegisteredResettingTimer(name string, r Registry) ResettingTimer {
  30. c := NewResettingTimer()
  31. if nil == r {
  32. r = DefaultRegistry
  33. }
  34. r.Register(name, c)
  35. return c
  36. }
  37. // NewResettingTimer constructs a new StandardResettingTimer
  38. func NewResettingTimer() ResettingTimer {
  39. if !Enabled {
  40. return NilResettingTimer{}
  41. }
  42. return &StandardResettingTimer{
  43. values: make([]int64, 0, InitialResettingTimerSliceCap),
  44. }
  45. }
  46. // NilResettingTimer is a no-op ResettingTimer.
  47. type NilResettingTimer struct {
  48. }
  49. // Values is a no-op.
  50. func (NilResettingTimer) Values() []int64 { return nil }
  51. // Snapshot is a no-op.
  52. func (NilResettingTimer) Snapshot() ResettingTimer { return NilResettingTimer{} }
  53. // Time is a no-op.
  54. func (NilResettingTimer) Time(func()) {}
  55. // Update is a no-op.
  56. func (NilResettingTimer) Update(time.Duration) {}
  57. // Percentiles panics.
  58. func (NilResettingTimer) Percentiles([]float64) []int64 {
  59. panic("Percentiles called on a NilResettingTimer")
  60. }
  61. // Mean panics.
  62. func (NilResettingTimer) Mean() float64 {
  63. panic("Mean called on a NilResettingTimer")
  64. }
  65. // UpdateSince is a no-op.
  66. func (NilResettingTimer) UpdateSince(time.Time) {}
  67. // StandardResettingTimer is the standard implementation of a ResettingTimer.
  68. // and Meter.
  69. type StandardResettingTimer struct {
  70. values []int64
  71. mutex sync.Mutex
  72. }
  73. // Values returns a slice with all measurements.
  74. func (t *StandardResettingTimer) Values() []int64 {
  75. return t.values
  76. }
  77. // Snapshot resets the timer and returns a read-only copy of its contents.
  78. func (t *StandardResettingTimer) Snapshot() ResettingTimer {
  79. t.mutex.Lock()
  80. defer t.mutex.Unlock()
  81. currentValues := t.values
  82. t.values = make([]int64, 0, InitialResettingTimerSliceCap)
  83. return &ResettingTimerSnapshot{
  84. values: currentValues,
  85. }
  86. }
  87. // Percentiles panics.
  88. func (t *StandardResettingTimer) Percentiles([]float64) []int64 {
  89. panic("Percentiles called on a StandardResettingTimer")
  90. }
  91. // Mean panics.
  92. func (t *StandardResettingTimer) Mean() float64 {
  93. panic("Mean called on a StandardResettingTimer")
  94. }
  95. // Record the duration of the execution of the given function.
  96. func (t *StandardResettingTimer) Time(f func()) {
  97. ts := time.Now()
  98. f()
  99. t.Update(time.Since(ts))
  100. }
  101. // Record the duration of an event.
  102. func (t *StandardResettingTimer) Update(d time.Duration) {
  103. t.mutex.Lock()
  104. defer t.mutex.Unlock()
  105. t.values = append(t.values, int64(d))
  106. }
  107. // Record the duration of an event that started at a time and ends now.
  108. func (t *StandardResettingTimer) UpdateSince(ts time.Time) {
  109. t.mutex.Lock()
  110. defer t.mutex.Unlock()
  111. t.values = append(t.values, int64(time.Since(ts)))
  112. }
  113. // ResettingTimerSnapshot is a point-in-time copy of another ResettingTimer.
  114. type ResettingTimerSnapshot struct {
  115. values []int64
  116. mean float64
  117. thresholdBoundaries []int64
  118. calculated bool
  119. }
  120. // Snapshot returns the snapshot.
  121. func (t *ResettingTimerSnapshot) Snapshot() ResettingTimer { return t }
  122. // Time panics.
  123. func (*ResettingTimerSnapshot) Time(func()) {
  124. panic("Time called on a ResettingTimerSnapshot")
  125. }
  126. // Update panics.
  127. func (*ResettingTimerSnapshot) Update(time.Duration) {
  128. panic("Update called on a ResettingTimerSnapshot")
  129. }
  130. // UpdateSince panics.
  131. func (*ResettingTimerSnapshot) UpdateSince(time.Time) {
  132. panic("UpdateSince called on a ResettingTimerSnapshot")
  133. }
  134. // Values returns all values from snapshot.
  135. func (t *ResettingTimerSnapshot) Values() []int64 {
  136. return t.values
  137. }
  138. // Percentiles returns the boundaries for the input percentiles.
  139. func (t *ResettingTimerSnapshot) Percentiles(percentiles []float64) []int64 {
  140. t.calc(percentiles)
  141. return t.thresholdBoundaries
  142. }
  143. // Mean returns the mean of the snapshotted values
  144. func (t *ResettingTimerSnapshot) Mean() float64 {
  145. if !t.calculated {
  146. t.calc([]float64{})
  147. }
  148. return t.mean
  149. }
  150. func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
  151. sort.Sort(Int64Slice(t.values))
  152. count := len(t.values)
  153. if count > 0 {
  154. min := t.values[0]
  155. max := t.values[count-1]
  156. cumulativeValues := make([]int64, count)
  157. cumulativeValues[0] = min
  158. for i := 1; i < count; i++ {
  159. cumulativeValues[i] = t.values[i] + cumulativeValues[i-1]
  160. }
  161. t.thresholdBoundaries = make([]int64, len(percentiles))
  162. thresholdBoundary := max
  163. for i, pct := range percentiles {
  164. if count > 1 {
  165. var abs float64
  166. if pct >= 0 {
  167. abs = pct
  168. } else {
  169. abs = 100 + pct
  170. }
  171. // poor man's math.Round(x):
  172. // math.Floor(x + 0.5)
  173. indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
  174. if pct >= 0 && indexOfPerc > 0 {
  175. indexOfPerc -= 1 // index offset=0
  176. }
  177. thresholdBoundary = t.values[indexOfPerc]
  178. }
  179. t.thresholdBoundaries[i] = thresholdBoundary
  180. }
  181. sum := cumulativeValues[count-1]
  182. t.mean = float64(sum) / float64(count)
  183. } else {
  184. t.thresholdBoundaries = make([]int64, len(percentiles))
  185. t.mean = 0
  186. }
  187. t.calculated = true
  188. }
  189. // Int64Slice attaches the methods of sort.Interface to []int64, sorting in increasing order.
  190. type Int64Slice []int64
  191. func (s Int64Slice) Len() int { return len(s) }
  192. func (s Int64Slice) Less(i, j int) bool { return s[i] < s[j] }
  193. func (s Int64Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }