Source file
src/time/sleep_test.go
Documentation: time
1
2
3
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
20
21
22
23
24
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
46
47
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
72
73
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
88
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
240
241
242
243
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
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
296
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
323
324
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
371
372
373
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
418
419
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
439
440
441
442 func TestOverflowSleep(t *testing.T) {
443 const big = Duration(int64(1<<63 - 1))
444
445 go func() {
446 Sleep(big)
447
448
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
457 }
458
459 const neg = Duration(-1 << 63)
460 Sleep(neg)
461 select {
462 case <-After(neg):
463
464 case <-After(1 * Second):
465 t.Fatalf("negative timeout didn't fire")
466 }
467 }
468
469
470
471 func TestIssue5745(t *testing.T) {
472 ticker := NewTicker(Hour)
473 defer func() {
474
475
476 ticker.Stop()
477
478 if r := recover(); r == nil {
479 t.Error("Expected panic, but none happened.")
480 }
481 }()
482
483
484 var timer *Timer
485 timer.Stop()
486 t.Error("Should be unreachable.")
487 }
488
489 func TestOverflowPeriodRuntimeTimer(t *testing.T) {
490
491
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
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
532
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
566
567
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
588
589
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
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
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
624 case 10:
625 indices[ii] = indices[len(indices)-1]
626 indices = indices[:len(indices)-1]
627 }
628 }
629 }
630
631
632
633
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
641 timerCount := gmp - 1
642 stats := make([]struct {
643 sum float64
644 max Duration
645 count int64
646 _ [5]int64
647 }, timerCount)
648
649
650
651 warmupScheduler(gmp)
652
653
654
655
656
657
658
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
685 }
686 wg.Done()
687 })
688 }
689
690 for atomic.LoadInt32(&count) < int32(timerCount) {
691
692 }
693 wg.Wait()
694
695
696
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
715
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
730 stats := make([]struct {
731 sum float64
732 max Duration
733 count int64
734 _ [5]int64
735 }, tickerCount)
736
737
738
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
792
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
802 }
803
804
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 }
817
View as plain text