github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/metrics/sample.go (about)

     1  package metrics
     2  
     3  import (
     4  	"math"
     5  	"math/rand"
     6  	"sort"
     7  	"sync"
     8  	"time"
     9  )
    10  
    11  const rescaleThreshold = time.Hour
    12  
    13  // Samples maintain a statistically-significant selection of values from
    14  // a stream.
    15  type Sample interface {
    16  	Clear()
    17  	Count() int64
    18  	Max() int64
    19  	Mean() float64
    20  	Min() int64
    21  	Percentile(float64) float64
    22  	Percentiles([]float64) []float64
    23  	Size() int
    24  	Snapshot() Sample
    25  	StdDev() float64
    26  	Sum() int64
    27  	Update(int64)
    28  	Values() []int64
    29  	Variance() float64
    30  }
    31  
    32  func NewBoundedHistogramSample() Sample {
    33  	return NewSlidingTimeWindowArraySample(time.Minute * 1)
    34  }
    35  
    36  // ExpDecaySample is an exponentially-decaying sample using a forward-decaying
    37  // priority reservoir.  See Cormode et al's "Forward Decay: A Practical Time
    38  // Decay Model for Streaming Systems".
    39  //
    40  // <http://dimacs.rutgers.edu/~graham/pubs/papers/fwddecay.pdf>
    41  type ExpDecaySample struct {
    42  	alpha         float64
    43  	count         int64
    44  	mutex         sync.Mutex
    45  	reservoirSize int
    46  	t0, t1        time.Time
    47  	values        *expDecaySampleHeap
    48  	rand          *rand.Rand
    49  }
    50  
    51  // NewExpDecaySample constructs a new exponentially-decaying sample with the
    52  // given reservoir size and alpha.
    53  func NewExpDecaySample(reservoirSize int, alpha float64) Sample {
    54  	if !Enabled {
    55  		return NilSample{}
    56  	}
    57  	s := &ExpDecaySample{
    58  		alpha:         alpha,
    59  		reservoirSize: reservoirSize,
    60  		t0:            time.Now(),
    61  		values:        newExpDecaySampleHeap(reservoirSize),
    62  	}
    63  	s.t1 = s.t0.Add(rescaleThreshold)
    64  	return s
    65  }
    66  
    67  // SetRand sets the random source (useful in tests)
    68  func (s *ExpDecaySample) SetRand(prng *rand.Rand) Sample {
    69  	s.rand = prng
    70  	return s
    71  }
    72  
    73  // Clear clears all samples.
    74  func (s *ExpDecaySample) Clear() {
    75  	s.mutex.Lock()
    76  	defer s.mutex.Unlock()
    77  	s.count = 0
    78  	s.t0 = time.Now()
    79  	s.t1 = s.t0.Add(rescaleThreshold)
    80  	s.values.Clear()
    81  }
    82  
    83  // Count returns the number of samples recorded, which may exceed the
    84  // reservoir size.
    85  func (s *ExpDecaySample) Count() int64 {
    86  	s.mutex.Lock()
    87  	defer s.mutex.Unlock()
    88  	return s.count
    89  }
    90  
    91  // Max returns the maximum value in the sample, which may not be the maximum
    92  // value ever to be part of the sample.
    93  func (s *ExpDecaySample) Max() int64 {
    94  	return SampleMax(s.Values())
    95  }
    96  
    97  // Mean returns the mean of the values in the sample.
    98  func (s *ExpDecaySample) Mean() float64 {
    99  	return SampleMean(s.Values())
   100  }
   101  
   102  // Min returns the minimum value in the sample, which may not be the minimum
   103  // value ever to be part of the sample.
   104  func (s *ExpDecaySample) Min() int64 {
   105  	return SampleMin(s.Values())
   106  }
   107  
   108  // Percentile returns an arbitrary percentile of values in the sample.
   109  func (s *ExpDecaySample) Percentile(p float64) float64 {
   110  	return SamplePercentile(s.Values(), p)
   111  }
   112  
   113  // Percentiles returns a slice of arbitrary percentiles of values in the
   114  // sample.
   115  func (s *ExpDecaySample) Percentiles(ps []float64) []float64 {
   116  	return SamplePercentiles(s.Values(), ps)
   117  }
   118  
   119  // Size returns the size of the sample, which is at most the reservoir size.
   120  func (s *ExpDecaySample) Size() int {
   121  	s.mutex.Lock()
   122  	defer s.mutex.Unlock()
   123  	return s.values.Size()
   124  }
   125  
   126  // Snapshot returns a read-only copy of the sample.
   127  func (s *ExpDecaySample) Snapshot() Sample {
   128  	s.mutex.Lock()
   129  	defer s.mutex.Unlock()
   130  	vals := s.values.Values()
   131  	values := make([]int64, len(vals))
   132  	for i, v := range vals {
   133  		values[i] = v.v
   134  	}
   135  	return &SampleSnapshot{
   136  		count:  s.count,
   137  		values: values,
   138  	}
   139  }
   140  
   141  // StdDev returns the standard deviation of the values in the sample.
   142  func (s *ExpDecaySample) StdDev() float64 {
   143  	return SampleStdDev(s.Values())
   144  }
   145  
   146  // Sum returns the sum of the values in the sample.
   147  func (s *ExpDecaySample) Sum() int64 {
   148  	return SampleSum(s.Values())
   149  }
   150  
   151  // Update samples a new value.
   152  func (s *ExpDecaySample) Update(v int64) {
   153  	s.update(time.Now(), v)
   154  }
   155  
   156  // Values returns a copy of the values in the sample.
   157  func (s *ExpDecaySample) Values() []int64 {
   158  	s.mutex.Lock()
   159  	defer s.mutex.Unlock()
   160  	vals := s.values.Values()
   161  	values := make([]int64, len(vals))
   162  	for i, v := range vals {
   163  		values[i] = v.v
   164  	}
   165  	return values
   166  }
   167  
   168  // Variance returns the variance of the values in the sample.
   169  func (s *ExpDecaySample) Variance() float64 {
   170  	return SampleVariance(s.Values())
   171  }
   172  
   173  // update samples a new value at a particular timestamp.  This is a method all
   174  // its own to facilitate testing.
   175  func (s *ExpDecaySample) update(t time.Time, v int64) {
   176  	s.mutex.Lock()
   177  	defer s.mutex.Unlock()
   178  	s.count++
   179  	if s.values.Size() == s.reservoirSize {
   180  		s.values.Pop()
   181  	}
   182  	var f64 float64
   183  	if s.rand != nil {
   184  		f64 = s.rand.Float64()
   185  	} else {
   186  		f64 = rand.Float64()
   187  	}
   188  	s.values.Push(expDecaySample{
   189  		k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / f64,
   190  		v: v,
   191  	})
   192  	if t.After(s.t1) {
   193  		values := s.values.Values()
   194  		t0 := s.t0
   195  		s.values.Clear()
   196  		s.t0 = t
   197  		s.t1 = s.t0.Add(rescaleThreshold)
   198  		for _, v := range values {
   199  			v.k = v.k * math.Exp(-s.alpha*s.t0.Sub(t0).Seconds())
   200  			s.values.Push(v)
   201  		}
   202  	}
   203  }
   204  
   205  // NilSample is a no-op Sample.
   206  type NilSample struct{}
   207  
   208  // Clear is a no-op.
   209  func (NilSample) Clear() {}
   210  
   211  // Count is a no-op.
   212  func (NilSample) Count() int64 { return 0 }
   213  
   214  // Max is a no-op.
   215  func (NilSample) Max() int64 { return 0 }
   216  
   217  // Mean is a no-op.
   218  func (NilSample) Mean() float64 { return 0.0 }
   219  
   220  // Min is a no-op.
   221  func (NilSample) Min() int64 { return 0 }
   222  
   223  // Percentile is a no-op.
   224  func (NilSample) Percentile(p float64) float64 { return 0.0 }
   225  
   226  // Percentiles is a no-op.
   227  func (NilSample) Percentiles(ps []float64) []float64 {
   228  	return make([]float64, len(ps))
   229  }
   230  
   231  // Size is a no-op.
   232  func (NilSample) Size() int { return 0 }
   233  
   234  // Sample is a no-op.
   235  func (NilSample) Snapshot() Sample { return NilSample{} }
   236  
   237  // StdDev is a no-op.
   238  func (NilSample) StdDev() float64 { return 0.0 }
   239  
   240  // Sum is a no-op.
   241  func (NilSample) Sum() int64 { return 0 }
   242  
   243  // Update is a no-op.
   244  func (NilSample) Update(v int64) {}
   245  
   246  // Values is a no-op.
   247  func (NilSample) Values() []int64 { return []int64{} }
   248  
   249  // Variance is a no-op.
   250  func (NilSample) Variance() float64 { return 0.0 }
   251  
   252  // SampleMax returns the maximum value of the slice of int64.
   253  func SampleMax(values []int64) int64 {
   254  	if len(values) == 0 {
   255  		return 0
   256  	}
   257  	var max int64 = math.MinInt64
   258  	for _, v := range values {
   259  		if max < v {
   260  			max = v
   261  		}
   262  	}
   263  	return max
   264  }
   265  
   266  // SampleMean returns the mean value of the slice of int64.
   267  func SampleMean(values []int64) float64 {
   268  	if len(values) == 0 {
   269  		return 0.0
   270  	}
   271  	return float64(SampleSum(values)) / float64(len(values))
   272  }
   273  
   274  // SampleMin returns the minimum value of the slice of int64.
   275  func SampleMin(values []int64) int64 {
   276  	if len(values) == 0 {
   277  		return 0
   278  	}
   279  	var min int64 = math.MaxInt64
   280  	for _, v := range values {
   281  		if min > v {
   282  			min = v
   283  		}
   284  	}
   285  	return min
   286  }
   287  
   288  // SamplePercentiles returns an arbitrary percentile of the slice of int64.
   289  func SamplePercentile(values int64Slice, p float64) float64 {
   290  	return SamplePercentiles(values, []float64{p})[0]
   291  }
   292  
   293  // SamplePercentiles returns a slice of arbitrary percentiles of the slice of
   294  // int64.
   295  func SamplePercentiles(values int64Slice, ps []float64) []float64 {
   296  	scores := make([]float64, len(ps))
   297  	size := len(values)
   298  	if size > 0 {
   299  		sort.Sort(values)
   300  		for i, p := range ps {
   301  			pos := p * float64(size+1)
   302  			if pos < 1.0 {
   303  				scores[i] = float64(values[0])
   304  			} else if pos >= float64(size) {
   305  				scores[i] = float64(values[size-1])
   306  			} else {
   307  				lower := float64(values[int(pos)-1])
   308  				upper := float64(values[int(pos)])
   309  				scores[i] = lower + (pos-math.Floor(pos))*(upper-lower)
   310  			}
   311  		}
   312  	}
   313  	return scores
   314  }
   315  
   316  // SampleSnapshot is a read-only copy of another Sample.
   317  type SampleSnapshot struct {
   318  	count  int64
   319  	values []int64
   320  }
   321  
   322  func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot {
   323  	return &SampleSnapshot{
   324  		count:  count,
   325  		values: values,
   326  	}
   327  }
   328  
   329  // Clear panics.
   330  func (*SampleSnapshot) Clear() {
   331  	panic("Clear called on a SampleSnapshot")
   332  }
   333  
   334  // Count returns the count of inputs at the time the snapshot was taken.
   335  func (s *SampleSnapshot) Count() int64 { return s.count }
   336  
   337  // Max returns the maximal value at the time the snapshot was taken.
   338  func (s *SampleSnapshot) Max() int64 { return SampleMax(s.values) }
   339  
   340  // Mean returns the mean value at the time the snapshot was taken.
   341  func (s *SampleSnapshot) Mean() float64 { return SampleMean(s.values) }
   342  
   343  // Min returns the minimal value at the time the snapshot was taken.
   344  func (s *SampleSnapshot) Min() int64 { return SampleMin(s.values) }
   345  
   346  // Percentile returns an arbitrary percentile of values at the time the
   347  // snapshot was taken.
   348  func (s *SampleSnapshot) Percentile(p float64) float64 {
   349  	return SamplePercentile(s.values, p)
   350  }
   351  
   352  // Percentiles returns a slice of arbitrary percentiles of values at the time
   353  // the snapshot was taken.
   354  func (s *SampleSnapshot) Percentiles(ps []float64) []float64 {
   355  	return SamplePercentiles(s.values, ps)
   356  }
   357  
   358  // Size returns the size of the sample at the time the snapshot was taken.
   359  func (s *SampleSnapshot) Size() int { return len(s.values) }
   360  
   361  // Snapshot returns the snapshot.
   362  func (s *SampleSnapshot) Snapshot() Sample { return s }
   363  
   364  // StdDev returns the standard deviation of values at the time the snapshot was
   365  // taken.
   366  func (s *SampleSnapshot) StdDev() float64 { return SampleStdDev(s.values) }
   367  
   368  // Sum returns the sum of values at the time the snapshot was taken.
   369  func (s *SampleSnapshot) Sum() int64 { return SampleSum(s.values) }
   370  
   371  // Update panics.
   372  func (*SampleSnapshot) Update(int64) {
   373  	panic("Update called on a SampleSnapshot")
   374  }
   375  
   376  // Values returns a copy of the values in the sample.
   377  func (s *SampleSnapshot) Values() []int64 {
   378  	values := make([]int64, len(s.values))
   379  	copy(values, s.values)
   380  	return values
   381  }
   382  
   383  // Variance returns the variance of values at the time the snapshot was taken.
   384  func (s *SampleSnapshot) Variance() float64 { return SampleVariance(s.values) }
   385  
   386  // SampleStdDev returns the standard deviation of the slice of int64.
   387  func SampleStdDev(values []int64) float64 {
   388  	return math.Sqrt(SampleVariance(values))
   389  }
   390  
   391  // SampleSum returns the sum of the slice of int64.
   392  func SampleSum(values []int64) int64 {
   393  	var sum int64
   394  	for _, v := range values {
   395  		sum += v
   396  	}
   397  	return sum
   398  }
   399  
   400  // SampleVariance returns the variance of the slice of int64.
   401  func SampleVariance(values []int64) float64 {
   402  	if len(values) == 0 {
   403  		return 0.0
   404  	}
   405  	m := SampleMean(values)
   406  	var sum float64
   407  	for _, v := range values {
   408  		d := float64(v) - m
   409  		sum += d * d
   410  	}
   411  	return sum / float64(len(values))
   412  }
   413  
   414  // A uniform sample using Vitter's Algorithm R.
   415  //
   416  // <http://www.cs.umd.edu/~samir/498/vitter.pdf>
   417  type UniformSample struct {
   418  	count         int64
   419  	mutex         sync.Mutex
   420  	reservoirSize int
   421  	values        []int64
   422  	rand          *rand.Rand
   423  }
   424  
   425  // NewUniformSample constructs a new uniform sample with the given reservoir
   426  // size.
   427  func NewUniformSample(reservoirSize int) Sample {
   428  	if !Enabled {
   429  		return NilSample{}
   430  	}
   431  	return &UniformSample{
   432  		reservoirSize: reservoirSize,
   433  		values:        make([]int64, 0, reservoirSize),
   434  	}
   435  }
   436  
   437  // SetRand sets the random source (useful in tests)
   438  func (s *UniformSample) SetRand(prng *rand.Rand) Sample {
   439  	s.rand = prng
   440  	return s
   441  }
   442  
   443  // Clear clears all samples.
   444  func (s *UniformSample) Clear() {
   445  	s.mutex.Lock()
   446  	defer s.mutex.Unlock()
   447  	s.count = 0
   448  	s.values = make([]int64, 0, s.reservoirSize)
   449  }
   450  
   451  // Count returns the number of samples recorded, which may exceed the
   452  // reservoir size.
   453  func (s *UniformSample) Count() int64 {
   454  	s.mutex.Lock()
   455  	defer s.mutex.Unlock()
   456  	return s.count
   457  }
   458  
   459  // Max returns the maximum value in the sample, which may not be the maximum
   460  // value ever to be part of the sample.
   461  func (s *UniformSample) Max() int64 {
   462  	s.mutex.Lock()
   463  	defer s.mutex.Unlock()
   464  	return SampleMax(s.values)
   465  }
   466  
   467  // Mean returns the mean of the values in the sample.
   468  func (s *UniformSample) Mean() float64 {
   469  	s.mutex.Lock()
   470  	defer s.mutex.Unlock()
   471  	return SampleMean(s.values)
   472  }
   473  
   474  // Min returns the minimum value in the sample, which may not be the minimum
   475  // value ever to be part of the sample.
   476  func (s *UniformSample) Min() int64 {
   477  	s.mutex.Lock()
   478  	defer s.mutex.Unlock()
   479  	return SampleMin(s.values)
   480  }
   481  
   482  // Percentile returns an arbitrary percentile of values in the sample.
   483  func (s *UniformSample) Percentile(p float64) float64 {
   484  	s.mutex.Lock()
   485  	defer s.mutex.Unlock()
   486  	return SamplePercentile(s.values, p)
   487  }
   488  
   489  // Percentiles returns a slice of arbitrary percentiles of values in the
   490  // sample.
   491  func (s *UniformSample) Percentiles(ps []float64) []float64 {
   492  	s.mutex.Lock()
   493  	defer s.mutex.Unlock()
   494  	return SamplePercentiles(s.values, ps)
   495  }
   496  
   497  // Size returns the size of the sample, which is at most the reservoir size.
   498  func (s *UniformSample) Size() int {
   499  	s.mutex.Lock()
   500  	defer s.mutex.Unlock()
   501  	return len(s.values)
   502  }
   503  
   504  // Snapshot returns a read-only copy of the sample.
   505  func (s *UniformSample) Snapshot() Sample {
   506  	s.mutex.Lock()
   507  	defer s.mutex.Unlock()
   508  	values := make([]int64, len(s.values))
   509  	copy(values, s.values)
   510  	return &SampleSnapshot{
   511  		count:  s.count,
   512  		values: values,
   513  	}
   514  }
   515  
   516  // StdDev returns the standard deviation of the values in the sample.
   517  func (s *UniformSample) StdDev() float64 {
   518  	s.mutex.Lock()
   519  	defer s.mutex.Unlock()
   520  	return SampleStdDev(s.values)
   521  }
   522  
   523  // Sum returns the sum of the values in the sample.
   524  func (s *UniformSample) Sum() int64 {
   525  	s.mutex.Lock()
   526  	defer s.mutex.Unlock()
   527  	return SampleSum(s.values)
   528  }
   529  
   530  // Update samples a new value.
   531  func (s *UniformSample) Update(v int64) {
   532  	s.mutex.Lock()
   533  	defer s.mutex.Unlock()
   534  	s.count++
   535  	if len(s.values) < s.reservoirSize {
   536  		s.values = append(s.values, v)
   537  	} else {
   538  		var r int64
   539  		if s.rand != nil {
   540  			r = s.rand.Int63n(s.count)
   541  		} else {
   542  			r = rand.Int63n(s.count)
   543  		}
   544  		if r < int64(len(s.values)) {
   545  			s.values[int(r)] = v
   546  		}
   547  	}
   548  }
   549  
   550  // Values returns a copy of the values in the sample.
   551  func (s *UniformSample) Values() []int64 {
   552  	s.mutex.Lock()
   553  	defer s.mutex.Unlock()
   554  	values := make([]int64, len(s.values))
   555  	copy(values, s.values)
   556  	return values
   557  }
   558  
   559  // Variance returns the variance of the values in the sample.
   560  func (s *UniformSample) Variance() float64 {
   561  	s.mutex.Lock()
   562  	defer s.mutex.Unlock()
   563  	return SampleVariance(s.values)
   564  }
   565  
   566  // expDecaySample represents an individual sample in a heap.
   567  type expDecaySample struct {
   568  	k float64
   569  	v int64
   570  }
   571  
   572  func newExpDecaySampleHeap(reservoirSize int) *expDecaySampleHeap {
   573  	return &expDecaySampleHeap{make([]expDecaySample, 0, reservoirSize)}
   574  }
   575  
   576  // expDecaySampleHeap is a min-heap of expDecaySamples.
   577  // The internal implementation is copied from the standard library's container/heap
   578  type expDecaySampleHeap struct {
   579  	s []expDecaySample
   580  }
   581  
   582  func (h *expDecaySampleHeap) Clear() {
   583  	h.s = h.s[:0]
   584  }
   585  
   586  func (h *expDecaySampleHeap) Push(s expDecaySample) {
   587  	n := len(h.s)
   588  	h.s = h.s[0 : n+1]
   589  	h.s[n] = s
   590  	h.up(n)
   591  }
   592  
   593  func (h *expDecaySampleHeap) Pop() expDecaySample {
   594  	n := len(h.s) - 1
   595  	h.s[0], h.s[n] = h.s[n], h.s[0]
   596  	h.down(0, n)
   597  
   598  	n = len(h.s)
   599  	s := h.s[n-1]
   600  	h.s = h.s[0 : n-1]
   601  	return s
   602  }
   603  
   604  func (h *expDecaySampleHeap) Size() int {
   605  	return len(h.s)
   606  }
   607  
   608  func (h *expDecaySampleHeap) Values() []expDecaySample {
   609  	return h.s
   610  }
   611  
   612  func (h *expDecaySampleHeap) up(j int) {
   613  	for {
   614  		i := (j - 1) / 2 // parent
   615  		if i == j || !(h.s[j].k < h.s[i].k) {
   616  			break
   617  		}
   618  		h.s[i], h.s[j] = h.s[j], h.s[i]
   619  		j = i
   620  	}
   621  }
   622  
   623  func (h *expDecaySampleHeap) down(i, n int) {
   624  	for {
   625  		j1 := 2*i + 1
   626  		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
   627  			break
   628  		}
   629  		j := j1 // left child
   630  		if j2 := j1 + 1; j2 < n && !(h.s[j1].k < h.s[j2].k) {
   631  			j = j2 // = 2*i + 2  // right child
   632  		}
   633  		if !(h.s[j].k < h.s[i].k) {
   634  			break
   635  		}
   636  		h.s[i], h.s[j] = h.s[j], h.s[i]
   637  		i = j
   638  	}
   639  }
   640  
   641  // SlidingTimeWindowArraySample is ported from Coda Hale's dropwizard library
   642  // <https://github.com/dropwizard/metrics/pull/1139>
   643  // A reservoir implementation backed by a sliding window that stores only the
   644  // measurements made in the last given window of time
   645  type SlidingTimeWindowArraySample struct {
   646  	startTick    int64
   647  	measurements *ChunkedAssociativeArray
   648  	window       int64
   649  	count        int64
   650  	lastTick     int64
   651  	mutex        sync.Mutex
   652  }
   653  
   654  const (
   655  	// SlidingTimeWindowCollisionBuffer allow this many duplicate ticks
   656  	// before overwriting measurements
   657  	SlidingTimeWindowCollisionBuffer = 256
   658  
   659  	// SlidingTimeWindowTrimThreshold is number of updates between trimming data
   660  	SlidingTimeWindowTrimThreshold = 256
   661  
   662  	// SlidingTimeWindowClearBufferTicks is the number of ticks to keep past the
   663  	// requested trim
   664  	SlidingTimeWindowClearBufferTicks = int64(time.Hour/time.Nanosecond) *
   665  		SlidingTimeWindowCollisionBuffer
   666  )
   667  
   668  // NewSlidingTimeWindowArraySample creates new object with given window of time
   669  func NewSlidingTimeWindowArraySample(window time.Duration) Sample {
   670  	if !Enabled {
   671  		return NilSample{}
   672  	}
   673  	return &SlidingTimeWindowArraySample{
   674  		startTick:    time.Now().UnixNano(),
   675  		measurements: NewChunkedAssociativeArray(ChunkedAssociativeArrayDefaultChunkSize),
   676  		window:       window.Nanoseconds() * SlidingTimeWindowCollisionBuffer,
   677  	}
   678  }
   679  
   680  // Clear clears all samples.
   681  func (s *SlidingTimeWindowArraySample) Clear() {
   682  	s.mutex.Lock()
   683  	defer s.mutex.Unlock()
   684  	s.count = 0
   685  	s.measurements.Clear()
   686  }
   687  
   688  // Count returns the number of samples recorded, which may exceed the
   689  // reservoir size.
   690  func (s *SlidingTimeWindowArraySample) Count() int64 {
   691  	s.mutex.Lock()
   692  	defer s.mutex.Unlock()
   693  	return s.count
   694  }
   695  
   696  // Max returns the maximum value in the sample, which may not be the maximum
   697  // value ever to be part of the sample.
   698  func (s *SlidingTimeWindowArraySample) Max() int64 {
   699  	s.mutex.Lock()
   700  	defer s.mutex.Unlock()
   701  	s.trim()
   702  	return SampleMax(s.measurements.Values())
   703  }
   704  
   705  // Mean returns the mean of the values in the sample.
   706  func (s *SlidingTimeWindowArraySample) Mean() float64 {
   707  	s.mutex.Lock()
   708  	defer s.mutex.Unlock()
   709  	s.trim()
   710  	return SampleMean(s.measurements.Values())
   711  }
   712  
   713  // Min returns the minimum value in the sample, which may not be the minimum
   714  // value ever to be part of the sample.
   715  func (s *SlidingTimeWindowArraySample) Min() int64 {
   716  	s.mutex.Lock()
   717  	defer s.mutex.Unlock()
   718  	s.trim()
   719  	return SampleMin(s.measurements.Values())
   720  }
   721  
   722  // Percentile returns an arbitrary percentile of values in the sample.
   723  func (s *SlidingTimeWindowArraySample) Percentile(p float64) float64 {
   724  	s.mutex.Lock()
   725  	defer s.mutex.Unlock()
   726  	s.trim()
   727  	return SamplePercentile(s.measurements.Values(), p)
   728  }
   729  
   730  // Percentiles returns a slice of arbitrary percentiles of values in the
   731  // sample.
   732  func (s *SlidingTimeWindowArraySample) Percentiles(ps []float64) []float64 {
   733  	s.mutex.Lock()
   734  	defer s.mutex.Unlock()
   735  	s.trim()
   736  	return SamplePercentiles(s.measurements.Values(), ps)
   737  }
   738  
   739  // Size returns the size of the sample, which is at most the reservoir size.
   740  func (s *SlidingTimeWindowArraySample) Size() int {
   741  	s.mutex.Lock()
   742  	defer s.mutex.Unlock()
   743  	s.trim()
   744  	return s.measurements.Size()
   745  }
   746  
   747  // trim requires s.mutex to already be acquired
   748  func (s *SlidingTimeWindowArraySample) trim() {
   749  	now := s.getTick()
   750  	windowStart := now - s.window
   751  	windowEnd := now + SlidingTimeWindowClearBufferTicks
   752  	if windowStart < windowEnd {
   753  		s.measurements.Trim(windowStart, windowEnd)
   754  	} else {
   755  		// long overflow handling that can only happen 1 year after class loading
   756  		s.measurements.Clear()
   757  	}
   758  }
   759  
   760  // getTick requires s.mutex to already be acquired
   761  func (s *SlidingTimeWindowArraySample) getTick() int64 {
   762  	oldTick := s.lastTick
   763  	tick := (time.Now().UnixNano() - s.startTick) * SlidingTimeWindowCollisionBuffer
   764  	var newTick int64
   765  	if tick-oldTick > 0 {
   766  		newTick = tick
   767  	} else {
   768  		newTick = oldTick + 1
   769  	}
   770  	s.lastTick = newTick
   771  	return newTick
   772  }
   773  
   774  // Snapshot returns a read-only copy of the sample.
   775  func (s *SlidingTimeWindowArraySample) Snapshot() Sample {
   776  	s.mutex.Lock()
   777  	defer s.mutex.Unlock()
   778  	s.trim()
   779  	origValues := s.measurements.Values()
   780  	values := make([]int64, len(origValues))
   781  	copy(values, origValues)
   782  	return &SampleSnapshot{
   783  		count:  s.count,
   784  		values: values,
   785  	}
   786  }
   787  
   788  // StdDev returns the standard deviation of the values in the sample.
   789  func (s *SlidingTimeWindowArraySample) StdDev() float64 {
   790  	s.mutex.Lock()
   791  	defer s.mutex.Unlock()
   792  	s.trim()
   793  	return SampleStdDev(s.measurements.Values())
   794  }
   795  
   796  // Sum returns the sum of the values in the sample.
   797  func (s *SlidingTimeWindowArraySample) Sum() int64 {
   798  	s.mutex.Lock()
   799  	defer s.mutex.Unlock()
   800  	s.trim()
   801  	return SampleSum(s.measurements.Values())
   802  }
   803  
   804  // Update samples a new value.
   805  func (s *SlidingTimeWindowArraySample) Update(v int64) {
   806  	s.mutex.Lock()
   807  	defer s.mutex.Unlock()
   808  	var newTick int64
   809  	s.count += 1
   810  	if s.count%SlidingTimeWindowTrimThreshold == 0 {
   811  		s.trim()
   812  	}
   813  	newTick = s.getTick()
   814  	longOverflow := newTick < s.lastTick
   815  	if longOverflow {
   816  		s.measurements.Clear()
   817  	}
   818  	s.measurements.Put(newTick, v)
   819  }
   820  
   821  // Values returns a copy of the values in the sample.
   822  func (s *SlidingTimeWindowArraySample) Values() []int64 {
   823  	s.mutex.Lock()
   824  	defer s.mutex.Unlock()
   825  	s.trim()
   826  	origValues := s.measurements.Values()
   827  	values := make([]int64, len(origValues))
   828  	copy(values, origValues)
   829  	return values
   830  }
   831  
   832  // Variance returns the variance of the values in the sample.
   833  func (s *SlidingTimeWindowArraySample) Variance() float64 {
   834  	s.mutex.Lock()
   835  	defer s.mutex.Unlock()
   836  	s.trim()
   837  	return SampleVariance(s.measurements.Values())
   838  }
   839  
   840  type int64Slice []int64
   841  
   842  func (p int64Slice) Len() int           { return len(p) }
   843  func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
   844  func (p int64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }