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 }