gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/segment/test/segment_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package segment 16 17 import ( 18 "fmt" 19 "math/rand" 20 "slices" 21 "testing" 22 ) 23 24 const ( 25 // testSize is the baseline number of elements inserted into sets under 26 // test, and is chosen to be large enough to ensure interesting amounts of 27 // tree rebalancing. 28 // 29 // Note that because checkSet is called between each insertion/removal in 30 // some tests that use it, tests may be quadratic in testSize. 31 testSize = 8000 32 33 // valueOffset is the difference between the value and start of test 34 // segments. 35 valueOffset = 100000 36 37 // intervalLength is the interval used by random gap tests. 38 intervalLength = 10 39 ) 40 41 func shuffle(xs []int) { 42 rand.Shuffle(len(xs), func(i, j int) { xs[i], xs[j] = xs[j], xs[i] }) 43 } 44 45 func randIntervalPermutation(size int) []int { 46 p := make([]int, size) 47 for i := range p { 48 p[i] = intervalLength * i 49 } 50 shuffle(p) 51 return p 52 } 53 54 // validate can be passed to Check. 55 func validate(nr int, r Range, v int) error { 56 if got, want := v, r.Start+valueOffset; got != want { 57 return fmt.Errorf("segment %d has key %d, value %d (expected %d)", nr, r.Start, got, want) 58 } 59 return nil 60 } 61 62 // checkSetMaxGap returns an error if maxGap inside all nodes of s is not well 63 // maintained. 64 func checkSetMaxGap(s *gapSet) error { 65 n := s.root 66 return checkNodeMaxGap(&n) 67 } 68 69 // checkNodeMaxGap returns an error if maxGap inside the subtree rooted by n is 70 // not well maintained. 71 func checkNodeMaxGap(n *gapnode) error { 72 var max int 73 if !n.hasChildren { 74 max = n.calculateMaxGapLeaf() 75 } else { 76 for i := 0; i <= n.nrSegments; i++ { 77 child := n.children[i] 78 if err := checkNodeMaxGap(child); err != nil { 79 return err 80 } 81 if temp := child.maxGap.Get(); i == 0 || temp > max { 82 max = temp 83 } 84 } 85 } 86 if max != n.maxGap.Get() { 87 return fmt.Errorf("maxGap wrong in node\n%vexpected: %d got: %d", n, max, n.maxGap) 88 } 89 return nil 90 } 91 92 func TestAddRandom(t *testing.T) { 93 var s Set 94 order := rand.Perm(testSize) 95 var nrInsertions int 96 for i, j := range order { 97 s.InsertWithoutMergingRange(Range{j, j + 1}, j+valueOffset) 98 nrInsertions++ 99 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 100 t.Errorf("Iteration %d: %v", i, err) 101 break 102 } 103 } 104 if got, want := s.countSegments(), nrInsertions; got != want { 105 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 106 } 107 if t.Failed() { 108 t.Logf("Insertion order: %v", order[:nrInsertions]) 109 t.Logf("Set contents:\n%v", &s) 110 } 111 } 112 113 func TestRemoveRandom(t *testing.T) { 114 var s Set 115 for i := 0; i < testSize; i++ { 116 s.InsertWithoutMergingRange(Range{i, i + 1}, i+valueOffset) 117 } 118 order := rand.Perm(testSize) 119 var nrRemovals int 120 for i, j := range order { 121 seg := s.FindSegment(j) 122 if !seg.Ok() { 123 t.Errorf("Iteration %d: failed to find segment with key %d", i, j) 124 break 125 } 126 s.Remove(seg) 127 nrRemovals++ 128 if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil { 129 t.Errorf("Iteration %d: %v", i, err) 130 break 131 } 132 } 133 if got, want := s.countSegments(), testSize-nrRemovals; got != want { 134 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 135 } 136 if t.Failed() { 137 t.Logf("Removal order: %v", order[:nrRemovals]) 138 t.Logf("Set contents:\n%v", &s) 139 t.FailNow() 140 } 141 } 142 143 func TestMaxGapAddRandom(t *testing.T) { 144 var s gapSet 145 order := rand.Perm(testSize) 146 var nrInsertions int 147 for i, j := range order { 148 s.InsertWithoutMergingRange(Range{j, j + 1}, j+valueOffset) 149 nrInsertions++ 150 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 151 t.Errorf("Iteration %d: %v", i, err) 152 break 153 } 154 if err := checkSetMaxGap(&s); err != nil { 155 t.Errorf("When inserting %d: %v", j, err) 156 break 157 } 158 } 159 if got, want := s.countSegments(), nrInsertions; got != want { 160 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 161 } 162 if t.Failed() { 163 t.Logf("Insertion order: %v", order[:nrInsertions]) 164 t.Logf("Set contents:\n%v", &s) 165 } 166 } 167 168 func TestMaxGapAddRandomWithRandomInterval(t *testing.T) { 169 var s gapSet 170 order := randIntervalPermutation(testSize) 171 var nrInsertions int 172 for i, j := range order { 173 s.InsertWithoutMergingRange(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset) 174 nrInsertions++ 175 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 176 t.Errorf("Iteration %d: %v", i, err) 177 break 178 } 179 if err := checkSetMaxGap(&s); err != nil { 180 t.Errorf("When inserting %d: %v", j, err) 181 break 182 } 183 } 184 if got, want := s.countSegments(), nrInsertions; got != want { 185 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 186 } 187 if t.Failed() { 188 t.Logf("Insertion order: %v", order[:nrInsertions]) 189 t.Logf("Set contents:\n%v", &s) 190 } 191 } 192 193 func TestMaxGapAddRandomWithMerge(t *testing.T) { 194 var s gapSet 195 order := randIntervalPermutation(testSize) 196 for _, j := range order { 197 s.InsertRange(Range{j, j + intervalLength}, 0) 198 if err := checkSetMaxGap(&s); err != nil { 199 t.Errorf("When inserting %d: %v", j, err) 200 break 201 } 202 } 203 if got, want := s.countSegments(), 1; got != want { 204 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 205 } 206 if t.Failed() { 207 t.Logf("Insertion order: %v", order) 208 t.Logf("Set contents:\n%v", &s) 209 } 210 } 211 212 func TestMaxGapRemoveRandom(t *testing.T) { 213 var s gapSet 214 for i := 0; i < testSize; i++ { 215 s.InsertWithoutMergingRange(Range{i, i + 1}, i+valueOffset) 216 } 217 order := rand.Perm(testSize) 218 var nrRemovals int 219 for i, j := range order { 220 seg := s.FindSegment(j) 221 if !seg.Ok() { 222 t.Errorf("Iteration %d: failed to find segment with key %d", i, j) 223 break 224 } 225 temprange := seg.Range() 226 s.Remove(seg) 227 nrRemovals++ 228 if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil { 229 t.Errorf("Iteration %d: %v", i, err) 230 break 231 } 232 if err := checkSetMaxGap(&s); err != nil { 233 t.Errorf("When removing %v: %v", temprange, err) 234 break 235 } 236 } 237 if got, want := s.countSegments(), testSize-nrRemovals; got != want { 238 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 239 } 240 if t.Failed() { 241 t.Logf("Removal order: %v", order[:nrRemovals]) 242 t.Logf("Set contents:\n%v", &s) 243 t.FailNow() 244 } 245 } 246 247 func TestMaxGapRemoveHalfRandom(t *testing.T) { 248 var s gapSet 249 for i := 0; i < testSize; i++ { 250 s.InsertWithoutMergingRange(Range{intervalLength * i, intervalLength*i + rand.Intn(intervalLength-1) + 1}, intervalLength*i+valueOffset) 251 } 252 order := randIntervalPermutation(testSize) 253 order = order[:testSize/2] 254 var nrRemovals int 255 for i, j := range order { 256 seg := s.FindSegment(j) 257 if !seg.Ok() { 258 t.Errorf("Iteration %d: failed to find segment with key %d", i, j) 259 break 260 } 261 temprange := seg.Range() 262 s.Remove(seg) 263 nrRemovals++ 264 if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil { 265 t.Errorf("Iteration %d: %v", i, err) 266 break 267 } 268 if err := checkSetMaxGap(&s); err != nil { 269 t.Errorf("When removing %v: %v", temprange, err) 270 break 271 } 272 } 273 if got, want := s.countSegments(), testSize-nrRemovals; got != want { 274 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 275 } 276 if t.Failed() { 277 t.Logf("Removal order: %v", order[:nrRemovals]) 278 t.Logf("Set contents:\n%v", &s) 279 t.FailNow() 280 } 281 } 282 283 func TestMaxGapRemoveHalfRandomWithMerge(t *testing.T) { 284 var s gapSet 285 s.InsertRange(Range{0, intervalLength * testSize}, 0) 286 order := randIntervalPermutation(testSize) 287 order = order[:testSize/2] 288 var nrRemovals int 289 for _, j := range order { 290 temprange := Range{j, j + intervalLength} 291 s.RemoveFullRange(temprange) 292 nrRemovals++ 293 if err := checkSetMaxGap(&s); err != nil { 294 t.Errorf("When removing %v: %v", temprange, err) 295 break 296 } 297 } 298 if t.Failed() { 299 t.Logf("Removal order: %v", order[:nrRemovals]) 300 t.Logf("Set contents:\n%v", &s) 301 t.FailNow() 302 } 303 } 304 305 func TestNextLargeEnoughGap(t *testing.T) { 306 var s gapSet 307 order := randIntervalPermutation(testSize * 2) 308 order = order[:testSize] 309 for _, j := range order { 310 s.InsertRange(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset) 311 if err := checkSetMaxGap(&s); err != nil { 312 t.Errorf("When inserting %d: %v", j, err) 313 break 314 } 315 } 316 shuffle(order) 317 order = order[:testSize/2] 318 for _, j := range order { 319 seg := s.FindSegment(j) 320 if !seg.Ok() { 321 continue 322 } 323 temprange := seg.Range() 324 s.Remove(seg) 325 if err := checkSetMaxGap(&s); err != nil { 326 t.Errorf("When removing %v: %v", temprange, err) 327 break 328 } 329 } 330 minSize := 7 331 var gapArr1 []int 332 for gap := s.LowerBoundGap(0).NextLargeEnoughGap(minSize); gap.Ok(); gap = gap.NextLargeEnoughGap(minSize) { 333 if gap.Range().Length() < minSize { 334 t.Errorf("NextLargeEnoughGap wrong, gap %v has length %d, wanted %d", gap.Range(), gap.Range().Length(), minSize) 335 } else { 336 gapArr1 = append(gapArr1, gap.Range().Start) 337 } 338 } 339 var gapArr2 []int 340 for gap := s.LowerBoundGap(0).NextGap(); gap.Ok(); gap = gap.NextGap() { 341 if gap.Range().Length() >= minSize { 342 gapArr2 = append(gapArr2, gap.Range().Start) 343 } 344 } 345 346 if !slices.Equal(gapArr2, gapArr1) { 347 t.Errorf("Search result not correct, got: %v, wanted: %v", gapArr1, gapArr2) 348 } 349 if t.Failed() { 350 t.Logf("Set contents:\n%v", &s) 351 t.FailNow() 352 } 353 } 354 355 func TestPrevLargeEnoughGap(t *testing.T) { 356 var s gapSet 357 order := randIntervalPermutation(testSize * 2) 358 order = order[:testSize] 359 for _, j := range order { 360 s.InsertRange(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset) 361 if err := checkSetMaxGap(&s); err != nil { 362 t.Errorf("When inserting %d: %v", j, err) 363 break 364 } 365 } 366 end := s.LastSegment().End() 367 shuffle(order) 368 order = order[:testSize/2] 369 for _, j := range order { 370 seg := s.FindSegment(j) 371 if !seg.Ok() { 372 continue 373 } 374 temprange := seg.Range() 375 s.Remove(seg) 376 if err := checkSetMaxGap(&s); err != nil { 377 t.Errorf("When removing %v: %v", temprange, err) 378 break 379 } 380 } 381 minSize := 7 382 var gapArr1 []int 383 for gap := s.UpperBoundGap(end + intervalLength).PrevLargeEnoughGap(minSize); gap.Ok(); gap = gap.PrevLargeEnoughGap(minSize) { 384 if gap.Range().Length() < minSize { 385 t.Errorf("PrevLargeEnoughGap wrong, gap length %d, wanted %d", gap.Range().Length(), minSize) 386 } else { 387 gapArr1 = append(gapArr1, gap.Range().Start) 388 } 389 } 390 var gapArr2 []int 391 for gap := s.UpperBoundGap(end + intervalLength).PrevGap(); gap.Ok(); gap = gap.PrevGap() { 392 if gap.Range().Length() >= minSize { 393 gapArr2 = append(gapArr2, gap.Range().Start) 394 } 395 } 396 if !slices.Equal(gapArr2, gapArr1) { 397 t.Errorf("Search result not correct, got: %v, wanted: %v", gapArr1, gapArr2) 398 } 399 if t.Failed() { 400 t.Logf("Set contents:\n%v", &s) 401 t.FailNow() 402 } 403 } 404 405 func TestAddSequentialAdjacent(t *testing.T) { 406 var s Set 407 var nrInsertions int 408 for i := 0; i < testSize; i++ { 409 s.InsertWithoutMergingRange(Range{i, i + 1}, i+valueOffset) 410 nrInsertions++ 411 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 412 t.Errorf("Iteration %d: %v", i, err) 413 break 414 } 415 } 416 if got, want := s.countSegments(), nrInsertions; got != want { 417 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 418 } 419 if t.Failed() { 420 t.Logf("Set contents:\n%v", &s) 421 } 422 423 first := s.FirstSegment() 424 gotSeg, gotGap := first.PrevNonEmpty() 425 if wantGap := s.FirstGap(); gotSeg.Ok() || gotGap != wantGap { 426 t.Errorf("FirstSegment().PrevNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", gotSeg, gotGap, wantGap) 427 } 428 gotSeg, gotGap = first.NextNonEmpty() 429 if wantSeg := first.NextSegment(); gotSeg != wantSeg || gotGap.Ok() { 430 t.Errorf("FirstSegment().NextNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", gotSeg, gotGap, wantSeg) 431 } 432 433 last := s.LastSegment() 434 gotSeg, gotGap = last.PrevNonEmpty() 435 if wantSeg := last.PrevSegment(); gotSeg != wantSeg || gotGap.Ok() { 436 t.Errorf("LastSegment().PrevNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", gotSeg, gotGap, wantSeg) 437 } 438 gotSeg, gotGap = last.NextNonEmpty() 439 if wantGap := s.LastGap(); gotSeg.Ok() || gotGap != wantGap { 440 t.Errorf("LastSegment().NextNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", gotSeg, gotGap, wantGap) 441 } 442 443 for seg := first.NextSegment(); seg != last; seg = seg.NextSegment() { 444 gotSeg, gotGap = seg.PrevNonEmpty() 445 if wantSeg := seg.PrevSegment(); gotSeg != wantSeg || gotGap.Ok() { 446 t.Errorf("%v.PrevNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", seg, gotSeg, gotGap, wantSeg) 447 } 448 gotSeg, gotGap = seg.NextNonEmpty() 449 if wantSeg := seg.NextSegment(); gotSeg != wantSeg || gotGap.Ok() { 450 t.Errorf("%v.NextNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", seg, gotSeg, gotGap, wantSeg) 451 } 452 } 453 } 454 455 func TestAddSequentialNonAdjacent(t *testing.T) { 456 var s Set 457 var nrInsertions int 458 for i := 0; i < testSize; i++ { 459 // The range here differs from TestAddSequentialAdjacent so that 460 // consecutive segments are not adjacent. 461 s.InsertWithoutMergingRange(Range{2 * i, 2*i + 1}, 2*i+valueOffset) 462 nrInsertions++ 463 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 464 t.Errorf("Iteration %d: %v", i, err) 465 break 466 } 467 } 468 if got, want := s.countSegments(), nrInsertions; got != want { 469 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 470 } 471 if t.Failed() { 472 t.Logf("Set contents:\n%v", &s) 473 } 474 475 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 476 gotSeg, gotGap := seg.PrevNonEmpty() 477 if wantGap := seg.PrevGap(); gotSeg.Ok() || gotGap != wantGap { 478 t.Errorf("%v.PrevNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", seg, gotSeg, gotGap, wantGap) 479 } 480 gotSeg, gotGap = seg.NextNonEmpty() 481 if wantGap := seg.NextGap(); gotSeg.Ok() || gotGap != wantGap { 482 t.Errorf("%v.NextNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", seg, gotSeg, gotGap, wantGap) 483 } 484 } 485 } 486 487 func TestMerge(t *testing.T) { 488 tests := []struct { 489 name string 490 initial []Range 491 split bool 492 splitAddr int 493 final []Range 494 }{ 495 { 496 name: "InsertRange merges after existing segment", 497 initial: []Range{{1000, 1100}, {1100, 1200}}, 498 final: []Range{{1000, 1200}}, 499 }, 500 { 501 name: "InsertRange merges before existing segment", 502 initial: []Range{{1100, 1200}, {1000, 1100}}, 503 final: []Range{{1000, 1200}}, 504 }, 505 { 506 name: "InsertRange merges between existing segments", 507 initial: []Range{{1000, 1100}, {1200, 1300}, {1100, 1200}}, 508 final: []Range{{1000, 1300}}, 509 }, 510 } 511 Tests: 512 for _, test := range tests { 513 var s Set 514 for _, r := range test.initial { 515 s.InsertRange(r, 0) 516 } 517 var i int 518 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 519 if i > len(test.final) { 520 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, s.countSegments(), len(test.final), &s) 521 continue Tests 522 } 523 if got, want := seg.Range(), test.final[i]; got != want { 524 t.Errorf("%s: Segment %d mismatch: got %v, wanted %v; set contents:\n%v", test.name, i, got, want, &s) 525 continue Tests 526 } 527 i++ 528 } 529 if i < len(test.final) { 530 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, i, len(test.final), &s) 531 } 532 } 533 } 534 535 func TestIsolate(t *testing.T) { 536 tests := []struct { 537 name string 538 initial Range 539 bounds Range 540 final []Range 541 }{ 542 { 543 name: "Isolate does not split a segment that falls inside bounds", 544 initial: Range{100, 200}, 545 bounds: Range{100, 200}, 546 final: []Range{{100, 200}}, 547 }, 548 { 549 name: "Isolate splits at beginning of segment", 550 initial: Range{50, 200}, 551 bounds: Range{100, 200}, 552 final: []Range{{50, 100}, {100, 200}}, 553 }, 554 { 555 name: "Isolate splits at end of segment", 556 initial: Range{100, 250}, 557 bounds: Range{100, 200}, 558 final: []Range{{100, 200}, {200, 250}}, 559 }, 560 { 561 name: "Isolate splits at beginning and end of segment", 562 initial: Range{50, 250}, 563 bounds: Range{100, 200}, 564 final: []Range{{50, 100}, {100, 200}, {200, 250}}, 565 }, 566 } 567 Tests: 568 for _, test := range tests { 569 var s Set 570 seg := s.Insert(s.FirstGap(), test.initial, 0) 571 seg = s.Isolate(seg, test.bounds) 572 if !test.bounds.IsSupersetOf(seg.Range()) { 573 t.Errorf("%s: Isolated segment %v lies outside bounds %v; set contents:\n%v", test.name, seg.Range(), test.bounds, &s) 574 } 575 var i int 576 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 577 if i > len(test.final) { 578 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, s.countSegments(), len(test.final), &s) 579 continue Tests 580 } 581 if got, want := seg.Range(), test.final[i]; got != want { 582 t.Errorf("%s: Segment %d mismatch: got %v, wanted %v; set contents:\n%v", test.name, i, got, want, &s) 583 continue Tests 584 } 585 i++ 586 } 587 if i < len(test.final) { 588 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, i, len(test.final), &s) 589 } 590 } 591 } 592 593 func TestMutateRange(t *testing.T) { 594 tests := []struct { 595 name string 596 initial []FlatSegment 597 increment Range 598 final []FlatSegment 599 }{ 600 { 601 name: "MutateRange no-op in empty set", 602 increment: Range{100, 200}, 603 }, 604 { 605 name: "MutateRange modifies existing segment", 606 initial: []FlatSegment{ 607 {100, 200, 0}, 608 }, 609 increment: Range{100, 200}, 610 final: []FlatSegment{ 611 {100, 200, 1}, 612 }, 613 }, 614 { 615 name: "MutateRange splits segments", 616 initial: []FlatSegment{ 617 {50, 150, 0}, 618 {150, 250, 2}, 619 }, 620 increment: Range{100, 200}, 621 final: []FlatSegment{ 622 {50, 100, 0}, 623 {100, 150, 1}, 624 {150, 200, 3}, 625 {200, 250, 2}, 626 }, 627 }, 628 { 629 name: "MutateRange merges compatible segments", 630 initial: []FlatSegment{ 631 {0, 100, 1}, 632 {100, 200, 0}, 633 {200, 300, 1}, 634 }, 635 increment: Range{100, 200}, 636 final: []FlatSegment{ 637 {0, 300, 1}, 638 }, 639 }, 640 } 641 for _, test := range tests { 642 t.Run(test.name, func(t *testing.T) { 643 var s Set 644 if err := s.ImportSlice(test.initial); err != nil { 645 t.Fatalf("Failed to import initial set: %v", err) 646 } 647 s.MutateRange(test.increment, func(seg Iterator) bool { 648 (*seg.ValuePtr())++ 649 return true 650 }) 651 if got := s.ExportSlice(); !slices.Equal(got, test.final) { 652 t.Errorf("Set mismatch after mutation: got %v, wanted %v", got, test.final) 653 } 654 }) 655 } 656 } 657 658 func benchmarkAddSequential(b *testing.B, size int) { 659 for n := 0; n < b.N; n++ { 660 var s Set 661 for i := 0; i < size; i++ { 662 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 663 } 664 } 665 } 666 667 func benchmarkAddRandom(b *testing.B, size int) { 668 order := rand.Perm(size) 669 670 b.ResetTimer() 671 for n := 0; n < b.N; n++ { 672 var s Set 673 for _, i := range order { 674 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 675 } 676 } 677 } 678 679 func benchmarkFindSequential(b *testing.B, size int) { 680 var s Set 681 for i := 0; i < size; i++ { 682 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 683 } 684 685 b.ResetTimer() 686 for n := 0; n < b.N; n++ { 687 for i := 0; i < size; i++ { 688 if seg := s.FindSegment(i); !seg.Ok() { 689 b.Fatalf("Failed to find segment %d", i) 690 } 691 } 692 } 693 } 694 695 func benchmarkFindRandom(b *testing.B, size int) { 696 var s Set 697 for i := 0; i < size; i++ { 698 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 699 } 700 order := rand.Perm(size) 701 702 b.ResetTimer() 703 for n := 0; n < b.N; n++ { 704 for _, i := range order { 705 if si := s.FindSegment(i); !si.Ok() { 706 b.Fatalf("Failed to find segment %d", i) 707 } 708 } 709 } 710 } 711 712 func benchmarkIteration(b *testing.B, size int) { 713 var s Set 714 for i := 0; i < size; i++ { 715 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 716 } 717 718 b.ResetTimer() 719 var count uint64 720 for n := 0; n < b.N; n++ { 721 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 722 count++ 723 } 724 } 725 if got, want := count, uint64(size)*uint64(b.N); got != want { 726 b.Fatalf("Iterated wrong number of segments: got %d, wanted %d", got, want) 727 } 728 } 729 730 func benchmarkAddFindRemoveSequential(b *testing.B, size int) { 731 for n := 0; n < b.N; n++ { 732 var s Set 733 for i := 0; i < size; i++ { 734 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 735 } 736 for i := 0; i < size; i++ { 737 seg := s.FindSegment(i) 738 if !seg.Ok() { 739 b.Fatalf("Failed to find segment %d", i) 740 } 741 s.Remove(seg) 742 } 743 if !s.IsEmpty() { 744 b.Fatalf("Set not empty after all removals:\n%v", &s) 745 } 746 } 747 } 748 749 func benchmarkAddFindRemoveRandom(b *testing.B, size int) { 750 order := rand.Perm(size) 751 752 b.ResetTimer() 753 for n := 0; n < b.N; n++ { 754 var s Set 755 for _, i := range order { 756 s.InsertWithoutMergingRange(Range{i, i + 1}, i) 757 } 758 for _, i := range order { 759 seg := s.FindSegment(i) 760 if !seg.Ok() { 761 b.Fatalf("Failed to find segment %d", i) 762 } 763 s.Remove(seg) 764 } 765 if !s.IsEmpty() { 766 b.Fatalf("Set not empty after all removals:\n%v", &s) 767 } 768 } 769 } 770 771 // Although we don't generally expect our segment sets to get this big, they're 772 // useful for emulating the effect of cache pressure. 773 var testSizes = []struct { 774 desc string 775 size int 776 }{ 777 {"64", 1 << 6}, 778 {"256", 1 << 8}, 779 {"1K", 1 << 10}, 780 {"4K", 1 << 12}, 781 {"16K", 1 << 14}, 782 {"64K", 1 << 16}, 783 } 784 785 func BenchmarkAddSequential(b *testing.B) { 786 for _, test := range testSizes { 787 b.Run(test.desc, func(b *testing.B) { 788 benchmarkAddSequential(b, test.size) 789 }) 790 } 791 } 792 793 func BenchmarkAddRandom(b *testing.B) { 794 for _, test := range testSizes { 795 b.Run(test.desc, func(b *testing.B) { 796 benchmarkAddRandom(b, test.size) 797 }) 798 } 799 } 800 801 func BenchmarkFindSequential(b *testing.B) { 802 for _, test := range testSizes { 803 b.Run(test.desc, func(b *testing.B) { 804 benchmarkFindSequential(b, test.size) 805 }) 806 } 807 } 808 809 func BenchmarkFindRandom(b *testing.B) { 810 for _, test := range testSizes { 811 b.Run(test.desc, func(b *testing.B) { 812 benchmarkFindRandom(b, test.size) 813 }) 814 } 815 } 816 817 func BenchmarkIteration(b *testing.B) { 818 for _, test := range testSizes { 819 b.Run(test.desc, func(b *testing.B) { 820 benchmarkIteration(b, test.size) 821 }) 822 } 823 } 824 825 func BenchmarkAddFindRemoveSequential(b *testing.B) { 826 for _, test := range testSizes { 827 b.Run(test.desc, func(b *testing.B) { 828 benchmarkAddFindRemoveSequential(b, test.size) 829 }) 830 } 831 } 832 833 func BenchmarkAddFindRemoveRandom(b *testing.B) { 834 for _, test := range testSizes { 835 b.Run(test.desc, func(b *testing.B) { 836 benchmarkAddFindRemoveRandom(b, test.size) 837 }) 838 } 839 }