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