gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sleep/sleep_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 sleep 16 17 import ( 18 "math/rand" 19 "runtime" 20 "sync" 21 "testing" 22 "time" 23 24 "gvisor.dev/gvisor/pkg/atomicbitops" 25 ) 26 27 // ZeroWakerNotAsserted tests that a zero-value waker is in non-asserted state. 28 func ZeroWakerNotAsserted(t *testing.T) { 29 var w Waker 30 if w.IsAsserted() { 31 t.Fatalf("Zero waker is asserted") 32 } 33 34 if w.Clear() { 35 t.Fatalf("Zero waker is asserted") 36 } 37 } 38 39 // AssertedWakerAfterAssert tests that a waker properly reports its state as 40 // asserted once its Assert() method is called. 41 func AssertedWakerAfterAssert(t *testing.T) { 42 var w Waker 43 w.Assert() 44 if !w.IsAsserted() { 45 t.Fatalf("Asserted waker is not reported as such") 46 } 47 48 if !w.Clear() { 49 t.Fatalf("Asserted waker is not reported as such") 50 } 51 } 52 53 // AssertedWakerAfterTwoAsserts tests that a waker properly reports its state as 54 // asserted once its Assert() method is called twice. 55 func AssertedWakerAfterTwoAsserts(t *testing.T) { 56 var w Waker 57 w.Assert() 58 w.Assert() 59 if !w.IsAsserted() { 60 t.Fatalf("Asserted waker is not reported as such") 61 } 62 63 if !w.Clear() { 64 t.Fatalf("Asserted waker is not reported as such") 65 } 66 } 67 68 // NotAssertedWakerWithSleeper tests that a waker properly reports its state as 69 // not asserted after a sleeper is associated with it. 70 func NotAssertedWakerWithSleeper(t *testing.T) { 71 var w Waker 72 var s Sleeper 73 s.AddWaker(&w) 74 if w.IsAsserted() { 75 t.Fatalf("Non-asserted waker is reported as asserted") 76 } 77 78 if w.Clear() { 79 t.Fatalf("Non-asserted waker is reported as asserted") 80 } 81 } 82 83 // NotAssertedWakerAfterWake tests that a waker properly reports its state as 84 // not asserted after a previous assert is consumed by a sleeper. That is, tests 85 // the "edge-triggered" behavior. 86 func NotAssertedWakerAfterWake(t *testing.T) { 87 var w Waker 88 var s Sleeper 89 s.AddWaker(&w) 90 w.Assert() 91 s.Fetch(true) 92 if w.IsAsserted() { 93 t.Fatalf("Consumed waker is reported as asserted") 94 } 95 96 if w.Clear() { 97 t.Fatalf("Consumed waker is reported as asserted") 98 } 99 } 100 101 // AssertedWakerBeforeAdd tests that a waker causes a sleeper to not sleep if 102 // it's already asserted before being added. 103 func AssertedWakerBeforeAdd(t *testing.T) { 104 var w Waker 105 var s Sleeper 106 w.Assert() 107 s.AddWaker(&w) 108 109 if s.Fetch(false) != &w { 110 t.Fatalf("Fetch did not match waker") 111 } 112 } 113 114 // ClearedWaker tests that a waker properly reports its state as not asserted 115 // after it is cleared. 116 func ClearedWaker(t *testing.T) { 117 var w Waker 118 w.Assert() 119 w.Clear() 120 if w.IsAsserted() { 121 t.Fatalf("Cleared waker is reported as asserted") 122 } 123 124 if w.Clear() { 125 t.Fatalf("Cleared waker is reported as asserted") 126 } 127 } 128 129 // ClearedWakerWithSleeper tests that a waker properly reports its state as 130 // not asserted when it is cleared while it has a sleeper associated with it. 131 func ClearedWakerWithSleeper(t *testing.T) { 132 var w Waker 133 var s Sleeper 134 s.AddWaker(&w) 135 w.Clear() 136 if w.IsAsserted() { 137 t.Fatalf("Cleared waker is reported as asserted") 138 } 139 140 if w.Clear() { 141 t.Fatalf("Cleared waker is reported as asserted") 142 } 143 } 144 145 // ClearedWakerAssertedWithSleeper tests that a waker properly reports its state 146 // as not asserted when it is cleared while it has a sleeper associated with it 147 // and has been asserted. 148 func ClearedWakerAssertedWithSleeper(t *testing.T) { 149 var w Waker 150 var s Sleeper 151 s.AddWaker(&w) 152 w.Assert() 153 w.Clear() 154 if w.IsAsserted() { 155 t.Fatalf("Cleared waker is reported as asserted") 156 } 157 158 if w.Clear() { 159 t.Fatalf("Cleared waker is reported as asserted") 160 } 161 } 162 163 // TestBlock tests that a sleeper actually blocks waiting for the waker to 164 // assert its state. 165 func TestBlock(t *testing.T) { 166 var w Waker 167 var s Sleeper 168 169 s.AddWaker(&w) 170 171 // Assert waker after one second. 172 before := time.Now() 173 time.AfterFunc(time.Second, w.Assert) 174 175 // Fetch the result and make sure it took at least 500ms. 176 if s.Fetch(true) != &w { 177 t.Fatalf("Fetch did not match waker") 178 } 179 if d := time.Now().Sub(before); d < 500*time.Millisecond { 180 t.Fatalf("Duration was too short: %v", d) 181 } 182 183 // Check that already-asserted waker completes inline. 184 w.Assert() 185 if s.Fetch(true) != &w { 186 t.Fatalf("Fetch did not match waker") 187 } 188 189 // Check that fetch sleeps if waker had been asserted but was reset 190 // before Fetch is called. 191 w.Assert() 192 w.Clear() 193 before = time.Now() 194 time.AfterFunc(time.Second, w.Assert) 195 196 if s.Fetch(true) != &w { 197 t.Fatalf("Fetch did not match waker") 198 } 199 if d := time.Now().Sub(before); d < 500*time.Millisecond { 200 t.Fatalf("Duration was too short: %v", d) 201 } 202 } 203 204 // TestNonBlock checks that a sleeper won't block if waker isn't asserted. 205 func TestNonBlock(t *testing.T) { 206 var w Waker 207 var s Sleeper 208 209 // Don't block when there's no waker. 210 if s.Fetch(false) != nil { 211 t.Fatalf("Fetch succeeded when there is no waker") 212 } 213 214 // Don't block when waker isn't asserted. 215 s.AddWaker(&w) 216 if s.Fetch(false) != nil { 217 t.Fatalf("Fetch succeeded when waker was not asserted") 218 } 219 220 // Don't block when waker was asserted, but isn't anymore. 221 w.Assert() 222 w.Clear() 223 if s.Fetch(false) != nil { 224 t.Fatalf("Fetch succeeded when waker was not asserted anymore") 225 } 226 227 // Don't block when waker was consumed by previous Fetch(). 228 w.Assert() 229 if s.Fetch(false) != &w { 230 t.Fatalf("Fetch failed even though waker was asserted") 231 } 232 233 if s.Fetch(false) != nil { 234 t.Fatalf("Fetch succeeded when waker had been consumed") 235 } 236 } 237 238 // TestMultiple checks that a sleeper can wait for and receives notifications 239 // from multiple wakers. 240 func TestMultiple(t *testing.T) { 241 s := Sleeper{} 242 w1 := Waker{} 243 w2 := Waker{} 244 245 s.AddWaker(&w1) 246 s.AddWaker(&w2) 247 248 w1.Assert() 249 w2.Assert() 250 251 v := s.Fetch(false) 252 if v == nil { 253 t.Fatalf("Fetch failed when there are asserted wakers") 254 } 255 if v != &w1 && v != &w2 { 256 t.Fatalf("Unexpected waker: %v", v) 257 } 258 259 want := &w1 260 if v == want { 261 want = &w2 // Other waiter. 262 } 263 v = s.Fetch(false) 264 if v == nil { 265 t.Fatalf("Fetch failed when there is an asserted waker") 266 } 267 if v != want { 268 t.Fatalf("Unexpected waker, got %v, want %v", v, want) 269 } 270 } 271 272 // TestDoneFunction tests if calling Done() on a sleeper works properly. 273 func TestDoneFunction(t *testing.T) { 274 // Trivial case of no waker. 275 s := Sleeper{} 276 s.Done() 277 278 // Cases when the sleeper has n wakers, but none are asserted. 279 for n := 1; n < 20; n++ { 280 s := Sleeper{} 281 w := make([]Waker, n) 282 for j := 0; j < n; j++ { 283 s.AddWaker(&w[j]) 284 } 285 s.Done() 286 } 287 288 // Cases when the sleeper has n wakers, and only the i-th one is 289 // asserted. 290 for n := 1; n < 20; n++ { 291 for i := 0; i < n; i++ { 292 s := Sleeper{} 293 w := make([]Waker, n) 294 for j := 0; j < n; j++ { 295 s.AddWaker(&w[j]) 296 } 297 w[i].Assert() 298 s.Done() 299 } 300 } 301 302 // Cases when the sleeper has n wakers, and the i-th one is asserted 303 // and cleared. 304 for n := 1; n < 20; n++ { 305 for i := 0; i < n; i++ { 306 s := Sleeper{} 307 w := make([]Waker, n) 308 for j := 0; j < n; j++ { 309 s.AddWaker(&w[j]) 310 } 311 w[i].Assert() 312 w[i].Clear() 313 s.Done() 314 } 315 } 316 317 // Cases when the sleeper has n wakers, with a random number of them 318 // asserted. 319 for n := 1; n < 20; n++ { 320 for iters := 0; iters < 1000; iters++ { 321 s := Sleeper{} 322 w := make([]Waker, n) 323 for j := 0; j < n; j++ { 324 s.AddWaker(&w[j]) 325 } 326 327 // Pick the number of asserted elements, then assert 328 // random wakers. 329 asserted := rand.Int() % (n + 1) 330 for j := 0; j < asserted; j++ { 331 w[rand.Int()%n].Assert() 332 } 333 s.Done() 334 } 335 } 336 } 337 338 // TestAssertFetch tests basic assert fetch functionality. 339 func TestAssertFetch(t *testing.T) { 340 const sleeperWakers = 100 341 const wakeRequests = 1000 342 const seedAsserts = 10 343 344 ws := make([]Waker, sleeperWakers) 345 ss := make([]Sleeper, sleeperWakers) 346 for i := 0; i < sleeperWakers; i++ { 347 ss[i].AddWaker(&ws[i]) 348 } 349 defer func() { 350 for i := 0; i < sleeperWakers; i++ { 351 defer ss[i].Done() 352 } 353 }() 354 var ( 355 count atomicbitops.Int32 356 wg sync.WaitGroup 357 ) 358 for i := 0; i < sleeperWakers; i++ { 359 wg.Add(1) 360 go func(i int) { 361 defer wg.Done() 362 ss[i].Fetch(true /* block */) 363 w := &ws[(i+1)%sleeperWakers] 364 for n := 0; n < wakeRequests; n++ { 365 count.Add(1) 366 ss[i].AssertAndFetch(w) 367 } 368 w.Assert() // Final wake-up. 369 }(i) 370 } 371 372 // Fire the first assertion. 373 ws[0].Assert() 374 wg.Wait() 375 376 // Check what we got. 377 if got, want := count.Load(), int32(sleeperWakers*wakeRequests); got != want { 378 t.Errorf("unexpected count: got %d, wanted %d", got, want) 379 } 380 } 381 382 // TestRace tests that multiple wakers can continuously send wake requests to 383 // the sleeper. 384 func TestRace(t *testing.T) { 385 const wakers = 100 386 const wakeRequests = 10000 387 388 counts := make(map[*Waker]int, wakers) 389 s := Sleeper{} 390 391 // Associate each waker and start goroutines that will assert them. 392 for i := 0; i < wakers; i++ { 393 var w Waker 394 s.AddWaker(&w) 395 go func() { 396 n := 0 397 for n < wakeRequests { 398 if !w.IsAsserted() { 399 w.Assert() 400 n++ 401 } else { 402 runtime.Gosched() 403 } 404 } 405 }() 406 } 407 408 // Wait for all wake up notifications from all wakers. 409 for i := 0; i < wakers*wakeRequests; i++ { 410 v := s.Fetch(true) 411 counts[v]++ 412 } 413 414 // Check that we got the right number for each. 415 if got := len(counts); got != wakers { 416 t.Errorf("Got %d wakers, wanted %d", got, wakers) 417 } 418 for _, count := range counts { 419 if count != wakeRequests { 420 t.Errorf("Waker only got %d wakes, wanted %d", count, wakeRequests) 421 } 422 } 423 } 424 425 // TestRaceInOrder tests that multiple wakers can continuously send wake requests to 426 // the sleeper and that the wakers are retrieved in the order asserted. 427 func TestRaceInOrder(t *testing.T) { 428 w := make([]Waker, 10000) 429 s := Sleeper{} 430 431 // Associate each waker and start goroutines that will assert them. 432 for i := range w { 433 s.AddWaker(&w[i]) 434 } 435 go func() { 436 for i := range w { 437 w[i].Assert() 438 } 439 }() 440 441 // Wait for all wake up notifications from all wakers. 442 for i := range w { 443 got := s.Fetch(true) 444 if want := &w[i]; got != want { 445 t.Fatalf("got %v want %v", got, want) 446 } 447 } 448 } 449 450 // BenchmarkSleeperMultiSelect measures how long it takes to fetch a wake up 451 // from 4 wakers when at least one is already asserted. 452 func BenchmarkSleeperMultiSelect(b *testing.B) { 453 const count = 4 454 s := Sleeper{} 455 w := make([]Waker, count) 456 for i := range w { 457 s.AddWaker(&w[i]) 458 } 459 460 b.ResetTimer() 461 for i := 0; i < b.N; i++ { 462 w[count-1].Assert() 463 s.Fetch(true) 464 } 465 } 466 467 // BenchmarkGoMultiSelect measures how long it takes to fetch a zero-length 468 // struct from one of 4 channels when at least one is ready. 469 func BenchmarkGoMultiSelect(b *testing.B) { 470 const count = 4 471 ch := make([]chan struct{}, count) 472 for i := range ch { 473 ch[i] = make(chan struct{}, 1) 474 } 475 476 b.ResetTimer() 477 for i := 0; i < b.N; i++ { 478 ch[count-1] <- struct{}{} 479 select { 480 case <-ch[0]: 481 case <-ch[1]: 482 case <-ch[2]: 483 case <-ch[3]: 484 } 485 } 486 } 487 488 // BenchmarkSleeperSingleSelect measures how long it takes to fetch a wake up 489 // from one waker that is already asserted. 490 func BenchmarkSleeperSingleSelect(b *testing.B) { 491 s := Sleeper{} 492 w := Waker{} 493 s.AddWaker(&w) 494 495 b.ResetTimer() 496 for i := 0; i < b.N; i++ { 497 w.Assert() 498 s.Fetch(true) 499 } 500 } 501 502 // BenchmarkGoSingleSelect measures how long it takes to fetch a zero-length 503 // struct from a channel that already has it buffered. 504 func BenchmarkGoSingleSelect(b *testing.B) { 505 ch := make(chan struct{}, 1) 506 507 b.ResetTimer() 508 for i := 0; i < b.N; i++ { 509 ch <- struct{}{} 510 <-ch 511 } 512 } 513 514 // BenchmarkSleeperAssertNonWaiting measures how long it takes to assert a 515 // channel that is already asserted. 516 func BenchmarkSleeperAssertNonWaiting(b *testing.B) { 517 w := Waker{} 518 w.Assert() 519 for i := 0; i < b.N; i++ { 520 w.Assert() 521 } 522 523 } 524 525 // BenchmarkGoAssertNonWaiting measures how long it takes to write to a channel 526 // that has already something written to it. 527 func BenchmarkGoAssertNonWaiting(b *testing.B) { 528 ch := make(chan struct{}, 1) 529 ch <- struct{}{} 530 for i := 0; i < b.N; i++ { 531 select { 532 case ch <- struct{}{}: 533 default: 534 } 535 } 536 } 537 538 // BenchmarkSleeperWaitOnSingleSelect measures how long it takes to wait on one 539 // waker channel while another goroutine wakes up the sleeper. 540 func BenchmarkSleeperWaitOnSingleSelect(b *testing.B) { 541 var ( 542 s Sleeper 543 w Waker 544 ns Sleeper 545 nw Waker 546 ) 547 ns.AddWaker(&nw) 548 s.AddWaker(&w) 549 go func() { 550 for i := 0; i < b.N; i++ { 551 ns.Fetch(true) 552 w.Assert() 553 } 554 }() 555 for i := 0; i < b.N; i++ { 556 nw.Assert() 557 s.Fetch(true) 558 } 559 } 560 561 // BenchmarkSleeperWaitOnSingleSelectSync is a modification of the similarly 562 // named benchmark, except it uses the synchronous AssertAndFetch. 563 func BenchmarkSleeperWaitOnSingleSelectSync(b *testing.B) { 564 var ( 565 s Sleeper 566 w Waker 567 ns Sleeper 568 nw Waker 569 ) 570 ns.AddWaker(&nw) 571 s.AddWaker(&w) 572 go func() { 573 ns.Fetch(true) 574 defer w.Assert() 575 for i := 0; i < b.N-1; i++ { 576 ns.AssertAndFetch(&w) 577 } 578 }() 579 for i := 0; i < b.N; i++ { 580 s.AssertAndFetch(&nw) 581 } 582 } 583 584 // BenchmarkGoWaitOnSingleSelect measures how long it takes to wait on one 585 // channel while another goroutine wakes up the sleeper. 586 func BenchmarkGoWaitOnSingleSelect(b *testing.B) { 587 ch := make(chan struct{}, 1) 588 nch := make(chan struct{}, 1) 589 go func() { 590 for i := 0; i < b.N; i++ { 591 <-nch 592 ch <- struct{}{} 593 } 594 }() 595 for i := 0; i < b.N; i++ { 596 nch <- struct{}{} 597 <-ch 598 } 599 } 600 601 // BenchmarkSleeperWaitOnMultiSelect measures how long it takes to wait on 4 602 // wakers while another goroutine wakes up the sleeper. 603 func BenchmarkSleeperWaitOnMultiSelect(b *testing.B) { 604 const count = 4 605 var ( 606 s Sleeper 607 ns Sleeper 608 nw Waker 609 ) 610 ns.AddWaker(&nw) 611 w := make([]Waker, count) 612 for i := range w { 613 s.AddWaker(&w[i]) 614 } 615 616 b.ResetTimer() 617 go func() { 618 for i := 0; i < b.N; i++ { 619 ns.Fetch(true) 620 w[count-1].Assert() 621 } 622 }() 623 for i := 0; i < b.N; i++ { 624 nw.Assert() 625 s.Fetch(true) 626 } 627 } 628 629 // BenchmarkSleeperWaitOnMultiSelectSync is a modification of the similarly 630 // named benchmark, except it uses the synchronous AssertAndFetch. 631 func BenchmarkSleeperWaitOnMultiSelectSync(b *testing.B) { 632 const count = 4 633 var ( 634 s Sleeper 635 ns Sleeper 636 nw Waker 637 ) 638 ns.AddWaker(&nw) 639 w := make([]Waker, count) 640 for i := range w { 641 s.AddWaker(&w[i]) 642 } 643 644 b.ResetTimer() 645 go func() { 646 ns.Fetch(true) 647 defer w[count-1].Assert() 648 for i := 0; i < b.N-1; i++ { 649 ns.AssertAndFetch(&w[count-1]) 650 } 651 }() 652 for i := 0; i < b.N; i++ { 653 s.AssertAndFetch(&nw) 654 } 655 } 656 657 // BenchmarkGoWaitOnMultiSelect measures how long it takes to wait on 4 channels 658 // while another goroutine wakes up the sleeper. 659 func BenchmarkGoWaitOnMultiSelect(b *testing.B) { 660 const count = 4 661 ch := make([]chan struct{}, count) 662 nch := make([]chan struct{}, count) 663 for i := range ch { 664 ch[i] = make(chan struct{}, 1) 665 nch[i] = make(chan struct{}, 1) 666 } 667 668 b.ResetTimer() 669 go func() { 670 for i := 0; i < b.N; i++ { 671 select { 672 case <-nch[0]: 673 case <-nch[1]: 674 case <-nch[2]: 675 case <-nch[3]: 676 } 677 ch[count-1] <- struct{}{} 678 } 679 }() 680 for i := 0; i < b.N; i++ { 681 nch[count-1] <- struct{}{} 682 select { 683 case <-ch[0]: 684 case <-ch[1]: 685 case <-ch[2]: 686 case <-ch[3]: 687 } 688 } 689 }