github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/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 for try := 0; try < N; try++ { 105 done := make(chan bool) 106 x := uint32(0) 107 for p := 0; p < P; p++ { 108 // Test that all P goroutines are scheduled at the same time 109 go func(p int) { 110 for i := 0; i < 3; i++ { 111 expected := uint32(P*i + p) 112 for atomic.LoadUint32(&x) != expected { 113 } 114 atomic.StoreUint32(&x, expected+1) 115 } 116 done <- true 117 }(p) 118 } 119 for p := 0; p < P; p++ { 120 <-done 121 } 122 } 123 } 124 125 func TestBlockLocked(t *testing.T) { 126 const N = 10 127 c := make(chan bool) 128 go func() { 129 runtime.LockOSThread() 130 for i := 0; i < N; i++ { 131 c <- true 132 } 133 runtime.UnlockOSThread() 134 }() 135 for i := 0; i < N; i++ { 136 <-c 137 } 138 } 139 140 func TestTimerFairness(t *testing.T) { 141 done := make(chan bool) 142 c := make(chan bool) 143 for i := 0; i < 2; i++ { 144 go func() { 145 for { 146 select { 147 case c <- true: 148 case <-done: 149 return 150 } 151 } 152 }() 153 } 154 155 timer := time.After(20 * time.Millisecond) 156 for { 157 select { 158 case <-c: 159 case <-timer: 160 close(done) 161 return 162 } 163 } 164 } 165 166 func TestTimerFairness2(t *testing.T) { 167 done := make(chan bool) 168 c := make(chan bool) 169 for i := 0; i < 2; i++ { 170 go func() { 171 timer := time.After(20 * time.Millisecond) 172 var buf [1]byte 173 for { 174 syscall.Read(0, buf[0:0]) 175 select { 176 case c <- true: 177 case <-c: 178 case <-timer: 179 done <- true 180 return 181 } 182 } 183 }() 184 } 185 <-done 186 <-done 187 } 188 189 // The function is used to test preemption at split stack checks. 190 // Declaring a var avoids inlining at the call site. 191 var preempt = func() int { 192 var a [128]int 193 sum := 0 194 for _, v := range a { 195 sum += v 196 } 197 return sum 198 } 199 200 func TestPreemption(t *testing.T) { 201 // Test that goroutines are preempted at function calls. 202 N := 5 203 if testing.Short() { 204 N = 2 205 } 206 c := make(chan bool) 207 var x uint32 208 for g := 0; g < 2; g++ { 209 go func(g int) { 210 for i := 0; i < N; i++ { 211 for atomic.LoadUint32(&x) != uint32(g) { 212 preempt() 213 } 214 atomic.StoreUint32(&x, uint32(1-g)) 215 } 216 c <- true 217 }(g) 218 } 219 <-c 220 <-c 221 } 222 223 func TestPreemptionGC(t *testing.T) { 224 // Test that pending GC preempts running goroutines. 225 P := 5 226 N := 10 227 if testing.Short() { 228 P = 3 229 N = 2 230 } 231 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1)) 232 var stop uint32 233 for i := 0; i < P; i++ { 234 go func() { 235 for atomic.LoadUint32(&stop) == 0 { 236 preempt() 237 } 238 }() 239 } 240 for i := 0; i < N; i++ { 241 runtime.Gosched() 242 runtime.GC() 243 } 244 atomic.StoreUint32(&stop, 1) 245 } 246 247 func stackGrowthRecursive(i int) { 248 var pad [128]uint64 249 if i != 0 && pad[0] == 0 { 250 stackGrowthRecursive(i - 1) 251 } 252 } 253 254 func TestPreemptSplitBig(t *testing.T) { 255 if testing.Short() { 256 t.Skip("skipping in -short mode") 257 } 258 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) 259 stop := make(chan int) 260 go big(stop) 261 for i := 0; i < 3; i++ { 262 time.Sleep(10 * time.Microsecond) // let big start running 263 runtime.GC() 264 } 265 close(stop) 266 } 267 268 func big(stop chan int) int { 269 n := 0 270 for { 271 // delay so that gc is sure to have asked for a preemption 272 for i := 0; i < 1e9; i++ { 273 n++ 274 } 275 276 // call bigframe, which used to miss the preemption in its prologue. 277 bigframe(stop) 278 279 // check if we've been asked to stop. 280 select { 281 case <-stop: 282 return n 283 } 284 } 285 } 286 287 func bigframe(stop chan int) int { 288 // not splitting the stack will overflow. 289 // small will notice that it needs a stack split and will 290 // catch the overflow. 291 var x [8192]byte 292 return small(stop, &x) 293 } 294 295 func small(stop chan int, x *[8192]byte) int { 296 for i := range x { 297 x[i] = byte(i) 298 } 299 sum := 0 300 for i := range x { 301 sum += int(x[i]) 302 } 303 304 // keep small from being a leaf function, which might 305 // make it not do any stack check at all. 306 nonleaf(stop) 307 308 return sum 309 } 310 311 func nonleaf(stop chan int) bool { 312 // do something that won't be inlined: 313 select { 314 case <-stop: 315 return true 316 default: 317 return false 318 } 319 } 320 321 func TestSchedLocalQueue(t *testing.T) { 322 runtime.TestSchedLocalQueue1() 323 } 324 325 func TestSchedLocalQueueSteal(t *testing.T) { 326 runtime.TestSchedLocalQueueSteal1() 327 } 328 329 func benchmarkStackGrowth(b *testing.B, rec int) { 330 const CallsPerSched = 1000 331 procs := runtime.GOMAXPROCS(-1) 332 N := int32(b.N / CallsPerSched) 333 c := make(chan bool, procs) 334 for p := 0; p < procs; p++ { 335 go func() { 336 for atomic.AddInt32(&N, -1) >= 0 { 337 runtime.Gosched() 338 for g := 0; g < CallsPerSched; g++ { 339 stackGrowthRecursive(rec) 340 } 341 } 342 c <- true 343 }() 344 } 345 for p := 0; p < procs; p++ { 346 <-c 347 } 348 } 349 350 func BenchmarkStackGrowth(b *testing.B) { 351 benchmarkStackGrowth(b, 10) 352 } 353 354 func BenchmarkStackGrowthDeep(b *testing.B) { 355 benchmarkStackGrowth(b, 1024) 356 } 357 358 func BenchmarkCreateGoroutines(b *testing.B) { 359 benchmarkCreateGoroutines(b, 1) 360 } 361 362 func BenchmarkCreateGoroutinesParallel(b *testing.B) { 363 benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1)) 364 } 365 366 func benchmarkCreateGoroutines(b *testing.B, procs int) { 367 c := make(chan bool) 368 var f func(n int) 369 f = func(n int) { 370 if n == 0 { 371 c <- true 372 return 373 } 374 go f(n - 1) 375 } 376 for i := 0; i < procs; i++ { 377 go f(b.N / procs) 378 } 379 for i := 0; i < procs; i++ { 380 <-c 381 } 382 } 383 384 type Matrix [][]float64 385 386 func BenchmarkMatmult(b *testing.B) { 387 b.StopTimer() 388 // matmult is O(N**3) but testing expects O(b.N), 389 // so we need to take cube root of b.N 390 n := int(math.Cbrt(float64(b.N))) + 1 391 A := makeMatrix(n) 392 B := makeMatrix(n) 393 C := makeMatrix(n) 394 b.StartTimer() 395 matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8) 396 } 397 398 func makeMatrix(n int) Matrix { 399 m := make(Matrix, n) 400 for i := 0; i < n; i++ { 401 m[i] = make([]float64, n) 402 for j := 0; j < n; j++ { 403 m[i][j] = float64(i*n + j) 404 } 405 } 406 return m 407 } 408 409 func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) { 410 di := i1 - i0 411 dj := j1 - j0 412 dk := k1 - k0 413 if di >= dj && di >= dk && di >= threshold { 414 // divide in two by y axis 415 mi := i0 + di/2 416 done1 := make(chan struct{}, 1) 417 go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold) 418 matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold) 419 <-done1 420 } else if dj >= dk && dj >= threshold { 421 // divide in two by x axis 422 mj := j0 + dj/2 423 done1 := make(chan struct{}, 1) 424 go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold) 425 matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold) 426 <-done1 427 } else if dk >= threshold { 428 // divide in two by "k" axis 429 // deliberately not parallel because of data races 430 mk := k0 + dk/2 431 matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold) 432 matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold) 433 } else { 434 // the matrices are small enough, compute directly 435 for i := i0; i < i1; i++ { 436 for j := j0; j < j1; j++ { 437 for k := k0; k < k1; k++ { 438 C[i][j] += A[i][k] * B[k][j] 439 } 440 } 441 } 442 } 443 if done != nil { 444 done <- struct{}{} 445 } 446 }