gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/common/metrics/sample_test.go (about)

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