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 }