github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/metrics/resetting_timer.go (about)

     1  package metrics
     2  
     3  import (
     4  	"math"
     5  	"sort"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  const InitialResettingTimerSliceCap = 10
    11  
    12  type ResettingTimer interface {
    13  	Values() []int64
    14  	Snapshot() ResettingTimer
    15  	Percentiles([]float64) []int64
    16  	Mean() float64
    17  	Time(func())
    18  	Update(time.Duration)
    19  	UpdateSince(time.Time)
    20  }
    21  
    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  
    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  
    38  func NewResettingTimer() ResettingTimer {
    39  	if !Enabled {
    40  		return NilResettingTimer{}
    41  	}
    42  	return &StandardResettingTimer{
    43  		values: make([]int64, 0, InitialResettingTimerSliceCap),
    44  	}
    45  }
    46  
    47  type NilResettingTimer struct {
    48  }
    49  
    50  func (NilResettingTimer) Values() []int64 { return nil }
    51  
    52  func (NilResettingTimer) Snapshot() ResettingTimer { return NilResettingTimer{} }
    53  
    54  func (NilResettingTimer) Time(func()) {}
    55  
    56  func (NilResettingTimer) Update(time.Duration) {}
    57  
    58  func (NilResettingTimer) Percentiles([]float64) []int64 {
    59  	panic("Percentiles called on a NilResettingTimer")
    60  }
    61  
    62  func (NilResettingTimer) Mean() float64 {
    63  	panic("Mean called on a NilResettingTimer")
    64  }
    65  
    66  func (NilResettingTimer) UpdateSince(time.Time) {}
    67  
    68  type StandardResettingTimer struct {
    69  	values []int64
    70  	mutex  sync.Mutex
    71  }
    72  
    73  func (t *StandardResettingTimer) Values() []int64 {
    74  	return t.values
    75  }
    76  
    77  func (t *StandardResettingTimer) Snapshot() ResettingTimer {
    78  	t.mutex.Lock()
    79  	defer t.mutex.Unlock()
    80  	currentValues := t.values
    81  	t.values = make([]int64, 0, InitialResettingTimerSliceCap)
    82  
    83  	return &ResettingTimerSnapshot{
    84  		values: currentValues,
    85  	}
    86  }
    87  
    88  func (t *StandardResettingTimer) Percentiles([]float64) []int64 {
    89  	panic("Percentiles called on a StandardResettingTimer")
    90  }
    91  
    92  func (t *StandardResettingTimer) Mean() float64 {
    93  	panic("Mean called on a StandardResettingTimer")
    94  }
    95  
    96  func (t *StandardResettingTimer) Time(f func()) {
    97  	ts := time.Now()
    98  	f()
    99  	t.Update(time.Since(ts))
   100  }
   101  
   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  
   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  
   114  type ResettingTimerSnapshot struct {
   115  	values              []int64
   116  	mean                float64
   117  	thresholdBoundaries []int64
   118  	calculated          bool
   119  }
   120  
   121  func (t *ResettingTimerSnapshot) Snapshot() ResettingTimer { return t }
   122  
   123  func (*ResettingTimerSnapshot) Time(func()) {
   124  	panic("Time called on a ResettingTimerSnapshot")
   125  }
   126  
   127  func (*ResettingTimerSnapshot) Update(time.Duration) {
   128  	panic("Update called on a ResettingTimerSnapshot")
   129  }
   130  
   131  func (*ResettingTimerSnapshot) UpdateSince(time.Time) {
   132  	panic("UpdateSince called on a ResettingTimerSnapshot")
   133  }
   134  
   135  func (t *ResettingTimerSnapshot) Values() []int64 {
   136  	return t.values
   137  }
   138  
   139  func (t *ResettingTimerSnapshot) Percentiles(percentiles []float64) []int64 {
   140  	t.calc(percentiles)
   141  
   142  	return t.thresholdBoundaries
   143  }
   144  
   145  func (t *ResettingTimerSnapshot) Mean() float64 {
   146  	if !t.calculated {
   147  		t.calc([]float64{})
   148  	}
   149  
   150  	return t.mean
   151  }
   152  
   153  func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
   154  	sort.Sort(Int64Slice(t.values))
   155  
   156  	count := len(t.values)
   157  	if count > 0 {
   158  		min := t.values[0]
   159  		max := t.values[count-1]
   160  
   161  		cumulativeValues := make([]int64, count)
   162  		cumulativeValues[0] = min
   163  		for i := 1; i < count; i++ {
   164  			cumulativeValues[i] = t.values[i] + cumulativeValues[i-1]
   165  		}
   166  
   167  		t.thresholdBoundaries = make([]int64, len(percentiles))
   168  
   169  		thresholdBoundary := max
   170  
   171  		for i, pct := range percentiles {
   172  			if count > 1 {
   173  				var abs float64
   174  				if pct >= 0 {
   175  					abs = pct
   176  				} else {
   177  					abs = 100 + pct
   178  				}
   179  
   180  				indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
   181  				if pct >= 0 {
   182  					indexOfPerc -= 1
   183  				}
   184  				thresholdBoundary = t.values[indexOfPerc]
   185  			}
   186  
   187  			t.thresholdBoundaries[i] = thresholdBoundary
   188  		}
   189  
   190  		sum := cumulativeValues[count-1]
   191  		t.mean = float64(sum) / float64(count)
   192  	} else {
   193  		t.thresholdBoundaries = make([]int64, len(percentiles))
   194  		t.mean = 0
   195  	}
   196  
   197  	t.calculated = true
   198  }
   199  
   200  type Int64Slice []int64
   201  
   202  func (s Int64Slice) Len() int           { return len(s) }
   203  func (s Int64Slice) Less(i, j int) bool { return s[i] < s[j] }
   204  func (s Int64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }