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 }