github.com/embeddedgo/x@v0.0.6-0.20191217015414-d79a36f562e7/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  	"runtime"
    11  	"strings"
    12  	"sync"
    13  	"sync/atomic"
    14  	"testing"
    15  	
    16  	. "github.com/embeddedgo/x/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  	AfterFunc(100*Millisecond, func() {})
   240  	t0 := NewTimer(50 * Millisecond)
   241  	c1 := make(chan bool, 1)
   242  	t1 := AfterFunc(150*Millisecond, func() { c1 <- true })
   243  	c2 := After(200 * Millisecond)
   244  	if !t0.Stop() {
   245  		t.Fatalf("failed to stop event 0")
   246  	}
   247  	if !t1.Stop() {
   248  		t.Fatalf("failed to stop event 1")
   249  	}
   250  	<-c2
   251  	select {
   252  	case <-t0.C:
   253  		t.Fatalf("event 0 was not stopped")
   254  	case <-c1:
   255  		t.Fatalf("event 1 was not stopped")
   256  	default:
   257  	}
   258  	if t1.Stop() {
   259  		t.Fatalf("Stop returned true twice")
   260  	}
   261  }
   262  
   263  func TestAfterQueuing(t *testing.T) {
   264  	// This test flakes out on some systems,
   265  	// so we'll try it a few times before declaring it a failure.
   266  	const attempts = 5
   267  	err := errors.New("!=nil")
   268  	for i := 0; i < attempts && err != nil; i++ {
   269  		delta := Duration(20+i*50) * Millisecond
   270  		if err = testAfterQueuing(delta); err != nil {
   271  			t.Logf("attempt %v failed: %v", i, err)
   272  		}
   273  	}
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  }
   278  
   279  var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0}
   280  
   281  type afterResult struct {
   282  	slot int
   283  	t    Time
   284  }
   285  
   286  func await(slot int, result chan<- afterResult, ac <-chan Time) {
   287  	result <- afterResult{slot, <-ac}
   288  }
   289  
   290  func testAfterQueuing(delta Duration) error {
   291  	// make the result channel buffered because we don't want
   292  	// to depend on channel queueing semantics that might
   293  	// possibly change in the future.
   294  	result := make(chan afterResult, len(slots))
   295  
   296  	t0 := Now()
   297  	for _, slot := range slots {
   298  		go await(slot, result, After(Duration(slot)*delta))
   299  	}
   300  	var order []int
   301  	var times []Time
   302  	for range slots {
   303  		r := <-result
   304  		order = append(order, r.slot)
   305  		times = append(times, r.t)
   306  	}
   307  	for i := range order {
   308  		if i > 0 && order[i] < order[i-1] {
   309  			return fmt.Errorf("After calls returned out of order: %v", order)
   310  		}
   311  	}
   312  	for i, t := range times {
   313  		dt := t.Sub(t0)
   314  		target := Duration(order[i]) * delta
   315  		if dt < target-delta/2 || dt > target+delta*10 {
   316  			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10)
   317  		}
   318  	}
   319  	return nil
   320  }
   321  
   322  func TestTimerStopStress(t *testing.T) {
   323  	if testing.Short() {
   324  		return
   325  	}
   326  	for i := 0; i < 100; i++ {
   327  		go func(i int) {
   328  			timer := AfterFunc(2*Second, func() {
   329  				t.Fatalf("timer %d was not stopped", i)
   330  			})
   331  			Sleep(1 * Second)
   332  			timer.Stop()
   333  		}(i)
   334  	}
   335  	Sleep(3 * Second)
   336  }
   337  
   338  func TestSleepZeroDeadlock(t *testing.T) {
   339  	// Sleep(0) used to hang, the sequence of events was as follows.
   340  	// Sleep(0) sets G's status to Gwaiting, but then immediately returns leaving the status.
   341  	// Then the goroutine calls e.g. new and falls down into the scheduler due to pending GC.
   342  	// After the GC nobody wakes up the goroutine from Gwaiting status.
   343  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
   344  	c := make(chan bool)
   345  	go func() {
   346  		for i := 0; i < 100; i++ {
   347  			runtime.GC()
   348  		}
   349  		c <- true
   350  	}()
   351  	for i := 0; i < 100; i++ {
   352  		Sleep(0)
   353  		tmp := make(chan bool, 1)
   354  		tmp <- true
   355  		<-tmp
   356  	}
   357  	<-c
   358  }
   359  
   360  func testReset(d Duration) error {
   361  	t0 := NewTimer(2 * d)
   362  	Sleep(d)
   363  	if !t0.Reset(3 * d) {
   364  		return errors.New("resetting unfired timer returned false")
   365  	}
   366  	Sleep(2 * d)
   367  	select {
   368  	case <-t0.C:
   369  		return errors.New("timer fired early")
   370  	default:
   371  	}
   372  	Sleep(2 * d)
   373  	select {
   374  	case <-t0.C:
   375  	default:
   376  		return errors.New("reset timer did not fire")
   377  	}
   378  
   379  	if t0.Reset(50 * Millisecond) {
   380  		return errors.New("resetting expired timer returned true")
   381  	}
   382  	return nil
   383  }
   384  
   385  func TestReset(t *testing.T) {
   386  	// We try to run this test with increasingly larger multiples
   387  	// until one works so slow, loaded hardware isn't as flaky,
   388  	// but without slowing down fast machines unnecessarily.
   389  	const unit = 25 * Millisecond
   390  	tries := []Duration{
   391  		1 * unit,
   392  		3 * unit,
   393  		7 * unit,
   394  		15 * unit,
   395  	}
   396  	var err error
   397  	for _, d := range tries {
   398  		err = testReset(d)
   399  		if err == nil {
   400  			t.Logf("passed using duration %v", d)
   401  			return
   402  		}
   403  	}
   404  	t.Error(err)
   405  }
   406  
   407  // Test that sleeping for an interval so large it overflows does not
   408  // result in a short sleep duration.
   409  func TestOverflowSleep(t *testing.T) {
   410  	const big = Duration(int64(1<<63 - 1))
   411  	select {
   412  	case <-After(big):
   413  		t.Fatalf("big timeout fired")
   414  	case <-After(25 * Millisecond):
   415  		// OK
   416  	}
   417  	const neg = Duration(-1 << 63)
   418  	select {
   419  	case <-After(neg):
   420  		// OK
   421  	case <-After(1 * Second):
   422  		t.Fatalf("negative timeout didn't fire")
   423  	}
   424  }
   425  
   426  // Test that a panic while deleting a timer does not leave
   427  // the timers mutex held, deadlocking a ticker.Stop in a defer.
   428  func TestIssue5745(t *testing.T) {
   429  	ticker := NewTicker(Hour)
   430  	defer func() {
   431  		// would deadlock here before the fix due to
   432  		// lock taken before the segfault.
   433  		ticker.Stop()
   434  
   435  		if r := recover(); r == nil {
   436  			t.Error("Expected panic, but none happened.")
   437  		}
   438  	}()
   439  
   440  	// cause a panic due to a segfault
   441  	var timer *Timer
   442  	timer.Stop()
   443  	t.Error("Should be unreachable.")
   444  }
   445  
   446  func TestOverflowRuntimeTimer(t *testing.T) {
   447  	if testing.Short() {
   448  		t.Skip("skipping in short mode, see issue 6874")
   449  	}
   450  	// This may hang forever if timers are broken. See comment near
   451  	// the end of CheckRuntimeTimerOverflow in internal_test.go.
   452  	CheckRuntimeTimerOverflow()
   453  }
   454  
   455  func checkZeroPanicString(t *testing.T) {
   456  	e := recover()
   457  	s, _ := e.(string)
   458  	if want := "called on uninitialized Timer"; !strings.Contains(s, want) {
   459  		t.Errorf("panic = %v; want substring %q", e, want)
   460  	}
   461  }
   462  
   463  func TestZeroTimerResetPanics(t *testing.T) {
   464  	defer checkZeroPanicString(t)
   465  	var tr Timer
   466  	tr.Reset(1)
   467  }
   468  
   469  func TestZeroTimerStopPanics(t *testing.T) {
   470  	defer checkZeroPanicString(t)
   471  	var tr Timer
   472  	tr.Stop()
   473  }