github.com/influxdata/influxdb/v2@v2.7.6/tsdb/series_set_test.go (about) 1 package tsdb 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "math/rand" 8 "runtime" 9 "sync" 10 "testing" 11 ) 12 13 func TestSeriesIDSet_AndNot(t *testing.T) { 14 examples := [][3][]uint64{ 15 { 16 {1, 10, 20, 30}, 17 {10, 12, 13, 14, 20}, 18 {1, 30}, 19 }, 20 { 21 {}, 22 {10}, 23 {}, 24 }, 25 { 26 {1, 10, 20, 30}, 27 {1, 10, 20, 30}, 28 {}, 29 }, 30 { 31 {1, 10}, 32 {1, 10, 100}, 33 {}, 34 }, 35 { 36 {1, 10}, 37 {}, 38 {1, 10}, 39 }, 40 } 41 42 for i, example := range examples { 43 t.Run(fmt.Sprint(i), func(t *testing.T) { 44 // Build sets. 45 a, b := NewSeriesIDSet(), NewSeriesIDSet() 46 for _, v := range example[0] { 47 a.Add(v) 48 } 49 for _, v := range example[1] { 50 b.Add(v) 51 } 52 53 expected := NewSeriesIDSet() 54 for _, v := range example[2] { 55 expected.Add(v) 56 } 57 58 got := a.AndNot(b) 59 if got.String() != expected.String() { 60 t.Fatalf("got %s, expected %s", got.String(), expected.String()) 61 } 62 }) 63 } 64 } 65 66 // Ensure that cloning is race-free. 67 func TestSeriesIDSet_Clone_Race(t *testing.T) { 68 main := NewSeriesIDSet() 69 total := NewSeriesIDSet() 70 for i := uint64(0); i < 1024; i++ { 71 main.AddNoLock(i) 72 total.AddNoLock(i) 73 } 74 75 // One test with a closure around the main SeriesIDSet, 76 // so that we can run a subtest with and without COW. 77 test := func(t *testing.T) { 78 n := 10 * (runtime.NumCPU() + 1) 79 clones := make([]*SeriesIDSet, n) 80 var wg sync.WaitGroup 81 wg.Add(n) 82 for i := 1; i <= n; i++ { 83 go func(i int) { 84 defer wg.Done() 85 clones[i-1] = main.Clone() 86 87 for j := 0; j < 1000; j++ { 88 id := uint64(j + (100000 * i)) 89 total.Add(id) 90 clones[i-1].AddNoLock(id) 91 } 92 }(i) 93 } 94 95 wg.Wait() 96 for _, o := range clones { 97 if got, exp := o.Cardinality(), uint64(2024); got != exp { 98 t.Errorf("got cardinality %d, expected %d", got, exp) 99 } 100 } 101 102 // The original set should be unaffected 103 if got, exp := main.Cardinality(), uint64(1024); got != exp { 104 t.Errorf("got cardinality %d, expected %d", got, exp) 105 } 106 107 // Merging the clones should result in only 1024 shared values. 108 union := NewSeriesIDSet() 109 for _, o := range clones { 110 o.ForEachNoLock(func(id uint64) { 111 union.AddNoLock(id) 112 }) 113 } 114 115 if !union.Equals(total) { 116 t.Fatal("union not equal to total") 117 } 118 } 119 t.Run("clone", test) 120 } 121 122 var resultBool bool 123 124 // Contains should be typically a constant time lookup. Example results on a laptop: 125 // 126 // BenchmarkSeriesIDSet_Contains/1-4 20000000 68.5 ns/op 0 B/op 0 allocs/op 127 // BenchmarkSeriesIDSet_Contains/2-4 20000000 70.8 ns/op 0 B/op 0 allocs/op 128 // BenchmarkSeriesIDSet_Contains/10-4 20000000 70.3 ns/op 0 B/op 0 allocs/op 129 // BenchmarkSeriesIDSet_Contains/100-4 20000000 71.3 ns/op 0 B/op 0 allocs/op 130 // BenchmarkSeriesIDSet_Contains/1000-4 20000000 80.5 ns/op 0 B/op 0 allocs/op 131 // BenchmarkSeriesIDSet_Contains/10000-4 20000000 67.3 ns/op 0 B/op 0 allocs/op 132 // BenchmarkSeriesIDSet_Contains/100000-4 20000000 73.1 ns/op 0 B/op 0 allocs/op 133 // BenchmarkSeriesIDSet_Contains/1000000-4 20000000 77.3 ns/op 0 B/op 0 allocs/op 134 // BenchmarkSeriesIDSet_Contains/10000000-4 20000000 75.3 ns/op 0 B/op 0 allocs/op 135 func BenchmarkSeriesIDSet_Contains(b *testing.B) { 136 cardinalities := []uint64{1, 2, 10, 100, 1000, 10000, 100000, 1000000, 10000000} 137 138 for _, cardinality := range cardinalities { 139 // Setup... 140 set := NewSeriesIDSet() 141 for i := uint64(0); i < cardinality; i++ { 142 set.Add(i) 143 } 144 145 lookup := cardinality / 2 146 b.Run(fmt.Sprint(cardinality), func(b *testing.B) { 147 for i := 0; i < b.N; i++ { 148 resultBool = set.Contains(lookup) 149 } 150 }) 151 } 152 } 153 154 var set *SeriesIDSet 155 156 // Adding to a larger bitset shouldn't be significantly more expensive than adding 157 // to a smaller one. This benchmark adds a value to different cardinality sets. 158 // 159 // Example results from a laptop: 160 // BenchmarkSeriesIDSet_Add/1-4 1000000 1053 ns/op 48 B/op 2 allocs/op 161 // BenchmarkSeriesIDSet_Add/2-4 5000000 303 ns/op 0 B/op 0 allocs/op 162 // BenchmarkSeriesIDSet_Add/10-4 5000000 348 ns/op 0 B/op 0 allocs/op 163 // BenchmarkSeriesIDSet_Add/100-4 5000000 373 ns/op 0 B/op 0 allocs/op 164 // BenchmarkSeriesIDSet_Add/1000-4 5000000 342 ns/op 0 B/op 0 allocs/op 165 func BenchmarkSeriesIDSet_AddMore(b *testing.B) { 166 cardinalities := []uint64{1, 2, 10, 100, 1000, 10000, 100000, 1000000, 10000000} 167 168 for _, cardinality := range cardinalities { 169 // Setup... 170 set = NewSeriesIDSet() 171 for i := uint64(0); i < cardinality-1; i++ { 172 set.Add(i) 173 } 174 175 b.Run(fmt.Sprint(cardinality), func(b *testing.B) { 176 for i := 0; i < b.N; i++ { 177 // Add next value 178 set.Add(cardinality) 179 180 b.StopTimer() 181 set.Remove(cardinality) 182 b.StartTimer() 183 } 184 }) 185 } 186 } 187 188 // Add benchmarks the cost of adding the same element to a set versus the 189 // cost of checking if it exists before adding it. 190 // 191 // Typical benchmarks from a laptop: 192 // 193 // BenchmarkSeriesIDSet_Add/cardinality_1000000_add/same-8 20000000 64.8 ns/op 0 B/op 0 allocs/op 194 // BenchmarkSeriesIDSet_Add/cardinality_1000000_add/random-8 2000000 704 ns/op 5 B/op 0 allocs/op 195 // BenchmarkSeriesIDSet_Add/cardinality_1000000_add/same_no_lock-8 50000000 40.3 ns/op 0 B/op 0 allocs/op 196 // BenchmarkSeriesIDSet_Add/cardinality_1000000_add/random_no_lock-8 2000000 644 ns/op 5 B/op 0 allocs/op 197 // BenchmarkSeriesIDSet_Add/cardinality_1000000_check_add/same_no_lock-8 50000000 34.0 ns/op 0 B/op 0 allocs/op 198 // BenchmarkSeriesIDSet_Add/cardinality_1000000_check_add/random_no_lock-8 2000000 860 ns/op 14 B/op 0 allocs/op 199 // BenchmarkSeriesIDSet_Add/cardinality_1000000_check_add/same_global_lock-8 30000000 49.8 ns/op 0 B/op 0 allocs/op 200 // BenchmarkSeriesIDSet_Add/cardinality_1000000_check_add/random_global_lock-8 2000000 914 ns/op 0 B/op 0 allocs/op 201 // BenchmarkSeriesIDSet_Add/cardinality_1000000_check_add/same_multi_lock-8 30000000 39.7 ns/op 0 B/op 0 allocs/op 202 // BenchmarkSeriesIDSet_Add/cardinality_1000000_check_add/random_multi_lock-8 1000000 1002 ns/op 0 B/op 0 allocs/op 203 func BenchmarkSeriesIDSet_Add(b *testing.B) { 204 // Setup... 205 set = NewSeriesIDSet() 206 for i := uint64(0); i < 1000000; i++ { 207 set.Add(i) 208 } 209 lookup := uint64(300032) 210 211 // Add the same value over and over. 212 b.Run("cardinality_1000000_add", func(b *testing.B) { 213 b.Run("same", func(b *testing.B) { 214 for i := 0; i < b.N; i++ { 215 set.Add(lookup) 216 } 217 }) 218 219 b.Run("random", func(b *testing.B) { 220 for i := 0; i < b.N; i++ { 221 b.StopTimer() 222 x := rand.Intn(math.MaxInt32) 223 b.StartTimer() 224 set.Add(uint64(x)) 225 } 226 }) 227 228 b.Run("same no lock", func(b *testing.B) { 229 for i := 0; i < b.N; i++ { 230 set.AddNoLock(lookup) 231 } 232 }) 233 234 b.Run("random no lock", func(b *testing.B) { 235 for i := 0; i < b.N; i++ { 236 b.StopTimer() 237 x := rand.Intn(math.MaxInt32) 238 b.StartTimer() 239 set.AddNoLock(uint64(x)) 240 } 241 }) 242 }) 243 244 // Add the same value over and over with no lock 245 b.Run("cardinality_1000000_check_add", func(b *testing.B) { 246 b.Run("same no lock", func(b *testing.B) { 247 for i := 0; i < b.N; i++ { 248 if !set.ContainsNoLock(lookup) { 249 set.AddNoLock(lookup) 250 } 251 } 252 }) 253 254 b.Run("random no lock", func(b *testing.B) { 255 for i := 0; i < b.N; i++ { 256 b.StopTimer() 257 x := rand.Intn(math.MaxInt32) 258 b.StartTimer() 259 if !set.ContainsNoLock(uint64(x)) { 260 set.AddNoLock(uint64(x)) 261 } 262 } 263 }) 264 265 b.Run("same global lock", func(b *testing.B) { 266 for i := 0; i < b.N; i++ { 267 set.Lock() 268 if !set.ContainsNoLock(lookup) { 269 set.AddNoLock(lookup) 270 } 271 set.Unlock() 272 } 273 }) 274 275 b.Run("random global lock", func(b *testing.B) { 276 for i := 0; i < b.N; i++ { 277 b.StopTimer() 278 x := rand.Intn(math.MaxInt32) 279 b.StartTimer() 280 set.Lock() 281 if !set.ContainsNoLock(uint64(x)) { 282 set.AddNoLock(uint64(x)) 283 } 284 set.Unlock() 285 } 286 }) 287 288 b.Run("same multi lock", func(b *testing.B) { 289 for i := 0; i < b.N; i++ { 290 if !set.Contains(lookup) { 291 set.Add(lookup) 292 } 293 } 294 }) 295 296 b.Run("random multi lock", func(b *testing.B) { 297 for i := 0; i < b.N; i++ { 298 b.StopTimer() 299 x := rand.Intn(math.MaxInt32) 300 b.StartTimer() 301 if !set.Contains(uint64(x)) { 302 set.Add(uint64(x)) 303 } 304 } 305 }) 306 }) 307 } 308 309 var ssResult *SeriesIDSet 310 311 // Benchmark various ways of creating a copy of a bitmap. Note, Clone_COW will result 312 // in a bitmap where future modifications will involve copies. 313 // 314 // Typical results from an i7 laptop. 315 // BenchmarkSeriesIDSet_Clone/cardinality_1000/re-use/Clone-8 30000 44171 ns/op 47200 B/op 1737 allocs/op 316 // BenchmarkSeriesIDSet_Clone/cardinality_1000/re-use/Merge-8 100000 17877 ns/op 39008 B/op 30 allocs/op 317 // BenchmarkSeriesIDSet_Clone/cardinality_1000/re-use/MergeInPlace-8 200000 7367 ns/op 0 B/op 0 allocs/op 318 // BenchmarkSeriesIDSet_Clone/cardinality_1000/re-use/Add-8 10000 137460 ns/op 62336 B/op 2596 allocs/op 319 // BenchmarkSeriesIDSet_Clone/cardinality_1000/re-use/WriteTo-8 30000 52896 ns/op 35872 B/op 866 allocs/op 320 // BenchmarkSeriesIDSet_Clone/cardinality_1000/don't_re-use/Clone-8 30000 41940 ns/op 47200 B/op 1737 allocs/op 321 // BenchmarkSeriesIDSet_Clone/cardinality_1000/don't_re-use/Merge-8 100000 17624 ns/op 39008 B/op 30 allocs/op 322 // BenchmarkSeriesIDSet_Clone/cardinality_1000/don't_re-use/MergeInPlace-8 100000 17320 ns/op 38880 B/op 28 allocs/op 323 // BenchmarkSeriesIDSet_Clone/cardinality_1000/don't_re-use/Add-8 10000 167544 ns/op 101216 B/op 2624 allocs/op 324 // BenchmarkSeriesIDSet_Clone/cardinality_1000/don't_re-use/WriteTo-8 20000 66976 ns/op 52897 B/op 869 allocs/op 325 // BenchmarkSeriesIDSet_Clone/cardinality_10000/re-use/Clone-8 10000 179933 ns/op 177072 B/op 5895 allocs/op 326 // BenchmarkSeriesIDSet_Clone/cardinality_10000/re-use/Merge-8 20000 77574 ns/op 210656 B/op 42 allocs/op 327 // BenchmarkSeriesIDSet_Clone/cardinality_10000/re-use/MergeInPlace-8 100000 23645 ns/op 0 B/op 0 allocs/op 328 // BenchmarkSeriesIDSet_Clone/cardinality_10000/re-use/Add-8 2000 689254 ns/op 224161 B/op 9572 allocs/op 329 // BenchmarkSeriesIDSet_Clone/cardinality_10000/re-use/WriteTo-8 10000 199052 ns/op 118791 B/op 2945 allocs/op 330 // BenchmarkSeriesIDSet_Clone/cardinality_10000/don't_re-use/Clone-8 10000 183137 ns/op 177073 B/op 5895 allocs/op 331 // BenchmarkSeriesIDSet_Clone/cardinality_10000/don't_re-use/Merge-8 20000 77502 ns/op 210656 B/op 42 allocs/op 332 // BenchmarkSeriesIDSet_Clone/cardinality_10000/don't_re-use/MergeInPlace-8 20000 72610 ns/op 210528 B/op 40 allocs/op 333 // BenchmarkSeriesIDSet_Clone/cardinality_10000/don't_re-use/Add-8 2000 724789 ns/op 434691 B/op 9612 allocs/op 334 // BenchmarkSeriesIDSet_Clone/cardinality_10000/don't_re-use/WriteTo-8 10000 215734 ns/op 177159 B/op 2948 allocs/op 335 // BenchmarkSeriesIDSet_Clone/cardinality_100000/re-use/Clone-8 5000 244971 ns/op 377648 B/op 6111 allocs/op 336 // BenchmarkSeriesIDSet_Clone/cardinality_100000/re-use/Merge-8 20000 90580 ns/op 210656 B/op 42 allocs/op 337 // BenchmarkSeriesIDSet_Clone/cardinality_100000/re-use/MergeInPlace-8 50000 24697 ns/op 0 B/op 0 allocs/op 338 // BenchmarkSeriesIDSet_Clone/cardinality_100000/re-use/Add-8 500 3274456 ns/op 758996 B/op 19853 allocs/op 339 // BenchmarkSeriesIDSet_Clone/cardinality_100000/re-use/WriteTo-8 5000 248791 ns/op 122392 B/op 3053 allocs/op 340 // BenchmarkSeriesIDSet_Clone/cardinality_100000/don't_re-use/Clone-8 5000 269152 ns/op 377648 B/op 6111 allocs/op 341 // BenchmarkSeriesIDSet_Clone/cardinality_100000/don't_re-use/Merge-8 20000 85948 ns/op 210657 B/op 42 allocs/op 342 // BenchmarkSeriesIDSet_Clone/cardinality_100000/don't_re-use/MergeInPlace-8 20000 78142 ns/op 210528 B/op 40 allocs/op 343 // BenchmarkSeriesIDSet_Clone/cardinality_100000/don't_re-use/Add-8 500 3123753 ns/op 969529 B/op 19893 allocs/op 344 // BenchmarkSeriesIDSet_Clone/cardinality_100000/don't_re-use/WriteTo-8 10000 230657 ns/op 180684 B/op 3056 allocs/op 345 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/re-use/Clone-8 3000 551781 ns/op 2245424 B/op 6111 allocs/op 346 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/re-use/Merge-8 20000 92104 ns/op 210656 B/op 42 allocs/op 347 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/re-use/MergeInPlace-8 50000 27408 ns/op 0 B/op 0 allocs/op 348 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/re-use/Add-8 100 22573498 ns/op 6420446 B/op 30520 allocs/op 349 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/re-use/WriteTo-8 5000 284901 ns/op 123522 B/op 3053 allocs/op 350 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/don't_re-use/Clone-8 3000 679284 ns/op 2245424 B/op 6111 allocs/op 351 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/don't_re-use/Merge-8 20000 68965 ns/op 210656 B/op 42 allocs/op 352 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/don't_re-use/MergeInPlace-8 20000 64236 ns/op 210528 B/op 40 allocs/op 353 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/don't_re-use/Add-8 100 21960668 ns/op 6630979 B/op 30560 allocs/op 354 // BenchmarkSeriesIDSet_Clone/cardinality_1000000/don't_re-use/WriteTo-8 5000 298276 ns/op 181890 B/op 3056 allocs/op 355 356 func BenchmarkSeriesIDSet_Clone(b *testing.B) { 357 toAddCardinalities := []int{1e3, 1e4, 1e5, 1e6} 358 359 runBenchmarks := func(b *testing.B, other *SeriesIDSet, init func() *SeriesIDSet) { 360 b.Run("Clone", func(b *testing.B) { 361 for i := 0; i < b.N; i++ { 362 ssResult = other.Clone() 363 } 364 }) 365 366 b.Run("Merge", func(b *testing.B) { 367 ssResult = init() 368 for i := 0; i < b.N; i++ { 369 ssResult.Merge(other) 370 b.StopTimer() 371 ssResult = init() 372 b.StartTimer() 373 } 374 }) 375 376 b.Run("MergeInPlace", func(b *testing.B) { 377 ssResult = init() 378 for i := 0; i < b.N; i++ { 379 ssResult.MergeInPlace(other) 380 b.StopTimer() 381 ssResult = init() 382 b.StartTimer() 383 } 384 }) 385 386 b.Run("Add", func(b *testing.B) { 387 ssResult = init() 388 for i := 0; i < b.N; i++ { 389 itr := other.Iterator() 390 ssResult.Lock() 391 for itr.HasNext() { 392 ssResult.AddNoLock(uint64(itr.Next())) 393 } 394 ssResult.Unlock() 395 b.StopTimer() 396 ssResult = init() 397 b.StartTimer() 398 } 399 }) 400 401 b.Run("WriteTo", func(b *testing.B) { 402 var buf bytes.Buffer 403 ssResult = init() 404 for i := 0; i < b.N; i++ { 405 other.WriteTo(&buf) 406 ssResult.UnmarshalBinaryUnsafe(buf.Bytes()) 407 b.StopTimer() 408 ssResult = init() 409 buf.Reset() 410 b.StartTimer() 411 } 412 }) 413 } 414 415 for _, toAddCardinality := range toAddCardinalities { 416 b.Run(fmt.Sprintf("cardinality %d", toAddCardinality), func(b *testing.B) { 417 ids := make([]uint64, 0, toAddCardinality) 418 for i := 0; i < toAddCardinality; i++ { 419 ids = append(ids, uint64(rand.Intn(200000000))) 420 } 421 other := NewSeriesIDSet(ids...) 422 423 b.Run("re-use", func(b *testing.B) { 424 base := NewSeriesIDSet() 425 runBenchmarks(b, other, func() *SeriesIDSet { 426 base.Clear() 427 return base 428 }) 429 }) 430 431 b.Run("don't re-use", func(b *testing.B) { 432 runBenchmarks(b, other, func() *SeriesIDSet { 433 return NewSeriesIDSet() 434 }) 435 }) 436 }) 437 } 438 } 439 func BenchmarkSeriesIDSet_AddMany(b *testing.B) { 440 cardinalities := []int{1, 1e3, 1e4, 1e5, 1e6} 441 toAddCardinalities := []int{1e3, 1e4, 1e5} 442 443 for _, cardinality := range cardinalities { 444 ids := make([]uint64, 0, cardinality) 445 for i := 0; i < cardinality; i++ { 446 ids = append(ids, uint64(rand.Intn(200000000))) 447 } 448 449 // Setup... 450 set = NewSeriesIDSet(ids...) 451 452 // Check if the value exists before adding it under two locks. 453 b.Run(fmt.Sprintf("cardinality %d", cardinality), func(b *testing.B) { 454 for _, toAddCardinality := range toAddCardinalities { 455 ids := make([]uint64, 0, toAddCardinality) 456 for i := 0; i < toAddCardinality; i++ { 457 ids = append(ids, uint64(rand.Intn(200000000))) 458 } 459 460 b.Run(fmt.Sprintf("adding %d", toAddCardinality), func(b *testing.B) { 461 b.Run("AddNoLock", func(b *testing.B) { 462 clone := set.Clone() 463 for i := 0; i < b.N; i++ { 464 for _, id := range ids { 465 clone.AddNoLock(id) 466 } 467 468 b.StopTimer() 469 clone = set.Clone() 470 b.StartTimer() 471 } 472 }) 473 474 b.Run("AddMany", func(b *testing.B) { 475 clone := set.Clone() 476 for i := 0; i < b.N; i++ { 477 clone.AddMany(ids...) 478 b.StopTimer() 479 clone = set.Clone() 480 b.StartTimer() 481 } 482 }) 483 484 // Merge will involve a new bitmap being allocated. 485 b.Run("Merge", func(b *testing.B) { 486 clone := set.Clone() 487 for i := 0; i < b.N; i++ { 488 other := NewSeriesIDSet(ids...) 489 clone.Merge(other) 490 491 b.StopTimer() 492 clone = set.Clone() 493 b.StartTimer() 494 } 495 }) 496 497 b.Run("MergeInPlace", func(b *testing.B) { 498 clone := set.Clone() 499 for i := 0; i < b.N; i++ { 500 other := NewSeriesIDSet(ids...) 501 clone.MergeInPlace(other) 502 503 b.StopTimer() 504 clone = set.Clone() 505 b.StartTimer() 506 } 507 }) 508 }) 509 510 } 511 }) 512 } 513 } 514 515 // Remove benchmarks the cost of removing the same element in a set versus the 516 // cost of checking if it exists before removing it. 517 // 518 // Typical benchmarks from a laptop: 519 // 520 // BenchmarkSeriesIDSet_Remove/cardinality_1000000_remove_same-4 20000000 99.1 ns/op 0 B/op 0 allocs/op 521 // BenchmarkSeriesIDSet_Remove/cardinality_1000000_check_remove_global_lock-4 20000000 57.7 ns/op 0 B/op 0 allocs/op 522 // BenchmarkSeriesIDSet_Remove/cardinality_1000000_check_remove_multi_lock-4 20000000 80.1 ns/op 0 B/op 0 allocs/op 523 func BenchmarkSeriesIDSet_Remove(b *testing.B) { 524 // Setup... 525 set = NewSeriesIDSet() 526 for i := uint64(0); i < 1000000; i++ { 527 set.Add(i) 528 } 529 lookup := uint64(300032) 530 531 // Remove the same value over and over. 532 b.Run("cardinality_1000000_remove_same", func(b *testing.B) { 533 for i := 0; i < b.N; i++ { 534 set.Remove(lookup) 535 } 536 }) 537 538 // Check if the value exists before adding it. Subsequent repeats of the code 539 // will result in contains checks. 540 b.Run("cardinality_1000000_check_remove_global_lock", func(b *testing.B) { 541 for i := 0; i < b.N; i++ { 542 set.Lock() 543 if set.ContainsNoLock(lookup) { 544 set.RemoveNoLock(lookup) 545 } 546 set.Unlock() 547 } 548 }) 549 550 // Check if the value exists before adding it under two locks. 551 b.Run("cardinality_1000000_check_remove_multi_lock", func(b *testing.B) { 552 for i := 0; i < b.N; i++ { 553 if set.Contains(lookup) { 554 set.Remove(lookup) 555 } 556 } 557 }) 558 } 559 560 // Typical benchmarks for a laptop: 561 // 562 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1/shards_1-4 200000 8095 ns/op 16656 B/op 11 allocs/op 563 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1/shards_10-4 200000 11755 ns/op 18032 B/op 47 allocs/op 564 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1/shards_100-4 50000 41632 ns/op 31794 B/op 407 allocs/op 565 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_10000/shards_1-4 200000 6022 ns/op 8384 B/op 7 allocs/op 566 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_10000/shards_10-4 100000 19674 ns/op 9760 B/op 43 allocs/op 567 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_10000/shards_100-4 10000 152865 ns/op 23522 B/op 403 allocs/op 568 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1000000/shards_1-4 200000 8252 ns/op 9712 B/op 44 allocs/op 569 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1000000/shards_10-4 50000 29566 ns/op 15984 B/op 143 allocs/op 570 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_1000000/shards_100-4 10000 237672 ns/op 78710 B/op 1133 allocs/op 571 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_10000000/shards_1-4 100000 21559 ns/op 25968 B/op 330 allocs/op 572 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_10000000/shards_10-4 20000 102326 ns/op 114325 B/op 537 allocs/op 573 // BenchmarkSeriesIDSet_Merge_Duplicates/cardinality_10000000/shards_100-4 2000 1042697 ns/op 997909 B/op 2608 allocs/op 574 func BenchmarkSeriesIDSet_Merge_Duplicates(b *testing.B) { 575 cardinalities := []int{1, 10000, 1000000, 10000000} 576 shards := []int{1, 10, 100} 577 578 for _, cardinality := range cardinalities { 579 set = NewSeriesIDSet() 580 for i := 0; i < cardinality; i++ { 581 set.Add(uint64(i)) 582 } 583 584 for _, shard := range shards { 585 others := make([]*SeriesIDSet, 0, shard) 586 for s := 0; s < shard; s++ { 587 others = append(others, &SeriesIDSet{bitmap: set.bitmap.Clone()}) 588 } 589 590 b.Run(fmt.Sprintf("cardinality_%d/shards_%d", cardinality, shard), func(b *testing.B) { 591 base := &SeriesIDSet{bitmap: set.bitmap.Clone()} 592 for i := 0; i < b.N; i++ { 593 base.Merge(others...) 594 b.StopTimer() 595 base.bitmap = set.bitmap.Clone() 596 b.StartTimer() 597 } 598 }) 599 600 } 601 } 602 } 603 604 // Typical benchmarks for a laptop: 605 // 606 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_1/shards_1-4 200000 7841 ns/op 16656 B/op 11 allocs/op 607 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_1/shards_10-4 200000 13093 ns/op 18048 B/op 47 allocs/op 608 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_1/shards_100-4 30000 57399 ns/op 31985 B/op 407 allocs/op 609 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_10000/shards_1-4 200000 7740 ns/op 8384 B/op 7 allocs/op 610 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_10000/shards_10-4 50000 37116 ns/op 18208 B/op 52 allocs/op 611 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_10000/shards_100-4 5000 409487 ns/op 210563 B/op 955 allocs/op 612 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_1000000/shards_1-4 100000 19289 ns/op 19328 B/op 79 allocs/op 613 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_1000000/shards_10-4 10000 129048 ns/op 159716 B/op 556 allocs/op 614 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_1000000/shards_100-4 500 3482907 ns/op 5428116 B/op 6174 allocs/op 615 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_10000000/shards_1-4 30000 43734 ns/op 51872 B/op 641 allocs/op 616 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_10000000/shards_10-4 3000 514412 ns/op 748678 B/op 3687 allocs/op 617 // BenchmarkSeriesIDSet_Merge_Unique/cardinality_10000000/shards_100-4 30 61891687 ns/op 69626539 B/op 36038 allocs/op 618 func BenchmarkSeriesIDSet_Merge_Unique(b *testing.B) { 619 cardinalities := []int{1, 10000, 1000000, 10000000} 620 shards := []int{1, 10, 100} 621 622 for _, cardinality := range cardinalities { 623 set = NewSeriesIDSet() 624 for i := 0; i < cardinality; i++ { 625 set.Add(uint64(i)) 626 } 627 628 for _, shard := range shards { 629 others := make([]*SeriesIDSet, 0, shard) 630 for s := 1; s <= shard; s++ { 631 other := NewSeriesIDSet() 632 for i := 0; i < cardinality; i++ { 633 other.Add(uint64(i + (s * cardinality))) 634 } 635 others = append(others, other) 636 } 637 638 b.Run(fmt.Sprintf("cardinality_%d/shards_%d", cardinality, shard), func(b *testing.B) { 639 base := &SeriesIDSet{bitmap: set.bitmap.Clone()} 640 for i := 0; i < b.N; i++ { 641 base.Merge(others...) 642 b.StopTimer() 643 base.bitmap = set.bitmap.Clone() 644 b.StartTimer() 645 } 646 }) 647 } 648 } 649 }