...
Run Format

Source file src/runtime/proc_test.go

Documentation: runtime

     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  	"net"
    10  	"runtime"
    11  	"runtime/debug"
    12  	"strings"
    13  	"sync"
    14  	"sync/atomic"
    15  	"syscall"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  var stop = make(chan bool, 1)
    21  
    22  func perpetuumMobile() {
    23  	select {
    24  	case <-stop:
    25  	default:
    26  		go perpetuumMobile()
    27  	}
    28  }
    29  
    30  func TestStopTheWorldDeadlock(t *testing.T) {
    31  	if testing.Short() {
    32  		t.Skip("skipping during short test")
    33  	}
    34  	maxprocs := runtime.GOMAXPROCS(3)
    35  	compl := make(chan bool, 2)
    36  	go func() {
    37  		for i := 0; i != 1000; i += 1 {
    38  			runtime.GC()
    39  		}
    40  		compl <- true
    41  	}()
    42  	go func() {
    43  		for i := 0; i != 1000; i += 1 {
    44  			runtime.GOMAXPROCS(3)
    45  		}
    46  		compl <- true
    47  	}()
    48  	go perpetuumMobile()
    49  	<-compl
    50  	<-compl
    51  	stop <- true
    52  	runtime.GOMAXPROCS(maxprocs)
    53  }
    54  
    55  func TestYieldProgress(t *testing.T) {
    56  	testYieldProgress(false)
    57  }
    58  
    59  func TestYieldLockedProgress(t *testing.T) {
    60  	testYieldProgress(true)
    61  }
    62  
    63  func testYieldProgress(locked bool) {
    64  	c := make(chan bool)
    65  	cack := make(chan bool)
    66  	go func() {
    67  		if locked {
    68  			runtime.LockOSThread()
    69  		}
    70  		for {
    71  			select {
    72  			case <-c:
    73  				cack <- true
    74  				return
    75  			default:
    76  				runtime.Gosched()
    77  			}
    78  		}
    79  	}()
    80  	time.Sleep(10 * time.Millisecond)
    81  	c <- true
    82  	<-cack
    83  }
    84  
    85  func TestYieldLocked(t *testing.T) {
    86  	const N = 10
    87  	c := make(chan bool)
    88  	go func() {
    89  		runtime.LockOSThread()
    90  		for i := 0; i < N; i++ {
    91  			runtime.Gosched()
    92  			time.Sleep(time.Millisecond)
    93  		}
    94  		c <- true
    95  		// runtime.UnlockOSThread() is deliberately omitted
    96  	}()
    97  	<-c
    98  }
    99  
   100  func TestGoroutineParallelism(t *testing.T) {
   101  	if runtime.NumCPU() == 1 {
   102  		// Takes too long, too easy to deadlock, etc.
   103  		t.Skip("skipping on uniprocessor")
   104  	}
   105  	P := 4
   106  	N := 10
   107  	if testing.Short() {
   108  		P = 3
   109  		N = 3
   110  	}
   111  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
   112  	// If runtime triggers a forced GC during this test then it will deadlock,
   113  	// since the goroutines can't be stopped/preempted.
   114  	// Disable GC for this test (see issue #10958).
   115  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   116  	for try := 0; try < N; try++ {
   117  		done := make(chan bool)
   118  		x := uint32(0)
   119  		for p := 0; p < P; p++ {
   120  			// Test that all P goroutines are scheduled at the same time
   121  			go func(p int) {
   122  				for i := 0; i < 3; i++ {
   123  					expected := uint32(P*i + p)
   124  					for atomic.LoadUint32(&x) != expected {
   125  					}
   126  					atomic.StoreUint32(&x, expected+1)
   127  				}
   128  				done <- true
   129  			}(p)
   130  		}
   131  		for p := 0; p < P; p++ {
   132  			<-done
   133  		}
   134  	}
   135  }
   136  
   137  // Test that all runnable goroutines are scheduled at the same time.
   138  func TestGoroutineParallelism2(t *testing.T) {
   139  	//testGoroutineParallelism2(t, false, false)
   140  	testGoroutineParallelism2(t, true, false)
   141  	testGoroutineParallelism2(t, false, true)
   142  	testGoroutineParallelism2(t, true, true)
   143  }
   144  
   145  func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
   146  	if runtime.NumCPU() == 1 {
   147  		// Takes too long, too easy to deadlock, etc.
   148  		t.Skip("skipping on uniprocessor")
   149  	}
   150  	P := 4
   151  	N := 10
   152  	if testing.Short() {
   153  		N = 3
   154  	}
   155  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
   156  	// If runtime triggers a forced GC during this test then it will deadlock,
   157  	// since the goroutines can't be stopped/preempted.
   158  	// Disable GC for this test (see issue #10958).
   159  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   160  	for try := 0; try < N; try++ {
   161  		if load {
   162  			// Create P goroutines and wait until they all run.
   163  			// When we run the actual test below, worker threads
   164  			// running the goroutines will start parking.
   165  			done := make(chan bool)
   166  			x := uint32(0)
   167  			for p := 0; p < P; p++ {
   168  				go func() {
   169  					if atomic.AddUint32(&x, 1) == uint32(P) {
   170  						done <- true
   171  						return
   172  					}
   173  					for atomic.LoadUint32(&x) != uint32(P) {
   174  					}
   175  				}()
   176  			}
   177  			<-done
   178  		}
   179  		if netpoll {
   180  			// Enable netpoller, affects schedler behavior.
   181  			laddr := "localhost:0"
   182  			if runtime.GOOS == "android" {
   183  				// On some Android devices, there are no records for localhost,
   184  				// see https://golang.org/issues/14486.
   185  				// Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
   186  				laddr = "127.0.0.1:0"
   187  			}
   188  			ln, err := net.Listen("tcp", laddr)
   189  			if err != nil {
   190  				defer ln.Close() // yup, defer in a loop
   191  			}
   192  		}
   193  		done := make(chan bool)
   194  		x := uint32(0)
   195  		// Spawn P goroutines in a nested fashion just to differ from TestGoroutineParallelism.
   196  		for p := 0; p < P/2; p++ {
   197  			go func(p int) {
   198  				for p2 := 0; p2 < 2; p2++ {
   199  					go func(p2 int) {
   200  						for i := 0; i < 3; i++ {
   201  							expected := uint32(P*i + p*2 + p2)
   202  							for atomic.LoadUint32(&x) != expected {
   203  							}
   204  							atomic.StoreUint32(&x, expected+1)
   205  						}
   206  						done <- true
   207  					}(p2)
   208  				}
   209  			}(p)
   210  		}
   211  		for p := 0; p < P; p++ {
   212  			<-done
   213  		}
   214  	}
   215  }
   216  
   217  func TestBlockLocked(t *testing.T) {
   218  	const N = 10
   219  	c := make(chan bool)
   220  	go func() {
   221  		runtime.LockOSThread()
   222  		for i := 0; i < N; i++ {
   223  			c <- true
   224  		}
   225  		runtime.UnlockOSThread()
   226  	}()
   227  	for i := 0; i < N; i++ {
   228  		<-c
   229  	}
   230  }
   231  
   232  func TestTimerFairness(t *testing.T) {
   233  	done := make(chan bool)
   234  	c := make(chan bool)
   235  	for i := 0; i < 2; i++ {
   236  		go func() {
   237  			for {
   238  				select {
   239  				case c <- true:
   240  				case <-done:
   241  					return
   242  				}
   243  			}
   244  		}()
   245  	}
   246  
   247  	timer := time.After(20 * time.Millisecond)
   248  	for {
   249  		select {
   250  		case <-c:
   251  		case <-timer:
   252  			close(done)
   253  			return
   254  		}
   255  	}
   256  }
   257  
   258  func TestTimerFairness2(t *testing.T) {
   259  	done := make(chan bool)
   260  	c := make(chan bool)
   261  	for i := 0; i < 2; i++ {
   262  		go func() {
   263  			timer := time.After(20 * time.Millisecond)
   264  			var buf [1]byte
   265  			for {
   266  				syscall.Read(0, buf[0:0])
   267  				select {
   268  				case c <- true:
   269  				case <-c:
   270  				case <-timer:
   271  					done <- true
   272  					return
   273  				}
   274  			}
   275  		}()
   276  	}
   277  	<-done
   278  	<-done
   279  }
   280  
   281  // The function is used to test preemption at split stack checks.
   282  // Declaring a var avoids inlining at the call site.
   283  var preempt = func() int {
   284  	var a [128]int
   285  	sum := 0
   286  	for _, v := range a {
   287  		sum += v
   288  	}
   289  	return sum
   290  }
   291  
   292  func TestPreemption(t *testing.T) {
   293  	// Test that goroutines are preempted at function calls.
   294  	N := 5
   295  	if testing.Short() {
   296  		N = 2
   297  	}
   298  	c := make(chan bool)
   299  	var x uint32
   300  	for g := 0; g < 2; g++ {
   301  		go func(g int) {
   302  			for i := 0; i < N; i++ {
   303  				for atomic.LoadUint32(&x) != uint32(g) {
   304  					preempt()
   305  				}
   306  				atomic.StoreUint32(&x, uint32(1-g))
   307  			}
   308  			c <- true
   309  		}(g)
   310  	}
   311  	<-c
   312  	<-c
   313  }
   314  
   315  func TestPreemptionGC(t *testing.T) {
   316  	// Test that pending GC preempts running goroutines.
   317  	P := 5
   318  	N := 10
   319  	if testing.Short() {
   320  		P = 3
   321  		N = 2
   322  	}
   323  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1))
   324  	var stop uint32
   325  	for i := 0; i < P; i++ {
   326  		go func() {
   327  			for atomic.LoadUint32(&stop) == 0 {
   328  				preempt()
   329  			}
   330  		}()
   331  	}
   332  	for i := 0; i < N; i++ {
   333  		runtime.Gosched()
   334  		runtime.GC()
   335  	}
   336  	atomic.StoreUint32(&stop, 1)
   337  }
   338  
   339  func TestGCFairness(t *testing.T) {
   340  	output := runTestProg(t, "testprog", "GCFairness")
   341  	want := "OK\n"
   342  	if output != want {
   343  		t.Fatalf("want %s, got %s\n", want, output)
   344  	}
   345  }
   346  
   347  func TestGCFairness2(t *testing.T) {
   348  	output := runTestProg(t, "testprog", "GCFairness2")
   349  	want := "OK\n"
   350  	if output != want {
   351  		t.Fatalf("want %s, got %s\n", want, output)
   352  	}
   353  }
   354  
   355  func TestNumGoroutine(t *testing.T) {
   356  	output := runTestProg(t, "testprog", "NumGoroutine")
   357  	want := "1\n"
   358  	if output != want {
   359  		t.Fatalf("want %q, got %q", want, output)
   360  	}
   361  
   362  	buf := make([]byte, 1<<20)
   363  
   364  	// Try up to 10 times for a match before giving up.
   365  	// This is a fundamentally racy check but it's important
   366  	// to notice if NumGoroutine and Stack are _always_ out of sync.
   367  	for i := 0; ; i++ {
   368  		// Give goroutines about to exit a chance to exit.
   369  		// The NumGoroutine and Stack below need to see
   370  		// the same state of the world, so anything we can do
   371  		// to keep it quiet is good.
   372  		runtime.Gosched()
   373  
   374  		n := runtime.NumGoroutine()
   375  		buf = buf[:runtime.Stack(buf, true)]
   376  
   377  		nstk := strings.Count(string(buf), "goroutine ")
   378  		if n == nstk {
   379  			break
   380  		}
   381  		if i >= 10 {
   382  			t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump: %s", n, nstk, buf)
   383  		}
   384  	}
   385  }
   386  
   387  func TestPingPongHog(t *testing.T) {
   388  	if testing.Short() {
   389  		t.Skip("skipping in -short mode")
   390  	}
   391  
   392  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
   393  	done := make(chan bool)
   394  	hogChan, lightChan := make(chan bool), make(chan bool)
   395  	hogCount, lightCount := 0, 0
   396  
   397  	run := func(limit int, counter *int, wake chan bool) {
   398  		for {
   399  			select {
   400  			case <-done:
   401  				return
   402  
   403  			case <-wake:
   404  				for i := 0; i < limit; i++ {
   405  					*counter++
   406  				}
   407  				wake <- true
   408  			}
   409  		}
   410  	}
   411  
   412  	// Start two co-scheduled hog goroutines.
   413  	for i := 0; i < 2; i++ {
   414  		go run(1e6, &hogCount, hogChan)
   415  	}
   416  
   417  	// Start two co-scheduled light goroutines.
   418  	for i := 0; i < 2; i++ {
   419  		go run(1e3, &lightCount, lightChan)
   420  	}
   421  
   422  	// Start goroutine pairs and wait for a few preemption rounds.
   423  	hogChan <- true
   424  	lightChan <- true
   425  	time.Sleep(100 * time.Millisecond)
   426  	close(done)
   427  	<-hogChan
   428  	<-lightChan
   429  
   430  	// Check that hogCount and lightCount are within a factor of
   431  	// 5, which indicates that both pairs of goroutines handed off
   432  	// the P within a time-slice to their buddy. We can use a
   433  	// fairly large factor here to make this robust: if the
   434  	// scheduler isn't working right, the gap should be ~1000X.
   435  	const factor = 5
   436  	if hogCount > lightCount*factor || lightCount > hogCount*factor {
   437  		t.Fatalf("want hogCount/lightCount in [%v, %v]; got %d/%d = %g", 1.0/factor, factor, hogCount, lightCount, float64(hogCount)/float64(lightCount))
   438  	}
   439  }
   440  
   441  func BenchmarkPingPongHog(b *testing.B) {
   442  	if b.N == 0 {
   443  		return
   444  	}
   445  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
   446  
   447  	// Create a CPU hog
   448  	stop, done := make(chan bool), make(chan bool)
   449  	go func() {
   450  		for {
   451  			select {
   452  			case <-stop:
   453  				done <- true
   454  				return
   455  			default:
   456  			}
   457  		}
   458  	}()
   459  
   460  	// Ping-pong b.N times
   461  	ping, pong := make(chan bool), make(chan bool)
   462  	go func() {
   463  		for j := 0; j < b.N; j++ {
   464  			pong <- <-ping
   465  		}
   466  		close(stop)
   467  		done <- true
   468  	}()
   469  	go func() {
   470  		for i := 0; i < b.N; i++ {
   471  			ping <- <-pong
   472  		}
   473  		done <- true
   474  	}()
   475  	b.ResetTimer()
   476  	ping <- true // Start ping-pong
   477  	<-stop
   478  	b.StopTimer()
   479  	<-ping // Let last ponger exit
   480  	<-done // Make sure goroutines exit
   481  	<-done
   482  	<-done
   483  }
   484  
   485  func stackGrowthRecursive(i int) {
   486  	var pad [128]uint64
   487  	if i != 0 && pad[0] == 0 {
   488  		stackGrowthRecursive(i - 1)
   489  	}
   490  }
   491  
   492  func TestPreemptSplitBig(t *testing.T) {
   493  	if testing.Short() {
   494  		t.Skip("skipping in -short mode")
   495  	}
   496  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
   497  	stop := make(chan int)
   498  	go big(stop)
   499  	for i := 0; i < 3; i++ {
   500  		time.Sleep(10 * time.Microsecond) // let big start running
   501  		runtime.GC()
   502  	}
   503  	close(stop)
   504  }
   505  
   506  func big(stop chan int) int {
   507  	n := 0
   508  	for {
   509  		// delay so that gc is sure to have asked for a preemption
   510  		for i := 0; i < 1e9; i++ {
   511  			n++
   512  		}
   513  
   514  		// call bigframe, which used to miss the preemption in its prologue.
   515  		bigframe(stop)
   516  
   517  		// check if we've been asked to stop.
   518  		select {
   519  		case <-stop:
   520  			return n
   521  		}
   522  	}
   523  }
   524  
   525  func bigframe(stop chan int) int {
   526  	// not splitting the stack will overflow.
   527  	// small will notice that it needs a stack split and will
   528  	// catch the overflow.
   529  	var x [8192]byte
   530  	return small(stop, &x)
   531  }
   532  
   533  func small(stop chan int, x *[8192]byte) int {
   534  	for i := range x {
   535  		x[i] = byte(i)
   536  	}
   537  	sum := 0
   538  	for i := range x {
   539  		sum += int(x[i])
   540  	}
   541  
   542  	// keep small from being a leaf function, which might
   543  	// make it not do any stack check at all.
   544  	nonleaf(stop)
   545  
   546  	return sum
   547  }
   548  
   549  func nonleaf(stop chan int) bool {
   550  	// do something that won't be inlined:
   551  	select {
   552  	case <-stop:
   553  		return true
   554  	default:
   555  		return false
   556  	}
   557  }
   558  
   559  func TestSchedLocalQueue(t *testing.T) {
   560  	runtime.RunSchedLocalQueueTest()
   561  }
   562  
   563  func TestSchedLocalQueueSteal(t *testing.T) {
   564  	runtime.RunSchedLocalQueueStealTest()
   565  }
   566  
   567  func TestSchedLocalQueueEmpty(t *testing.T) {
   568  	if runtime.NumCPU() == 1 {
   569  		// Takes too long and does not trigger the race.
   570  		t.Skip("skipping on uniprocessor")
   571  	}
   572  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
   573  
   574  	// If runtime triggers a forced GC during this test then it will deadlock,
   575  	// since the goroutines can't be stopped/preempted during spin wait.
   576  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   577  
   578  	iters := int(1e5)
   579  	if testing.Short() {
   580  		iters = 1e2
   581  	}
   582  	runtime.RunSchedLocalQueueEmptyTest(iters)
   583  }
   584  
   585  func benchmarkStackGrowth(b *testing.B, rec int) {
   586  	b.RunParallel(func(pb *testing.PB) {
   587  		for pb.Next() {
   588  			stackGrowthRecursive(rec)
   589  		}
   590  	})
   591  }
   592  
   593  func BenchmarkStackGrowth(b *testing.B) {
   594  	benchmarkStackGrowth(b, 10)
   595  }
   596  
   597  func BenchmarkStackGrowthDeep(b *testing.B) {
   598  	benchmarkStackGrowth(b, 1024)
   599  }
   600  
   601  func BenchmarkCreateGoroutines(b *testing.B) {
   602  	benchmarkCreateGoroutines(b, 1)
   603  }
   604  
   605  func BenchmarkCreateGoroutinesParallel(b *testing.B) {
   606  	benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
   607  }
   608  
   609  func benchmarkCreateGoroutines(b *testing.B, procs int) {
   610  	c := make(chan bool)
   611  	var f func(n int)
   612  	f = func(n int) {
   613  		if n == 0 {
   614  			c <- true
   615  			return
   616  		}
   617  		go f(n - 1)
   618  	}
   619  	for i := 0; i < procs; i++ {
   620  		go f(b.N / procs)
   621  	}
   622  	for i := 0; i < procs; i++ {
   623  		<-c
   624  	}
   625  }
   626  
   627  func BenchmarkCreateGoroutinesCapture(b *testing.B) {
   628  	b.ReportAllocs()
   629  	for i := 0; i < b.N; i++ {
   630  		const N = 4
   631  		var wg sync.WaitGroup
   632  		wg.Add(N)
   633  		for i := 0; i < N; i++ {
   634  			i := i
   635  			go func() {
   636  				if i >= N {
   637  					b.Logf("bad") // just to capture b
   638  				}
   639  				wg.Done()
   640  			}()
   641  		}
   642  		wg.Wait()
   643  	}
   644  }
   645  
   646  func BenchmarkClosureCall(b *testing.B) {
   647  	sum := 0
   648  	off1 := 1
   649  	for i := 0; i < b.N; i++ {
   650  		off2 := 2
   651  		func() {
   652  			sum += i + off1 + off2
   653  		}()
   654  	}
   655  	_ = sum
   656  }
   657  
   658  func benchmarkWakeupParallel(b *testing.B, spin func(time.Duration)) {
   659  	if runtime.GOMAXPROCS(0) == 1 {
   660  		b.Skip("skipping: GOMAXPROCS=1")
   661  	}
   662  
   663  	wakeDelay := 5 * time.Microsecond
   664  	for _, delay := range []time.Duration{
   665  		0,
   666  		1 * time.Microsecond,
   667  		2 * time.Microsecond,
   668  		5 * time.Microsecond,
   669  		10 * time.Microsecond,
   670  		20 * time.Microsecond,
   671  		50 * time.Microsecond,
   672  		100 * time.Microsecond,
   673  	} {
   674  		b.Run(delay.String(), func(b *testing.B) {
   675  			if b.N == 0 {
   676  				return
   677  			}
   678  			// Start two goroutines, which alternate between being
   679  			// sender and receiver in the following protocol:
   680  			//
   681  			// - The receiver spins for `delay` and then does a
   682  			// blocking receive on a channel.
   683  			//
   684  			// - The sender spins for `delay+wakeDelay` and then
   685  			// sends to the same channel. (The addition of
   686  			// `wakeDelay` improves the probability that the
   687  			// receiver will be blocking when the send occurs when
   688  			// the goroutines execute in parallel.)
   689  			//
   690  			// In each iteration of the benchmark, each goroutine
   691  			// acts once as sender and once as receiver, so each
   692  			// goroutine spins for delay twice.
   693  			//
   694  			// BenchmarkWakeupParallel is used to estimate how
   695  			// efficiently the scheduler parallelizes goroutines in
   696  			// the presence of blocking:
   697  			//
   698  			// - If both goroutines are executed on the same core,
   699  			// an increase in delay by N will increase the time per
   700  			// iteration by 4*N, because all 4 delays are
   701  			// serialized.
   702  			//
   703  			// - Otherwise, an increase in delay by N will increase
   704  			// the time per iteration by 2*N, and the time per
   705  			// iteration is 2 * (runtime overhead + chan
   706  			// send/receive pair + delay + wakeDelay). This allows
   707  			// the runtime overhead, including the time it takes
   708  			// for the unblocked goroutine to be scheduled, to be
   709  			// estimated.
   710  			ping, pong := make(chan struct{}), make(chan struct{})
   711  			start := make(chan struct{})
   712  			done := make(chan struct{})
   713  			go func() {
   714  				<-start
   715  				for i := 0; i < b.N; i++ {
   716  					// sender
   717  					spin(delay + wakeDelay)
   718  					ping <- struct{}{}
   719  					// receiver
   720  					spin(delay)
   721  					<-pong
   722  				}
   723  				done <- struct{}{}
   724  			}()
   725  			go func() {
   726  				for i := 0; i < b.N; i++ {
   727  					// receiver
   728  					spin(delay)
   729  					<-ping
   730  					// sender
   731  					spin(delay + wakeDelay)
   732  					pong <- struct{}{}
   733  				}
   734  				done <- struct{}{}
   735  			}()
   736  			b.ResetTimer()
   737  			start <- struct{}{}
   738  			<-done
   739  			<-done
   740  		})
   741  	}
   742  }
   743  
   744  func BenchmarkWakeupParallelSpinning(b *testing.B) {
   745  	benchmarkWakeupParallel(b, func(d time.Duration) {
   746  		end := time.Now().Add(d)
   747  		for time.Now().Before(end) {
   748  			// do nothing
   749  		}
   750  	})
   751  }
   752  
   753  // sysNanosleep is defined by OS-specific files (such as runtime_linux_test.go)
   754  // to sleep for the given duration. If nil, dependent tests are skipped.
   755  // The implementation should invoke a blocking system call and not
   756  // call time.Sleep, which would deschedule the goroutine.
   757  var sysNanosleep func(d time.Duration)
   758  
   759  func BenchmarkWakeupParallelSyscall(b *testing.B) {
   760  	if sysNanosleep == nil {
   761  		b.Skipf("skipping on %v; sysNanosleep not defined", runtime.GOOS)
   762  	}
   763  	benchmarkWakeupParallel(b, func(d time.Duration) {
   764  		sysNanosleep(d)
   765  	})
   766  }
   767  
   768  type Matrix [][]float64
   769  
   770  func BenchmarkMatmult(b *testing.B) {
   771  	b.StopTimer()
   772  	// matmult is O(N**3) but testing expects O(b.N),
   773  	// so we need to take cube root of b.N
   774  	n := int(math.Cbrt(float64(b.N))) + 1
   775  	A := makeMatrix(n)
   776  	B := makeMatrix(n)
   777  	C := makeMatrix(n)
   778  	b.StartTimer()
   779  	matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
   780  }
   781  
   782  func makeMatrix(n int) Matrix {
   783  	m := make(Matrix, n)
   784  	for i := 0; i < n; i++ {
   785  		m[i] = make([]float64, n)
   786  		for j := 0; j < n; j++ {
   787  			m[i][j] = float64(i*n + j)
   788  		}
   789  	}
   790  	return m
   791  }
   792  
   793  func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
   794  	di := i1 - i0
   795  	dj := j1 - j0
   796  	dk := k1 - k0
   797  	if di >= dj && di >= dk && di >= threshold {
   798  		// divide in two by y axis
   799  		mi := i0 + di/2
   800  		done1 := make(chan struct{}, 1)
   801  		go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
   802  		matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
   803  		<-done1
   804  	} else if dj >= dk && dj >= threshold {
   805  		// divide in two by x axis
   806  		mj := j0 + dj/2
   807  		done1 := make(chan struct{}, 1)
   808  		go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
   809  		matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
   810  		<-done1
   811  	} else if dk >= threshold {
   812  		// divide in two by "k" axis
   813  		// deliberately not parallel because of data races
   814  		mk := k0 + dk/2
   815  		matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
   816  		matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
   817  	} else {
   818  		// the matrices are small enough, compute directly
   819  		for i := i0; i < i1; i++ {
   820  			for j := j0; j < j1; j++ {
   821  				for k := k0; k < k1; k++ {
   822  					C[i][j] += A[i][k] * B[k][j]
   823  				}
   824  			}
   825  		}
   826  	}
   827  	if done != nil {
   828  		done <- struct{}{}
   829  	}
   830  }
   831  
   832  func TestStealOrder(t *testing.T) {
   833  	runtime.RunStealOrderTest()
   834  }
   835  
   836  func TestLockOSThreadNesting(t *testing.T) {
   837  	go func() {
   838  		e, i := runtime.LockOSCounts()
   839  		if e != 0 || i != 0 {
   840  			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
   841  			return
   842  		}
   843  		runtime.LockOSThread()
   844  		runtime.LockOSThread()
   845  		runtime.UnlockOSThread()
   846  		e, i = runtime.LockOSCounts()
   847  		if e != 1 || i != 0 {
   848  			t.Errorf("want locked counts 1, 0; got %d, %d", e, i)
   849  			return
   850  		}
   851  		runtime.UnlockOSThread()
   852  		e, i = runtime.LockOSCounts()
   853  		if e != 0 || i != 0 {
   854  			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
   855  			return
   856  		}
   857  	}()
   858  }
   859  
   860  func TestLockOSThreadExit(t *testing.T) {
   861  	testLockOSThreadExit(t, "testprog")
   862  }
   863  
   864  func testLockOSThreadExit(t *testing.T, prog string) {
   865  	output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1")
   866  	want := "OK\n"
   867  	if output != want {
   868  		t.Errorf("want %s, got %s\n", want, output)
   869  	}
   870  
   871  	output = runTestProg(t, prog, "LockOSThreadAlt")
   872  	if output != want {
   873  		t.Errorf("want %s, got %s\n", want, output)
   874  	}
   875  }
   876  

View as plain text