github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/runtime/proc_test.go (about) 1 // Copyright 2011 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 runtime_test 6 7 import ( 8 "math" 9 "net" 10 "runtime" 11 "runtime/debug" 12 "strings" 13 "sync" 14 "sync/atomic" 15 "syscall" 16 "testing" 17 "time" 18 ) 19 20 var stop = make(chan bool, 1) 21 22 func perpetuumMobile() { 23 select { 24 case <-stop: 25 default: 26 go perpetuumMobile() 27 } 28 } 29 30 func TestStopTheWorldDeadlock(t *testing.T) { 31 if testing.Short() { 32 t.Skip("skipping during short test") 33 } 34 maxprocs := runtime.GOMAXPROCS(3) 35 compl := make(chan bool, 2) 36 go func() { 37 for i := 0; i != 1000; i += 1 { 38 runtime.GC() 39 } 40 compl <- true 41 }() 42 go func() { 43 for i := 0; i != 1000; i += 1 { 44 runtime.GOMAXPROCS(3) 45 } 46 compl <- true 47 }() 48 go perpetuumMobile() 49 <-compl 50 <-compl 51 stop <- true 52 runtime.GOMAXPROCS(maxprocs) 53 } 54 55 func TestYieldProgress(t *testing.T) { 56 testYieldProgress(t, false) 57 } 58 59 func TestYieldLockedProgress(t *testing.T) { 60 testYieldProgress(t, true) 61 } 62 63 func testYieldProgress(t *testing.T, locked bool) { 64 c := make(chan bool) 65 cack := make(chan bool) 66 go func() { 67 if locked { 68 runtime.LockOSThread() 69 } 70 for { 71 select { 72 case <-c: 73 cack <- true 74 return 75 default: 76 runtime.Gosched() 77 } 78 } 79 }() 80 time.Sleep(10 * time.Millisecond) 81 c <- true 82 <-cack 83 } 84 85 func TestYieldLocked(t *testing.T) { 86 const N = 10 87 c := make(chan bool) 88 go func() { 89 runtime.LockOSThread() 90 for i := 0; i < N; i++ { 91 runtime.Gosched() 92 time.Sleep(time.Millisecond) 93 } 94 c <- true 95 // runtime.UnlockOSThread() is deliberately omitted 96 }() 97 <-c 98 } 99 100 func TestGoroutineParallelism(t *testing.T) { 101 if runtime.NumCPU() == 1 { 102 // Takes too long, too easy to deadlock, etc. 103 t.Skip("skipping on uniprocessor") 104 } 105 P := 4 106 N := 10 107 if testing.Short() { 108 P = 3 109 N = 3 110 } 111 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) 112 // If runtime triggers a forced GC during this test then it will deadlock, 113 // since the goroutines can't be stopped/preempted. 114 // Disable GC for this test (see issue #10958). 115 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 116 for try := 0; try < N; try++ { 117 done := make(chan bool) 118 x := uint32(0) 119 for p := 0; p < P; p++ { 120 // Test that all P goroutines are scheduled at the same time 121 go func(p int) { 122 for i := 0; i < 3; i++ { 123 expected := uint32(P*i + p) 124 for atomic.LoadUint32(&x) != expected { 125 } 126 atomic.StoreUint32(&x, expected+1) 127 } 128 done <- true 129 }(p) 130 } 131 for p := 0; p < P; p++ { 132 <-done 133 } 134 } 135 } 136 137 // Test that all runnable goroutines are scheduled at the same time. 138 func TestGoroutineParallelism2(t *testing.T) { 139 //testGoroutineParallelism2(t, false, false) 140 testGoroutineParallelism2(t, true, false) 141 testGoroutineParallelism2(t, false, true) 142 testGoroutineParallelism2(t, true, true) 143 } 144 145 func testGoroutineParallelism2(t *testing.T, load, netpoll bool) { 146 if runtime.NumCPU() == 1 { 147 // Takes too long, too easy to deadlock, etc. 148 t.Skip("skipping on uniprocessor") 149 } 150 P := 4 151 N := 10 152 if testing.Short() { 153 N = 3 154 } 155 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) 156 // If runtime triggers a forced GC during this test then it will deadlock, 157 // since the goroutines can't be stopped/preempted. 158 // Disable GC for this test (see issue #10958). 159 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 160 for try := 0; try < N; try++ { 161 if load { 162 // Create P goroutines and wait until they all run. 163 // When we run the actual test below, worker threads 164 // running the goroutines will start parking. 165 done := make(chan bool) 166 x := uint32(0) 167 for p := 0; p < P; p++ { 168 go func() { 169 if atomic.AddUint32(&x, 1) == uint32(P) { 170 done <- true 171 return 172 } 173 for atomic.LoadUint32(&x) != uint32(P) { 174 } 175 }() 176 } 177 <-done 178 } 179 if netpoll { 180 // Enable netpoller, affects schedler behavior. 181 laddr := "localhost:0" 182 if runtime.GOOS == "android" { 183 // On some Android devices, there are no records for localhost, 184 // see https://golang.org/issues/14486. 185 // Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems. 186 laddr = "127.0.0.1:0" 187 } 188 ln, err := net.Listen("tcp", laddr) 189 if err != nil { 190 defer ln.Close() // yup, defer in a loop 191 } 192 } 193 done := make(chan bool) 194 x := uint32(0) 195 // Spawn P goroutines in a nested fashion just to differ from TestGoroutineParallelism. 196 for p := 0; p < P/2; p++ { 197 go func(p int) { 198 for p2 := 0; p2 < 2; p2++ { 199 go func(p2 int) { 200 for i := 0; i < 3; i++ { 201 expected := uint32(P*i + p*2 + p2) 202 for atomic.LoadUint32(&x) != expected { 203 } 204 atomic.StoreUint32(&x, expected+1) 205 } 206 done <- true 207 }(p2) 208 } 209 }(p) 210 } 211 for p := 0; p < P; p++ { 212 <-done 213 } 214 } 215 } 216 217 func TestBlockLocked(t *testing.T) { 218 const N = 10 219 c := make(chan bool) 220 go func() { 221 runtime.LockOSThread() 222 for i := 0; i < N; i++ { 223 c <- true 224 } 225 runtime.UnlockOSThread() 226 }() 227 for i := 0; i < N; i++ { 228 <-c 229 } 230 } 231 232 func TestTimerFairness(t *testing.T) { 233 done := make(chan bool) 234 c := make(chan bool) 235 for i := 0; i < 2; i++ { 236 go func() { 237 for { 238 select { 239 case c <- true: 240 case <-done: 241 return 242 } 243 } 244 }() 245 } 246 247 timer := time.After(20 * time.Millisecond) 248 for { 249 select { 250 case <-c: 251 case <-timer: 252 close(done) 253 return 254 } 255 } 256 } 257 258 func TestTimerFairness2(t *testing.T) { 259 done := make(chan bool) 260 c := make(chan bool) 261 for i := 0; i < 2; i++ { 262 go func() { 263 timer := time.After(20 * time.Millisecond) 264 var buf [1]byte 265 for { 266 syscall.Read(0, buf[0:0]) 267 select { 268 case c <- true: 269 case <-c: 270 case <-timer: 271 done <- true 272 return 273 } 274 } 275 }() 276 } 277 <-done 278 <-done 279 } 280 281 // The function is used to test preemption at split stack checks. 282 // Declaring a var avoids inlining at the call site. 283 var preempt = func() int { 284 var a [128]int 285 sum := 0 286 for _, v := range a { 287 sum += v 288 } 289 return sum 290 } 291 292 func TestPreemption(t *testing.T) { 293 // Test that goroutines are preempted at function calls. 294 N := 5 295 if testing.Short() { 296 N = 2 297 } 298 c := make(chan bool) 299 var x uint32 300 for g := 0; g < 2; g++ { 301 go func(g int) { 302 for i := 0; i < N; i++ { 303 for atomic.LoadUint32(&x) != uint32(g) { 304 preempt() 305 } 306 atomic.StoreUint32(&x, uint32(1-g)) 307 } 308 c <- true 309 }(g) 310 } 311 <-c 312 <-c 313 } 314 315 func TestPreemptionGC(t *testing.T) { 316 // Test that pending GC preempts running goroutines. 317 P := 5 318 N := 10 319 if testing.Short() { 320 P = 3 321 N = 2 322 } 323 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1)) 324 var stop uint32 325 for i := 0; i < P; i++ { 326 go func() { 327 for atomic.LoadUint32(&stop) == 0 { 328 preempt() 329 } 330 }() 331 } 332 for i := 0; i < N; i++ { 333 runtime.Gosched() 334 runtime.GC() 335 } 336 atomic.StoreUint32(&stop, 1) 337 } 338 339 func TestGCFairness(t *testing.T) { 340 output := runTestProg(t, "testprog", "GCFairness") 341 want := "OK\n" 342 if output != want { 343 t.Fatalf("want %s, got %s\n", want, output) 344 } 345 } 346 347 func TestGCFairness2(t *testing.T) { 348 output := runTestProg(t, "testprog", "GCFairness2") 349 want := "OK\n" 350 if output != want { 351 t.Fatalf("want %s, got %s\n", want, output) 352 } 353 } 354 355 func TestNumGoroutine(t *testing.T) { 356 output := runTestProg(t, "testprog", "NumGoroutine") 357 want := "1\n" 358 if output != want { 359 t.Fatalf("want %q, got %q", want, output) 360 } 361 362 buf := make([]byte, 1<<20) 363 364 // Try up to 10 times for a match before giving up. 365 // This is a fundamentally racy check but it's important 366 // to notice if NumGoroutine and Stack are _always_ out of sync. 367 for i := 0; ; i++ { 368 // Give goroutines about to exit a chance to exit. 369 // The NumGoroutine and Stack below need to see 370 // the same state of the world, so anything we can do 371 // to keep it quiet is good. 372 runtime.Gosched() 373 374 n := runtime.NumGoroutine() 375 buf = buf[:runtime.Stack(buf, true)] 376 377 nstk := strings.Count(string(buf), "goroutine ") 378 if n == nstk { 379 break 380 } 381 if i >= 10 { 382 t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump: %s", n, nstk, buf) 383 } 384 } 385 } 386 387 func TestPingPongHog(t *testing.T) { 388 if testing.Short() { 389 t.Skip("skipping in -short mode") 390 } 391 392 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 393 done := make(chan bool) 394 hogChan, lightChan := make(chan bool), make(chan bool) 395 hogCount, lightCount := 0, 0 396 397 run := func(limit int, counter *int, wake chan bool) { 398 for { 399 select { 400 case <-done: 401 return 402 403 case <-wake: 404 for i := 0; i < limit; i++ { 405 *counter++ 406 } 407 wake <- true 408 } 409 } 410 } 411 412 // Start two co-scheduled hog goroutines. 413 for i := 0; i < 2; i++ { 414 go run(1e6, &hogCount, hogChan) 415 } 416 417 // Start two co-scheduled light goroutines. 418 for i := 0; i < 2; i++ { 419 go run(1e3, &lightCount, lightChan) 420 } 421 422 // Start goroutine pairs and wait for a few preemption rounds. 423 hogChan <- true 424 lightChan <- true 425 time.Sleep(100 * time.Millisecond) 426 close(done) 427 <-hogChan 428 <-lightChan 429 430 // Check that hogCount and lightCount are within a factor of 431 // 2, which indicates that both pairs of goroutines handed off 432 // the P within a time-slice to their buddy. 433 if hogCount > lightCount*2 || lightCount > hogCount*2 { 434 t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount)) 435 } 436 } 437 438 func BenchmarkPingPongHog(b *testing.B) { 439 if b.N == 0 { 440 return 441 } 442 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 443 444 // Create a CPU hog 445 stop, done := make(chan bool), make(chan bool) 446 go func() { 447 for { 448 select { 449 case <-stop: 450 done <- true 451 return 452 default: 453 } 454 } 455 }() 456 457 // Ping-pong b.N times 458 ping, pong := make(chan bool), make(chan bool) 459 go func() { 460 for j := 0; j < b.N; j++ { 461 pong <- <-ping 462 } 463 close(stop) 464 done <- true 465 }() 466 go func() { 467 for i := 0; i < b.N; i++ { 468 ping <- <-pong 469 } 470 done <- true 471 }() 472 b.ResetTimer() 473 ping <- true // Start ping-pong 474 <-stop 475 b.StopTimer() 476 <-ping // Let last ponger exit 477 <-done // Make sure goroutines exit 478 <-done 479 <-done 480 } 481 482 func stackGrowthRecursive(i int) { 483 var pad [128]uint64 484 if i != 0 && pad[0] == 0 { 485 stackGrowthRecursive(i - 1) 486 } 487 } 488 489 func TestPreemptSplitBig(t *testing.T) { 490 if testing.Short() { 491 t.Skip("skipping in -short mode") 492 } 493 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 494 stop := make(chan int) 495 go big(stop) 496 for i := 0; i < 3; i++ { 497 time.Sleep(10 * time.Microsecond) // let big start running 498 runtime.GC() 499 } 500 close(stop) 501 } 502 503 func big(stop chan int) int { 504 n := 0 505 for { 506 // delay so that gc is sure to have asked for a preemption 507 for i := 0; i < 1e9; i++ { 508 n++ 509 } 510 511 // call bigframe, which used to miss the preemption in its prologue. 512 bigframe(stop) 513 514 // check if we've been asked to stop. 515 select { 516 case <-stop: 517 return n 518 } 519 } 520 } 521 522 func bigframe(stop chan int) int { 523 // not splitting the stack will overflow. 524 // small will notice that it needs a stack split and will 525 // catch the overflow. 526 var x [8192]byte 527 return small(stop, &x) 528 } 529 530 func small(stop chan int, x *[8192]byte) int { 531 for i := range x { 532 x[i] = byte(i) 533 } 534 sum := 0 535 for i := range x { 536 sum += int(x[i]) 537 } 538 539 // keep small from being a leaf function, which might 540 // make it not do any stack check at all. 541 nonleaf(stop) 542 543 return sum 544 } 545 546 func nonleaf(stop chan int) bool { 547 // do something that won't be inlined: 548 select { 549 case <-stop: 550 return true 551 default: 552 return false 553 } 554 } 555 556 func TestSchedLocalQueue(t *testing.T) { 557 runtime.RunSchedLocalQueueTest() 558 } 559 560 func TestSchedLocalQueueSteal(t *testing.T) { 561 runtime.RunSchedLocalQueueStealTest() 562 } 563 564 func TestSchedLocalQueueEmpty(t *testing.T) { 565 if runtime.NumCPU() == 1 { 566 // Takes too long and does not trigger the race. 567 t.Skip("skipping on uniprocessor") 568 } 569 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 570 571 // If runtime triggers a forced GC during this test then it will deadlock, 572 // since the goroutines can't be stopped/preempted during spin wait. 573 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 574 575 iters := int(1e5) 576 if testing.Short() { 577 iters = 1e2 578 } 579 runtime.RunSchedLocalQueueEmptyTest(iters) 580 } 581 582 func benchmarkStackGrowth(b *testing.B, rec int) { 583 b.RunParallel(func(pb *testing.PB) { 584 for pb.Next() { 585 stackGrowthRecursive(rec) 586 } 587 }) 588 } 589 590 func BenchmarkStackGrowth(b *testing.B) { 591 benchmarkStackGrowth(b, 10) 592 } 593 594 func BenchmarkStackGrowthDeep(b *testing.B) { 595 benchmarkStackGrowth(b, 1024) 596 } 597 598 func BenchmarkCreateGoroutines(b *testing.B) { 599 benchmarkCreateGoroutines(b, 1) 600 } 601 602 func BenchmarkCreateGoroutinesParallel(b *testing.B) { 603 benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1)) 604 } 605 606 func benchmarkCreateGoroutines(b *testing.B, procs int) { 607 c := make(chan bool) 608 var f func(n int) 609 f = func(n int) { 610 if n == 0 { 611 c <- true 612 return 613 } 614 go f(n - 1) 615 } 616 for i := 0; i < procs; i++ { 617 go f(b.N / procs) 618 } 619 for i := 0; i < procs; i++ { 620 <-c 621 } 622 } 623 624 func BenchmarkCreateGoroutinesCapture(b *testing.B) { 625 b.ReportAllocs() 626 for i := 0; i < b.N; i++ { 627 const N = 4 628 var wg sync.WaitGroup 629 wg.Add(N) 630 for i := 0; i < N; i++ { 631 i := i 632 go func() { 633 if i >= N { 634 b.Logf("bad") // just to capture b 635 } 636 wg.Done() 637 }() 638 } 639 wg.Wait() 640 } 641 } 642 643 func BenchmarkClosureCall(b *testing.B) { 644 sum := 0 645 off1 := 1 646 for i := 0; i < b.N; i++ { 647 off2 := 2 648 func() { 649 sum += i + off1 + off2 650 }() 651 } 652 _ = sum 653 } 654 655 type Matrix [][]float64 656 657 func BenchmarkMatmult(b *testing.B) { 658 b.StopTimer() 659 // matmult is O(N**3) but testing expects O(b.N), 660 // so we need to take cube root of b.N 661 n := int(math.Cbrt(float64(b.N))) + 1 662 A := makeMatrix(n) 663 B := makeMatrix(n) 664 C := makeMatrix(n) 665 b.StartTimer() 666 matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8) 667 } 668 669 func makeMatrix(n int) Matrix { 670 m := make(Matrix, n) 671 for i := 0; i < n; i++ { 672 m[i] = make([]float64, n) 673 for j := 0; j < n; j++ { 674 m[i][j] = float64(i*n + j) 675 } 676 } 677 return m 678 } 679 680 func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) { 681 di := i1 - i0 682 dj := j1 - j0 683 dk := k1 - k0 684 if di >= dj && di >= dk && di >= threshold { 685 // divide in two by y axis 686 mi := i0 + di/2 687 done1 := make(chan struct{}, 1) 688 go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold) 689 matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold) 690 <-done1 691 } else if dj >= dk && dj >= threshold { 692 // divide in two by x axis 693 mj := j0 + dj/2 694 done1 := make(chan struct{}, 1) 695 go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold) 696 matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold) 697 <-done1 698 } else if dk >= threshold { 699 // divide in two by "k" axis 700 // deliberately not parallel because of data races 701 mk := k0 + dk/2 702 matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold) 703 matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold) 704 } else { 705 // the matrices are small enough, compute directly 706 for i := i0; i < i1; i++ { 707 for j := j0; j < j1; j++ { 708 for k := k0; k < k1; k++ { 709 C[i][j] += A[i][k] * B[k][j] 710 } 711 } 712 } 713 } 714 if done != nil { 715 done <- struct{}{} 716 } 717 } 718 719 func TestStealOrder(t *testing.T) { 720 runtime.RunStealOrderTest() 721 }