Rebase.
[official-gcc.git] / libgo / go / runtime / proc_test.go
blob4f364dc4636d52b59eb5be775fa91a48d64d0ab6
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.
5 package runtime_test
7 import (
8 "math"
9 "runtime"
10 "sync/atomic"
11 "syscall"
12 "testing"
13 "time"
16 var stop = make(chan bool, 1)
18 func perpetuumMobile() {
19 select {
20 case <-stop:
21 default:
22 go perpetuumMobile()
26 func TestStopTheWorldDeadlock(t *testing.T) {
27 if testing.Short() {
28 t.Skip("skipping during short test")
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()
36 compl <- true
37 }()
38 go func() {
39 for i := 0; i != 1000; i += 1 {
40 runtime.GOMAXPROCS(3)
42 compl <- true
43 }()
44 go perpetuumMobile()
45 <-compl
46 <-compl
47 stop <- true
48 runtime.GOMAXPROCS(maxprocs)
51 func TestYieldProgress(t *testing.T) {
52 testYieldProgress(t, false)
55 func TestYieldLockedProgress(t *testing.T) {
56 testYieldProgress(t, true)
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()
66 for {
67 select {
68 case <-c:
69 cack <- true
70 return
71 default:
72 runtime.Gosched()
75 }()
76 time.Sleep(10 * time.Millisecond)
77 c <- true
78 <-cack
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)
90 c <- true
91 // runtime.UnlockOSThread() is deliberately omitted
92 }()
93 <-c
96 func TestGoroutineParallelism(t *testing.T) {
97 P := 4
98 N := 10
99 if testing.Short() {
100 P = 3
101 N = 3
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 {
114 atomic.StoreUint32(&x, expected+1)
116 done <- true
117 }(p)
119 for p := 0; p < P; p++ {
120 <-done
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
133 runtime.UnlockOSThread()
135 for i := 0; i < N; i++ {
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
155 timer := time.After(20 * time.Millisecond)
156 for {
157 select {
158 case <-c:
159 case <-timer:
160 close(done)
161 return
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
185 <-done
186 <-done
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
197 return sum
200 func TestPreemption(t *testing.T) {
201 t.Skip("gccgo does not implement preemption")
202 // Test that goroutines are preempted at function calls.
203 N := 5
204 if testing.Short() {
205 N = 2
207 c := make(chan bool)
208 var x uint32
209 for g := 0; g < 2; g++ {
210 go func(g int) {
211 for i := 0; i < N; i++ {
212 for atomic.LoadUint32(&x) != uint32(g) {
213 preempt()
215 atomic.StoreUint32(&x, uint32(1-g))
217 c <- true
218 }(g)
224 func TestPreemptionGC(t *testing.T) {
225 t.Skip("gccgo does not implement preemption")
226 // Test that pending GC preempts running goroutines.
227 P := 5
228 N := 10
229 if testing.Short() {
230 P = 3
231 N = 2
233 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1))
234 var stop uint32
235 for i := 0; i < P; i++ {
236 go func() {
237 for atomic.LoadUint32(&stop) == 0 {
238 preempt()
242 for i := 0; i < N; i++ {
243 runtime.Gosched()
244 runtime.GC()
246 atomic.StoreUint32(&stop, 1)
249 func TestGCFairness(t *testing.T) {
250 output := executeTest(t, testGCFairnessSource, nil)
251 want := "OK\n"
252 if output != want {
253 t.Fatalf("want %s, got %s\n", want, output)
257 const testGCFairnessSource = `
258 package main
260 import (
261 "fmt"
262 "os"
263 "runtime"
264 "time"
267 func main() {
268 runtime.GOMAXPROCS(1)
269 f, err := os.Open("/dev/null")
270 if os.IsNotExist(err) {
271 // This test tests what it is intended to test only if writes are fast.
272 // If there is no /dev/null, we just don't execute the test.
273 fmt.Println("OK")
274 return
276 if err != nil {
277 fmt.Println(err)
278 os.Exit(1)
280 for i := 0; i < 2; i++ {
281 go func() {
282 for {
283 f.Write([]byte("."))
287 time.Sleep(10 * time.Millisecond)
288 fmt.Println("OK")
292 func stackGrowthRecursive(i int) {
293 var pad [128]uint64
294 if i != 0 && pad[0] == 0 {
295 stackGrowthRecursive(i - 1)
299 func TestPreemptSplitBig(t *testing.T) {
300 if testing.Short() {
301 t.Skip("skipping in -short mode")
303 t.Skip("gccgo does not implement preemption")
304 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
305 stop := make(chan int)
306 go big(stop)
307 for i := 0; i < 3; i++ {
308 time.Sleep(10 * time.Microsecond) // let big start running
309 runtime.GC()
311 close(stop)
314 func big(stop chan int) int {
315 n := 0
316 for {
317 // delay so that gc is sure to have asked for a preemption
318 for i := 0; i < 1e9; i++ {
322 // call bigframe, which used to miss the preemption in its prologue.
323 bigframe(stop)
325 // check if we've been asked to stop.
326 select {
327 case <-stop:
328 return n
333 func bigframe(stop chan int) int {
334 // not splitting the stack will overflow.
335 // small will notice that it needs a stack split and will
336 // catch the overflow.
337 var x [8192]byte
338 return small(stop, &x)
341 func small(stop chan int, x *[8192]byte) int {
342 for i := range x {
343 x[i] = byte(i)
345 sum := 0
346 for i := range x {
347 sum += int(x[i])
350 // keep small from being a leaf function, which might
351 // make it not do any stack check at all.
352 nonleaf(stop)
354 return sum
357 func nonleaf(stop chan int) bool {
358 // do something that won't be inlined:
359 select {
360 case <-stop:
361 return true
362 default:
363 return false
367 func TestSchedLocalQueue(t *testing.T) {
368 runtime.TestSchedLocalQueue1()
371 func TestSchedLocalQueueSteal(t *testing.T) {
372 runtime.TestSchedLocalQueueSteal1()
375 func benchmarkStackGrowth(b *testing.B, rec int) {
376 b.RunParallel(func(pb *testing.PB) {
377 for pb.Next() {
378 stackGrowthRecursive(rec)
383 func BenchmarkStackGrowth(b *testing.B) {
384 benchmarkStackGrowth(b, 10)
387 func BenchmarkStackGrowthDeep(b *testing.B) {
388 benchmarkStackGrowth(b, 1024)
391 func BenchmarkCreateGoroutines(b *testing.B) {
392 benchmarkCreateGoroutines(b, 1)
395 func BenchmarkCreateGoroutinesParallel(b *testing.B) {
396 benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
399 func benchmarkCreateGoroutines(b *testing.B, procs int) {
400 c := make(chan bool)
401 var f func(n int)
402 f = func(n int) {
403 if n == 0 {
404 c <- true
405 return
407 go f(n - 1)
409 for i := 0; i < procs; i++ {
410 go f(b.N / procs)
412 for i := 0; i < procs; i++ {
417 type Matrix [][]float64
419 func BenchmarkMatmult(b *testing.B) {
420 b.StopTimer()
421 // matmult is O(N**3) but testing expects O(b.N),
422 // so we need to take cube root of b.N
423 n := int(math.Cbrt(float64(b.N))) + 1
424 A := makeMatrix(n)
425 B := makeMatrix(n)
426 C := makeMatrix(n)
427 b.StartTimer()
428 matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
431 func makeMatrix(n int) Matrix {
432 m := make(Matrix, n)
433 for i := 0; i < n; i++ {
434 m[i] = make([]float64, n)
435 for j := 0; j < n; j++ {
436 m[i][j] = float64(i*n + j)
439 return m
442 func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
443 di := i1 - i0
444 dj := j1 - j0
445 dk := k1 - k0
446 if di >= dj && di >= dk && di >= threshold {
447 // divide in two by y axis
448 mi := i0 + di/2
449 done1 := make(chan struct{}, 1)
450 go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
451 matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
452 <-done1
453 } else if dj >= dk && dj >= threshold {
454 // divide in two by x axis
455 mj := j0 + dj/2
456 done1 := make(chan struct{}, 1)
457 go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
458 matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
459 <-done1
460 } else if dk >= threshold {
461 // divide in two by "k" axis
462 // deliberately not parallel because of data races
463 mk := k0 + dk/2
464 matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
465 matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
466 } else {
467 // the matrices are small enough, compute directly
468 for i := i0; i < i1; i++ {
469 for j := j0; j < j1; j++ {
470 for k := k0; k < k1; k++ {
471 C[i][j] += A[i][k] * B[k][j]
476 if done != nil {
477 done <- struct{}{}