github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/time/sleep_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package time_test 6 7 import ( 8 "errors" 9 "fmt" 10 "math/rand" 11 "runtime" 12 "strings" 13 "sync" 14 "sync/atomic" 15 "testing" 16 . "time" 17 ) 18 19 // Go runtime uses different Windows timers for time.Now and sleeping. 20 // These can tick at different frequencies and can arrive out of sync. 21 // The effect can be seen, for example, as time.Sleep(100ms) is actually 22 // shorter then 100ms when measured as difference between time.Now before and 23 // after time.Sleep call. This was observed on Windows XP SP3 (windows/386). 24 // windowsInaccuracy is to ignore such errors. 25 const windowsInaccuracy = 17 * Millisecond 26 27 func TestSleep(t *testing.T) { 28 const delay = 100 * Millisecond 29 go func() { 30 Sleep(delay / 2) 31 Interrupt() 32 }() 33 start := Now() 34 Sleep(delay) 35 delayadj := delay 36 if runtime.GOOS == "windows" { 37 delayadj -= windowsInaccuracy 38 } 39 duration := Now().Sub(start) 40 if duration < delayadj { 41 t.Fatalf("Sleep(%s) slept for only %s", delay, duration) 42 } 43 } 44 45 // Test the basic function calling behavior. Correct queueing 46 // behavior is tested elsewhere, since After and AfterFunc share 47 // the same code. 48 func TestAfterFunc(t *testing.T) { 49 i := 10 50 c := make(chan bool) 51 var f func() 52 f = func() { 53 i-- 54 if i >= 0 { 55 AfterFunc(0, f) 56 Sleep(1 * Second) 57 } else { 58 c <- true 59 } 60 } 61 62 AfterFunc(0, f) 63 <-c 64 } 65 66 func TestAfterStress(t *testing.T) { 67 stop := uint32(0) 68 go func() { 69 for atomic.LoadUint32(&stop) == 0 { 70 runtime.GC() 71 // Yield so that the OS can wake up the timer thread, 72 // so that it can generate channel sends for the main goroutine, 73 // which will eventually set stop = 1 for us. 74 Sleep(Nanosecond) 75 } 76 }() 77 ticker := NewTicker(1) 78 for i := 0; i < 100; i++ { 79 <-ticker.C 80 } 81 ticker.Stop() 82 atomic.StoreUint32(&stop, 1) 83 } 84 85 func benchmark(b *testing.B, bench func(n int)) { 86 87 // Create equal number of garbage timers on each P before starting 88 // the benchmark. 89 var wg sync.WaitGroup 90 garbageAll := make([][]*Timer, runtime.GOMAXPROCS(0)) 91 for i := range garbageAll { 92 wg.Add(1) 93 go func(i int) { 94 defer wg.Done() 95 garbage := make([]*Timer, 1<<15) 96 for j := range garbage { 97 garbage[j] = AfterFunc(Hour, nil) 98 } 99 garbageAll[i] = garbage 100 }(i) 101 } 102 wg.Wait() 103 104 b.ResetTimer() 105 b.RunParallel(func(pb *testing.PB) { 106 for pb.Next() { 107 bench(1000) 108 } 109 }) 110 b.StopTimer() 111 112 for _, garbage := range garbageAll { 113 for _, t := range garbage { 114 t.Stop() 115 } 116 } 117 } 118 119 func BenchmarkAfterFunc(b *testing.B) { 120 benchmark(b, func(n int) { 121 c := make(chan bool) 122 var f func() 123 f = func() { 124 n-- 125 if n >= 0 { 126 AfterFunc(0, f) 127 } else { 128 c <- true 129 } 130 } 131 132 AfterFunc(0, f) 133 <-c 134 }) 135 } 136 137 func BenchmarkAfter(b *testing.B) { 138 benchmark(b, func(n int) { 139 for i := 0; i < n; i++ { 140 <-After(1) 141 } 142 }) 143 } 144 145 func BenchmarkStop(b *testing.B) { 146 benchmark(b, func(n int) { 147 for i := 0; i < n; i++ { 148 NewTimer(1 * Second).Stop() 149 } 150 }) 151 } 152 153 func BenchmarkSimultaneousAfterFunc(b *testing.B) { 154 benchmark(b, func(n int) { 155 var wg sync.WaitGroup 156 wg.Add(n) 157 for i := 0; i < n; i++ { 158 AfterFunc(0, wg.Done) 159 } 160 wg.Wait() 161 }) 162 } 163 164 func BenchmarkStartStop(b *testing.B) { 165 benchmark(b, func(n int) { 166 timers := make([]*Timer, n) 167 for i := 0; i < n; i++ { 168 timers[i] = AfterFunc(Hour, nil) 169 } 170 171 for i := 0; i < n; i++ { 172 timers[i].Stop() 173 } 174 }) 175 } 176 177 func BenchmarkReset(b *testing.B) { 178 benchmark(b, func(n int) { 179 t := NewTimer(Hour) 180 for i := 0; i < n; i++ { 181 t.Reset(Hour) 182 } 183 t.Stop() 184 }) 185 } 186 187 func BenchmarkSleep(b *testing.B) { 188 benchmark(b, func(n int) { 189 var wg sync.WaitGroup 190 wg.Add(n) 191 for i := 0; i < n; i++ { 192 go func() { 193 Sleep(Nanosecond) 194 wg.Done() 195 }() 196 } 197 wg.Wait() 198 }) 199 } 200 201 func TestAfter(t *testing.T) { 202 const delay = 100 * Millisecond 203 start := Now() 204 end := <-After(delay) 205 delayadj := delay 206 if runtime.GOOS == "windows" { 207 delayadj -= windowsInaccuracy 208 } 209 if duration := Now().Sub(start); duration < delayadj { 210 t.Fatalf("After(%s) slept for only %d ns", delay, duration) 211 } 212 if min := start.Add(delayadj); end.Before(min) { 213 t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end) 214 } 215 } 216 217 func TestAfterTick(t *testing.T) { 218 const Count = 10 219 Delta := 100 * Millisecond 220 if testing.Short() { 221 Delta = 10 * Millisecond 222 } 223 t0 := Now() 224 for i := 0; i < Count; i++ { 225 <-After(Delta) 226 } 227 t1 := Now() 228 d := t1.Sub(t0) 229 target := Delta * Count 230 if d < target*9/10 { 231 t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target) 232 } 233 if !testing.Short() && d > target*30/10 { 234 t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target) 235 } 236 } 237 238 func TestAfterStop(t *testing.T) { 239 // We want to test that we stop a timer before it runs. 240 // We also want to test that it didn't run after a longer timer. 241 // Since we don't want the test to run for too long, we don't 242 // want to use lengthy times. That makes the test inherently flaky. 243 // So only report an error if it fails five times in a row. 244 245 var errs []string 246 logErrs := func() { 247 for _, e := range errs { 248 t.Log(e) 249 } 250 } 251 252 for i := 0; i < 5; i++ { 253 AfterFunc(100*Millisecond, func() {}) 254 t0 := NewTimer(50 * Millisecond) 255 c1 := make(chan bool, 1) 256 t1 := AfterFunc(150*Millisecond, func() { c1 <- true }) 257 c2 := After(200 * Millisecond) 258 if !t0.Stop() { 259 errs = append(errs, "failed to stop event 0") 260 continue 261 } 262 if !t1.Stop() { 263 errs = append(errs, "failed to stop event 1") 264 continue 265 } 266 <-c2 267 select { 268 case <-t0.C: 269 errs = append(errs, "event 0 was not stopped") 270 continue 271 case <-c1: 272 errs = append(errs, "event 1 was not stopped") 273 continue 274 default: 275 } 276 if t1.Stop() { 277 errs = append(errs, "Stop returned true twice") 278 continue 279 } 280 281 // Test passed, so all done. 282 if len(errs) > 0 { 283 t.Logf("saw %d errors, ignoring to avoid flakiness", len(errs)) 284 logErrs() 285 } 286 287 return 288 } 289 290 t.Errorf("saw %d errors", len(errs)) 291 logErrs() 292 } 293 294 func TestAfterQueuing(t *testing.T) { 295 // This test flakes out on some systems, 296 // so we'll try it a few times before declaring it a failure. 297 const attempts = 5 298 err := errors.New("!=nil") 299 for i := 0; i < attempts && err != nil; i++ { 300 delta := Duration(20+i*50) * Millisecond 301 if err = testAfterQueuing(delta); err != nil { 302 t.Logf("attempt %v failed: %v", i, err) 303 } 304 } 305 if err != nil { 306 t.Fatal(err) 307 } 308 } 309 310 var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0} 311 312 type afterResult struct { 313 slot int 314 t Time 315 } 316 317 func await(slot int, result chan<- afterResult, ac <-chan Time) { 318 result <- afterResult{slot, <-ac} 319 } 320 321 func testAfterQueuing(delta Duration) error { 322 // make the result channel buffered because we don't want 323 // to depend on channel queueing semantics that might 324 // possibly change in the future. 325 result := make(chan afterResult, len(slots)) 326 327 t0 := Now() 328 for _, slot := range slots { 329 go await(slot, result, After(Duration(slot)*delta)) 330 } 331 var order []int 332 var times []Time 333 for range slots { 334 r := <-result 335 order = append(order, r.slot) 336 times = append(times, r.t) 337 } 338 for i := range order { 339 if i > 0 && order[i] < order[i-1] { 340 return fmt.Errorf("After calls returned out of order: %v", order) 341 } 342 } 343 for i, t := range times { 344 dt := t.Sub(t0) 345 target := Duration(order[i]) * delta 346 if dt < target-delta/2 || dt > target+delta*10 { 347 return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10) 348 } 349 } 350 return nil 351 } 352 353 func TestTimerStopStress(t *testing.T) { 354 if testing.Short() { 355 return 356 } 357 for i := 0; i < 100; i++ { 358 go func(i int) { 359 timer := AfterFunc(2*Second, func() { 360 t.Errorf("timer %d was not stopped", i) 361 }) 362 Sleep(1 * Second) 363 timer.Stop() 364 }(i) 365 } 366 Sleep(3 * Second) 367 } 368 369 func TestSleepZeroDeadlock(t *testing.T) { 370 // Sleep(0) used to hang, the sequence of events was as follows. 371 // Sleep(0) sets G's status to Gwaiting, but then immediately returns leaving the status. 372 // Then the goroutine calls e.g. new and falls down into the scheduler due to pending GC. 373 // After the GC nobody wakes up the goroutine from Gwaiting status. 374 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 375 c := make(chan bool) 376 go func() { 377 for i := 0; i < 100; i++ { 378 runtime.GC() 379 } 380 c <- true 381 }() 382 for i := 0; i < 100; i++ { 383 Sleep(0) 384 tmp := make(chan bool, 1) 385 tmp <- true 386 <-tmp 387 } 388 <-c 389 } 390 391 func testReset(d Duration) error { 392 t0 := NewTimer(2 * d) 393 Sleep(d) 394 if !t0.Reset(3 * d) { 395 return errors.New("resetting unfired timer returned false") 396 } 397 Sleep(2 * d) 398 select { 399 case <-t0.C: 400 return errors.New("timer fired early") 401 default: 402 } 403 Sleep(2 * d) 404 select { 405 case <-t0.C: 406 default: 407 return errors.New("reset timer did not fire") 408 } 409 410 if t0.Reset(50 * Millisecond) { 411 return errors.New("resetting expired timer returned true") 412 } 413 return nil 414 } 415 416 func TestReset(t *testing.T) { 417 // We try to run this test with increasingly larger multiples 418 // until one works so slow, loaded hardware isn't as flaky, 419 // but without slowing down fast machines unnecessarily. 420 const unit = 25 * Millisecond 421 tries := []Duration{ 422 1 * unit, 423 3 * unit, 424 7 * unit, 425 15 * unit, 426 } 427 var err error 428 for _, d := range tries { 429 err = testReset(d) 430 if err == nil { 431 t.Logf("passed using duration %v", d) 432 return 433 } 434 } 435 t.Error(err) 436 } 437 438 // Test that sleeping (via Sleep or Timer) for an interval so large it 439 // overflows does not result in a short sleep duration. Nor does it interfere 440 // with execution of other timers. If it does, timers in this or subsequent 441 // tests may not fire. 442 func TestOverflowSleep(t *testing.T) { 443 const big = Duration(int64(1<<63 - 1)) 444 445 go func() { 446 Sleep(big) 447 // On failure, this may return after the test has completed, so 448 // we need to panic instead. 449 panic("big sleep returned") 450 }() 451 452 select { 453 case <-After(big): 454 t.Fatalf("big timeout fired") 455 case <-After(25 * Millisecond): 456 // OK 457 } 458 459 const neg = Duration(-1 << 63) 460 Sleep(neg) // Returns immediately. 461 select { 462 case <-After(neg): 463 // OK 464 case <-After(1 * Second): 465 t.Fatalf("negative timeout didn't fire") 466 } 467 } 468 469 // Test that a panic while deleting a timer does not leave 470 // the timers mutex held, deadlocking a ticker.Stop in a defer. 471 func TestIssue5745(t *testing.T) { 472 ticker := NewTicker(Hour) 473 defer func() { 474 // would deadlock here before the fix due to 475 // lock taken before the segfault. 476 ticker.Stop() 477 478 if r := recover(); r == nil { 479 t.Error("Expected panic, but none happened.") 480 } 481 }() 482 483 // cause a panic due to a segfault 484 var timer *Timer 485 timer.Stop() 486 t.Error("Should be unreachable.") 487 } 488 489 func TestOverflowPeriodRuntimeTimer(t *testing.T) { 490 // This may hang forever if timers are broken. See comment near 491 // the end of CheckRuntimeTimerOverflow in internal_test.go. 492 CheckRuntimeTimerPeriodOverflow() 493 } 494 495 func checkZeroPanicString(t *testing.T) { 496 e := recover() 497 s, _ := e.(string) 498 if want := "called on uninitialized Timer"; !strings.Contains(s, want) { 499 t.Errorf("panic = %v; want substring %q", e, want) 500 } 501 } 502 503 func TestZeroTimerResetPanics(t *testing.T) { 504 defer checkZeroPanicString(t) 505 var tr Timer 506 tr.Reset(1) 507 } 508 509 func TestZeroTimerStopPanics(t *testing.T) { 510 defer checkZeroPanicString(t) 511 var tr Timer 512 tr.Stop() 513 } 514 515 // Test that zero duration timers aren't missed by the scheduler. Regression test for issue 44868. 516 func TestZeroTimer(t *testing.T) { 517 if testing.Short() { 518 t.Skip("-short") 519 } 520 521 for i := 0; i < 1000000; i++ { 522 s := Now() 523 ti := NewTimer(0) 524 <-ti.C 525 if diff := Since(s); diff > 2*Second { 526 t.Errorf("Expected time to get value from Timer channel in less than 2 sec, took %v", diff) 527 } 528 } 529 } 530 531 // Test that rapidly moving a timer earlier doesn't cause it to get dropped. 532 // Issue 47329. 533 func TestTimerModifiedEarlier(t *testing.T) { 534 past := Until(Unix(0, 0)) 535 count := 1000 536 fail := 0 537 for i := 0; i < count; i++ { 538 timer := NewTimer(Hour) 539 for j := 0; j < 10; j++ { 540 if !timer.Stop() { 541 <-timer.C 542 } 543 timer.Reset(past) 544 } 545 546 deadline := NewTimer(10 * Second) 547 defer deadline.Stop() 548 now := Now() 549 select { 550 case <-timer.C: 551 if since := Since(now); since > 8*Second { 552 t.Errorf("timer took too long (%v)", since) 553 fail++ 554 } 555 case <-deadline.C: 556 t.Error("deadline expired") 557 } 558 } 559 560 if fail > 0 { 561 t.Errorf("%d failures", fail) 562 } 563 } 564 565 // Test that rapidly moving timers earlier and later doesn't cause 566 // some of the sleep times to be lost. 567 // Issue 47762 568 func TestAdjustTimers(t *testing.T) { 569 var rnd = rand.New(rand.NewSource(Now().UnixNano())) 570 571 timers := make([]*Timer, 100) 572 states := make([]int, len(timers)) 573 indices := rnd.Perm(len(timers)) 574 575 for len(indices) != 0 { 576 var ii = rnd.Intn(len(indices)) 577 var i = indices[ii] 578 579 var timer = timers[i] 580 var state = states[i] 581 states[i]++ 582 583 switch state { 584 case 0: 585 timers[i] = NewTimer(0) 586 case 1: 587 <-timer.C // Timer is now idle. 588 589 // Reset to various long durations, which we'll cancel. 590 case 2: 591 if timer.Reset(1 * Minute) { 592 panic("shouldn't be active (1)") 593 } 594 case 4: 595 if timer.Reset(3 * Minute) { 596 panic("shouldn't be active (3)") 597 } 598 case 6: 599 if timer.Reset(2 * Minute) { 600 panic("shouldn't be active (2)") 601 } 602 603 // Stop and drain a long-duration timer. 604 case 3, 5, 7: 605 if !timer.Stop() { 606 t.Logf("timer %d state %d Stop returned false", i, state) 607 <-timer.C 608 } 609 610 // Start a short-duration timer we expect to select without blocking. 611 case 8: 612 if timer.Reset(0) { 613 t.Fatal("timer.Reset returned true") 614 } 615 case 9: 616 now := Now() 617 <-timer.C 618 dur := Since(now) 619 if dur > 750*Millisecond { 620 t.Errorf("timer %d took %v to complete", i, dur) 621 } 622 623 // Timer is done. Swap with tail and remove. 624 case 10: 625 indices[ii] = indices[len(indices)-1] 626 indices = indices[:len(indices)-1] 627 } 628 } 629 } 630 631 // Benchmark timer latency when the thread that creates the timer is busy with 632 // other work and the timers must be serviced by other threads. 633 // https://golang.org/issue/38860 634 func BenchmarkParallelTimerLatency(b *testing.B) { 635 gmp := runtime.GOMAXPROCS(0) 636 if gmp < 2 || runtime.NumCPU() < gmp { 637 b.Skip("skipping with GOMAXPROCS < 2 or NumCPU < GOMAXPROCS") 638 } 639 640 // allocate memory now to avoid GC interference later. 641 timerCount := gmp - 1 642 stats := make([]struct { 643 sum float64 644 max Duration 645 count int64 646 _ [5]int64 // cache line padding 647 }, timerCount) 648 649 // Ensure the time to start new threads to service timers will not pollute 650 // the results. 651 warmupScheduler(gmp) 652 653 // Note that other than the AfterFunc calls this benchmark is measuring it 654 // avoids using any other timers. In particular, the main goroutine uses 655 // doWork to spin for some durations because up through Go 1.15 if all 656 // threads are idle sysmon could leave deep sleep when we wake. 657 658 // Ensure sysmon is in deep sleep. 659 doWork(30 * Millisecond) 660 661 b.ResetTimer() 662 663 const delay = Millisecond 664 var wg sync.WaitGroup 665 var count int32 666 for i := 0; i < b.N; i++ { 667 wg.Add(timerCount) 668 atomic.StoreInt32(&count, 0) 669 for j := 0; j < timerCount; j++ { 670 j := j 671 expectedWakeup := Now().Add(delay) 672 AfterFunc(delay, func() { 673 late := Since(expectedWakeup) 674 if late < 0 { 675 late = 0 676 } 677 stats[j].count++ 678 stats[j].sum += float64(late.Nanoseconds()) 679 if late > stats[j].max { 680 stats[j].max = late 681 } 682 atomic.AddInt32(&count, 1) 683 for atomic.LoadInt32(&count) < int32(timerCount) { 684 // spin until all timers fired 685 } 686 wg.Done() 687 }) 688 } 689 690 for atomic.LoadInt32(&count) < int32(timerCount) { 691 // spin until all timers fired 692 } 693 wg.Wait() 694 695 // Spin for a bit to let the other scheduler threads go idle before the 696 // next round. 697 doWork(Millisecond) 698 } 699 var total float64 700 var samples float64 701 max := Duration(0) 702 for _, s := range stats { 703 if s.max > max { 704 max = s.max 705 } 706 total += s.sum 707 samples += float64(s.count) 708 } 709 b.ReportMetric(0, "ns/op") 710 b.ReportMetric(total/samples, "avg-late-ns") 711 b.ReportMetric(float64(max.Nanoseconds()), "max-late-ns") 712 } 713 714 // Benchmark timer latency with staggered wakeup times and varying CPU bound 715 // workloads. https://golang.org/issue/38860 716 func BenchmarkStaggeredTickerLatency(b *testing.B) { 717 gmp := runtime.GOMAXPROCS(0) 718 if gmp < 2 || runtime.NumCPU() < gmp { 719 b.Skip("skipping with GOMAXPROCS < 2 or NumCPU < GOMAXPROCS") 720 } 721 722 const delay = 3 * Millisecond 723 724 for _, dur := range []Duration{300 * Microsecond, 2 * Millisecond} { 725 b.Run(fmt.Sprintf("work-dur=%s", dur), func(b *testing.B) { 726 for tickersPerP := 1; tickersPerP < int(delay/dur)+1; tickersPerP++ { 727 tickerCount := gmp * tickersPerP 728 b.Run(fmt.Sprintf("tickers-per-P=%d", tickersPerP), func(b *testing.B) { 729 // allocate memory now to avoid GC interference later. 730 stats := make([]struct { 731 sum float64 732 max Duration 733 count int64 734 _ [5]int64 // cache line padding 735 }, tickerCount) 736 737 // Ensure the time to start new threads to service timers 738 // will not pollute the results. 739 warmupScheduler(gmp) 740 741 b.ResetTimer() 742 743 var wg sync.WaitGroup 744 wg.Add(tickerCount) 745 for j := 0; j < tickerCount; j++ { 746 j := j 747 doWork(delay / Duration(gmp)) 748 expectedWakeup := Now().Add(delay) 749 ticker := NewTicker(delay) 750 go func(c int, ticker *Ticker, firstWake Time) { 751 defer ticker.Stop() 752 753 for ; c > 0; c-- { 754 <-ticker.C 755 late := Since(expectedWakeup) 756 if late < 0 { 757 late = 0 758 } 759 stats[j].count++ 760 stats[j].sum += float64(late.Nanoseconds()) 761 if late > stats[j].max { 762 stats[j].max = late 763 } 764 expectedWakeup = expectedWakeup.Add(delay) 765 doWork(dur) 766 } 767 wg.Done() 768 }(b.N, ticker, expectedWakeup) 769 } 770 wg.Wait() 771 772 var total float64 773 var samples float64 774 max := Duration(0) 775 for _, s := range stats { 776 if s.max > max { 777 max = s.max 778 } 779 total += s.sum 780 samples += float64(s.count) 781 } 782 b.ReportMetric(0, "ns/op") 783 b.ReportMetric(total/samples, "avg-late-ns") 784 b.ReportMetric(float64(max.Nanoseconds()), "max-late-ns") 785 }) 786 } 787 }) 788 } 789 } 790 791 // warmupScheduler ensures the scheduler has at least targetThreadCount threads 792 // in its thread pool. 793 func warmupScheduler(targetThreadCount int) { 794 var wg sync.WaitGroup 795 var count int32 796 for i := 0; i < targetThreadCount; i++ { 797 wg.Add(1) 798 go func() { 799 atomic.AddInt32(&count, 1) 800 for atomic.LoadInt32(&count) < int32(targetThreadCount) { 801 // spin until all threads started 802 } 803 804 // spin a bit more to ensure they are all running on separate CPUs. 805 doWork(Millisecond) 806 wg.Done() 807 }() 808 } 809 wg.Wait() 810 } 811 812 func doWork(dur Duration) { 813 start := Now() 814 for Since(start) < dur { 815 } 816 }