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 }