github.com/MikyChow/arbitrum-go-ethereum@v0.0.0-20230306102812-078da49636de/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  	rand.Seed(1)
    96  	s := NewExpDecaySample(100, 0.99)
    97  	for i := 0; i < 10; i++ {
    98  		s.Update(int64(i))
    99  	}
   100  	if size := s.Count(); size != 10 {
   101  		t.Errorf("s.Count(): 10 != %v\n", size)
   102  	}
   103  	if size := s.Size(); size != 10 {
   104  		t.Errorf("s.Size(): 10 != %v\n", size)
   105  	}
   106  	if l := len(s.Values()); l != 10 {
   107  		t.Errorf("len(s.Values()): 10 != %v\n", l)
   108  	}
   109  	for _, v := range s.Values() {
   110  		if v > 10 || v < 0 {
   111  			t.Errorf("out of range [0, 10): %v\n", v)
   112  		}
   113  	}
   114  }
   115  
   116  func TestExpDecaySample100(t *testing.T) {
   117  	rand.Seed(1)
   118  	s := NewExpDecaySample(1000, 0.01)
   119  	for i := 0; i < 100; i++ {
   120  		s.Update(int64(i))
   121  	}
   122  	if size := s.Count(); size != 100 {
   123  		t.Errorf("s.Count(): 100 != %v\n", size)
   124  	}
   125  	if size := s.Size(); size != 100 {
   126  		t.Errorf("s.Size(): 100 != %v\n", size)
   127  	}
   128  	if l := len(s.Values()); l != 100 {
   129  		t.Errorf("len(s.Values()): 100 != %v\n", l)
   130  	}
   131  	for _, v := range s.Values() {
   132  		if v > 100 || v < 0 {
   133  			t.Errorf("out of range [0, 100): %v\n", v)
   134  		}
   135  	}
   136  }
   137  
   138  func TestExpDecaySample1000(t *testing.T) {
   139  	rand.Seed(1)
   140  	s := NewExpDecaySample(100, 0.99)
   141  	for i := 0; i < 1000; i++ {
   142  		s.Update(int64(i))
   143  	}
   144  	if size := s.Count(); size != 1000 {
   145  		t.Errorf("s.Count(): 1000 != %v\n", size)
   146  	}
   147  	if size := s.Size(); size != 100 {
   148  		t.Errorf("s.Size(): 100 != %v\n", size)
   149  	}
   150  	if l := len(s.Values()); l != 100 {
   151  		t.Errorf("len(s.Values()): 100 != %v\n", l)
   152  	}
   153  	for _, v := range s.Values() {
   154  		if v > 1000 || v < 0 {
   155  			t.Errorf("out of range [0, 1000): %v\n", v)
   156  		}
   157  	}
   158  }
   159  
   160  // This test makes sure that the sample's priority is not amplified by using
   161  // nanosecond duration since start rather than second duration since start.
   162  // The priority becomes +Inf quickly after starting if this is done,
   163  // effectively freezing the set of samples until a rescale step happens.
   164  func TestExpDecaySampleNanosecondRegression(t *testing.T) {
   165  	rand.Seed(1)
   166  	s := NewExpDecaySample(100, 0.99)
   167  	for i := 0; i < 100; i++ {
   168  		s.Update(10)
   169  	}
   170  	time.Sleep(1 * time.Millisecond)
   171  	for i := 0; i < 100; i++ {
   172  		s.Update(20)
   173  	}
   174  	v := s.Values()
   175  	avg := float64(0)
   176  	for i := 0; i < len(v); i++ {
   177  		avg += float64(v[i])
   178  	}
   179  	avg /= float64(len(v))
   180  	if avg > 16 || avg < 14 {
   181  		t.Errorf("out of range [14, 16]: %v\n", avg)
   182  	}
   183  }
   184  
   185  func TestExpDecaySampleRescale(t *testing.T) {
   186  	s := NewExpDecaySample(2, 0.001).(*ExpDecaySample)
   187  	s.update(time.Now(), 1)
   188  	s.update(time.Now().Add(time.Hour+time.Microsecond), 1)
   189  	for _, v := range s.values.Values() {
   190  		if v.k == 0.0 {
   191  			t.Fatal("v.k == 0.0")
   192  		}
   193  	}
   194  }
   195  
   196  func TestExpDecaySampleSnapshot(t *testing.T) {
   197  	now := time.Now()
   198  	rand.Seed(1)
   199  	s := NewExpDecaySample(100, 0.99)
   200  	for i := 1; i <= 10000; i++ {
   201  		s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i))
   202  	}
   203  	snapshot := s.Snapshot()
   204  	s.Update(1)
   205  	testExpDecaySampleStatistics(t, snapshot)
   206  }
   207  
   208  func TestExpDecaySampleStatistics(t *testing.T) {
   209  	now := time.Now()
   210  	rand.Seed(1)
   211  	s := NewExpDecaySample(100, 0.99)
   212  	for i := 1; i <= 10000; i++ {
   213  		s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i))
   214  	}
   215  	testExpDecaySampleStatistics(t, s)
   216  }
   217  
   218  func TestUniformSample(t *testing.T) {
   219  	rand.Seed(1)
   220  	s := NewUniformSample(100)
   221  	for i := 0; i < 1000; i++ {
   222  		s.Update(int64(i))
   223  	}
   224  	if size := s.Count(); size != 1000 {
   225  		t.Errorf("s.Count(): 1000 != %v\n", size)
   226  	}
   227  	if size := s.Size(); size != 100 {
   228  		t.Errorf("s.Size(): 100 != %v\n", size)
   229  	}
   230  	if l := len(s.Values()); l != 100 {
   231  		t.Errorf("len(s.Values()): 100 != %v\n", l)
   232  	}
   233  	for _, v := range s.Values() {
   234  		if v > 1000 || v < 0 {
   235  			t.Errorf("out of range [0, 100): %v\n", v)
   236  		}
   237  	}
   238  }
   239  
   240  func TestUniformSampleIncludesTail(t *testing.T) {
   241  	rand.Seed(1)
   242  	s := NewUniformSample(100)
   243  	max := 100
   244  	for i := 0; i < max; i++ {
   245  		s.Update(int64(i))
   246  	}
   247  	v := s.Values()
   248  	sum := 0
   249  	exp := (max - 1) * max / 2
   250  	for i := 0; i < len(v); i++ {
   251  		sum += int(v[i])
   252  	}
   253  	if exp != sum {
   254  		t.Errorf("sum: %v != %v\n", exp, sum)
   255  	}
   256  }
   257  
   258  func TestUniformSampleSnapshot(t *testing.T) {
   259  	s := NewUniformSample(100)
   260  	for i := 1; i <= 10000; i++ {
   261  		s.Update(int64(i))
   262  	}
   263  	snapshot := s.Snapshot()
   264  	s.Update(1)
   265  	testUniformSampleStatistics(t, snapshot)
   266  }
   267  
   268  func TestUniformSampleStatistics(t *testing.T) {
   269  	rand.Seed(1)
   270  	s := NewUniformSample(100)
   271  	for i := 1; i <= 10000; i++ {
   272  		s.Update(int64(i))
   273  	}
   274  	testUniformSampleStatistics(t, s)
   275  }
   276  
   277  func benchmarkSample(b *testing.B, s Sample) {
   278  	var memStats runtime.MemStats
   279  	runtime.ReadMemStats(&memStats)
   280  	pauseTotalNs := memStats.PauseTotalNs
   281  	b.ResetTimer()
   282  	for i := 0; i < b.N; i++ {
   283  		s.Update(1)
   284  	}
   285  	b.StopTimer()
   286  	runtime.GC()
   287  	runtime.ReadMemStats(&memStats)
   288  	b.Logf("GC cost: %d ns/op", int(memStats.PauseTotalNs-pauseTotalNs)/b.N)
   289  }
   290  
   291  func testExpDecaySampleStatistics(t *testing.T, s Sample) {
   292  	if count := s.Count(); count != 10000 {
   293  		t.Errorf("s.Count(): 10000 != %v\n", count)
   294  	}
   295  	if min := s.Min(); min != 107 {
   296  		t.Errorf("s.Min(): 107 != %v\n", min)
   297  	}
   298  	if max := s.Max(); max != 10000 {
   299  		t.Errorf("s.Max(): 10000 != %v\n", max)
   300  	}
   301  	if mean := s.Mean(); mean != 4965.98 {
   302  		t.Errorf("s.Mean(): 4965.98 != %v\n", mean)
   303  	}
   304  	if stdDev := s.StdDev(); stdDev != 2959.825156930727 {
   305  		t.Errorf("s.StdDev(): 2959.825156930727 != %v\n", stdDev)
   306  	}
   307  	ps := s.Percentiles([]float64{0.5, 0.75, 0.99})
   308  	if ps[0] != 4615 {
   309  		t.Errorf("median: 4615 != %v\n", ps[0])
   310  	}
   311  	if ps[1] != 7672 {
   312  		t.Errorf("75th percentile: 7672 != %v\n", ps[1])
   313  	}
   314  	if ps[2] != 9998.99 {
   315  		t.Errorf("99th percentile: 9998.99 != %v\n", ps[2])
   316  	}
   317  }
   318  
   319  func testUniformSampleStatistics(t *testing.T, s Sample) {
   320  	if count := s.Count(); count != 10000 {
   321  		t.Errorf("s.Count(): 10000 != %v\n", count)
   322  	}
   323  	if min := s.Min(); min != 37 {
   324  		t.Errorf("s.Min(): 37 != %v\n", min)
   325  	}
   326  	if max := s.Max(); max != 9989 {
   327  		t.Errorf("s.Max(): 9989 != %v\n", max)
   328  	}
   329  	if mean := s.Mean(); mean != 4748.14 {
   330  		t.Errorf("s.Mean(): 4748.14 != %v\n", mean)
   331  	}
   332  	if stdDev := s.StdDev(); stdDev != 2826.684117548333 {
   333  		t.Errorf("s.StdDev(): 2826.684117548333 != %v\n", stdDev)
   334  	}
   335  	ps := s.Percentiles([]float64{0.5, 0.75, 0.99})
   336  	if ps[0] != 4599 {
   337  		t.Errorf("median: 4599 != %v\n", ps[0])
   338  	}
   339  	if ps[1] != 7380.5 {
   340  		t.Errorf("75th percentile: 7380.5 != %v\n", ps[1])
   341  	}
   342  	if math.Abs(9986.429999999998-ps[2]) > epsilonPercentile {
   343  		t.Errorf("99th percentile: 9986.429999999998 != %v\n", ps[2])
   344  	}
   345  }
   346  
   347  // TestUniformSampleConcurrentUpdateCount would expose data race problems with
   348  // concurrent Update and Count calls on Sample when test is called with -race
   349  // argument
   350  func TestUniformSampleConcurrentUpdateCount(t *testing.T) {
   351  	if testing.Short() {
   352  		t.Skip("skipping in short mode")
   353  	}
   354  	s := NewUniformSample(100)
   355  	for i := 0; i < 100; i++ {
   356  		s.Update(int64(i))
   357  	}
   358  	quit := make(chan struct{})
   359  	go func() {
   360  		t := time.NewTicker(10 * time.Millisecond)
   361  		defer t.Stop()
   362  		for {
   363  			select {
   364  			case <-t.C:
   365  				s.Update(rand.Int63())
   366  			case <-quit:
   367  				t.Stop()
   368  				return
   369  			}
   370  		}
   371  	}()
   372  	for i := 0; i < 1000; i++ {
   373  		s.Count()
   374  		time.Sleep(5 * time.Millisecond)
   375  	}
   376  	quit <- struct{}{}
   377  }