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  }