github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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  	"testing"
    12  	"time"
    13  )
    14  
    15  var stop = make(chan bool, 1)
    16  
    17  func perpetuumMobile() {
    18  	select {
    19  	case <-stop:
    20  	default:
    21  		go perpetuumMobile()
    22  	}
    23  }
    24  
    25  func TestStopTheWorldDeadlock(t *testing.T) {
    26  	if testing.Short() {
    27  		t.Skip("skipping during short test")
    28  	}
    29  	maxprocs := runtime.GOMAXPROCS(3)
    30  	compl := make(chan bool, 2)
    31  	go func() {
    32  		for i := 0; i != 1000; i += 1 {
    33  			runtime.GC()
    34  		}
    35  		compl <- true
    36  	}()
    37  	go func() {
    38  		for i := 0; i != 1000; i += 1 {
    39  			runtime.GOMAXPROCS(3)
    40  		}
    41  		compl <- true
    42  	}()
    43  	go perpetuumMobile()
    44  	<-compl
    45  	<-compl
    46  	stop <- true
    47  	runtime.GOMAXPROCS(maxprocs)
    48  }
    49  
    50  func TestYieldProgress(t *testing.T) {
    51  	testYieldProgress(t, false)
    52  }
    53  
    54  func TestYieldLockedProgress(t *testing.T) {
    55  	testYieldProgress(t, true)
    56  }
    57  
    58  func testYieldProgress(t *testing.T, locked bool) {
    59  	c := make(chan bool)
    60  	cack := make(chan bool)
    61  	go func() {
    62  		if locked {
    63  			runtime.LockOSThread()
    64  		}
    65  		for {
    66  			select {
    67  			case <-c:
    68  				cack <- true
    69  				return
    70  			default:
    71  				runtime.Gosched()
    72  			}
    73  		}
    74  	}()
    75  	time.Sleep(10 * time.Millisecond)
    76  	c <- true
    77  	<-cack
    78  }
    79  
    80  func TestYieldLocked(t *testing.T) {
    81  	const N = 10
    82  	c := make(chan bool)
    83  	go func() {
    84  		runtime.LockOSThread()
    85  		for i := 0; i < N; i++ {
    86  			runtime.Gosched()
    87  			time.Sleep(time.Millisecond)
    88  		}
    89  		c <- true
    90  		// runtime.UnlockOSThread() is deliberately omitted
    91  	}()
    92  	<-c
    93  }
    94  
    95  func TestBlockLocked(t *testing.T) {
    96  	const N = 10
    97  	c := make(chan bool)
    98  	go func() {
    99  		runtime.LockOSThread()
   100  		for i := 0; i < N; i++ {
   101  			c <- true
   102  		}
   103  		runtime.UnlockOSThread()
   104  	}()
   105  	for i := 0; i < N; i++ {
   106  		<-c
   107  	}
   108  }
   109  
   110  func stackGrowthRecursive(i int) {
   111  	var pad [128]uint64
   112  	if i != 0 && pad[0] == 0 {
   113  		stackGrowthRecursive(i - 1)
   114  	}
   115  }
   116  
   117  func TestSchedLocalQueue(t *testing.T) {
   118  	runtime.TestSchedLocalQueue1()
   119  }
   120  
   121  func TestSchedLocalQueueSteal(t *testing.T) {
   122  	runtime.TestSchedLocalQueueSteal1()
   123  }
   124  
   125  func benchmarkStackGrowth(b *testing.B, rec int) {
   126  	const CallsPerSched = 1000
   127  	procs := runtime.GOMAXPROCS(-1)
   128  	N := int32(b.N / CallsPerSched)
   129  	c := make(chan bool, procs)
   130  	for p := 0; p < procs; p++ {
   131  		go func() {
   132  			for atomic.AddInt32(&N, -1) >= 0 {
   133  				runtime.Gosched()
   134  				for g := 0; g < CallsPerSched; g++ {
   135  					stackGrowthRecursive(rec)
   136  				}
   137  			}
   138  			c <- true
   139  		}()
   140  	}
   141  	for p := 0; p < procs; p++ {
   142  		<-c
   143  	}
   144  }
   145  
   146  func BenchmarkStackGrowth(b *testing.B) {
   147  	benchmarkStackGrowth(b, 10)
   148  }
   149  
   150  func BenchmarkStackGrowthDeep(b *testing.B) {
   151  	benchmarkStackGrowth(b, 1024)
   152  }
   153  
   154  func BenchmarkSyscall(b *testing.B) {
   155  	benchmarkSyscall(b, 0, 1)
   156  }
   157  
   158  func BenchmarkSyscallWork(b *testing.B) {
   159  	benchmarkSyscall(b, 100, 1)
   160  }
   161  
   162  func BenchmarkSyscallExcess(b *testing.B) {
   163  	benchmarkSyscall(b, 0, 4)
   164  }
   165  
   166  func BenchmarkSyscallExcessWork(b *testing.B) {
   167  	benchmarkSyscall(b, 100, 4)
   168  }
   169  
   170  func benchmarkSyscall(b *testing.B, work, excess int) {
   171  	const CallsPerSched = 1000
   172  	procs := runtime.GOMAXPROCS(-1) * excess
   173  	N := int32(b.N / CallsPerSched)
   174  	c := make(chan bool, procs)
   175  	for p := 0; p < procs; p++ {
   176  		go func() {
   177  			foo := 42
   178  			for atomic.AddInt32(&N, -1) >= 0 {
   179  				runtime.Gosched()
   180  				for g := 0; g < CallsPerSched; g++ {
   181  					runtime.Entersyscall()
   182  					for i := 0; i < work; i++ {
   183  						foo *= 2
   184  						foo /= 2
   185  					}
   186  					runtime.Exitsyscall()
   187  				}
   188  			}
   189  			c <- foo == 42
   190  		}()
   191  	}
   192  	for p := 0; p < procs; p++ {
   193  		<-c
   194  	}
   195  }
   196  
   197  func BenchmarkCreateGoroutines(b *testing.B) {
   198  	benchmarkCreateGoroutines(b, 1)
   199  }
   200  
   201  func BenchmarkCreateGoroutinesParallel(b *testing.B) {
   202  	benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
   203  }
   204  
   205  func benchmarkCreateGoroutines(b *testing.B, procs int) {
   206  	c := make(chan bool)
   207  	var f func(n int)
   208  	f = func(n int) {
   209  		if n == 0 {
   210  			c <- true
   211  			return
   212  		}
   213  		go f(n - 1)
   214  	}
   215  	for i := 0; i < procs; i++ {
   216  		go f(b.N / procs)
   217  	}
   218  	for i := 0; i < procs; i++ {
   219  		<-c
   220  	}
   221  }
   222  
   223  type Matrix [][]float64
   224  
   225  func BenchmarkMatmult(b *testing.B) {
   226  	b.StopTimer()
   227  	// matmult is O(N**3) but testing expects O(b.N),
   228  	// so we need to take cube root of b.N
   229  	n := int(math.Cbrt(float64(b.N))) + 1
   230  	A := makeMatrix(n)
   231  	B := makeMatrix(n)
   232  	C := makeMatrix(n)
   233  	b.StartTimer()
   234  	matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
   235  }
   236  
   237  func makeMatrix(n int) Matrix {
   238  	m := make(Matrix, n)
   239  	for i := 0; i < n; i++ {
   240  		m[i] = make([]float64, n)
   241  		for j := 0; j < n; j++ {
   242  			m[i][j] = float64(i*n + j)
   243  		}
   244  	}
   245  	return m
   246  }
   247  
   248  func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
   249  	di := i1 - i0
   250  	dj := j1 - j0
   251  	dk := k1 - k0
   252  	if di >= dj && di >= dk && di >= threshold {
   253  		// divide in two by y axis
   254  		mi := i0 + di/2
   255  		done1 := make(chan struct{}, 1)
   256  		go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
   257  		matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
   258  		<-done1
   259  	} else if dj >= dk && dj >= threshold {
   260  		// divide in two by x axis
   261  		mj := j0 + dj/2
   262  		done1 := make(chan struct{}, 1)
   263  		go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
   264  		matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
   265  		<-done1
   266  	} else if dk >= threshold {
   267  		// divide in two by "k" axis
   268  		// deliberately not parallel because of data races
   269  		mk := k0 + dk/2
   270  		matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
   271  		matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
   272  	} else {
   273  		// the matrices are small enough, compute directly
   274  		for i := i0; i < i1; i++ {
   275  			for j := j0; j < j1; j++ {
   276  				for k := k0; k < k1; k++ {
   277  					C[i][j] += A[i][k] * B[k][j]
   278  				}
   279  			}
   280  		}
   281  	}
   282  	if done != nil {
   283  		done <- struct{}{}
   284  	}
   285  }