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  }