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

     1  package metrics
     2  
     3  import (
     4  	"math"
     5  	"math/rand"
     6  	"runtime"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  // Benchmark{Compute,Copy}{1000,1000000} demonstrate that, even for relatively
    12  // expensive computations like Variance, the cost of copying the Sample, as
    13  // approximated by a make and copy, is much greater than the cost of the
    14  // computation for small samples and only slightly less for large samples.
    15  func BenchmarkCompute1000(b *testing.B) {
    16  	s := make([]int64, 1000)
    17  	for i := 0; i < len(s); i++ {
    18  		s[i] = int64(i)
    19  	}
    20  	b.ResetTimer()
    21  	for i := 0; i < b.N; i++ {
    22  		SampleVariance(s)
    23  	}
    24  }
    25  func BenchmarkCompute1000000(b *testing.B) {
    26  	s := make([]int64, 1000000)
    27  	for i := 0; i < len(s); i++ {
    28  		s[i] = int64(i)
    29  	}
    30  	b.ResetTimer()
    31  	for i := 0; i < b.N; i++ {
    32  		SampleVariance(s)
    33  	}
    34  }
    35  func BenchmarkCopy1000(b *testing.B) {
    36  	s := make([]int64, 1000)
    37  	for i := 0; i < len(s); i++ {
    38  		s[i] = int64(i)
    39  	}
    40  	b.ResetTimer()
    41  	for i := 0; i < b.N; i++ {
    42  		sCopy := make([]int64, len(s))
    43  		copy(sCopy, s)
    44  	}
    45  }
    46  func BenchmarkCopy1000000(b *testing.B) {
    47  	s := make([]int64, 1000000)
    48  	for i := 0; i < len(s); i++ {
    49  		s[i] = int64(i)
    50  	}
    51  	b.ResetTimer()
    52  	for i := 0; i < b.N; i++ {
    53  		sCopy := make([]int64, len(s))
    54  		copy(sCopy, s)
    55  	}
    56  }
    57  
    58  func BenchmarkExpDecaySample257(b *testing.B) {
    59  	benchmarkSample(b, NewExpDecaySample(257, 0.015))
    60  }
    61  
    62  func BenchmarkExpDecaySample514(b *testing.B) {
    63  	benchmarkSample(b, NewExpDecaySample(514, 0.015))
    64  }
    65  
    66  func BenchmarkExpDecaySample1028(b *testing.B) {
    67  	benchmarkSample(b, NewExpDecaySample(1028, 0.015))
    68  }
    69  
    70  func BenchmarkUniformSample257(b *testing.B) {
    71  	benchmarkSample(b, NewUniformSample(257))
    72  }
    73  
    74  func BenchmarkUniformSample514(b *testing.B) {
    75  	benchmarkSample(b, NewUniformSample(514))
    76  }
    77  
    78  func BenchmarkUniformSample1028(b *testing.B) {
    79  	benchmarkSample(b, NewUniformSample(1028))
    80  }
    81  
    82  func BenchmarkSlidingWindowArraySample257(b *testing.B) {
    83  	benchmarkSample(b, NewSlidingTimeWindowArraySample(257))
    84  }
    85  
    86  func BenchmarkSlidingWindowArraySample514(b *testing.B) {
    87  	benchmarkSample(b, NewSlidingTimeWindowArraySample(514))
    88  }
    89  
    90  func BenchmarkSlidingWindowArraySample1028(b *testing.B) {
    91  	benchmarkSample(b, NewSlidingTimeWindowArraySample(1028))
    92  }
    93  
    94  func TestExpDecaySample10(t *testing.T) {
    95  	s := NewExpDecaySample(100, 0.99)
    96  	for i := 0; i < 10; i++ {
    97  		s.Update(int64(i))
    98  	}
    99  	if size := s.Count(); size != 10 {
   100  		t.Errorf("s.Count(): 10 != %v\n", size)
   101  	}
   102  	if size := s.Size(); size != 10 {
   103  		t.Errorf("s.Size(): 10 != %v\n", size)
   104  	}
   105  	if l := len(s.Values()); l != 10 {
   106  		t.Errorf("len(s.Values()): 10 != %v\n", l)
   107  	}
   108  	for _, v := range s.Values() {
   109  		if v > 10 || v < 0 {
   110  			t.Errorf("out of range [0, 10): %v\n", v)
   111  		}
   112  	}
   113  }
   114  
   115  func TestExpDecaySample100(t *testing.T) {
   116  	s := NewExpDecaySample(1000, 0.01)
   117  	for i := 0; i < 100; i++ {
   118  		s.Update(int64(i))
   119  	}
   120  	if size := s.Count(); size != 100 {
   121  		t.Errorf("s.Count(): 100 != %v\n", size)
   122  	}
   123  	if size := s.Size(); size != 100 {
   124  		t.Errorf("s.Size(): 100 != %v\n", size)
   125  	}
   126  	if l := len(s.Values()); l != 100 {
   127  		t.Errorf("len(s.Values()): 100 != %v\n", l)
   128  	}
   129  	for _, v := range s.Values() {
   130  		if v > 100 || v < 0 {
   131  			t.Errorf("out of range [0, 100): %v\n", v)
   132  		}
   133  	}
   134  }
   135  
   136  func TestExpDecaySample1000(t *testing.T) {
   137  	s := NewExpDecaySample(100, 0.99)
   138  	for i := 0; i < 1000; i++ {
   139  		s.Update(int64(i))
   140  	}
   141  	if size := s.Count(); size != 1000 {
   142  		t.Errorf("s.Count(): 1000 != %v\n", size)
   143  	}
   144  	if size := s.Size(); size != 100 {
   145  		t.Errorf("s.Size(): 100 != %v\n", size)
   146  	}
   147  	if l := len(s.Values()); l != 100 {
   148  		t.Errorf("len(s.Values()): 100 != %v\n", l)
   149  	}
   150  	for _, v := range s.Values() {
   151  		if v > 1000 || v < 0 {
   152  			t.Errorf("out of range [0, 1000): %v\n", v)
   153  		}
   154  	}
   155  }
   156  
   157  // This test makes sure that the sample's priority is not amplified by using
   158  // nanosecond duration since start rather than second duration since start.
   159  // The priority becomes +Inf quickly after starting if this is done,
   160  // effectively freezing the set of samples until a rescale step happens.
   161  func TestExpDecaySampleNanosecondRegression(t *testing.T) {
   162  	s := NewExpDecaySample(100, 0.99)
   163  	for i := 0; i < 100; i++ {
   164  		s.Update(10)
   165  	}
   166  	time.Sleep(1 * time.Millisecond)
   167  	for i := 0; i < 100; i++ {
   168  		s.Update(20)
   169  	}
   170  	v := s.Values()
   171  	avg := float64(0)
   172  	for i := 0; i < len(v); i++ {
   173  		avg += float64(v[i])
   174  	}
   175  	avg /= float64(len(v))
   176  	if avg > 16 || avg < 14 {
   177  		t.Errorf("out of range [14, 16]: %v\n", avg)
   178  	}
   179  }
   180  
   181  func TestExpDecaySampleRescale(t *testing.T) {
   182  	s := NewExpDecaySample(2, 0.001).(*ExpDecaySample)
   183  	s.update(time.Now(), 1)
   184  	s.update(time.Now().Add(time.Hour+time.Microsecond), 1)
   185  	for _, v := range s.values.Values() {
   186  		if v.k == 0.0 {
   187  			t.Fatal("v.k == 0.0")
   188  		}
   189  	}
   190  }
   191  
   192  func TestExpDecaySampleSnapshot(t *testing.T) {
   193  	now := time.Now()
   194  	s := NewExpDecaySample(100, 0.99).(*ExpDecaySample).SetRand(rand.New(rand.NewSource(1)))
   195  	for i := 1; i <= 10000; i++ {
   196  		s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i))
   197  	}
   198  	snapshot := s.Snapshot()
   199  	s.Update(1)
   200  	testExpDecaySampleStatistics(t, snapshot)
   201  }
   202  
   203  func TestExpDecaySampleStatistics(t *testing.T) {
   204  	now := time.Now()
   205  	s := NewExpDecaySample(100, 0.99).(*ExpDecaySample).SetRand(rand.New(rand.NewSource(1)))
   206  	for i := 1; i <= 10000; i++ {
   207  		s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i))
   208  	}
   209  	testExpDecaySampleStatistics(t, s)
   210  }
   211  
   212  func TestUniformSample(t *testing.T) {
   213  	s := NewUniformSample(100)
   214  	for i := 0; i < 1000; i++ {
   215  		s.Update(int64(i))
   216  	}
   217  	if size := s.Count(); size != 1000 {
   218  		t.Errorf("s.Count(): 1000 != %v\n", size)
   219  	}
   220  	if size := s.Size(); size != 100 {
   221  		t.Errorf("s.Size(): 100 != %v\n", size)
   222  	}
   223  	if l := len(s.Values()); l != 100 {
   224  		t.Errorf("len(s.Values()): 100 != %v\n", l)
   225  	}
   226  	for _, v := range s.Values() {
   227  		if v > 1000 || v < 0 {
   228  			t.Errorf("out of range [0, 100): %v\n", v)
   229  		}
   230  	}
   231  }
   232  
   233  func TestUniformSampleIncludesTail(t *testing.T) {
   234  	s := NewUniformSample(100)
   235  	max := 100
   236  	for i := 0; i < max; i++ {
   237  		s.Update(int64(i))
   238  	}
   239  	v := s.Values()
   240  	sum := 0
   241  	exp := (max - 1) * max / 2
   242  	for i := 0; i < len(v); i++ {
   243  		sum += int(v[i])
   244  	}
   245  	if exp != sum {
   246  		t.Errorf("sum: %v != %v\n", exp, sum)
   247  	}
   248  }
   249  
   250  func TestUniformSampleSnapshot(t *testing.T) {
   251  	s := NewUniformSample(100).(*UniformSample).SetRand(rand.New(rand.NewSource(1)))
   252  	for i := 1; i <= 10000; i++ {
   253  		s.Update(int64(i))
   254  	}
   255  	snapshot := s.Snapshot()
   256  	s.Update(1)
   257  	testUniformSampleStatistics(t, snapshot)
   258  }
   259  
   260  func TestUniformSampleStatistics(t *testing.T) {
   261  	s := NewUniformSample(100).(*UniformSample).SetRand(rand.New(rand.NewSource(1)))
   262  	for i := 1; i <= 10000; i++ {
   263  		s.Update(int64(i))
   264  	}
   265  	testUniformSampleStatistics(t, s)
   266  }
   267  
   268  func benchmarkSample(b *testing.B, s Sample) {
   269  	var memStats runtime.MemStats
   270  	runtime.ReadMemStats(&memStats)
   271  	pauseTotalNs := memStats.PauseTotalNs
   272  	b.ResetTimer()
   273  	for i := 0; i < b.N; i++ {
   274  		s.Update(1)
   275  	}
   276  	b.StopTimer()
   277  	runtime.GC()
   278  	runtime.ReadMemStats(&memStats)
   279  	b.Logf("GC cost: %d ns/op", int(memStats.PauseTotalNs-pauseTotalNs)/b.N)
   280  }
   281  
   282  func testExpDecaySampleStatistics(t *testing.T, s Sample) {
   283  	if count := s.Count(); count != 10000 {
   284  		t.Errorf("s.Count(): 10000 != %v\n", count)
   285  	}
   286  	if min := s.Min(); min != 107 {
   287  		t.Errorf("s.Min(): 107 != %v\n", min)
   288  	}
   289  	if max := s.Max(); max != 10000 {
   290  		t.Errorf("s.Max(): 10000 != %v\n", max)
   291  	}
   292  	if mean := s.Mean(); mean != 4965.98 {
   293  		t.Errorf("s.Mean(): 4965.98 != %v\n", mean)
   294  	}
   295  	if stdDev := s.StdDev(); stdDev != 2959.825156930727 {
   296  		t.Errorf("s.StdDev(): 2959.825156930727 != %v\n", stdDev)
   297  	}
   298  	ps := s.Percentiles([]float64{0.5, 0.75, 0.99})
   299  	if ps[0] != 4615 {
   300  		t.Errorf("median: 4615 != %v\n", ps[0])
   301  	}
   302  	if ps[1] != 7672 {
   303  		t.Errorf("75th percentile: 7672 != %v\n", ps[1])
   304  	}
   305  	if ps[2] != 9998.99 {
   306  		t.Errorf("99th percentile: 9998.99 != %v\n", ps[2])
   307  	}
   308  }
   309  
   310  func testUniformSampleStatistics(t *testing.T, s Sample) {
   311  	if count := s.Count(); count != 10000 {
   312  		t.Errorf("s.Count(): 10000 != %v\n", count)
   313  	}
   314  	if min := s.Min(); min != 37 {
   315  		t.Errorf("s.Min(): 37 != %v\n", min)
   316  	}
   317  	if max := s.Max(); max != 9989 {
   318  		t.Errorf("s.Max(): 9989 != %v\n", max)
   319  	}
   320  	if mean := s.Mean(); mean != 4748.14 {
   321  		t.Errorf("s.Mean(): 4748.14 != %v\n", mean)
   322  	}
   323  	if stdDev := s.StdDev(); stdDev != 2826.684117548333 {
   324  		t.Errorf("s.StdDev(): 2826.684117548333 != %v\n", stdDev)
   325  	}
   326  	ps := s.Percentiles([]float64{0.5, 0.75, 0.99})
   327  	if ps[0] != 4599 {
   328  		t.Errorf("median: 4599 != %v\n", ps[0])
   329  	}
   330  	if ps[1] != 7380.5 {
   331  		t.Errorf("75th percentile: 7380.5 != %v\n", ps[1])
   332  	}
   333  	if math.Abs(9986.429999999998-ps[2]) > epsilonPercentile {
   334  		t.Errorf("99th percentile: 9986.429999999998 != %v\n", ps[2])
   335  	}
   336  }
   337  
   338  // TestUniformSampleConcurrentUpdateCount would expose data race problems with
   339  // concurrent Update and Count calls on Sample when test is called with -race
   340  // argument
   341  func TestUniformSampleConcurrentUpdateCount(t *testing.T) {
   342  	if testing.Short() {
   343  		t.Skip("skipping in short mode")
   344  	}
   345  	s := NewUniformSample(100)
   346  	for i := 0; i < 100; i++ {
   347  		s.Update(int64(i))
   348  	}
   349  	quit := make(chan struct{})
   350  	go func() {
   351  		t := time.NewTicker(10 * time.Millisecond)
   352  		defer t.Stop()
   353  		for {
   354  			select {
   355  			case <-t.C:
   356  				s.Update(rand.Int63())
   357  			case <-quit:
   358  				t.Stop()
   359  				return
   360  			}
   361  		}
   362  	}()
   363  	for i := 0; i < 1000; i++ {
   364  		s.Count()
   365  		time.Sleep(5 * time.Millisecond)
   366  	}
   367  	quit <- struct{}{}
   368  }