github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 "reflect" 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 if !s.AddWithoutMerging(Range{j, j + 1}, j+valueOffset) { 98 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 99 break 100 } 101 nrInsertions++ 102 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 103 t.Errorf("Iteration %d: %v", i, err) 104 break 105 } 106 } 107 if got, want := s.countSegments(), nrInsertions; got != want { 108 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 109 } 110 if t.Failed() { 111 t.Logf("Insertion order: %v", order[:nrInsertions]) 112 t.Logf("Set contents:\n%v", &s) 113 } 114 } 115 116 func TestRemoveRandom(t *testing.T) { 117 var s Set 118 for i := 0; i < testSize; i++ { 119 if !s.AddWithoutMerging(Range{i, i + 1}, i+valueOffset) { 120 t.Fatalf("Failed to insert segment %d", i) 121 } 122 } 123 order := rand.Perm(testSize) 124 var nrRemovals int 125 for i, j := range order { 126 seg := s.FindSegment(j) 127 if !seg.Ok() { 128 t.Errorf("Iteration %d: failed to find segment with key %d", i, j) 129 break 130 } 131 s.Remove(seg) 132 nrRemovals++ 133 if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil { 134 t.Errorf("Iteration %d: %v", i, err) 135 break 136 } 137 } 138 if got, want := s.countSegments(), testSize-nrRemovals; got != want { 139 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 140 } 141 if t.Failed() { 142 t.Logf("Removal order: %v", order[:nrRemovals]) 143 t.Logf("Set contents:\n%v", &s) 144 t.FailNow() 145 } 146 } 147 148 func TestMaxGapAddRandom(t *testing.T) { 149 var s gapSet 150 order := rand.Perm(testSize) 151 var nrInsertions int 152 for i, j := range order { 153 if !s.AddWithoutMerging(Range{j, j + 1}, j+valueOffset) { 154 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 155 break 156 } 157 nrInsertions++ 158 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 159 t.Errorf("Iteration %d: %v", i, err) 160 break 161 } 162 if err := checkSetMaxGap(&s); err != nil { 163 t.Errorf("When inserting %d: %v", j, err) 164 break 165 } 166 } 167 if got, want := s.countSegments(), nrInsertions; got != want { 168 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 169 } 170 if t.Failed() { 171 t.Logf("Insertion order: %v", order[:nrInsertions]) 172 t.Logf("Set contents:\n%v", &s) 173 } 174 } 175 176 func TestMaxGapAddRandomWithRandomInterval(t *testing.T) { 177 var s gapSet 178 order := randIntervalPermutation(testSize) 179 var nrInsertions int 180 for i, j := range order { 181 if !s.AddWithoutMerging(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset) { 182 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 183 break 184 } 185 nrInsertions++ 186 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 187 t.Errorf("Iteration %d: %v", i, err) 188 break 189 } 190 if err := checkSetMaxGap(&s); err != nil { 191 t.Errorf("When inserting %d: %v", j, err) 192 break 193 } 194 } 195 if got, want := s.countSegments(), nrInsertions; got != want { 196 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 197 } 198 if t.Failed() { 199 t.Logf("Insertion order: %v", order[:nrInsertions]) 200 t.Logf("Set contents:\n%v", &s) 201 } 202 } 203 204 func TestMaxGapAddRandomWithMerge(t *testing.T) { 205 var s gapSet 206 order := randIntervalPermutation(testSize) 207 nrInsertions := 1 208 for i, j := range order { 209 if !s.Add(Range{j, j + intervalLength}, j+valueOffset) { 210 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 211 break 212 } 213 if err := checkSetMaxGap(&s); err != nil { 214 t.Errorf("When inserting %d: %v", j, err) 215 break 216 } 217 } 218 if got, want := s.countSegments(), nrInsertions; got != want { 219 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 220 } 221 if t.Failed() { 222 t.Logf("Insertion order: %v", order) 223 t.Logf("Set contents:\n%v", &s) 224 } 225 } 226 227 func TestMaxGapRemoveRandom(t *testing.T) { 228 var s gapSet 229 for i := 0; i < testSize; i++ { 230 if !s.AddWithoutMerging(Range{i, i + 1}, i+valueOffset) { 231 t.Fatalf("Failed to insert segment %d", i) 232 } 233 } 234 order := rand.Perm(testSize) 235 var nrRemovals int 236 for i, j := range order { 237 seg := s.FindSegment(j) 238 if !seg.Ok() { 239 t.Errorf("Iteration %d: failed to find segment with key %d", i, j) 240 break 241 } 242 temprange := seg.Range() 243 s.Remove(seg) 244 nrRemovals++ 245 if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil { 246 t.Errorf("Iteration %d: %v", i, err) 247 break 248 } 249 if err := checkSetMaxGap(&s); err != nil { 250 t.Errorf("When removing %v: %v", temprange, err) 251 break 252 } 253 } 254 if got, want := s.countSegments(), testSize-nrRemovals; got != want { 255 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 256 } 257 if t.Failed() { 258 t.Logf("Removal order: %v", order[:nrRemovals]) 259 t.Logf("Set contents:\n%v", &s) 260 t.FailNow() 261 } 262 } 263 264 func TestMaxGapRemoveHalfRandom(t *testing.T) { 265 var s gapSet 266 for i := 0; i < testSize; i++ { 267 if !s.AddWithoutMerging(Range{intervalLength * i, intervalLength*i + rand.Intn(intervalLength-1) + 1}, intervalLength*i+valueOffset) { 268 t.Fatalf("Failed to insert segment %d", i) 269 } 270 } 271 order := randIntervalPermutation(testSize) 272 order = order[:testSize/2] 273 var nrRemovals int 274 for i, j := range order { 275 seg := s.FindSegment(j) 276 if !seg.Ok() { 277 t.Errorf("Iteration %d: failed to find segment with key %d", i, j) 278 break 279 } 280 temprange := seg.Range() 281 s.Remove(seg) 282 nrRemovals++ 283 if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil { 284 t.Errorf("Iteration %d: %v", i, err) 285 break 286 } 287 if err := checkSetMaxGap(&s); err != nil { 288 t.Errorf("When removing %v: %v", temprange, err) 289 break 290 } 291 } 292 if got, want := s.countSegments(), testSize-nrRemovals; got != want { 293 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 294 } 295 if t.Failed() { 296 t.Logf("Removal order: %v", order[:nrRemovals]) 297 t.Logf("Set contents:\n%v", &s) 298 t.FailNow() 299 } 300 } 301 302 func TestMaxGapAddRandomRemoveRandomHalfWithMerge(t *testing.T) { 303 var s gapSet 304 order := randIntervalPermutation(testSize * 2) 305 order = order[:testSize] 306 for i, j := range order { 307 if !s.Add(Range{j, j + intervalLength}, j+valueOffset) { 308 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 309 break 310 } 311 if err := checkSetMaxGap(&s); err != nil { 312 t.Errorf("When inserting %d: %v", j, err) 313 break 314 } 315 } 316 shuffle(order) 317 var nrRemovals int 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 nrRemovals++ 326 if err := checkSetMaxGap(&s); err != nil { 327 t.Errorf("When removing %v: %v", temprange, err) 328 break 329 } 330 } 331 if t.Failed() { 332 t.Logf("Removal order: %v", order[:nrRemovals]) 333 t.Logf("Set contents:\n%v", &s) 334 t.FailNow() 335 } 336 } 337 338 func TestNextLargeEnoughGap(t *testing.T) { 339 var s gapSet 340 order := randIntervalPermutation(testSize * 2) 341 order = order[:testSize] 342 for i, j := range order { 343 if !s.Add(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset) { 344 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 345 break 346 } 347 if err := checkSetMaxGap(&s); err != nil { 348 t.Errorf("When inserting %d: %v", j, err) 349 break 350 } 351 } 352 shuffle(order) 353 order = order[:testSize/2] 354 for _, j := range order { 355 seg := s.FindSegment(j) 356 if !seg.Ok() { 357 continue 358 } 359 temprange := seg.Range() 360 s.Remove(seg) 361 if err := checkSetMaxGap(&s); err != nil { 362 t.Errorf("When removing %v: %v", temprange, err) 363 break 364 } 365 } 366 minSize := 7 367 var gapArr1 []int 368 for gap := s.LowerBoundGap(0).NextLargeEnoughGap(minSize); gap.Ok(); gap = gap.NextLargeEnoughGap(minSize) { 369 if gap.Range().Length() < minSize { 370 t.Errorf("NextLargeEnoughGap wrong, gap %v has length %d, wanted %d", gap.Range(), gap.Range().Length(), minSize) 371 } else { 372 gapArr1 = append(gapArr1, gap.Range().Start) 373 } 374 } 375 var gapArr2 []int 376 for gap := s.LowerBoundGap(0).NextGap(); gap.Ok(); gap = gap.NextGap() { 377 if gap.Range().Length() >= minSize { 378 gapArr2 = append(gapArr2, gap.Range().Start) 379 } 380 } 381 382 if !reflect.DeepEqual(gapArr2, gapArr1) { 383 t.Errorf("Search result not correct, got: %v, wanted: %v", gapArr1, gapArr2) 384 } 385 if t.Failed() { 386 t.Logf("Set contents:\n%v", &s) 387 t.FailNow() 388 } 389 } 390 391 func TestPrevLargeEnoughGap(t *testing.T) { 392 var s gapSet 393 order := randIntervalPermutation(testSize * 2) 394 order = order[:testSize] 395 for i, j := range order { 396 if !s.Add(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset) { 397 t.Errorf("Iteration %d: failed to insert segment with key %d", i, j) 398 break 399 } 400 if err := checkSetMaxGap(&s); err != nil { 401 t.Errorf("When inserting %d: %v", j, err) 402 break 403 } 404 } 405 end := s.LastSegment().End() 406 shuffle(order) 407 order = order[:testSize/2] 408 for _, j := range order { 409 seg := s.FindSegment(j) 410 if !seg.Ok() { 411 continue 412 } 413 temprange := seg.Range() 414 s.Remove(seg) 415 if err := checkSetMaxGap(&s); err != nil { 416 t.Errorf("When removing %v: %v", temprange, err) 417 break 418 } 419 } 420 minSize := 7 421 var gapArr1 []int 422 for gap := s.UpperBoundGap(end + intervalLength).PrevLargeEnoughGap(minSize); gap.Ok(); gap = gap.PrevLargeEnoughGap(minSize) { 423 if gap.Range().Length() < minSize { 424 t.Errorf("PrevLargeEnoughGap wrong, gap length %d, wanted %d", gap.Range().Length(), minSize) 425 } else { 426 gapArr1 = append(gapArr1, gap.Range().Start) 427 } 428 } 429 var gapArr2 []int 430 for gap := s.UpperBoundGap(end + intervalLength).PrevGap(); gap.Ok(); gap = gap.PrevGap() { 431 if gap.Range().Length() >= minSize { 432 gapArr2 = append(gapArr2, gap.Range().Start) 433 } 434 } 435 if !reflect.DeepEqual(gapArr2, gapArr1) { 436 t.Errorf("Search result not correct, got: %v, wanted: %v", gapArr1, gapArr2) 437 } 438 if t.Failed() { 439 t.Logf("Set contents:\n%v", &s) 440 t.FailNow() 441 } 442 } 443 444 func TestAddSequentialAdjacent(t *testing.T) { 445 var s Set 446 var nrInsertions int 447 for i := 0; i < testSize; i++ { 448 if !s.AddWithoutMerging(Range{i, i + 1}, i+valueOffset) { 449 t.Fatalf("Failed to insert segment %d", i) 450 } 451 nrInsertions++ 452 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 453 t.Errorf("Iteration %d: %v", i, err) 454 break 455 } 456 } 457 if got, want := s.countSegments(), nrInsertions; got != want { 458 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 459 } 460 if t.Failed() { 461 t.Logf("Set contents:\n%v", &s) 462 } 463 464 first := s.FirstSegment() 465 gotSeg, gotGap := first.PrevNonEmpty() 466 if wantGap := s.FirstGap(); gotSeg.Ok() || gotGap != wantGap { 467 t.Errorf("FirstSegment().PrevNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", gotSeg, gotGap, wantGap) 468 } 469 gotSeg, gotGap = first.NextNonEmpty() 470 if wantSeg := first.NextSegment(); gotSeg != wantSeg || gotGap.Ok() { 471 t.Errorf("FirstSegment().NextNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", gotSeg, gotGap, wantSeg) 472 } 473 474 last := s.LastSegment() 475 gotSeg, gotGap = last.PrevNonEmpty() 476 if wantSeg := last.PrevSegment(); gotSeg != wantSeg || gotGap.Ok() { 477 t.Errorf("LastSegment().PrevNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", gotSeg, gotGap, wantSeg) 478 } 479 gotSeg, gotGap = last.NextNonEmpty() 480 if wantGap := s.LastGap(); gotSeg.Ok() || gotGap != wantGap { 481 t.Errorf("LastSegment().NextNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", gotSeg, gotGap, wantGap) 482 } 483 484 for seg := first.NextSegment(); seg != last; seg = seg.NextSegment() { 485 gotSeg, gotGap = seg.PrevNonEmpty() 486 if wantSeg := seg.PrevSegment(); gotSeg != wantSeg || gotGap.Ok() { 487 t.Errorf("%v.PrevNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", seg, gotSeg, gotGap, wantSeg) 488 } 489 gotSeg, gotGap = seg.NextNonEmpty() 490 if wantSeg := seg.NextSegment(); gotSeg != wantSeg || gotGap.Ok() { 491 t.Errorf("%v.NextNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", seg, gotSeg, gotGap, wantSeg) 492 } 493 } 494 } 495 496 func TestAddSequentialNonAdjacent(t *testing.T) { 497 var s Set 498 var nrInsertions int 499 for i := 0; i < testSize; i++ { 500 // The range here differs from TestAddSequentialAdjacent so that 501 // consecutive segments are not adjacent. 502 if !s.AddWithoutMerging(Range{2 * i, 2*i + 1}, 2*i+valueOffset) { 503 t.Fatalf("Failed to insert segment %d", i) 504 } 505 nrInsertions++ 506 if err := s.segmentTestCheck(nrInsertions, validate); err != nil { 507 t.Errorf("Iteration %d: %v", i, err) 508 break 509 } 510 } 511 if got, want := s.countSegments(), nrInsertions; got != want { 512 t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want) 513 } 514 if t.Failed() { 515 t.Logf("Set contents:\n%v", &s) 516 } 517 518 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 519 gotSeg, gotGap := seg.PrevNonEmpty() 520 if wantGap := seg.PrevGap(); gotSeg.Ok() || gotGap != wantGap { 521 t.Errorf("%v.PrevNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", seg, gotSeg, gotGap, wantGap) 522 } 523 gotSeg, gotGap = seg.NextNonEmpty() 524 if wantGap := seg.NextGap(); gotSeg.Ok() || gotGap != wantGap { 525 t.Errorf("%v.NextNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", seg, gotSeg, gotGap, wantGap) 526 } 527 } 528 } 529 530 func TestMergeSplit(t *testing.T) { 531 tests := []struct { 532 name string 533 initial []Range 534 split bool 535 splitAddr int 536 final []Range 537 }{ 538 { 539 name: "Add merges after existing segment", 540 initial: []Range{{1000, 1100}, {1100, 1200}}, 541 final: []Range{{1000, 1200}}, 542 }, 543 { 544 name: "Add merges before existing segment", 545 initial: []Range{{1100, 1200}, {1000, 1100}}, 546 final: []Range{{1000, 1200}}, 547 }, 548 { 549 name: "Add merges between existing segments", 550 initial: []Range{{1000, 1100}, {1200, 1300}, {1100, 1200}}, 551 final: []Range{{1000, 1300}}, 552 }, 553 { 554 name: "SplitAt does nothing at a free address", 555 initial: []Range{{100, 200}}, 556 split: true, 557 splitAddr: 300, 558 final: []Range{{100, 200}}, 559 }, 560 { 561 name: "SplitAt does nothing at the beginning of a segment", 562 initial: []Range{{100, 200}}, 563 split: true, 564 splitAddr: 100, 565 final: []Range{{100, 200}}, 566 }, 567 { 568 name: "SplitAt does nothing at the end of a segment", 569 initial: []Range{{100, 200}}, 570 split: true, 571 splitAddr: 200, 572 final: []Range{{100, 200}}, 573 }, 574 { 575 name: "SplitAt splits in the middle of a segment", 576 initial: []Range{{100, 200}}, 577 split: true, 578 splitAddr: 150, 579 final: []Range{{100, 150}, {150, 200}}, 580 }, 581 } 582 Tests: 583 for _, test := range tests { 584 var s Set 585 for _, r := range test.initial { 586 if !s.Add(r, 0) { 587 t.Errorf("%s: Add(%v) failed; set contents:\n%v", test.name, r, &s) 588 continue Tests 589 } 590 } 591 if test.split { 592 s.SplitAt(test.splitAddr) 593 } 594 var i int 595 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 596 if i > len(test.final) { 597 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, s.countSegments(), len(test.final), &s) 598 continue Tests 599 } 600 if got, want := seg.Range(), test.final[i]; got != want { 601 t.Errorf("%s: Segment %d mismatch: got %v, wanted %v; set contents:\n%v", test.name, i, got, want, &s) 602 continue Tests 603 } 604 i++ 605 } 606 if i < len(test.final) { 607 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, i, len(test.final), &s) 608 } 609 } 610 } 611 612 func TestIsolate(t *testing.T) { 613 tests := []struct { 614 name string 615 initial Range 616 bounds Range 617 final []Range 618 }{ 619 { 620 name: "Isolate does not split a segment that falls inside bounds", 621 initial: Range{100, 200}, 622 bounds: Range{100, 200}, 623 final: []Range{{100, 200}}, 624 }, 625 { 626 name: "Isolate splits at beginning of segment", 627 initial: Range{50, 200}, 628 bounds: Range{100, 200}, 629 final: []Range{{50, 100}, {100, 200}}, 630 }, 631 { 632 name: "Isolate splits at end of segment", 633 initial: Range{100, 250}, 634 bounds: Range{100, 200}, 635 final: []Range{{100, 200}, {200, 250}}, 636 }, 637 { 638 name: "Isolate splits at beginning and end of segment", 639 initial: Range{50, 250}, 640 bounds: Range{100, 200}, 641 final: []Range{{50, 100}, {100, 200}, {200, 250}}, 642 }, 643 } 644 Tests: 645 for _, test := range tests { 646 var s Set 647 seg := s.Insert(s.FirstGap(), test.initial, 0) 648 seg = s.Isolate(seg, test.bounds) 649 if !test.bounds.IsSupersetOf(seg.Range()) { 650 t.Errorf("%s: Isolated segment %v lies outside bounds %v; set contents:\n%v", test.name, seg.Range(), test.bounds, &s) 651 } 652 var i int 653 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 654 if i > len(test.final) { 655 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, s.countSegments(), len(test.final), &s) 656 continue Tests 657 } 658 if got, want := seg.Range(), test.final[i]; got != want { 659 t.Errorf("%s: Segment %d mismatch: got %v, wanted %v; set contents:\n%v", test.name, i, got, want, &s) 660 continue Tests 661 } 662 i++ 663 } 664 if i < len(test.final) { 665 t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, i, len(test.final), &s) 666 } 667 } 668 } 669 670 func benchmarkAddSequential(b *testing.B, size int) { 671 for n := 0; n < b.N; n++ { 672 var s Set 673 for i := 0; i < size; i++ { 674 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 675 b.Fatalf("Failed to insert segment %d", i) 676 } 677 } 678 } 679 } 680 681 func benchmarkAddRandom(b *testing.B, size int) { 682 order := rand.Perm(size) 683 684 b.ResetTimer() 685 for n := 0; n < b.N; n++ { 686 var s Set 687 for _, i := range order { 688 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 689 b.Fatalf("Failed to insert segment %d", i) 690 } 691 } 692 } 693 } 694 695 func benchmarkFindSequential(b *testing.B, size int) { 696 var s Set 697 for i := 0; i < size; i++ { 698 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 699 b.Fatalf("Failed to insert segment %d", i) 700 } 701 } 702 703 b.ResetTimer() 704 for n := 0; n < b.N; n++ { 705 for i := 0; i < size; i++ { 706 if seg := s.FindSegment(i); !seg.Ok() { 707 b.Fatalf("Failed to find segment %d", i) 708 } 709 } 710 } 711 } 712 713 func benchmarkFindRandom(b *testing.B, size int) { 714 var s Set 715 for i := 0; i < size; i++ { 716 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 717 b.Fatalf("Failed to insert segment %d", i) 718 } 719 } 720 order := rand.Perm(size) 721 722 b.ResetTimer() 723 for n := 0; n < b.N; n++ { 724 for _, i := range order { 725 if si := s.FindSegment(i); !si.Ok() { 726 b.Fatalf("Failed to find segment %d", i) 727 } 728 } 729 } 730 } 731 732 func benchmarkIteration(b *testing.B, size int) { 733 var s Set 734 for i := 0; i < size; i++ { 735 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 736 b.Fatalf("Failed to insert segment %d", i) 737 } 738 } 739 740 b.ResetTimer() 741 var count uint64 742 for n := 0; n < b.N; n++ { 743 for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 744 count++ 745 } 746 } 747 if got, want := count, uint64(size)*uint64(b.N); got != want { 748 b.Fatalf("Iterated wrong number of segments: got %d, wanted %d", got, want) 749 } 750 } 751 752 func benchmarkAddFindRemoveSequential(b *testing.B, size int) { 753 for n := 0; n < b.N; n++ { 754 var s Set 755 for i := 0; i < size; i++ { 756 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 757 b.Fatalf("Failed to insert segment %d", i) 758 } 759 } 760 for i := 0; i < size; i++ { 761 seg := s.FindSegment(i) 762 if !seg.Ok() { 763 b.Fatalf("Failed to find segment %d", i) 764 } 765 s.Remove(seg) 766 } 767 if !s.IsEmpty() { 768 b.Fatalf("Set not empty after all removals:\n%v", &s) 769 } 770 } 771 } 772 773 func benchmarkAddFindRemoveRandom(b *testing.B, size int) { 774 order := rand.Perm(size) 775 776 b.ResetTimer() 777 for n := 0; n < b.N; n++ { 778 var s Set 779 for _, i := range order { 780 if !s.AddWithoutMerging(Range{i, i + 1}, i) { 781 b.Fatalf("Failed to insert segment %d", i) 782 } 783 } 784 for _, i := range order { 785 seg := s.FindSegment(i) 786 if !seg.Ok() { 787 b.Fatalf("Failed to find segment %d", i) 788 } 789 s.Remove(seg) 790 } 791 if !s.IsEmpty() { 792 b.Fatalf("Set not empty after all removals:\n%v", &s) 793 } 794 } 795 } 796 797 // Although we don't generally expect our segment sets to get this big, they're 798 // useful for emulating the effect of cache pressure. 799 var testSizes = []struct { 800 desc string 801 size int 802 }{ 803 {"64", 1 << 6}, 804 {"256", 1 << 8}, 805 {"1K", 1 << 10}, 806 {"4K", 1 << 12}, 807 {"16K", 1 << 14}, 808 {"64K", 1 << 16}, 809 } 810 811 func BenchmarkAddSequential(b *testing.B) { 812 for _, test := range testSizes { 813 b.Run(test.desc, func(b *testing.B) { 814 benchmarkAddSequential(b, test.size) 815 }) 816 } 817 } 818 819 func BenchmarkAddRandom(b *testing.B) { 820 for _, test := range testSizes { 821 b.Run(test.desc, func(b *testing.B) { 822 benchmarkAddRandom(b, test.size) 823 }) 824 } 825 } 826 827 func BenchmarkFindSequential(b *testing.B) { 828 for _, test := range testSizes { 829 b.Run(test.desc, func(b *testing.B) { 830 benchmarkFindSequential(b, test.size) 831 }) 832 } 833 } 834 835 func BenchmarkFindRandom(b *testing.B) { 836 for _, test := range testSizes { 837 b.Run(test.desc, func(b *testing.B) { 838 benchmarkFindRandom(b, test.size) 839 }) 840 } 841 } 842 843 func BenchmarkIteration(b *testing.B) { 844 for _, test := range testSizes { 845 b.Run(test.desc, func(b *testing.B) { 846 benchmarkIteration(b, test.size) 847 }) 848 } 849 } 850 851 func BenchmarkAddFindRemoveSequential(b *testing.B) { 852 for _, test := range testSizes { 853 b.Run(test.desc, func(b *testing.B) { 854 benchmarkAddFindRemoveSequential(b, test.size) 855 }) 856 } 857 } 858 859 func BenchmarkAddFindRemoveRandom(b *testing.B) { 860 for _, test := range testSizes { 861 b.Run(test.desc, func(b *testing.B) { 862 benchmarkAddFindRemoveRandom(b, test.size) 863 }) 864 } 865 }