github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/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  	"runtime/debug"
    11  	"sync"
    12  	"sync/atomic"
    13  	"syscall"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  var stop = make(chan bool, 1)
    19  
    20  func perpetuumMobile() {
    21  	select {
    22  	case <-stop:
    23  	default:
    24  		go perpetuumMobile()
    25  	}
    26  }
    27  
    28  func TestStopTheWorldDeadlock(t *testing.T) {
    29  	if testing.Short() {
    30  		t.Skip("skipping during short test")
    31  	}
    32  	maxprocs := runtime.GOMAXPROCS(3)
    33  	compl := make(chan bool, 2)
    34  	go func() {
    35  		for i := 0; i != 1000; i += 1 {
    36  			runtime.GC()
    37  		}
    38  		compl <- true
    39  	}()
    40  	go func() {
    41  		for i := 0; i != 1000; i += 1 {
    42  			runtime.GOMAXPROCS(3)
    43  		}
    44  		compl <- true
    45  	}()
    46  	go perpetuumMobile()
    47  	<-compl
    48  	<-compl
    49  	stop <- true
    50  	runtime.GOMAXPROCS(maxprocs)
    51  }
    52  
    53  func TestYieldProgress(t *testing.T) {
    54  	testYieldProgress(t, false)
    55  }
    56  
    57  func TestYieldLockedProgress(t *testing.T) {
    58  	testYieldProgress(t, true)
    59  }
    60  
    61  func testYieldProgress(t *testing.T, locked bool) {
    62  	c := make(chan bool)
    63  	cack := make(chan bool)
    64  	go func() {
    65  		if locked {
    66  			runtime.LockOSThread()
    67  		}
    68  		for {
    69  			select {
    70  			case <-c:
    71  				cack <- true
    72  				return
    73  			default:
    74  				runtime.Gosched()
    75  			}
    76  		}
    77  	}()
    78  	time.Sleep(10 * time.Millisecond)
    79  	c <- true
    80  	<-cack
    81  }
    82  
    83  func TestYieldLocked(t *testing.T) {
    84  	const N = 10
    85  	c := make(chan bool)
    86  	go func() {
    87  		runtime.LockOSThread()
    88  		for i := 0; i < N; i++ {
    89  			runtime.Gosched()
    90  			time.Sleep(time.Millisecond)
    91  		}
    92  		c <- true
    93  		// runtime.UnlockOSThread() is deliberately omitted
    94  	}()
    95  	<-c
    96  }
    97  
    98  func TestGoroutineParallelism(t *testing.T) {
    99  	if runtime.NumCPU() == 1 {
   100  		// Takes too long, too easy to deadlock, etc.
   101  		t.Skip("skipping on uniprocessor")
   102  	}
   103  	P := 4
   104  	N := 10
   105  	if testing.Short() {
   106  		P = 3
   107  		N = 3
   108  	}
   109  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
   110  	// If runtime triggers a forced GC during this test then it will deadlock,
   111  	// since the goroutines can't be stopped/preempted.
   112  	// Disable GC for this test (see issue #10958).
   113  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   114  	for try := 0; try < N; try++ {
   115  		done := make(chan bool)
   116  		x := uint32(0)
   117  		for p := 0; p < P; p++ {
   118  			// Test that all P goroutines are scheduled at the same time
   119  			go func(p int) {
   120  				for i := 0; i < 3; i++ {
   121  					expected := uint32(P*i + p)
   122  					for atomic.LoadUint32(&x) != expected {
   123  					}
   124  					atomic.StoreUint32(&x, expected+1)
   125  				}
   126  				done <- true
   127  			}(p)
   128  		}
   129  		for p := 0; p < P; p++ {
   130  			<-done
   131  		}
   132  	}
   133  }
   134  
   135  func TestBlockLocked(t *testing.T) {
   136  	const N = 10
   137  	c := make(chan bool)
   138  	go func() {
   139  		runtime.LockOSThread()
   140  		for i := 0; i < N; i++ {
   141  			c <- true
   142  		}
   143  		runtime.UnlockOSThread()
   144  	}()
   145  	for i := 0; i < N; i++ {
   146  		<-c
   147  	}
   148  }
   149  
   150  func TestTimerFairness(t *testing.T) {
   151  	done := make(chan bool)
   152  	c := make(chan bool)
   153  	for i := 0; i < 2; i++ {
   154  		go func() {
   155  			for {
   156  				select {
   157  				case c <- true:
   158  				case <-done:
   159  					return
   160  				}
   161  			}
   162  		}()
   163  	}
   164  
   165  	timer := time.After(20 * time.Millisecond)
   166  	for {
   167  		select {
   168  		case <-c:
   169  		case <-timer:
   170  			close(done)
   171  			return
   172  		}
   173  	}
   174  }
   175  
   176  func TestTimerFairness2(t *testing.T) {
   177  	done := make(chan bool)
   178  	c := make(chan bool)
   179  	for i := 0; i < 2; i++ {
   180  		go func() {
   181  			timer := time.After(20 * time.Millisecond)
   182  			var buf [1]byte
   183  			for {
   184  				syscall.Read(0, buf[0:0])
   185  				select {
   186  				case c <- true:
   187  				case <-c:
   188  				case <-timer:
   189  					done <- true
   190  					return
   191  				}
   192  			}
   193  		}()
   194  	}
   195  	<-done
   196  	<-done
   197  }
   198  
   199  // The function is used to test preemption at split stack checks.
   200  // Declaring a var avoids inlining at the call site.
   201  var preempt = func() int {
   202  	var a [128]int
   203  	sum := 0
   204  	for _, v := range a {
   205  		sum += v
   206  	}
   207  	return sum
   208  }
   209  
   210  func TestPreemption(t *testing.T) {
   211  	t.Skip("gccgo does not implement preemption")
   212  	// Test that goroutines are preempted at function calls.
   213  	N := 5
   214  	if testing.Short() {
   215  		N = 2
   216  	}
   217  	c := make(chan bool)
   218  	var x uint32
   219  	for g := 0; g < 2; g++ {
   220  		go func(g int) {
   221  			for i := 0; i < N; i++ {
   222  				for atomic.LoadUint32(&x) != uint32(g) {
   223  					preempt()
   224  				}
   225  				atomic.StoreUint32(&x, uint32(1-g))
   226  			}
   227  			c <- true
   228  		}(g)
   229  	}
   230  	<-c
   231  	<-c
   232  }
   233  
   234  func TestPreemptionGC(t *testing.T) {
   235  	t.Skip("gccgo does not implement preemption")
   236  	// Test that pending GC preempts running goroutines.
   237  	P := 5
   238  	N := 10
   239  	if testing.Short() {
   240  		P = 3
   241  		N = 2
   242  	}
   243  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1))
   244  	var stop uint32
   245  	for i := 0; i < P; i++ {
   246  		go func() {
   247  			for atomic.LoadUint32(&stop) == 0 {
   248  				preempt()
   249  			}
   250  		}()
   251  	}
   252  	for i := 0; i < N; i++ {
   253  		runtime.Gosched()
   254  		runtime.GC()
   255  	}
   256  	atomic.StoreUint32(&stop, 1)
   257  }
   258  
   259  func TestGCFairness(t *testing.T) {
   260  	output := executeTest(t, testGCFairnessSource, nil)
   261  	want := "OK\n"
   262  	if output != want {
   263  		t.Fatalf("want %s, got %s\n", want, output)
   264  	}
   265  }
   266  
   267  const testGCFairnessSource = `
   268  package main
   269  
   270  import (
   271  	"fmt"
   272  	"os"
   273  	"runtime"
   274  	"time"
   275  )
   276  
   277  func main() {
   278  	runtime.GOMAXPROCS(1)
   279  	f, err := os.Open("/dev/null")
   280  	if os.IsNotExist(err) {
   281  		// This test tests what it is intended to test only if writes are fast.
   282  		// If there is no /dev/null, we just don't execute the test.
   283  		fmt.Println("OK")
   284  		return
   285  	}
   286  	if err != nil {
   287  		fmt.Println(err)
   288  		os.Exit(1)
   289  	}
   290  	for i := 0; i < 2; i++ {
   291  		go func() {
   292  			for {
   293  				f.Write([]byte("."))
   294  			}
   295  		}()
   296  	}
   297  	time.Sleep(10 * time.Millisecond)
   298  	fmt.Println("OK")
   299  }
   300  `
   301  
   302  func TestPingPongHog(t *testing.T) {
   303  	if testing.Short() {
   304  		t.Skip("skipping in -short mode")
   305  	}
   306  
   307  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
   308  	done := make(chan bool)
   309  	hogChan, lightChan := make(chan bool), make(chan bool)
   310  	hogCount, lightCount := 0, 0
   311  
   312  	run := func(limit int, counter *int, wake chan bool) {
   313  		for {
   314  			select {
   315  			case <-done:
   316  				return
   317  
   318  			case <-wake:
   319  				for i := 0; i < limit; i++ {
   320  					*counter++
   321  				}
   322  				wake <- true
   323  			}
   324  		}
   325  	}
   326  
   327  	// Start two co-scheduled hog goroutines.
   328  	for i := 0; i < 2; i++ {
   329  		go run(1e6, &hogCount, hogChan)
   330  	}
   331  
   332  	// Start two co-scheduled light goroutines.
   333  	for i := 0; i < 2; i++ {
   334  		go run(1e3, &lightCount, lightChan)
   335  	}
   336  
   337  	// Start goroutine pairs and wait for a few preemption rounds.
   338  	hogChan <- true
   339  	lightChan <- true
   340  	time.Sleep(100 * time.Millisecond)
   341  	close(done)
   342  	<-hogChan
   343  	<-lightChan
   344  
   345  	// Check that hogCount and lightCount are within a factor of
   346  	// 2, which indicates that both pairs of goroutines handed off
   347  	// the P within a time-slice to their buddy.
   348  	if hogCount > lightCount*2 || lightCount > hogCount*2 {
   349  		t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount))
   350  	}
   351  }
   352  
   353  func BenchmarkPingPongHog(b *testing.B) {
   354  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
   355  
   356  	// Create a CPU hog
   357  	stop, done := make(chan bool), make(chan bool)
   358  	go func() {
   359  		for {
   360  			select {
   361  			case <-stop:
   362  				done <- true
   363  				return
   364  			default:
   365  			}
   366  		}
   367  	}()
   368  
   369  	// Ping-pong b.N times
   370  	ping, pong := make(chan bool), make(chan bool)
   371  	go func() {
   372  		for j := 0; j < b.N; j++ {
   373  			pong <- <-ping
   374  		}
   375  		close(stop)
   376  		done <- true
   377  	}()
   378  	go func() {
   379  		for i := 0; i < b.N; i++ {
   380  			ping <- <-pong
   381  		}
   382  		done <- true
   383  	}()
   384  	b.ResetTimer()
   385  	ping <- true // Start ping-pong
   386  	<-stop
   387  	b.StopTimer()
   388  	<-ping // Let last ponger exit
   389  	<-done // Make sure goroutines exit
   390  	<-done
   391  	<-done
   392  }
   393  
   394  func stackGrowthRecursive(i int) {
   395  	var pad [128]uint64
   396  	if i != 0 && pad[0] == 0 {
   397  		stackGrowthRecursive(i - 1)
   398  	}
   399  }
   400  
   401  func TestPreemptSplitBig(t *testing.T) {
   402  	if testing.Short() {
   403  		t.Skip("skipping in -short mode")
   404  	}
   405  	t.Skip("gccgo does not implement preemption")
   406  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
   407  	stop := make(chan int)
   408  	go big(stop)
   409  	for i := 0; i < 3; i++ {
   410  		time.Sleep(10 * time.Microsecond) // let big start running
   411  		runtime.GC()
   412  	}
   413  	close(stop)
   414  }
   415  
   416  func big(stop chan int) int {
   417  	n := 0
   418  	for {
   419  		// delay so that gc is sure to have asked for a preemption
   420  		for i := 0; i < 1e9; i++ {
   421  			n++
   422  		}
   423  
   424  		// call bigframe, which used to miss the preemption in its prologue.
   425  		bigframe(stop)
   426  
   427  		// check if we've been asked to stop.
   428  		select {
   429  		case <-stop:
   430  			return n
   431  		}
   432  	}
   433  }
   434  
   435  func bigframe(stop chan int) int {
   436  	// not splitting the stack will overflow.
   437  	// small will notice that it needs a stack split and will
   438  	// catch the overflow.
   439  	var x [8192]byte
   440  	return small(stop, &x)
   441  }
   442  
   443  func small(stop chan int, x *[8192]byte) int {
   444  	for i := range x {
   445  		x[i] = byte(i)
   446  	}
   447  	sum := 0
   448  	for i := range x {
   449  		sum += int(x[i])
   450  	}
   451  
   452  	// keep small from being a leaf function, which might
   453  	// make it not do any stack check at all.
   454  	nonleaf(stop)
   455  
   456  	return sum
   457  }
   458  
   459  func nonleaf(stop chan int) bool {
   460  	// do something that won't be inlined:
   461  	select {
   462  	case <-stop:
   463  		return true
   464  	default:
   465  		return false
   466  	}
   467  }
   468  
   469  /*
   470  func TestSchedLocalQueue(t *testing.T) {
   471  	runtime.TestSchedLocalQueue1()
   472  }
   473  */
   474  
   475  /*
   476  func TestSchedLocalQueueSteal(t *testing.T) {
   477  	runtime.TestSchedLocalQueueSteal1()
   478  }
   479  */
   480  
   481  func benchmarkStackGrowth(b *testing.B, rec int) {
   482  	b.RunParallel(func(pb *testing.PB) {
   483  		for pb.Next() {
   484  			stackGrowthRecursive(rec)
   485  		}
   486  	})
   487  }
   488  
   489  func BenchmarkStackGrowth(b *testing.B) {
   490  	benchmarkStackGrowth(b, 10)
   491  }
   492  
   493  func BenchmarkStackGrowthDeep(b *testing.B) {
   494  	benchmarkStackGrowth(b, 1024)
   495  }
   496  
   497  func BenchmarkCreateGoroutines(b *testing.B) {
   498  	benchmarkCreateGoroutines(b, 1)
   499  }
   500  
   501  func BenchmarkCreateGoroutinesParallel(b *testing.B) {
   502  	benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
   503  }
   504  
   505  func benchmarkCreateGoroutines(b *testing.B, procs int) {
   506  	c := make(chan bool)
   507  	var f func(n int)
   508  	f = func(n int) {
   509  		if n == 0 {
   510  			c <- true
   511  			return
   512  		}
   513  		go f(n - 1)
   514  	}
   515  	for i := 0; i < procs; i++ {
   516  		go f(b.N / procs)
   517  	}
   518  	for i := 0; i < procs; i++ {
   519  		<-c
   520  	}
   521  }
   522  
   523  func BenchmarkCreateGoroutinesCapture(b *testing.B) {
   524  	b.ReportAllocs()
   525  	for i := 0; i < b.N; i++ {
   526  		const N = 4
   527  		var wg sync.WaitGroup
   528  		wg.Add(N)
   529  		for i := 0; i < N; i++ {
   530  			i := i
   531  			go func() {
   532  				if i >= N {
   533  					b.Logf("bad") // just to capture b
   534  				}
   535  				wg.Done()
   536  			}()
   537  		}
   538  		wg.Wait()
   539  	}
   540  }
   541  
   542  func BenchmarkClosureCall(b *testing.B) {
   543  	sum := 0
   544  	off1 := 1
   545  	for i := 0; i < b.N; i++ {
   546  		off2 := 2
   547  		func() {
   548  			sum += i + off1 + off2
   549  		}()
   550  	}
   551  	_ = sum
   552  }
   553  
   554  type Matrix [][]float64
   555  
   556  func BenchmarkMatmult(b *testing.B) {
   557  	b.StopTimer()
   558  	// matmult is O(N**3) but testing expects O(b.N),
   559  	// so we need to take cube root of b.N
   560  	n := int(math.Cbrt(float64(b.N))) + 1
   561  	A := makeMatrix(n)
   562  	B := makeMatrix(n)
   563  	C := makeMatrix(n)
   564  	b.StartTimer()
   565  	matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
   566  }
   567  
   568  func makeMatrix(n int) Matrix {
   569  	m := make(Matrix, n)
   570  	for i := 0; i < n; i++ {
   571  		m[i] = make([]float64, n)
   572  		for j := 0; j < n; j++ {
   573  			m[i][j] = float64(i*n + j)
   574  		}
   575  	}
   576  	return m
   577  }
   578  
   579  func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
   580  	di := i1 - i0
   581  	dj := j1 - j0
   582  	dk := k1 - k0
   583  	if di >= dj && di >= dk && di >= threshold {
   584  		// divide in two by y axis
   585  		mi := i0 + di/2
   586  		done1 := make(chan struct{}, 1)
   587  		go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
   588  		matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
   589  		<-done1
   590  	} else if dj >= dk && dj >= threshold {
   591  		// divide in two by x axis
   592  		mj := j0 + dj/2
   593  		done1 := make(chan struct{}, 1)
   594  		go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
   595  		matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
   596  		<-done1
   597  	} else if dk >= threshold {
   598  		// divide in two by "k" axis
   599  		// deliberately not parallel because of data races
   600  		mk := k0 + dk/2
   601  		matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
   602  		matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
   603  	} else {
   604  		// the matrices are small enough, compute directly
   605  		for i := i0; i < i1; i++ {
   606  			for j := j0; j < j1; j++ {
   607  				for k := k0; k < k1; k++ {
   608  					C[i][j] += A[i][k] * B[k][j]
   609  				}
   610  			}
   611  		}
   612  	}
   613  	if done != nil {
   614  		done <- struct{}{}
   615  	}
   616  }