| // Copyright 2011 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package runtime_test | |
| import ( | |
| "runtime" | |
| "sync/atomic" | |
| "testing" | |
| "time" | |
| ) | |
| var stop = make(chan bool, 1) | |
| func perpetuumMobile() { | |
| select { | |
| case <-stop: | |
| default: | |
| go perpetuumMobile() | |
| } | |
| } | |
| func TestStopTheWorldDeadlock(t *testing.T) { | |
| if testing.Short() { | |
| t.Skip("skipping during short test") | |
| } | |
| maxprocs := runtime.GOMAXPROCS(3) | |
| compl := make(chan bool, 2) | |
| go func() { | |
| for i := 0; i != 1000; i += 1 { | |
| runtime.GC() | |
| } | |
| compl <- true | |
| }() | |
| go func() { | |
| for i := 0; i != 1000; i += 1 { | |
| runtime.GOMAXPROCS(3) | |
| } | |
| compl <- true | |
| }() | |
| go perpetuumMobile() | |
| <-compl | |
| <-compl | |
| stop <- true | |
| runtime.GOMAXPROCS(maxprocs) | |
| } | |
| func TestYieldProgress(t *testing.T) { | |
| testYieldProgress(t, false) | |
| } | |
| func TestYieldLockedProgress(t *testing.T) { | |
| testYieldProgress(t, true) | |
| } | |
| func testYieldProgress(t *testing.T, locked bool) { | |
| c := make(chan bool) | |
| cack := make(chan bool) | |
| go func() { | |
| if locked { | |
| runtime.LockOSThread() | |
| } | |
| for { | |
| select { | |
| case <-c: | |
| cack <- true | |
| return | |
| default: | |
| runtime.Gosched() | |
| } | |
| } | |
| }() | |
| time.Sleep(10 * time.Millisecond) | |
| c <- true | |
| <-cack | |
| } | |
| func TestYieldLocked(t *testing.T) { | |
| const N = 10 | |
| c := make(chan bool) | |
| go func() { | |
| runtime.LockOSThread() | |
| for i := 0; i < N; i++ { | |
| runtime.Gosched() | |
| time.Sleep(time.Millisecond) | |
| } | |
| c <- true | |
| // runtime.UnlockOSThread() is deliberately omitted | |
| }() | |
| <-c | |
| } | |
| func TestBlockLocked(t *testing.T) { | |
| const N = 10 | |
| c := make(chan bool) | |
| go func() { | |
| runtime.LockOSThread() | |
| for i := 0; i < N; i++ { | |
| c <- true | |
| } | |
| runtime.UnlockOSThread() | |
| }() | |
| for i := 0; i < N; i++ { | |
| <-c | |
| } | |
| } | |
| func stackGrowthRecursive(i int) { | |
| var pad [128]uint64 | |
| if i != 0 && pad[0] == 0 { | |
| stackGrowthRecursive(i - 1) | |
| } | |
| } | |
| func benchmarkStackGrowth(b *testing.B, rec int) { | |
| const CallsPerSched = 1000 | |
| procs := runtime.GOMAXPROCS(-1) | |
| N := int32(b.N / CallsPerSched) | |
| c := make(chan bool, procs) | |
| for p := 0; p < procs; p++ { | |
| go func() { | |
| for atomic.AddInt32(&N, -1) >= 0 { | |
| runtime.Gosched() | |
| for g := 0; g < CallsPerSched; g++ { | |
| stackGrowthRecursive(rec) | |
| } | |
| } | |
| c <- true | |
| }() | |
| } | |
| for p := 0; p < procs; p++ { | |
| <-c | |
| } | |
| } | |
| func BenchmarkStackGrowth(b *testing.B) { | |
| benchmarkStackGrowth(b, 10) | |
| } | |
| func BenchmarkStackGrowthDeep(b *testing.B) { | |
| benchmarkStackGrowth(b, 1024) | |
| } | |
| func BenchmarkSyscall(b *testing.B) { | |
| const CallsPerSched = 1000 | |
| procs := runtime.GOMAXPROCS(-1) | |
| N := int32(b.N / CallsPerSched) | |
| c := make(chan bool, procs) | |
| for p := 0; p < procs; p++ { | |
| go func() { | |
| for atomic.AddInt32(&N, -1) >= 0 { | |
| runtime.Gosched() | |
| for g := 0; g < CallsPerSched; g++ { | |
| runtime.Entersyscall() | |
| runtime.Exitsyscall() | |
| } | |
| } | |
| c <- true | |
| }() | |
| } | |
| for p := 0; p < procs; p++ { | |
| <-c | |
| } | |
| } | |
| func BenchmarkSyscallWork(b *testing.B) { | |
| const CallsPerSched = 1000 | |
| const LocalWork = 100 | |
| procs := runtime.GOMAXPROCS(-1) | |
| N := int32(b.N / CallsPerSched) | |
| c := make(chan bool, procs) | |
| for p := 0; p < procs; p++ { | |
| go func() { | |
| foo := 42 | |
| for atomic.AddInt32(&N, -1) >= 0 { | |
| runtime.Gosched() | |
| for g := 0; g < CallsPerSched; g++ { | |
| runtime.Entersyscall() | |
| for i := 0; i < LocalWork; i++ { | |
| foo *= 2 | |
| foo /= 2 | |
| } | |
| runtime.Exitsyscall() | |
| } | |
| } | |
| c <- foo == 42 | |
| }() | |
| } | |
| for p := 0; p < procs; p++ { | |
| <-c | |
| } | |
| } | |
| func BenchmarkCreateGoroutines(b *testing.B) { | |
| benchmarkCreateGoroutines(b, 1) | |
| } | |
| func BenchmarkCreateGoroutinesParallel(b *testing.B) { | |
| benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1)) | |
| } | |
| func benchmarkCreateGoroutines(b *testing.B, procs int) { | |
| c := make(chan bool) | |
| var f func(n int) | |
| f = func(n int) { | |
| if n == 0 { | |
| c <- true | |
| return | |
| } | |
| go f(n - 1) | |
| } | |
| for i := 0; i < procs; i++ { | |
| go f(b.N / procs) | |
| } | |
| for i := 0; i < procs; i++ { | |
| <-c | |
| } | |
| } |