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