github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/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 "runtime" 10 "runtime/debug" 11 "sync" 12 "sync/atomic" 13 "syscall" 14 "testing" 15 "time" 16 ) 17 18 var stop = make(chan bool, 1) 19 20 func perpetuumMobile() { 21 select { 22 case <-stop: 23 default: 24 go perpetuumMobile() 25 } 26 } 27 28 func TestStopTheWorldDeadlock(t *testing.T) { 29 if testing.Short() { 30 t.Skip("skipping during short test") 31 } 32 maxprocs := runtime.GOMAXPROCS(3) 33 compl := make(chan bool, 2) 34 go func() { 35 for i := 0; i != 1000; i += 1 { 36 runtime.GC() 37 } 38 compl <- true 39 }() 40 go func() { 41 for i := 0; i != 1000; i += 1 { 42 runtime.GOMAXPROCS(3) 43 } 44 compl <- true 45 }() 46 go perpetuumMobile() 47 <-compl 48 <-compl 49 stop <- true 50 runtime.GOMAXPROCS(maxprocs) 51 } 52 53 func TestYieldProgress(t *testing.T) { 54 testYieldProgress(t, false) 55 } 56 57 func TestYieldLockedProgress(t *testing.T) { 58 testYieldProgress(t, true) 59 } 60 61 func testYieldProgress(t *testing.T, locked bool) { 62 c := make(chan bool) 63 cack := make(chan bool) 64 go func() { 65 if locked { 66 runtime.LockOSThread() 67 } 68 for { 69 select { 70 case <-c: 71 cack <- true 72 return 73 default: 74 runtime.Gosched() 75 } 76 } 77 }() 78 time.Sleep(10 * time.Millisecond) 79 c <- true 80 <-cack 81 } 82 83 func TestYieldLocked(t *testing.T) { 84 const N = 10 85 c := make(chan bool) 86 go func() { 87 runtime.LockOSThread() 88 for i := 0; i < N; i++ { 89 runtime.Gosched() 90 time.Sleep(time.Millisecond) 91 } 92 c <- true 93 // runtime.UnlockOSThread() is deliberately omitted 94 }() 95 <-c 96 } 97 98 func TestGoroutineParallelism(t *testing.T) { 99 if runtime.NumCPU() == 1 { 100 // Takes too long, too easy to deadlock, etc. 101 t.Skip("skipping on uniprocessor") 102 } 103 P := 4 104 N := 10 105 if testing.Short() { 106 P = 3 107 N = 3 108 } 109 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) 110 // If runtime triggers a forced GC during this test then it will deadlock, 111 // since the goroutines can't be stopped/preempted. 112 // Disable GC for this test (see issue #10958). 113 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 114 for try := 0; try < N; try++ { 115 done := make(chan bool) 116 x := uint32(0) 117 for p := 0; p < P; p++ { 118 // Test that all P goroutines are scheduled at the same time 119 go func(p int) { 120 for i := 0; i < 3; i++ { 121 expected := uint32(P*i + p) 122 for atomic.LoadUint32(&x) != expected { 123 } 124 atomic.StoreUint32(&x, expected+1) 125 } 126 done <- true 127 }(p) 128 } 129 for p := 0; p < P; p++ { 130 <-done 131 } 132 } 133 } 134 135 func TestBlockLocked(t *testing.T) { 136 const N = 10 137 c := make(chan bool) 138 go func() { 139 runtime.LockOSThread() 140 for i := 0; i < N; i++ { 141 c <- true 142 } 143 runtime.UnlockOSThread() 144 }() 145 for i := 0; i < N; i++ { 146 <-c 147 } 148 } 149 150 func TestTimerFairness(t *testing.T) { 151 done := make(chan bool) 152 c := make(chan bool) 153 for i := 0; i < 2; i++ { 154 go func() { 155 for { 156 select { 157 case c <- true: 158 case <-done: 159 return 160 } 161 } 162 }() 163 } 164 165 timer := time.After(20 * time.Millisecond) 166 for { 167 select { 168 case <-c: 169 case <-timer: 170 close(done) 171 return 172 } 173 } 174 } 175 176 func TestTimerFairness2(t *testing.T) { 177 done := make(chan bool) 178 c := make(chan bool) 179 for i := 0; i < 2; i++ { 180 go func() { 181 timer := time.After(20 * time.Millisecond) 182 var buf [1]byte 183 for { 184 syscall.Read(0, buf[0:0]) 185 select { 186 case c <- true: 187 case <-c: 188 case <-timer: 189 done <- true 190 return 191 } 192 } 193 }() 194 } 195 <-done 196 <-done 197 } 198 199 // The function is used to test preemption at split stack checks. 200 // Declaring a var avoids inlining at the call site. 201 var preempt = func() int { 202 var a [128]int 203 sum := 0 204 for _, v := range a { 205 sum += v 206 } 207 return sum 208 } 209 210 func TestPreemption(t *testing.T) { 211 t.Skip("gccgo does not implement preemption") 212 // Test that goroutines are preempted at function calls. 213 N := 5 214 if testing.Short() { 215 N = 2 216 } 217 c := make(chan bool) 218 var x uint32 219 for g := 0; g < 2; g++ { 220 go func(g int) { 221 for i := 0; i < N; i++ { 222 for atomic.LoadUint32(&x) != uint32(g) { 223 preempt() 224 } 225 atomic.StoreUint32(&x, uint32(1-g)) 226 } 227 c <- true 228 }(g) 229 } 230 <-c 231 <-c 232 } 233 234 func TestPreemptionGC(t *testing.T) { 235 t.Skip("gccgo does not implement preemption") 236 // Test that pending GC preempts running goroutines. 237 P := 5 238 N := 10 239 if testing.Short() { 240 P = 3 241 N = 2 242 } 243 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1)) 244 var stop uint32 245 for i := 0; i < P; i++ { 246 go func() { 247 for atomic.LoadUint32(&stop) == 0 { 248 preempt() 249 } 250 }() 251 } 252 for i := 0; i < N; i++ { 253 runtime.Gosched() 254 runtime.GC() 255 } 256 atomic.StoreUint32(&stop, 1) 257 } 258 259 func TestGCFairness(t *testing.T) { 260 output := executeTest(t, testGCFairnessSource, nil) 261 want := "OK\n" 262 if output != want { 263 t.Fatalf("want %s, got %s\n", want, output) 264 } 265 } 266 267 const testGCFairnessSource = ` 268 package main 269 270 import ( 271 "fmt" 272 "os" 273 "runtime" 274 "time" 275 ) 276 277 func main() { 278 runtime.GOMAXPROCS(1) 279 f, err := os.Open("/dev/null") 280 if os.IsNotExist(err) { 281 // This test tests what it is intended to test only if writes are fast. 282 // If there is no /dev/null, we just don't execute the test. 283 fmt.Println("OK") 284 return 285 } 286 if err != nil { 287 fmt.Println(err) 288 os.Exit(1) 289 } 290 for i := 0; i < 2; i++ { 291 go func() { 292 for { 293 f.Write([]byte(".")) 294 } 295 }() 296 } 297 time.Sleep(10 * time.Millisecond) 298 fmt.Println("OK") 299 } 300 ` 301 302 func TestPingPongHog(t *testing.T) { 303 if testing.Short() { 304 t.Skip("skipping in -short mode") 305 } 306 307 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 308 done := make(chan bool) 309 hogChan, lightChan := make(chan bool), make(chan bool) 310 hogCount, lightCount := 0, 0 311 312 run := func(limit int, counter *int, wake chan bool) { 313 for { 314 select { 315 case <-done: 316 return 317 318 case <-wake: 319 for i := 0; i < limit; i++ { 320 *counter++ 321 } 322 wake <- true 323 } 324 } 325 } 326 327 // Start two co-scheduled hog goroutines. 328 for i := 0; i < 2; i++ { 329 go run(1e6, &hogCount, hogChan) 330 } 331 332 // Start two co-scheduled light goroutines. 333 for i := 0; i < 2; i++ { 334 go run(1e3, &lightCount, lightChan) 335 } 336 337 // Start goroutine pairs and wait for a few preemption rounds. 338 hogChan <- true 339 lightChan <- true 340 time.Sleep(100 * time.Millisecond) 341 close(done) 342 <-hogChan 343 <-lightChan 344 345 // Check that hogCount and lightCount are within a factor of 346 // 2, which indicates that both pairs of goroutines handed off 347 // the P within a time-slice to their buddy. 348 if hogCount > lightCount*2 || lightCount > hogCount*2 { 349 t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount)) 350 } 351 } 352 353 func BenchmarkPingPongHog(b *testing.B) { 354 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 355 356 // Create a CPU hog 357 stop, done := make(chan bool), make(chan bool) 358 go func() { 359 for { 360 select { 361 case <-stop: 362 done <- true 363 return 364 default: 365 } 366 } 367 }() 368 369 // Ping-pong b.N times 370 ping, pong := make(chan bool), make(chan bool) 371 go func() { 372 for j := 0; j < b.N; j++ { 373 pong <- <-ping 374 } 375 close(stop) 376 done <- true 377 }() 378 go func() { 379 for i := 0; i < b.N; i++ { 380 ping <- <-pong 381 } 382 done <- true 383 }() 384 b.ResetTimer() 385 ping <- true // Start ping-pong 386 <-stop 387 b.StopTimer() 388 <-ping // Let last ponger exit 389 <-done // Make sure goroutines exit 390 <-done 391 <-done 392 } 393 394 func stackGrowthRecursive(i int) { 395 var pad [128]uint64 396 if i != 0 && pad[0] == 0 { 397 stackGrowthRecursive(i - 1) 398 } 399 } 400 401 func TestPreemptSplitBig(t *testing.T) { 402 if testing.Short() { 403 t.Skip("skipping in -short mode") 404 } 405 t.Skip("gccgo does not implement preemption") 406 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 407 stop := make(chan int) 408 go big(stop) 409 for i := 0; i < 3; i++ { 410 time.Sleep(10 * time.Microsecond) // let big start running 411 runtime.GC() 412 } 413 close(stop) 414 } 415 416 func big(stop chan int) int { 417 n := 0 418 for { 419 // delay so that gc is sure to have asked for a preemption 420 for i := 0; i < 1e9; i++ { 421 n++ 422 } 423 424 // call bigframe, which used to miss the preemption in its prologue. 425 bigframe(stop) 426 427 // check if we've been asked to stop. 428 select { 429 case <-stop: 430 return n 431 } 432 } 433 } 434 435 func bigframe(stop chan int) int { 436 // not splitting the stack will overflow. 437 // small will notice that it needs a stack split and will 438 // catch the overflow. 439 var x [8192]byte 440 return small(stop, &x) 441 } 442 443 func small(stop chan int, x *[8192]byte) int { 444 for i := range x { 445 x[i] = byte(i) 446 } 447 sum := 0 448 for i := range x { 449 sum += int(x[i]) 450 } 451 452 // keep small from being a leaf function, which might 453 // make it not do any stack check at all. 454 nonleaf(stop) 455 456 return sum 457 } 458 459 func nonleaf(stop chan int) bool { 460 // do something that won't be inlined: 461 select { 462 case <-stop: 463 return true 464 default: 465 return false 466 } 467 } 468 469 /* 470 func TestSchedLocalQueue(t *testing.T) { 471 runtime.TestSchedLocalQueue1() 472 } 473 */ 474 475 /* 476 func TestSchedLocalQueueSteal(t *testing.T) { 477 runtime.TestSchedLocalQueueSteal1() 478 } 479 */ 480 481 func benchmarkStackGrowth(b *testing.B, rec int) { 482 b.RunParallel(func(pb *testing.PB) { 483 for pb.Next() { 484 stackGrowthRecursive(rec) 485 } 486 }) 487 } 488 489 func BenchmarkStackGrowth(b *testing.B) { 490 benchmarkStackGrowth(b, 10) 491 } 492 493 func BenchmarkStackGrowthDeep(b *testing.B) { 494 benchmarkStackGrowth(b, 1024) 495 } 496 497 func BenchmarkCreateGoroutines(b *testing.B) { 498 benchmarkCreateGoroutines(b, 1) 499 } 500 501 func BenchmarkCreateGoroutinesParallel(b *testing.B) { 502 benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1)) 503 } 504 505 func benchmarkCreateGoroutines(b *testing.B, procs int) { 506 c := make(chan bool) 507 var f func(n int) 508 f = func(n int) { 509 if n == 0 { 510 c <- true 511 return 512 } 513 go f(n - 1) 514 } 515 for i := 0; i < procs; i++ { 516 go f(b.N / procs) 517 } 518 for i := 0; i < procs; i++ { 519 <-c 520 } 521 } 522 523 func BenchmarkCreateGoroutinesCapture(b *testing.B) { 524 b.ReportAllocs() 525 for i := 0; i < b.N; i++ { 526 const N = 4 527 var wg sync.WaitGroup 528 wg.Add(N) 529 for i := 0; i < N; i++ { 530 i := i 531 go func() { 532 if i >= N { 533 b.Logf("bad") // just to capture b 534 } 535 wg.Done() 536 }() 537 } 538 wg.Wait() 539 } 540 } 541 542 func BenchmarkClosureCall(b *testing.B) { 543 sum := 0 544 off1 := 1 545 for i := 0; i < b.N; i++ { 546 off2 := 2 547 func() { 548 sum += i + off1 + off2 549 }() 550 } 551 _ = sum 552 } 553 554 type Matrix [][]float64 555 556 func BenchmarkMatmult(b *testing.B) { 557 b.StopTimer() 558 // matmult is O(N**3) but testing expects O(b.N), 559 // so we need to take cube root of b.N 560 n := int(math.Cbrt(float64(b.N))) + 1 561 A := makeMatrix(n) 562 B := makeMatrix(n) 563 C := makeMatrix(n) 564 b.StartTimer() 565 matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8) 566 } 567 568 func makeMatrix(n int) Matrix { 569 m := make(Matrix, n) 570 for i := 0; i < n; i++ { 571 m[i] = make([]float64, n) 572 for j := 0; j < n; j++ { 573 m[i][j] = float64(i*n + j) 574 } 575 } 576 return m 577 } 578 579 func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) { 580 di := i1 - i0 581 dj := j1 - j0 582 dk := k1 - k0 583 if di >= dj && di >= dk && di >= threshold { 584 // divide in two by y axis 585 mi := i0 + di/2 586 done1 := make(chan struct{}, 1) 587 go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold) 588 matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold) 589 <-done1 590 } else if dj >= dk && dj >= threshold { 591 // divide in two by x axis 592 mj := j0 + dj/2 593 done1 := make(chan struct{}, 1) 594 go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold) 595 matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold) 596 <-done1 597 } else if dk >= threshold { 598 // divide in two by "k" axis 599 // deliberately not parallel because of data races 600 mk := k0 + dk/2 601 matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold) 602 matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold) 603 } else { 604 // the matrices are small enough, compute directly 605 for i := i0; i < i1; i++ { 606 for j := j0; j < j1; j++ { 607 for k := k0; k < k1; k++ { 608 C[i][j] += A[i][k] * B[k][j] 609 } 610 } 611 } 612 } 613 if done != nil { 614 done <- struct{}{} 615 } 616 }