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