github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/rcrowley/go-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  // ExpDecaySample is an exponentially-decaying sample using a forward-decaying
    33  // priority reservoir.  See Cormode et al's "Forward Decay: A Practical Time
    34  // Decay Model for Streaming Systems".
    35  //
    36  // <http://www.research.att.com/people/Cormode_Graham/library/publications/CormodeShkapenyukSrivastavaXu09.pdf>
    37  type ExpDecaySample struct {
    38  	alpha         float64
    39  	count         int64
    40  	mutex         sync.Mutex
    41  	reservoirSize int
    42  	t0, t1        time.Time
    43  	values        *expDecaySampleHeap
    44  }
    45  
    46  // NewExpDecaySample constructs a new exponentially-decaying sample with the
    47  // given reservoir size and alpha.
    48  func NewExpDecaySample(reservoirSize int, alpha float64) Sample {
    49  	if UseNilMetrics {
    50  		return NilSample{}
    51  	}
    52  	s := &ExpDecaySample{
    53  		alpha:         alpha,
    54  		reservoirSize: reservoirSize,
    55  		t0:            time.Now(),
    56  		values:        newExpDecaySampleHeap(reservoirSize),
    57  	}
    58  	s.t1 = s.t0.Add(rescaleThreshold)
    59  	return s
    60  }
    61  
    62  // Clear clears all samples.
    63  func (s *ExpDecaySample) Clear() {
    64  	s.mutex.Lock()
    65  	defer s.mutex.Unlock()
    66  	s.count = 0
    67  	s.t0 = time.Now()
    68  	s.t1 = s.t0.Add(rescaleThreshold)
    69  	s.values.Clear()
    70  }
    71  
    72  // Count returns the number of samples recorded, which may exceed the
    73  // reservoir size.
    74  func (s *ExpDecaySample) Count() int64 {
    75  	s.mutex.Lock()
    76  	defer s.mutex.Unlock()
    77  	return s.count
    78  }
    79  
    80  // Max returns the maximum value in the sample, which may not be the maximum
    81  // value ever to be part of the sample.
    82  func (s *ExpDecaySample) Max() int64 {
    83  	return SampleMax(s.Values())
    84  }
    85  
    86  // Mean returns the mean of the values in the sample.
    87  func (s *ExpDecaySample) Mean() float64 {
    88  	return SampleMean(s.Values())
    89  }
    90  
    91  // Min returns the minimum value in the sample, which may not be the minimum
    92  // value ever to be part of the sample.
    93  func (s *ExpDecaySample) Min() int64 {
    94  	return SampleMin(s.Values())
    95  }
    96  
    97  // Percentile returns an arbitrary percentile of values in the sample.
    98  func (s *ExpDecaySample) Percentile(p float64) float64 {
    99  	return SamplePercentile(s.Values(), p)
   100  }
   101  
   102  // Percentiles returns a slice of arbitrary percentiles of values in the
   103  // sample.
   104  func (s *ExpDecaySample) Percentiles(ps []float64) []float64 {
   105  	return SamplePercentiles(s.Values(), ps)
   106  }
   107  
   108  // Size returns the size of the sample, which is at most the reservoir size.
   109  func (s *ExpDecaySample) Size() int {
   110  	s.mutex.Lock()
   111  	defer s.mutex.Unlock()
   112  	return s.values.Size()
   113  }
   114  
   115  // Snapshot returns a read-only copy of the sample.
   116  func (s *ExpDecaySample) Snapshot() Sample {
   117  	s.mutex.Lock()
   118  	defer s.mutex.Unlock()
   119  	vals := s.values.Values()
   120  	values := make([]int64, len(vals))
   121  	for i, v := range vals {
   122  		values[i] = v.v
   123  	}
   124  	return &SampleSnapshot{
   125  		count:  s.count,
   126  		values: values,
   127  	}
   128  }
   129  
   130  // StdDev returns the standard deviation of the values in the sample.
   131  func (s *ExpDecaySample) StdDev() float64 {
   132  	return SampleStdDev(s.Values())
   133  }
   134  
   135  // Sum returns the sum of the values in the sample.
   136  func (s *ExpDecaySample) Sum() int64 {
   137  	return SampleSum(s.Values())
   138  }
   139  
   140  // Update samples a new value.
   141  func (s *ExpDecaySample) Update(v int64) {
   142  	s.update(time.Now(), v)
   143  }
   144  
   145  // Values returns a copy of the values in the sample.
   146  func (s *ExpDecaySample) Values() []int64 {
   147  	s.mutex.Lock()
   148  	defer s.mutex.Unlock()
   149  	vals := s.values.Values()
   150  	values := make([]int64, len(vals))
   151  	for i, v := range vals {
   152  		values[i] = v.v
   153  	}
   154  	return values
   155  }
   156  
   157  // Variance returns the variance of the values in the sample.
   158  func (s *ExpDecaySample) Variance() float64 {
   159  	return SampleVariance(s.Values())
   160  }
   161  
   162  // update samples a new value at a particular timestamp.  This is a method all
   163  // its own to facilitate testing.
   164  func (s *ExpDecaySample) update(t time.Time, v int64) {
   165  	s.mutex.Lock()
   166  	defer s.mutex.Unlock()
   167  	s.count++
   168  	if s.values.Size() == s.reservoirSize {
   169  		s.values.Pop()
   170  	}
   171  	s.values.Push(expDecaySample{
   172  		k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / rand.Float64(),
   173  		v: v,
   174  	})
   175  	if t.After(s.t1) {
   176  		values := s.values.Values()
   177  		t0 := s.t0
   178  		s.values.Clear()
   179  		s.t0 = t
   180  		s.t1 = s.t0.Add(rescaleThreshold)
   181  		for _, v := range values {
   182  			v.k = v.k * math.Exp(-s.alpha*s.t0.Sub(t0).Seconds())
   183  			s.values.Push(v)
   184  		}
   185  	}
   186  }
   187  
   188  // NilSample is a no-op Sample.
   189  type NilSample struct{}
   190  
   191  // Clear is a no-op.
   192  func (NilSample) Clear() {}
   193  
   194  // Count is a no-op.
   195  func (NilSample) Count() int64 { return 0 }
   196  
   197  // Max is a no-op.
   198  func (NilSample) Max() int64 { return 0 }
   199  
   200  // Mean is a no-op.
   201  func (NilSample) Mean() float64 { return 0.0 }
   202  
   203  // Min is a no-op.
   204  func (NilSample) Min() int64 { return 0 }
   205  
   206  // Percentile is a no-op.
   207  func (NilSample) Percentile(p float64) float64 { return 0.0 }
   208  
   209  // Percentiles is a no-op.
   210  func (NilSample) Percentiles(ps []float64) []float64 {
   211  	return make([]float64, len(ps))
   212  }
   213  
   214  // Size is a no-op.
   215  func (NilSample) Size() int { return 0 }
   216  
   217  // Sample is a no-op.
   218  func (NilSample) Snapshot() Sample { return NilSample{} }
   219  
   220  // StdDev is a no-op.
   221  func (NilSample) StdDev() float64 { return 0.0 }
   222  
   223  // Sum is a no-op.
   224  func (NilSample) Sum() int64 { return 0 }
   225  
   226  // Update is a no-op.
   227  func (NilSample) Update(v int64) {}
   228  
   229  // Values is a no-op.
   230  func (NilSample) Values() []int64 { return []int64{} }
   231  
   232  // Variance is a no-op.
   233  func (NilSample) Variance() float64 { return 0.0 }
   234  
   235  // SampleMax returns the maximum value of the slice of int64.
   236  func SampleMax(values []int64) int64 {
   237  	if 0 == len(values) {
   238  		return 0
   239  	}
   240  	var max int64 = math.MinInt64
   241  	for _, v := range values {
   242  		if max < v {
   243  			max = v
   244  		}
   245  	}
   246  	return max
   247  }
   248  
   249  // SampleMean returns the mean value of the slice of int64.
   250  func SampleMean(values []int64) float64 {
   251  	if 0 == len(values) {
   252  		return 0.0
   253  	}
   254  	return float64(SampleSum(values)) / float64(len(values))
   255  }
   256  
   257  // SampleMin returns the minimum value of the slice of int64.
   258  func SampleMin(values []int64) int64 {
   259  	if 0 == len(values) {
   260  		return 0
   261  	}
   262  	var min int64 = math.MaxInt64
   263  	for _, v := range values {
   264  		if min > v {
   265  			min = v
   266  		}
   267  	}
   268  	return min
   269  }
   270  
   271  // SamplePercentiles returns an arbitrary percentile of the slice of int64.
   272  func SamplePercentile(values int64Slice, p float64) float64 {
   273  	return SamplePercentiles(values, []float64{p})[0]
   274  }
   275  
   276  // SamplePercentiles returns a slice of arbitrary percentiles of the slice of
   277  // int64.
   278  func SamplePercentiles(values int64Slice, ps []float64) []float64 {
   279  	scores := make([]float64, len(ps))
   280  	size := len(values)
   281  	if size > 0 {
   282  		sort.Sort(values)
   283  		for i, p := range ps {
   284  			pos := p * float64(size+1)
   285  			if pos < 1.0 {
   286  				scores[i] = float64(values[0])
   287  			} else if pos >= float64(size) {
   288  				scores[i] = float64(values[size-1])
   289  			} else {
   290  				lower := float64(values[int(pos)-1])
   291  				upper := float64(values[int(pos)])
   292  				scores[i] = lower + (pos-math.Floor(pos))*(upper-lower)
   293  			}
   294  		}
   295  	}
   296  	return scores
   297  }
   298  
   299  // SampleSnapshot is a read-only copy of another Sample.
   300  type SampleSnapshot struct {
   301  	count  int64
   302  	values []int64
   303  }
   304  
   305  // Clear panics.
   306  func (*SampleSnapshot) Clear() {
   307  	panic("Clear called on a SampleSnapshot")
   308  }
   309  
   310  // Count returns the count of inputs at the time the snapshot was taken.
   311  func (s *SampleSnapshot) Count() int64 { return s.count }
   312  
   313  // Max returns the maximal value at the time the snapshot was taken.
   314  func (s *SampleSnapshot) Max() int64 { return SampleMax(s.values) }
   315  
   316  // Mean returns the mean value at the time the snapshot was taken.
   317  func (s *SampleSnapshot) Mean() float64 { return SampleMean(s.values) }
   318  
   319  // Min returns the minimal value at the time the snapshot was taken.
   320  func (s *SampleSnapshot) Min() int64 { return SampleMin(s.values) }
   321  
   322  // Percentile returns an arbitrary percentile of values at the time the
   323  // snapshot was taken.
   324  func (s *SampleSnapshot) Percentile(p float64) float64 {
   325  	return SamplePercentile(s.values, p)
   326  }
   327  
   328  // Percentiles returns a slice of arbitrary percentiles of values at the time
   329  // the snapshot was taken.
   330  func (s *SampleSnapshot) Percentiles(ps []float64) []float64 {
   331  	return SamplePercentiles(s.values, ps)
   332  }
   333  
   334  // Size returns the size of the sample at the time the snapshot was taken.
   335  func (s *SampleSnapshot) Size() int { return len(s.values) }
   336  
   337  // Snapshot returns the snapshot.
   338  func (s *SampleSnapshot) Snapshot() Sample { return s }
   339  
   340  // StdDev returns the standard deviation of values at the time the snapshot was
   341  // taken.
   342  func (s *SampleSnapshot) StdDev() float64 { return SampleStdDev(s.values) }
   343  
   344  // Sum returns the sum of values at the time the snapshot was taken.
   345  func (s *SampleSnapshot) Sum() int64 { return SampleSum(s.values) }
   346  
   347  // Update panics.
   348  func (*SampleSnapshot) Update(int64) {
   349  	panic("Update called on a SampleSnapshot")
   350  }
   351  
   352  // Values returns a copy of the values in the sample.
   353  func (s *SampleSnapshot) Values() []int64 {
   354  	values := make([]int64, len(s.values))
   355  	copy(values, s.values)
   356  	return values
   357  }
   358  
   359  // Variance returns the variance of values at the time the snapshot was taken.
   360  func (s *SampleSnapshot) Variance() float64 { return SampleVariance(s.values) }
   361  
   362  // SampleStdDev returns the standard deviation of the slice of int64.
   363  func SampleStdDev(values []int64) float64 {
   364  	return math.Sqrt(SampleVariance(values))
   365  }
   366  
   367  // SampleSum returns the sum of the slice of int64.
   368  func SampleSum(values []int64) int64 {
   369  	var sum int64
   370  	for _, v := range values {
   371  		sum += v
   372  	}
   373  	return sum
   374  }
   375  
   376  // SampleVariance returns the variance of the slice of int64.
   377  func SampleVariance(values []int64) float64 {
   378  	if 0 == len(values) {
   379  		return 0.0
   380  	}
   381  	m := SampleMean(values)
   382  	var sum float64
   383  	for _, v := range values {
   384  		d := float64(v) - m
   385  		sum += d * d
   386  	}
   387  	return sum / float64(len(values))
   388  }
   389  
   390  // A uniform sample using Vitter's Algorithm R.
   391  //
   392  // <http://www.cs.umd.edu/~samir/498/vitter.pdf>
   393  type UniformSample struct {
   394  	count         int64
   395  	mutex         sync.Mutex
   396  	reservoirSize int
   397  	values        []int64
   398  }
   399  
   400  // NewUniformSample constructs a new uniform sample with the given reservoir
   401  // size.
   402  func NewUniformSample(reservoirSize int) Sample {
   403  	if UseNilMetrics {
   404  		return NilSample{}
   405  	}
   406  	return &UniformSample{
   407  		reservoirSize: reservoirSize,
   408  		values:        make([]int64, 0, reservoirSize),
   409  	}
   410  }
   411  
   412  // Clear clears all samples.
   413  func (s *UniformSample) Clear() {
   414  	s.mutex.Lock()
   415  	defer s.mutex.Unlock()
   416  	s.count = 0
   417  	s.values = make([]int64, 0, s.reservoirSize)
   418  }
   419  
   420  // Count returns the number of samples recorded, which may exceed the
   421  // reservoir size.
   422  func (s *UniformSample) Count() int64 {
   423  	s.mutex.Lock()
   424  	defer s.mutex.Unlock()
   425  	return s.count
   426  }
   427  
   428  // Max returns the maximum value in the sample, which may not be the maximum
   429  // value ever to be part of the sample.
   430  func (s *UniformSample) Max() int64 {
   431  	s.mutex.Lock()
   432  	defer s.mutex.Unlock()
   433  	return SampleMax(s.values)
   434  }
   435  
   436  // Mean returns the mean of the values in the sample.
   437  func (s *UniformSample) Mean() float64 {
   438  	s.mutex.Lock()
   439  	defer s.mutex.Unlock()
   440  	return SampleMean(s.values)
   441  }
   442  
   443  // Min returns the minimum value in the sample, which may not be the minimum
   444  // value ever to be part of the sample.
   445  func (s *UniformSample) Min() int64 {
   446  	s.mutex.Lock()
   447  	defer s.mutex.Unlock()
   448  	return SampleMin(s.values)
   449  }
   450  
   451  // Percentile returns an arbitrary percentile of values in the sample.
   452  func (s *UniformSample) Percentile(p float64) float64 {
   453  	s.mutex.Lock()
   454  	defer s.mutex.Unlock()
   455  	return SamplePercentile(s.values, p)
   456  }
   457  
   458  // Percentiles returns a slice of arbitrary percentiles of values in the
   459  // sample.
   460  func (s *UniformSample) Percentiles(ps []float64) []float64 {
   461  	s.mutex.Lock()
   462  	defer s.mutex.Unlock()
   463  	return SamplePercentiles(s.values, ps)
   464  }
   465  
   466  // Size returns the size of the sample, which is at most the reservoir size.
   467  func (s *UniformSample) Size() int {
   468  	s.mutex.Lock()
   469  	defer s.mutex.Unlock()
   470  	return len(s.values)
   471  }
   472  
   473  // Snapshot returns a read-only copy of the sample.
   474  func (s *UniformSample) Snapshot() Sample {
   475  	s.mutex.Lock()
   476  	defer s.mutex.Unlock()
   477  	values := make([]int64, len(s.values))
   478  	copy(values, s.values)
   479  	return &SampleSnapshot{
   480  		count:  s.count,
   481  		values: values,
   482  	}
   483  }
   484  
   485  // StdDev returns the standard deviation of the values in the sample.
   486  func (s *UniformSample) StdDev() float64 {
   487  	s.mutex.Lock()
   488  	defer s.mutex.Unlock()
   489  	return SampleStdDev(s.values)
   490  }
   491  
   492  // Sum returns the sum of the values in the sample.
   493  func (s *UniformSample) Sum() int64 {
   494  	s.mutex.Lock()
   495  	defer s.mutex.Unlock()
   496  	return SampleSum(s.values)
   497  }
   498  
   499  // Update samples a new value.
   500  func (s *UniformSample) Update(v int64) {
   501  	s.mutex.Lock()
   502  	defer s.mutex.Unlock()
   503  	s.count++
   504  	if len(s.values) < s.reservoirSize {
   505  		s.values = append(s.values, v)
   506  	} else {
   507  		r := rand.Int63n(s.count)
   508  		if r < int64(len(s.values)) {
   509  			s.values[int(r)] = v
   510  		}
   511  	}
   512  }
   513  
   514  // Values returns a copy of the values in the sample.
   515  func (s *UniformSample) Values() []int64 {
   516  	s.mutex.Lock()
   517  	defer s.mutex.Unlock()
   518  	values := make([]int64, len(s.values))
   519  	copy(values, s.values)
   520  	return values
   521  }
   522  
   523  // Variance returns the variance of the values in the sample.
   524  func (s *UniformSample) Variance() float64 {
   525  	s.mutex.Lock()
   526  	defer s.mutex.Unlock()
   527  	return SampleVariance(s.values)
   528  }
   529  
   530  // expDecaySample represents an individual sample in a heap.
   531  type expDecaySample struct {
   532  	k float64
   533  	v int64
   534  }
   535  
   536  func newExpDecaySampleHeap(reservoirSize int) *expDecaySampleHeap {
   537  	return &expDecaySampleHeap{make([]expDecaySample, 0, reservoirSize)}
   538  }
   539  
   540  // expDecaySampleHeap is a min-heap of expDecaySamples.
   541  // The internal implementation is copied from the standard library's container/heap
   542  type expDecaySampleHeap struct {
   543  	s []expDecaySample
   544  }
   545  
   546  func (h *expDecaySampleHeap) Clear() {
   547  	h.s = h.s[:0]
   548  }
   549  
   550  func (h *expDecaySampleHeap) Push(s expDecaySample) {
   551  	n := len(h.s)
   552  	h.s = h.s[0 : n+1]
   553  	h.s[n] = s
   554  	h.up(n)
   555  }
   556  
   557  func (h *expDecaySampleHeap) Pop() expDecaySample {
   558  	n := len(h.s) - 1
   559  	h.s[0], h.s[n] = h.s[n], h.s[0]
   560  	h.down(0, n)
   561  
   562  	n = len(h.s)
   563  	s := h.s[n-1]
   564  	h.s = h.s[0 : n-1]
   565  	return s
   566  }
   567  
   568  func (h *expDecaySampleHeap) Size() int {
   569  	return len(h.s)
   570  }
   571  
   572  func (h *expDecaySampleHeap) Values() []expDecaySample {
   573  	return h.s
   574  }
   575  
   576  func (h *expDecaySampleHeap) up(j int) {
   577  	for {
   578  		i := (j - 1) / 2 // parent
   579  		if i == j || !(h.s[j].k < h.s[i].k) {
   580  			break
   581  		}
   582  		h.s[i], h.s[j] = h.s[j], h.s[i]
   583  		j = i
   584  	}
   585  }
   586  
   587  func (h *expDecaySampleHeap) down(i, n int) {
   588  	for {
   589  		j1 := 2*i + 1
   590  		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
   591  			break
   592  		}
   593  		j := j1 // left child
   594  		if j2 := j1 + 1; j2 < n && !(h.s[j1].k < h.s[j2].k) {
   595  			j = j2 // = 2*i + 2  // right child
   596  		}
   597  		if !(h.s[j].k < h.s[i].k) {
   598  			break
   599  		}
   600  		h.s[i], h.s[j] = h.s[j], h.s[i]
   601  		i = j
   602  	}
   603  }
   604  
   605  type int64Slice []int64
   606  
   607  func (p int64Slice) Len() int           { return len(p) }
   608  func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
   609  func (p int64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }