github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/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  type Sample interface {
    14  	Clear()
    15  	Count() int64
    16  	Max() int64
    17  	Mean() float64
    18  	Min() int64
    19  	Percentile(float64) float64
    20  	Percentiles([]float64) []float64
    21  	Size() int
    22  	Snapshot() Sample
    23  	StdDev() float64
    24  	Sum() int64
    25  	Update(int64)
    26  	Values() []int64
    27  	Variance() float64
    28  }
    29  
    30  type ExpDecaySample struct {
    31  	alpha         float64
    32  	count         int64
    33  	mutex         sync.Mutex
    34  	reservoirSize int
    35  	t0, t1        time.Time
    36  	values        *expDecaySampleHeap
    37  }
    38  
    39  func NewExpDecaySample(reservoirSize int, alpha float64) Sample {
    40  	if !Enabled {
    41  		return NilSample{}
    42  	}
    43  	s := &ExpDecaySample{
    44  		alpha:         alpha,
    45  		reservoirSize: reservoirSize,
    46  		t0:            time.Now(),
    47  		values:        newExpDecaySampleHeap(reservoirSize),
    48  	}
    49  	s.t1 = s.t0.Add(rescaleThreshold)
    50  	return s
    51  }
    52  
    53  func (s *ExpDecaySample) Clear() {
    54  	s.mutex.Lock()
    55  	defer s.mutex.Unlock()
    56  	s.count = 0
    57  	s.t0 = time.Now()
    58  	s.t1 = s.t0.Add(rescaleThreshold)
    59  	s.values.Clear()
    60  }
    61  
    62  func (s *ExpDecaySample) Count() int64 {
    63  	s.mutex.Lock()
    64  	defer s.mutex.Unlock()
    65  	return s.count
    66  }
    67  
    68  func (s *ExpDecaySample) Max() int64 {
    69  	return SampleMax(s.Values())
    70  }
    71  
    72  func (s *ExpDecaySample) Mean() float64 {
    73  	return SampleMean(s.Values())
    74  }
    75  
    76  func (s *ExpDecaySample) Min() int64 {
    77  	return SampleMin(s.Values())
    78  }
    79  
    80  func (s *ExpDecaySample) Percentile(p float64) float64 {
    81  	return SamplePercentile(s.Values(), p)
    82  }
    83  
    84  func (s *ExpDecaySample) Percentiles(ps []float64) []float64 {
    85  	return SamplePercentiles(s.Values(), ps)
    86  }
    87  
    88  func (s *ExpDecaySample) Size() int {
    89  	s.mutex.Lock()
    90  	defer s.mutex.Unlock()
    91  	return s.values.Size()
    92  }
    93  
    94  func (s *ExpDecaySample) Snapshot() Sample {
    95  	s.mutex.Lock()
    96  	defer s.mutex.Unlock()
    97  	vals := s.values.Values()
    98  	values := make([]int64, len(vals))
    99  	for i, v := range vals {
   100  		values[i] = v.v
   101  	}
   102  	return &SampleSnapshot{
   103  		count:  s.count,
   104  		values: values,
   105  	}
   106  }
   107  
   108  func (s *ExpDecaySample) StdDev() float64 {
   109  	return SampleStdDev(s.Values())
   110  }
   111  
   112  func (s *ExpDecaySample) Sum() int64 {
   113  	return SampleSum(s.Values())
   114  }
   115  
   116  func (s *ExpDecaySample) Update(v int64) {
   117  	s.update(time.Now(), v)
   118  }
   119  
   120  func (s *ExpDecaySample) Values() []int64 {
   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 values
   129  }
   130  
   131  func (s *ExpDecaySample) Variance() float64 {
   132  	return SampleVariance(s.Values())
   133  }
   134  
   135  func (s *ExpDecaySample) update(t time.Time, v int64) {
   136  	s.mutex.Lock()
   137  	defer s.mutex.Unlock()
   138  	s.count++
   139  	if s.values.Size() == s.reservoirSize {
   140  		s.values.Pop()
   141  	}
   142  	s.values.Push(expDecaySample{
   143  		k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / rand.Float64(),
   144  		v: v,
   145  	})
   146  	if t.After(s.t1) {
   147  		values := s.values.Values()
   148  		t0 := s.t0
   149  		s.values.Clear()
   150  		s.t0 = t
   151  		s.t1 = s.t0.Add(rescaleThreshold)
   152  		for _, v := range values {
   153  			v.k = v.k * math.Exp(-s.alpha*s.t0.Sub(t0).Seconds())
   154  			s.values.Push(v)
   155  		}
   156  	}
   157  }
   158  
   159  type NilSample struct{}
   160  
   161  func (NilSample) Clear() {}
   162  
   163  func (NilSample) Count() int64 { return 0 }
   164  
   165  func (NilSample) Max() int64 { return 0 }
   166  
   167  func (NilSample) Mean() float64 { return 0.0 }
   168  
   169  func (NilSample) Min() int64 { return 0 }
   170  
   171  func (NilSample) Percentile(p float64) float64 { return 0.0 }
   172  
   173  func (NilSample) Percentiles(ps []float64) []float64 {
   174  	return make([]float64, len(ps))
   175  }
   176  
   177  func (NilSample) Size() int { return 0 }
   178  
   179  func (NilSample) Snapshot() Sample { return NilSample{} }
   180  
   181  func (NilSample) StdDev() float64 { return 0.0 }
   182  
   183  func (NilSample) Sum() int64 { return 0 }
   184  
   185  func (NilSample) Update(v int64) {}
   186  
   187  func (NilSample) Values() []int64 { return []int64{} }
   188  
   189  func (NilSample) Variance() float64 { return 0.0 }
   190  
   191  func SampleMax(values []int64) int64 {
   192  	if 0 == len(values) {
   193  		return 0
   194  	}
   195  	var max int64 = math.MinInt64
   196  	for _, v := range values {
   197  		if max < v {
   198  			max = v
   199  		}
   200  	}
   201  	return max
   202  }
   203  
   204  func SampleMean(values []int64) float64 {
   205  	if 0 == len(values) {
   206  		return 0.0
   207  	}
   208  	return float64(SampleSum(values)) / float64(len(values))
   209  }
   210  
   211  func SampleMin(values []int64) int64 {
   212  	if 0 == len(values) {
   213  		return 0
   214  	}
   215  	var min int64 = math.MaxInt64
   216  	for _, v := range values {
   217  		if min > v {
   218  			min = v
   219  		}
   220  	}
   221  	return min
   222  }
   223  
   224  func SamplePercentile(values int64Slice, p float64) float64 {
   225  	return SamplePercentiles(values, []float64{p})[0]
   226  }
   227  
   228  func SamplePercentiles(values int64Slice, ps []float64) []float64 {
   229  	scores := make([]float64, len(ps))
   230  	size := len(values)
   231  	if size > 0 {
   232  		sort.Sort(values)
   233  		for i, p := range ps {
   234  			pos := p * float64(size+1)
   235  			if pos < 1.0 {
   236  				scores[i] = float64(values[0])
   237  			} else if pos >= float64(size) {
   238  				scores[i] = float64(values[size-1])
   239  			} else {
   240  				lower := float64(values[int(pos)-1])
   241  				upper := float64(values[int(pos)])
   242  				scores[i] = lower + (pos-math.Floor(pos))*(upper-lower)
   243  			}
   244  		}
   245  	}
   246  	return scores
   247  }
   248  
   249  type SampleSnapshot struct {
   250  	count  int64
   251  	values []int64
   252  }
   253  
   254  func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot {
   255  	return &SampleSnapshot{
   256  		count:  count,
   257  		values: values,
   258  	}
   259  }
   260  
   261  func (*SampleSnapshot) Clear() {
   262  	panic("Clear called on a SampleSnapshot")
   263  }
   264  
   265  func (s *SampleSnapshot) Count() int64 { return s.count }
   266  
   267  func (s *SampleSnapshot) Max() int64 { return SampleMax(s.values) }
   268  
   269  func (s *SampleSnapshot) Mean() float64 { return SampleMean(s.values) }
   270  
   271  func (s *SampleSnapshot) Min() int64 { return SampleMin(s.values) }
   272  
   273  func (s *SampleSnapshot) Percentile(p float64) float64 {
   274  	return SamplePercentile(s.values, p)
   275  }
   276  
   277  func (s *SampleSnapshot) Percentiles(ps []float64) []float64 {
   278  	return SamplePercentiles(s.values, ps)
   279  }
   280  
   281  func (s *SampleSnapshot) Size() int { return len(s.values) }
   282  
   283  func (s *SampleSnapshot) Snapshot() Sample { return s }
   284  
   285  func (s *SampleSnapshot) StdDev() float64 { return SampleStdDev(s.values) }
   286  
   287  func (s *SampleSnapshot) Sum() int64 { return SampleSum(s.values) }
   288  
   289  func (*SampleSnapshot) Update(int64) {
   290  	panic("Update called on a SampleSnapshot")
   291  }
   292  
   293  func (s *SampleSnapshot) Values() []int64 {
   294  	values := make([]int64, len(s.values))
   295  	copy(values, s.values)
   296  	return values
   297  }
   298  
   299  func (s *SampleSnapshot) Variance() float64 { return SampleVariance(s.values) }
   300  
   301  func SampleStdDev(values []int64) float64 {
   302  	return math.Sqrt(SampleVariance(values))
   303  }
   304  
   305  func SampleSum(values []int64) int64 {
   306  	var sum int64
   307  	for _, v := range values {
   308  		sum += v
   309  	}
   310  	return sum
   311  }
   312  
   313  func SampleVariance(values []int64) float64 {
   314  	if 0 == len(values) {
   315  		return 0.0
   316  	}
   317  	m := SampleMean(values)
   318  	var sum float64
   319  	for _, v := range values {
   320  		d := float64(v) - m
   321  		sum += d * d
   322  	}
   323  	return sum / float64(len(values))
   324  }
   325  
   326  type UniformSample struct {
   327  	count         int64
   328  	mutex         sync.Mutex
   329  	reservoirSize int
   330  	values        []int64
   331  }
   332  
   333  func NewUniformSample(reservoirSize int) Sample {
   334  	if !Enabled {
   335  		return NilSample{}
   336  	}
   337  	return &UniformSample{
   338  		reservoirSize: reservoirSize,
   339  		values:        make([]int64, 0, reservoirSize),
   340  	}
   341  }
   342  
   343  func (s *UniformSample) Clear() {
   344  	s.mutex.Lock()
   345  	defer s.mutex.Unlock()
   346  	s.count = 0
   347  	s.values = make([]int64, 0, s.reservoirSize)
   348  }
   349  
   350  func (s *UniformSample) Count() int64 {
   351  	s.mutex.Lock()
   352  	defer s.mutex.Unlock()
   353  	return s.count
   354  }
   355  
   356  func (s *UniformSample) Max() int64 {
   357  	s.mutex.Lock()
   358  	defer s.mutex.Unlock()
   359  	return SampleMax(s.values)
   360  }
   361  
   362  func (s *UniformSample) Mean() float64 {
   363  	s.mutex.Lock()
   364  	defer s.mutex.Unlock()
   365  	return SampleMean(s.values)
   366  }
   367  
   368  func (s *UniformSample) Min() int64 {
   369  	s.mutex.Lock()
   370  	defer s.mutex.Unlock()
   371  	return SampleMin(s.values)
   372  }
   373  
   374  func (s *UniformSample) Percentile(p float64) float64 {
   375  	s.mutex.Lock()
   376  	defer s.mutex.Unlock()
   377  	return SamplePercentile(s.values, p)
   378  }
   379  
   380  func (s *UniformSample) Percentiles(ps []float64) []float64 {
   381  	s.mutex.Lock()
   382  	defer s.mutex.Unlock()
   383  	return SamplePercentiles(s.values, ps)
   384  }
   385  
   386  func (s *UniformSample) Size() int {
   387  	s.mutex.Lock()
   388  	defer s.mutex.Unlock()
   389  	return len(s.values)
   390  }
   391  
   392  func (s *UniformSample) Snapshot() Sample {
   393  	s.mutex.Lock()
   394  	defer s.mutex.Unlock()
   395  	values := make([]int64, len(s.values))
   396  	copy(values, s.values)
   397  	return &SampleSnapshot{
   398  		count:  s.count,
   399  		values: values,
   400  	}
   401  }
   402  
   403  func (s *UniformSample) StdDev() float64 {
   404  	s.mutex.Lock()
   405  	defer s.mutex.Unlock()
   406  	return SampleStdDev(s.values)
   407  }
   408  
   409  func (s *UniformSample) Sum() int64 {
   410  	s.mutex.Lock()
   411  	defer s.mutex.Unlock()
   412  	return SampleSum(s.values)
   413  }
   414  
   415  func (s *UniformSample) Update(v int64) {
   416  	s.mutex.Lock()
   417  	defer s.mutex.Unlock()
   418  	s.count++
   419  	if len(s.values) < s.reservoirSize {
   420  		s.values = append(s.values, v)
   421  	} else {
   422  		r := rand.Int63n(s.count)
   423  		if r < int64(len(s.values)) {
   424  			s.values[int(r)] = v
   425  		}
   426  	}
   427  }
   428  
   429  func (s *UniformSample) Values() []int64 {
   430  	s.mutex.Lock()
   431  	defer s.mutex.Unlock()
   432  	values := make([]int64, len(s.values))
   433  	copy(values, s.values)
   434  	return values
   435  }
   436  
   437  func (s *UniformSample) Variance() float64 {
   438  	s.mutex.Lock()
   439  	defer s.mutex.Unlock()
   440  	return SampleVariance(s.values)
   441  }
   442  
   443  type expDecaySample struct {
   444  	k float64
   445  	v int64
   446  }
   447  
   448  func newExpDecaySampleHeap(reservoirSize int) *expDecaySampleHeap {
   449  	return &expDecaySampleHeap{make([]expDecaySample, 0, reservoirSize)}
   450  }
   451  
   452  type expDecaySampleHeap struct {
   453  	s []expDecaySample
   454  }
   455  
   456  func (h *expDecaySampleHeap) Clear() {
   457  	h.s = h.s[:0]
   458  }
   459  
   460  func (h *expDecaySampleHeap) Push(s expDecaySample) {
   461  	n := len(h.s)
   462  	h.s = h.s[0 : n+1]
   463  	h.s[n] = s
   464  	h.up(n)
   465  }
   466  
   467  func (h *expDecaySampleHeap) Pop() expDecaySample {
   468  	n := len(h.s) - 1
   469  	h.s[0], h.s[n] = h.s[n], h.s[0]
   470  	h.down(0, n)
   471  
   472  	n = len(h.s)
   473  	s := h.s[n-1]
   474  	h.s = h.s[0 : n-1]
   475  	return s
   476  }
   477  
   478  func (h *expDecaySampleHeap) Size() int {
   479  	return len(h.s)
   480  }
   481  
   482  func (h *expDecaySampleHeap) Values() []expDecaySample {
   483  	return h.s
   484  }
   485  
   486  func (h *expDecaySampleHeap) up(j int) {
   487  	for {
   488  		i := (j - 1) / 2
   489  		if i == j || !(h.s[j].k < h.s[i].k) {
   490  			break
   491  		}
   492  		h.s[i], h.s[j] = h.s[j], h.s[i]
   493  		j = i
   494  	}
   495  }
   496  
   497  func (h *expDecaySampleHeap) down(i, n int) {
   498  	for {
   499  		j1 := 2*i + 1
   500  		if j1 >= n || j1 < 0 {
   501  			break
   502  		}
   503  		j := j1
   504  		if j2 := j1 + 1; j2 < n && !(h.s[j1].k < h.s[j2].k) {
   505  			j = j2
   506  		}
   507  		if !(h.s[j].k < h.s[i].k) {
   508  			break
   509  		}
   510  		h.s[i], h.s[j] = h.s[j], h.s[i]
   511  		i = j
   512  	}
   513  }
   514  
   515  type int64Slice []int64
   516  
   517  func (p int64Slice) Len() int           { return len(p) }
   518  func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
   519  func (p int64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }