github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/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(false) 57 } 58 59 func TestYieldLockedProgress(t *testing.T) { 60 testYieldProgress(true) 61 } 62 63 func testYieldProgress(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 // 5, which indicates that both pairs of goroutines handed off 432 // the P within a time-slice to their buddy. We can use a 433 // fairly large factor here to make this robust: if the 434 // scheduler isn't working right, the gap should be ~1000X. 435 const factor = 5 436 if hogCount > lightCount*factor || lightCount > hogCount*factor { 437 t.Fatalf("want hogCount/lightCount in [%v, %v]; got %d/%d = %g", 1.0/factor, factor, hogCount, lightCount, float64(hogCount)/float64(lightCount)) 438 } 439 } 440 441 func BenchmarkPingPongHog(b *testing.B) { 442 if b.N == 0 { 443 return 444 } 445 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 446 447 // Create a CPU hog 448 stop, done := make(chan bool), make(chan bool) 449 go func() { 450 for { 451 select { 452 case <-stop: 453 done <- true 454 return 455 default: 456 } 457 } 458 }() 459 460 // Ping-pong b.N times 461 ping, pong := make(chan bool), make(chan bool) 462 go func() { 463 for j := 0; j < b.N; j++ { 464 pong <- <-ping 465 } 466 close(stop) 467 done <- true 468 }() 469 go func() { 470 for i := 0; i < b.N; i++ { 471 ping <- <-pong 472 } 473 done <- true 474 }() 475 b.ResetTimer() 476 ping <- true // Start ping-pong 477 <-stop 478 b.StopTimer() 479 <-ping // Let last ponger exit 480 <-done // Make sure goroutines exit 481 <-done 482 <-done 483 } 484 485 func stackGrowthRecursive(i int) { 486 var pad [128]uint64 487 if i != 0 && pad[0] == 0 { 488 stackGrowthRecursive(i - 1) 489 } 490 } 491 492 func TestPreemptSplitBig(t *testing.T) { 493 if testing.Short() { 494 t.Skip("skipping in -short mode") 495 } 496 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 497 stop := make(chan int) 498 go big(stop) 499 for i := 0; i < 3; i++ { 500 time.Sleep(10 * time.Microsecond) // let big start running 501 runtime.GC() 502 } 503 close(stop) 504 } 505 506 func big(stop chan int) int { 507 n := 0 508 for { 509 // delay so that gc is sure to have asked for a preemption 510 for i := 0; i < 1e9; i++ { 511 n++ 512 } 513 514 // call bigframe, which used to miss the preemption in its prologue. 515 bigframe(stop) 516 517 // check if we've been asked to stop. 518 select { 519 case <-stop: 520 return n 521 } 522 } 523 } 524 525 func bigframe(stop chan int) int { 526 // not splitting the stack will overflow. 527 // small will notice that it needs a stack split and will 528 // catch the overflow. 529 var x [8192]byte 530 return small(stop, &x) 531 } 532 533 func small(stop chan int, x *[8192]byte) int { 534 for i := range x { 535 x[i] = byte(i) 536 } 537 sum := 0 538 for i := range x { 539 sum += int(x[i]) 540 } 541 542 // keep small from being a leaf function, which might 543 // make it not do any stack check at all. 544 nonleaf(stop) 545 546 return sum 547 } 548 549 func nonleaf(stop chan int) bool { 550 // do something that won't be inlined: 551 select { 552 case <-stop: 553 return true 554 default: 555 return false 556 } 557 } 558 559 func TestSchedLocalQueue(t *testing.T) { 560 runtime.RunSchedLocalQueueTest() 561 } 562 563 func TestSchedLocalQueueSteal(t *testing.T) { 564 runtime.RunSchedLocalQueueStealTest() 565 } 566 567 func TestSchedLocalQueueEmpty(t *testing.T) { 568 if runtime.NumCPU() == 1 { 569 // Takes too long and does not trigger the race. 570 t.Skip("skipping on uniprocessor") 571 } 572 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 573 574 // If runtime triggers a forced GC during this test then it will deadlock, 575 // since the goroutines can't be stopped/preempted during spin wait. 576 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 577 578 iters := int(1e5) 579 if testing.Short() { 580 iters = 1e2 581 } 582 runtime.RunSchedLocalQueueEmptyTest(iters) 583 } 584 585 func benchmarkStackGrowth(b *testing.B, rec int) { 586 b.RunParallel(func(pb *testing.PB) { 587 for pb.Next() { 588 stackGrowthRecursive(rec) 589 } 590 }) 591 } 592 593 func BenchmarkStackGrowth(b *testing.B) { 594 benchmarkStackGrowth(b, 10) 595 } 596 597 func BenchmarkStackGrowthDeep(b *testing.B) { 598 benchmarkStackGrowth(b, 1024) 599 } 600 601 func BenchmarkCreateGoroutines(b *testing.B) { 602 benchmarkCreateGoroutines(b, 1) 603 } 604 605 func BenchmarkCreateGoroutinesParallel(b *testing.B) { 606 benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1)) 607 } 608 609 func benchmarkCreateGoroutines(b *testing.B, procs int) { 610 c := make(chan bool) 611 var f func(n int) 612 f = func(n int) { 613 if n == 0 { 614 c <- true 615 return 616 } 617 go f(n - 1) 618 } 619 for i := 0; i < procs; i++ { 620 go f(b.N / procs) 621 } 622 for i := 0; i < procs; i++ { 623 <-c 624 } 625 } 626 627 func BenchmarkCreateGoroutinesCapture(b *testing.B) { 628 b.ReportAllocs() 629 for i := 0; i < b.N; i++ { 630 const N = 4 631 var wg sync.WaitGroup 632 wg.Add(N) 633 for i := 0; i < N; i++ { 634 i := i 635 go func() { 636 if i >= N { 637 b.Logf("bad") // just to capture b 638 } 639 wg.Done() 640 }() 641 } 642 wg.Wait() 643 } 644 } 645 646 func BenchmarkClosureCall(b *testing.B) { 647 sum := 0 648 off1 := 1 649 for i := 0; i < b.N; i++ { 650 off2 := 2 651 func() { 652 sum += i + off1 + off2 653 }() 654 } 655 _ = sum 656 } 657 658 type Matrix [][]float64 659 660 func BenchmarkMatmult(b *testing.B) { 661 b.StopTimer() 662 // matmult is O(N**3) but testing expects O(b.N), 663 // so we need to take cube root of b.N 664 n := int(math.Cbrt(float64(b.N))) + 1 665 A := makeMatrix(n) 666 B := makeMatrix(n) 667 C := makeMatrix(n) 668 b.StartTimer() 669 matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8) 670 } 671 672 func makeMatrix(n int) Matrix { 673 m := make(Matrix, n) 674 for i := 0; i < n; i++ { 675 m[i] = make([]float64, n) 676 for j := 0; j < n; j++ { 677 m[i][j] = float64(i*n + j) 678 } 679 } 680 return m 681 } 682 683 func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) { 684 di := i1 - i0 685 dj := j1 - j0 686 dk := k1 - k0 687 if di >= dj && di >= dk && di >= threshold { 688 // divide in two by y axis 689 mi := i0 + di/2 690 done1 := make(chan struct{}, 1) 691 go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold) 692 matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold) 693 <-done1 694 } else if dj >= dk && dj >= threshold { 695 // divide in two by x axis 696 mj := j0 + dj/2 697 done1 := make(chan struct{}, 1) 698 go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold) 699 matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold) 700 <-done1 701 } else if dk >= threshold { 702 // divide in two by "k" axis 703 // deliberately not parallel because of data races 704 mk := k0 + dk/2 705 matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold) 706 matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold) 707 } else { 708 // the matrices are small enough, compute directly 709 for i := i0; i < i1; i++ { 710 for j := j0; j < j1; j++ { 711 for k := k0; k < k1; k++ { 712 C[i][j] += A[i][k] * B[k][j] 713 } 714 } 715 } 716 } 717 if done != nil { 718 done <- struct{}{} 719 } 720 } 721 722 func TestStealOrder(t *testing.T) { 723 runtime.RunStealOrderTest() 724 } 725 726 func TestLockOSThreadNesting(t *testing.T) { 727 go func() { 728 e, i := runtime.LockOSCounts() 729 if e != 0 || i != 0 { 730 t.Errorf("want locked counts 0, 0; got %d, %d", e, i) 731 return 732 } 733 runtime.LockOSThread() 734 runtime.LockOSThread() 735 runtime.UnlockOSThread() 736 e, i = runtime.LockOSCounts() 737 if e != 1 || i != 0 { 738 t.Errorf("want locked counts 1, 0; got %d, %d", e, i) 739 return 740 } 741 runtime.UnlockOSThread() 742 e, i = runtime.LockOSCounts() 743 if e != 0 || i != 0 { 744 t.Errorf("want locked counts 0, 0; got %d, %d", e, i) 745 return 746 } 747 }() 748 } 749 750 func TestLockOSThreadExit(t *testing.T) { 751 testLockOSThreadExit(t, "testprog") 752 } 753 754 func testLockOSThreadExit(t *testing.T, prog string) { 755 output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1") 756 want := "OK\n" 757 if output != want { 758 t.Errorf("want %s, got %s\n", want, output) 759 } 760 761 output = runTestProg(t, prog, "LockOSThreadAlt") 762 if output != want { 763 t.Errorf("want %s, got %s\n", want, output) 764 } 765 }