github.com/searKing/golang/go@v1.2.117/time/sleep_test.go (about)

     1  // Copyright 2020 The searKing Author. 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  	"time"
    16  
    17  	time_ "github.com/searKing/golang/go/time"
    18  )
    19  
    20  // Go runtime uses different Windows timers for time.Now and sleeping.
    21  // These can tick at different frequencies and can arrive out of sync.
    22  // The effect can be seen, for example, as time.Sleep(100ms) is actually
    23  // shorter then 100ms when measured as difference between time.Now before and
    24  // after time.Sleep call. This was observed on Windows XP SP3 (windows/386).
    25  // windowsInaccuracy is to ignore such errors.
    26  const windowsInaccuracy = 17 * time.Millisecond
    27  
    28  // Test the basic function calling behavior. Correct queueing
    29  // behavior is tested elsewhere, since After and AfterFunc share
    30  // the same code.
    31  func TestAfterFunc(t *testing.T) {
    32  	i := 10
    33  	c := make(chan bool)
    34  	var f func()
    35  	f = func() {
    36  		i--
    37  		if i >= 0 {
    38  			time_.AfterFunc(0, f)
    39  			time.Sleep(1 * time.Second)
    40  		} else {
    41  			c <- true
    42  		}
    43  	}
    44  
    45  	time_.AfterFunc(0, f)
    46  	<-c
    47  }
    48  
    49  func TestAfterStress(t *testing.T) {
    50  	stop := uint32(0)
    51  	go func() {
    52  		for atomic.LoadUint32(&stop) == 0 {
    53  			runtime.GC()
    54  			// Yield so that the OS can wake up the timer thread,
    55  			// so that it can generate channel sends for the main goroutine,
    56  			// which will eventually set stop = 1 for us.
    57  			time.Sleep(time.Nanosecond)
    58  		}
    59  	}()
    60  	ticker := time.NewTicker(1)
    61  	for i := 0; i < 100; i++ {
    62  		<-ticker.C
    63  	}
    64  	ticker.Stop()
    65  	atomic.StoreUint32(&stop, 1)
    66  }
    67  
    68  func benchmark(b *testing.B, bench func(n int)) {
    69  	// Create equal number of garbage timers on each P before starting
    70  	// the benchmark.
    71  	var wg sync.WaitGroup
    72  	garbageAll := make([][]*time_.Timer, runtime.GOMAXPROCS(0))
    73  	for i := range garbageAll {
    74  		wg.Add(1)
    75  		go func(i int) {
    76  			defer wg.Done()
    77  			garbage := make([]*time_.Timer, 1<<15)
    78  			for j := range garbage {
    79  				garbage[j] = time_.AfterFunc(time.Hour, nil)
    80  			}
    81  			garbageAll[i] = garbage
    82  		}(i)
    83  	}
    84  	wg.Wait()
    85  
    86  	b.ResetTimer()
    87  	b.RunParallel(func(pb *testing.PB) {
    88  		for pb.Next() {
    89  			bench(1000)
    90  		}
    91  	})
    92  	b.StopTimer()
    93  
    94  	for _, garbage := range garbageAll {
    95  		for _, t := range garbage {
    96  			t.Stop()
    97  		}
    98  	}
    99  }
   100  
   101  func BenchmarkAfterFunc(b *testing.B) {
   102  	benchmark(b, func(n int) {
   103  		c := make(chan bool)
   104  		var f func()
   105  		f = func() {
   106  			n--
   107  			if n >= 0 {
   108  				time_.AfterFunc(0, f)
   109  			} else {
   110  				c <- true
   111  			}
   112  		}
   113  
   114  		time_.AfterFunc(0, f)
   115  		<-c
   116  	})
   117  }
   118  
   119  func BenchmarkAfter(b *testing.B) {
   120  	benchmark(b, func(n int) {
   121  		for i := 0; i < n; i++ {
   122  			<-time_.After(1)
   123  		}
   124  	})
   125  }
   126  
   127  func BenchmarkStop(b *testing.B) {
   128  	benchmark(b, func(n int) {
   129  		for i := 0; i < n; i++ {
   130  			time_.NewTimer(1 * time.Second).Stop()
   131  		}
   132  	})
   133  }
   134  
   135  func BenchmarkSimultaneousAfterFunc(b *testing.B) {
   136  	benchmark(b, func(n int) {
   137  		var wg sync.WaitGroup
   138  		wg.Add(n)
   139  		for i := 0; i < n; i++ {
   140  			time_.AfterFunc(0, wg.Done)
   141  		}
   142  		wg.Wait()
   143  	})
   144  }
   145  
   146  func BenchmarkStartStop(b *testing.B) {
   147  	benchmark(b, func(n int) {
   148  		timers := make([]*time_.Timer, n)
   149  		for i := 0; i < n; i++ {
   150  			timers[i] = time_.AfterFunc(time.Hour, nil)
   151  		}
   152  
   153  		for i := 0; i < n; i++ {
   154  			timers[i].Stop()
   155  		}
   156  	})
   157  }
   158  
   159  func BenchmarkReset(b *testing.B) {
   160  	benchmark(b, func(n int) {
   161  		t := time_.NewTimer(time.Hour)
   162  		for i := 0; i < n; i++ {
   163  			t.Reset(time.Hour)
   164  		}
   165  		t.Stop()
   166  	})
   167  }
   168  
   169  func TestAfter(t *testing.T) {
   170  	const delay = 100 * time.Millisecond
   171  	start := time.Now()
   172  	end := <-time_.After(delay)
   173  	delayadj := delay
   174  	if runtime.GOOS == "windows" {
   175  		delayadj -= windowsInaccuracy
   176  	}
   177  	if duration := time.Now().Sub(start); duration < delayadj {
   178  		t.Fatalf("After(%s) slept for only %d ns", delay, duration)
   179  	}
   180  	if min := start.Add(delayadj); end.Before(min) {
   181  		t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end)
   182  	}
   183  }
   184  
   185  func TestAfterTick(t *testing.T) {
   186  	const Count = 10
   187  	Delta := 100 * time.Millisecond
   188  	if testing.Short() {
   189  		Delta = 10 * time.Millisecond
   190  	}
   191  	t0 := time.Now()
   192  	for i := 0; i < Count; i++ {
   193  		<-time_.After(Delta)
   194  	}
   195  	t1 := time.Now()
   196  	d := t1.Sub(t0)
   197  	target := Delta * Count
   198  	if d < target*9/10 {
   199  		t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target)
   200  	}
   201  	if !testing.Short() && d > target*30/10 {
   202  		t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target)
   203  	}
   204  }
   205  
   206  func TestAfterStop(t *testing.T) {
   207  	time_.AfterFunc(100*time.Millisecond, func() {})
   208  	t0 := time_.NewTimer(50 * time.Millisecond)
   209  	c1 := make(chan bool, 1)
   210  	t1 := time_.AfterFunc(150*time.Millisecond, func() { c1 <- true })
   211  	c2 := time_.After(200 * time.Millisecond)
   212  	if !t0.Stop() {
   213  		t.Fatalf("failed to stop event 0")
   214  	}
   215  	if !t1.Stop() {
   216  		t.Fatalf("failed to stop event 1")
   217  	}
   218  	<-c2
   219  	select {
   220  	case <-t0.C:
   221  		t.Fatalf("event 0 was not stopped")
   222  	case <-c1:
   223  		t.Fatalf("event 1 was not stopped")
   224  	default:
   225  	}
   226  	if t1.Stop() {
   227  		t.Fatalf("Stop returned true twice")
   228  	}
   229  }
   230  
   231  func TestAfterQueuing(t *testing.T) {
   232  	// This test flakes out on some systems,
   233  	// so we'll try it a few times before declaring it a failure.
   234  	const attempts = 5
   235  	err := errors.New("!=nil")
   236  	for i := 0; i < attempts && err != nil; i++ {
   237  		delta := time.Duration(20+i*50) * time.Millisecond
   238  		if err = testAfterQueuing(delta); err != nil {
   239  			t.Logf("attempt %v failed: %v", i, err)
   240  		}
   241  	}
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  }
   246  
   247  var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0}
   248  
   249  type afterResult struct {
   250  	slot int
   251  	t    time.Time
   252  }
   253  
   254  func await(slot int, result chan<- afterResult, ac <-chan time.Time) {
   255  	result <- afterResult{slot, <-ac}
   256  }
   257  
   258  func testAfterQueuing(delta time.Duration) error {
   259  	// make the result channel buffered because we don't want
   260  	// to depend on channel queueing semantics that might
   261  	// possibly change in the future.
   262  	result := make(chan afterResult, len(slots))
   263  
   264  	t0 := time.Now()
   265  	for _, slot := range slots {
   266  		go await(slot, result, time_.After(time.Duration(slot)*delta))
   267  	}
   268  	var order []int
   269  	var times []time.Time
   270  	for range slots {
   271  		r := <-result
   272  		order = append(order, r.slot)
   273  		times = append(times, r.t)
   274  	}
   275  	for i := range order {
   276  		if i > 0 && order[i] < order[i-1] {
   277  			return fmt.Errorf("After calls returned out of order: %v", order)
   278  		}
   279  	}
   280  	for i, t := range times {
   281  		dt := t.Sub(t0)
   282  		target := time.Duration(order[i]) * delta
   283  		if dt < target-delta/2 || dt > target+delta*10 {
   284  			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10)
   285  		}
   286  	}
   287  	return nil
   288  }
   289  
   290  func TestTimerStopStress(t *testing.T) {
   291  	if testing.Short() {
   292  		return
   293  	}
   294  	for i := 0; i < 100; i++ {
   295  		go func(i int) {
   296  			timer := time_.AfterFunc(2*time.Second, func() {
   297  				t.Fatalf("timer %d was not stopped", i)
   298  			})
   299  			time.Sleep(1 * time.Second)
   300  			timer.Stop()
   301  		}(i)
   302  	}
   303  	time.Sleep(3 * time.Second)
   304  }
   305  
   306  // Test that a panic while deleting a timer does not leave
   307  // the timers mutex held, deadlocking a ticker.Stop in a defer.
   308  func TestIssue5745(t *testing.T) {
   309  	ticker := time.NewTicker(time.Hour)
   310  	defer func() {
   311  		// would deadlock here before the fix due to
   312  		// lock taken before the segfault.
   313  		ticker.Stop()
   314  
   315  		if r := recover(); r == nil {
   316  			t.Error("Expected panic, but none happened.")
   317  		}
   318  	}()
   319  
   320  	// cause a panic due to a segfault
   321  	var timer *time_.Timer
   322  	timer.Stop()
   323  	t.Error("Should be unreachable.")
   324  }
   325  
   326  func TestSleepZeroDeadlock(t *testing.T) {
   327  	// Sleep(0) used to hang, the sequence of events was as follows.
   328  	// Sleep(0) sets G's status to Gwaiting, but then immediately returns leaving the status.
   329  	// Then the goroutine calls e.g. new and falls down into the scheduler due to pending GC.
   330  	// After the GC nobody wakes up the goroutine from Gwaiting status.
   331  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
   332  	c := make(chan bool)
   333  	go func() {
   334  		for i := 0; i < 100; i++ {
   335  			runtime.GC()
   336  		}
   337  		c <- true
   338  	}()
   339  	for i := 0; i < 100; i++ {
   340  		time.Sleep(0)
   341  		tmp := make(chan bool, 1)
   342  		tmp <- true
   343  		<-tmp
   344  	}
   345  	<-c
   346  }
   347  
   348  func testReset(d time.Duration) error {
   349  	t0 := time.NewTimer(2 * d)
   350  	time.Sleep(d)
   351  	if !t0.Reset(3 * d) {
   352  		return errors.New("resetting unfired timer returned false")
   353  	}
   354  	time.Sleep(2 * d)
   355  	select {
   356  	case <-t0.C:
   357  		return errors.New("timer fired early")
   358  	default:
   359  	}
   360  	time.Sleep(2 * d)
   361  	select {
   362  	case <-t0.C:
   363  	default:
   364  		return errors.New("reset timer did not fire")
   365  	}
   366  
   367  	if t0.Reset(50 * time.Millisecond) {
   368  		return errors.New("resetting expired timer returned true")
   369  	}
   370  	return nil
   371  }
   372  
   373  func TestReset(t *testing.T) {
   374  	// We try to run this test with increasingly larger multiples
   375  	// until one works so slow, loaded hardware isn't as flaky,
   376  	// but without slowing down fast machines unnecessarily.
   377  	const unit = 25 * time.Millisecond
   378  	tries := []time.Duration{
   379  		1 * unit,
   380  		3 * unit,
   381  		7 * unit,
   382  		15 * unit,
   383  	}
   384  	var err error
   385  	for _, d := range tries {
   386  		err = testReset(d)
   387  		if err == nil {
   388  			t.Logf("passed using duration %v", d)
   389  			return
   390  		}
   391  	}
   392  	t.Error(err)
   393  }
   394  
   395  func checkZeroPanicString(t *testing.T) {
   396  	e := recover()
   397  	s, _ := e.(string)
   398  	if want := "called on uninitialized Timer"; !strings.Contains(s, want) {
   399  		t.Errorf("panic = %v; want substring %q", e, want)
   400  	}
   401  }
   402  
   403  func TestZeroTimerResetPanics(t *testing.T) {
   404  	defer checkZeroPanicString(t)
   405  	var tr time_.Timer
   406  	tr.Reset(1)
   407  }
   408  
   409  func TestTimer_Reset(t *testing.T) {
   410  	tr := time_.NewTimer(25 * time.Millisecond)
   411  	defer func() {
   412  		tr.Stop()
   413  	}()
   414  	<-tr.C
   415  }