github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/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 "runtime" 10 "sync/atomic" 11 "syscall" 12 "testing" 13 "time" 14 ) 15 16 var stop = make(chan bool, 1) 17 18 func perpetuumMobile() { 19 select { 20 case <-stop: 21 default: 22 go perpetuumMobile() 23 } 24 } 25 26 func TestStopTheWorldDeadlock(t *testing.T) { 27 if testing.Short() { 28 t.Skip("skipping during short test") 29 } 30 maxprocs := runtime.GOMAXPROCS(3) 31 compl := make(chan bool, 2) 32 go func() { 33 for i := 0; i != 1000; i += 1 { 34 runtime.GC() 35 } 36 compl <- true 37 }() 38 go func() { 39 for i := 0; i != 1000; i += 1 { 40 runtime.GOMAXPROCS(3) 41 } 42 compl <- true 43 }() 44 go perpetuumMobile() 45 <-compl 46 <-compl 47 stop <- true 48 runtime.GOMAXPROCS(maxprocs) 49 } 50 51 func TestYieldProgress(t *testing.T) { 52 testYieldProgress(t, false) 53 } 54 55 func TestYieldLockedProgress(t *testing.T) { 56 testYieldProgress(t, true) 57 } 58 59 func testYieldProgress(t *testing.T, locked bool) { 60 c := make(chan bool) 61 cack := make(chan bool) 62 go func() { 63 if locked { 64 runtime.LockOSThread() 65 } 66 for { 67 select { 68 case <-c: 69 cack <- true 70 return 71 default: 72 runtime.Gosched() 73 } 74 } 75 }() 76 time.Sleep(10 * time.Millisecond) 77 c <- true 78 <-cack 79 } 80 81 func TestYieldLocked(t *testing.T) { 82 const N = 10 83 c := make(chan bool) 84 go func() { 85 runtime.LockOSThread() 86 for i := 0; i < N; i++ { 87 runtime.Gosched() 88 time.Sleep(time.Millisecond) 89 } 90 c <- true 91 // runtime.UnlockOSThread() is deliberately omitted 92 }() 93 <-c 94 } 95 96 func TestGoroutineParallelism(t *testing.T) { 97 P := 4 98 N := 10 99 if testing.Short() { 100 P = 3 101 N = 3 102 } 103 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) 104 // If runtime triggers a forced GC during this test then it will deadlock, 105 // since the goroutines can't be stopped/preempted. 106 // So give this test as much time as possible. 107 runtime.GC() 108 for try := 0; try < N; try++ { 109 done := make(chan bool) 110 x := uint32(0) 111 for p := 0; p < P; p++ { 112 // Test that all P goroutines are scheduled at the same time 113 go func(p int) { 114 for i := 0; i < 3; i++ { 115 expected := uint32(P*i + p) 116 for atomic.LoadUint32(&x) != expected { 117 } 118 atomic.StoreUint32(&x, expected+1) 119 } 120 done <- true 121 }(p) 122 } 123 for p := 0; p < P; p++ { 124 <-done 125 } 126 } 127 } 128 129 func TestBlockLocked(t *testing.T) { 130 const N = 10 131 c := make(chan bool) 132 go func() { 133 runtime.LockOSThread() 134 for i := 0; i < N; i++ { 135 c <- true 136 } 137 runtime.UnlockOSThread() 138 }() 139 for i := 0; i < N; i++ { 140 <-c 141 } 142 } 143 144 func TestTimerFairness(t *testing.T) { 145 done := make(chan bool) 146 c := make(chan bool) 147 for i := 0; i < 2; i++ { 148 go func() { 149 for { 150 select { 151 case c <- true: 152 case <-done: 153 return 154 } 155 } 156 }() 157 } 158 159 timer := time.After(20 * time.Millisecond) 160 for { 161 select { 162 case <-c: 163 case <-timer: 164 close(done) 165 return 166 } 167 } 168 } 169 170 func TestTimerFairness2(t *testing.T) { 171 done := make(chan bool) 172 c := make(chan bool) 173 for i := 0; i < 2; i++ { 174 go func() { 175 timer := time.After(20 * time.Millisecond) 176 var buf [1]byte 177 for { 178 syscall.Read(0, buf[0:0]) 179 select { 180 case c <- true: 181 case <-c: 182 case <-timer: 183 done <- true 184 return 185 } 186 } 187 }() 188 } 189 <-done 190 <-done 191 } 192 193 // The function is used to test preemption at split stack checks. 194 // Declaring a var avoids inlining at the call site. 195 var preempt = func() int { 196 var a [128]int 197 sum := 0 198 for _, v := range a { 199 sum += v 200 } 201 return sum 202 } 203 204 func TestPreemption(t *testing.T) { 205 // Test that goroutines are preempted at function calls. 206 N := 5 207 if testing.Short() { 208 N = 2 209 } 210 c := make(chan bool) 211 var x uint32 212 for g := 0; g < 2; g++ { 213 go func(g int) { 214 for i := 0; i < N; i++ { 215 for atomic.LoadUint32(&x) != uint32(g) { 216 preempt() 217 } 218 atomic.StoreUint32(&x, uint32(1-g)) 219 } 220 c <- true 221 }(g) 222 } 223 <-c 224 <-c 225 } 226 227 func TestPreemptionGC(t *testing.T) { 228 // Test that pending GC preempts running goroutines. 229 P := 5 230 N := 10 231 if testing.Short() { 232 P = 3 233 N = 2 234 } 235 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1)) 236 var stop uint32 237 for i := 0; i < P; i++ { 238 go func() { 239 for atomic.LoadUint32(&stop) == 0 { 240 preempt() 241 } 242 }() 243 } 244 for i := 0; i < N; i++ { 245 runtime.Gosched() 246 runtime.GC() 247 } 248 atomic.StoreUint32(&stop, 1) 249 } 250 251 func TestGCFairness(t *testing.T) { 252 output := executeTest(t, testGCFairnessSource, nil) 253 want := "OK\n" 254 if output != want { 255 t.Fatalf("want %s, got %s\n", want, output) 256 } 257 } 258 259 const testGCFairnessSource = ` 260 package main 261 262 import ( 263 "fmt" 264 "os" 265 "runtime" 266 "time" 267 ) 268 269 func main() { 270 runtime.GOMAXPROCS(1) 271 f, err := os.Open("/dev/null") 272 if os.IsNotExist(err) { 273 // This test tests what it is intended to test only if writes are fast. 274 // If there is no /dev/null, we just don't execute the test. 275 fmt.Println("OK") 276 return 277 } 278 if err != nil { 279 fmt.Println(err) 280 os.Exit(1) 281 } 282 for i := 0; i < 2; i++ { 283 go func() { 284 for { 285 f.Write([]byte(".")) 286 } 287 }() 288 } 289 time.Sleep(10 * time.Millisecond) 290 fmt.Println("OK") 291 } 292 ` 293 294 func stackGrowthRecursive(i int) { 295 var pad [128]uint64 296 if i != 0 && pad[0] == 0 { 297 stackGrowthRecursive(i - 1) 298 } 299 } 300 301 func TestPreemptSplitBig(t *testing.T) { 302 if testing.Short() { 303 t.Skip("skipping in -short mode") 304 } 305 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 306 stop := make(chan int) 307 go big(stop) 308 for i := 0; i < 3; i++ { 309 time.Sleep(10 * time.Microsecond) // let big start running 310 runtime.GC() 311 } 312 close(stop) 313 } 314 315 func big(stop chan int) int { 316 n := 0 317 for { 318 // delay so that gc is sure to have asked for a preemption 319 for i := 0; i < 1e9; i++ { 320 n++ 321 } 322 323 // call bigframe, which used to miss the preemption in its prologue. 324 bigframe(stop) 325 326 // check if we've been asked to stop. 327 select { 328 case <-stop: 329 return n 330 } 331 } 332 } 333 334 func bigframe(stop chan int) int { 335 // not splitting the stack will overflow. 336 // small will notice that it needs a stack split and will 337 // catch the overflow. 338 var x [8192]byte 339 return small(stop, &x) 340 } 341 342 func small(stop chan int, x *[8192]byte) int { 343 for i := range x { 344 x[i] = byte(i) 345 } 346 sum := 0 347 for i := range x { 348 sum += int(x[i]) 349 } 350 351 // keep small from being a leaf function, which might 352 // make it not do any stack check at all. 353 nonleaf(stop) 354 355 return sum 356 } 357 358 func nonleaf(stop chan int) bool { 359 // do something that won't be inlined: 360 select { 361 case <-stop: 362 return true 363 default: 364 return false 365 } 366 } 367 368 func TestSchedLocalQueue(t *testing.T) { 369 runtime.RunSchedLocalQueueTest() 370 } 371 372 func TestSchedLocalQueueSteal(t *testing.T) { 373 runtime.RunSchedLocalQueueStealTest() 374 } 375 376 func benchmarkStackGrowth(b *testing.B, rec int) { 377 b.RunParallel(func(pb *testing.PB) { 378 for pb.Next() { 379 stackGrowthRecursive(rec) 380 } 381 }) 382 } 383 384 func BenchmarkStackGrowth(b *testing.B) { 385 benchmarkStackGrowth(b, 10) 386 } 387 388 func BenchmarkStackGrowthDeep(b *testing.B) { 389 benchmarkStackGrowth(b, 1024) 390 } 391 392 func BenchmarkCreateGoroutines(b *testing.B) { 393 benchmarkCreateGoroutines(b, 1) 394 } 395 396 func BenchmarkCreateGoroutinesParallel(b *testing.B) { 397 benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1)) 398 } 399 400 func benchmarkCreateGoroutines(b *testing.B, procs int) { 401 c := make(chan bool) 402 var f func(n int) 403 f = func(n int) { 404 if n == 0 { 405 c <- true 406 return 407 } 408 go f(n - 1) 409 } 410 for i := 0; i < procs; i++ { 411 go f(b.N / procs) 412 } 413 for i := 0; i < procs; i++ { 414 <-c 415 } 416 } 417 418 type Matrix [][]float64 419 420 func BenchmarkMatmult(b *testing.B) { 421 b.StopTimer() 422 // matmult is O(N**3) but testing expects O(b.N), 423 // so we need to take cube root of b.N 424 n := int(math.Cbrt(float64(b.N))) + 1 425 A := makeMatrix(n) 426 B := makeMatrix(n) 427 C := makeMatrix(n) 428 b.StartTimer() 429 matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8) 430 } 431 432 func makeMatrix(n int) Matrix { 433 m := make(Matrix, n) 434 for i := 0; i < n; i++ { 435 m[i] = make([]float64, n) 436 for j := 0; j < n; j++ { 437 m[i][j] = float64(i*n + j) 438 } 439 } 440 return m 441 } 442 443 func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) { 444 di := i1 - i0 445 dj := j1 - j0 446 dk := k1 - k0 447 if di >= dj && di >= dk && di >= threshold { 448 // divide in two by y axis 449 mi := i0 + di/2 450 done1 := make(chan struct{}, 1) 451 go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold) 452 matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold) 453 <-done1 454 } else if dj >= dk && dj >= threshold { 455 // divide in two by x axis 456 mj := j0 + dj/2 457 done1 := make(chan struct{}, 1) 458 go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold) 459 matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold) 460 <-done1 461 } else if dk >= threshold { 462 // divide in two by "k" axis 463 // deliberately not parallel because of data races 464 mk := k0 + dk/2 465 matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold) 466 matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold) 467 } else { 468 // the matrices are small enough, compute directly 469 for i := i0; i < i1; i++ { 470 for j := j0; j < j1; j++ { 471 for k := k0; k < k1; k++ { 472 C[i][j] += A[i][k] * B[k][j] 473 } 474 } 475 } 476 } 477 if done != nil { 478 done <- struct{}{} 479 } 480 }