Source file src/runtime/proc_test.go

     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  	"bytes"
     9  	"fmt"
    10  	"internal/race"
    11  	"internal/testenv"
    12  	"internal/trace"
    13  	"internal/trace/testtrace"
    14  	"io"
    15  	"math"
    16  	"net"
    17  	"runtime"
    18  	"runtime/debug"
    19  	"slices"
    20  	"strings"
    21  	"sync"
    22  	"sync/atomic"
    23  	"syscall"
    24  	"testing"
    25  	"time"
    26  )
    27  
    28  var stop = make(chan bool, 1)
    29  
    30  func perpetuumMobile() {
    31  	select {
    32  	case <-stop:
    33  	default:
    34  		go perpetuumMobile()
    35  	}
    36  }
    37  
    38  func TestStopTheWorldDeadlock(t *testing.T) {
    39  	if runtime.GOARCH == "wasm" {
    40  		t.Skip("no preemption on wasm yet")
    41  	}
    42  	if testing.Short() {
    43  		t.Skip("skipping during short test")
    44  	}
    45  	maxprocs := runtime.GOMAXPROCS(3)
    46  	compl := make(chan bool, 2)
    47  	go func() {
    48  		for i := 0; i != 1000; i += 1 {
    49  			runtime.GC()
    50  		}
    51  		compl <- true
    52  	}()
    53  	go func() {
    54  		for i := 0; i != 1000; i += 1 {
    55  			runtime.GOMAXPROCS(3)
    56  		}
    57  		compl <- true
    58  	}()
    59  	go perpetuumMobile()
    60  	<-compl
    61  	<-compl
    62  	stop <- true
    63  	runtime.GOMAXPROCS(maxprocs)
    64  }
    65  
    66  func TestYieldProgress(t *testing.T) {
    67  	testYieldProgress(false)
    68  }
    69  
    70  func TestYieldLockedProgress(t *testing.T) {
    71  	testYieldProgress(true)
    72  }
    73  
    74  func testYieldProgress(locked bool) {
    75  	c := make(chan bool)
    76  	cack := make(chan bool)
    77  	go func() {
    78  		if locked {
    79  			runtime.LockOSThread()
    80  		}
    81  		for {
    82  			select {
    83  			case <-c:
    84  				cack <- true
    85  				return
    86  			default:
    87  				runtime.Gosched()
    88  			}
    89  		}
    90  	}()
    91  	time.Sleep(10 * time.Millisecond)
    92  	c <- true
    93  	<-cack
    94  }
    95  
    96  func TestYieldLocked(t *testing.T) {
    97  	const N = 10
    98  	c := make(chan bool)
    99  	go func() {
   100  		runtime.LockOSThread()
   101  		for i := 0; i < N; i++ {
   102  			runtime.Gosched()
   103  			time.Sleep(time.Millisecond)
   104  		}
   105  		c <- true
   106  		// runtime.UnlockOSThread() is deliberately omitted
   107  	}()
   108  	<-c
   109  }
   110  
   111  func TestGoroutineParallelism(t *testing.T) {
   112  	if runtime.NumCPU() == 1 {
   113  		// Takes too long, too easy to deadlock, etc.
   114  		t.Skip("skipping on uniprocessor")
   115  	}
   116  	P := 4
   117  	N := 10
   118  	if testing.Short() {
   119  		P = 3
   120  		N = 3
   121  	}
   122  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
   123  	// If runtime triggers a forced GC during this test then it will deadlock,
   124  	// since the goroutines can't be stopped/preempted.
   125  	// Disable GC for this test (see issue #10958).
   126  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   127  	// SetGCPercent waits until the mark phase is over, but the runtime
   128  	// also preempts at the start of the sweep phase, so make sure that's
   129  	// done too. See #45867.
   130  	runtime.GC()
   131  	for try := 0; try < N; try++ {
   132  		done := make(chan bool)
   133  		x := uint32(0)
   134  		for p := 0; p < P; p++ {
   135  			// Test that all P goroutines are scheduled at the same time
   136  			go func(p int) {
   137  				for i := 0; i < 3; i++ {
   138  					expected := uint32(P*i + p)
   139  					for atomic.LoadUint32(&x) != expected {
   140  					}
   141  					atomic.StoreUint32(&x, expected+1)
   142  				}
   143  				done <- true
   144  			}(p)
   145  		}
   146  		for p := 0; p < P; p++ {
   147  			<-done
   148  		}
   149  	}
   150  }
   151  
   152  // Test that all runnable goroutines are scheduled at the same time.
   153  func TestGoroutineParallelism2(t *testing.T) {
   154  	//testGoroutineParallelism2(t, false, false)
   155  	testGoroutineParallelism2(t, true, false)
   156  	testGoroutineParallelism2(t, false, true)
   157  	testGoroutineParallelism2(t, true, true)
   158  }
   159  
   160  func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
   161  	if runtime.NumCPU() == 1 {
   162  		// Takes too long, too easy to deadlock, etc.
   163  		t.Skip("skipping on uniprocessor")
   164  	}
   165  	P := 4
   166  	N := 10
   167  	if testing.Short() {
   168  		N = 3
   169  	}
   170  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
   171  	// If runtime triggers a forced GC during this test then it will deadlock,
   172  	// since the goroutines can't be stopped/preempted.
   173  	// Disable GC for this test (see issue #10958).
   174  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   175  	// SetGCPercent waits until the mark phase is over, but the runtime
   176  	// also preempts at the start of the sweep phase, so make sure that's
   177  	// done too. See #45867.
   178  	runtime.GC()
   179  	for try := 0; try < N; try++ {
   180  		if load {
   181  			// Create P goroutines and wait until they all run.
   182  			// When we run the actual test below, worker threads
   183  			// running the goroutines will start parking.
   184  			done := make(chan bool)
   185  			x := uint32(0)
   186  			for p := 0; p < P; p++ {
   187  				go func() {
   188  					if atomic.AddUint32(&x, 1) == uint32(P) {
   189  						done <- true
   190  						return
   191  					}
   192  					for atomic.LoadUint32(&x) != uint32(P) {
   193  					}
   194  				}()
   195  			}
   196  			<-done
   197  		}
   198  		if netpoll {
   199  			// Enable netpoller, affects schedler behavior.
   200  			laddr := "localhost:0"
   201  			if runtime.GOOS == "android" {
   202  				// On some Android devices, there are no records for localhost,
   203  				// see https://golang.org/issues/14486.
   204  				// Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
   205  				laddr = "127.0.0.1:0"
   206  			}
   207  			ln, err := net.Listen("tcp", laddr)
   208  			if err == nil {
   209  				defer ln.Close() // yup, defer in a loop
   210  			}
   211  		}
   212  		done := make(chan bool)
   213  		x := uint32(0)
   214  		// Spawn P goroutines in a nested fashion just to differ from TestGoroutineParallelism.
   215  		for p := 0; p < P/2; p++ {
   216  			go func(p int) {
   217  				for p2 := 0; p2 < 2; p2++ {
   218  					go func(p2 int) {
   219  						for i := 0; i < 3; i++ {
   220  							expected := uint32(P*i + p*2 + p2)
   221  							for atomic.LoadUint32(&x) != expected {
   222  							}
   223  							atomic.StoreUint32(&x, expected+1)
   224  						}
   225  						done <- true
   226  					}(p2)
   227  				}
   228  			}(p)
   229  		}
   230  		for p := 0; p < P; p++ {
   231  			<-done
   232  		}
   233  	}
   234  }
   235  
   236  func TestBlockLocked(t *testing.T) {
   237  	const N = 10
   238  	c := make(chan bool)
   239  	go func() {
   240  		runtime.LockOSThread()
   241  		for i := 0; i < N; i++ {
   242  			c <- true
   243  		}
   244  		runtime.UnlockOSThread()
   245  	}()
   246  	for i := 0; i < N; i++ {
   247  		<-c
   248  	}
   249  }
   250  
   251  func TestTimerFairness(t *testing.T) {
   252  	if runtime.GOARCH == "wasm" {
   253  		t.Skip("no preemption on wasm yet")
   254  	}
   255  
   256  	done := make(chan bool)
   257  	c := make(chan bool)
   258  	for i := 0; i < 2; i++ {
   259  		go func() {
   260  			for {
   261  				select {
   262  				case c <- true:
   263  				case <-done:
   264  					return
   265  				}
   266  			}
   267  		}()
   268  	}
   269  
   270  	timer := time.After(20 * time.Millisecond)
   271  	for {
   272  		select {
   273  		case <-c:
   274  		case <-timer:
   275  			close(done)
   276  			return
   277  		}
   278  	}
   279  }
   280  
   281  func TestTimerFairness2(t *testing.T) {
   282  	if runtime.GOARCH == "wasm" {
   283  		t.Skip("no preemption on wasm yet")
   284  	}
   285  
   286  	done := make(chan bool)
   287  	c := make(chan bool)
   288  	for i := 0; i < 2; i++ {
   289  		go func() {
   290  			timer := time.After(20 * time.Millisecond)
   291  			var buf [1]byte
   292  			for {
   293  				syscall.Read(0, buf[0:0])
   294  				select {
   295  				case c <- true:
   296  				case <-c:
   297  				case <-timer:
   298  					done <- true
   299  					return
   300  				}
   301  			}
   302  		}()
   303  	}
   304  	<-done
   305  	<-done
   306  }
   307  
   308  // The function is used to test preemption at split stack checks.
   309  // Declaring a var avoids inlining at the call site.
   310  var preempt = func() int {
   311  	var a [128]int
   312  	sum := 0
   313  	for _, v := range a {
   314  		sum += v
   315  	}
   316  	return sum
   317  }
   318  
   319  func TestPreemption(t *testing.T) {
   320  	if runtime.GOARCH == "wasm" {
   321  		t.Skip("no preemption on wasm yet")
   322  	}
   323  
   324  	// Test that goroutines are preempted at function calls.
   325  	N := 5
   326  	if testing.Short() {
   327  		N = 2
   328  	}
   329  	c := make(chan bool)
   330  	var x uint32
   331  	for g := 0; g < 2; g++ {
   332  		go func(g int) {
   333  			for i := 0; i < N; i++ {
   334  				for atomic.LoadUint32(&x) != uint32(g) {
   335  					preempt()
   336  				}
   337  				atomic.StoreUint32(&x, uint32(1-g))
   338  			}
   339  			c <- true
   340  		}(g)
   341  	}
   342  	<-c
   343  	<-c
   344  }
   345  
   346  func TestPreemptionGC(t *testing.T) {
   347  	if runtime.GOARCH == "wasm" {
   348  		t.Skip("no preemption on wasm yet")
   349  	}
   350  
   351  	// Test that pending GC preempts running goroutines.
   352  	P := 5
   353  	N := 10
   354  	if testing.Short() {
   355  		P = 3
   356  		N = 2
   357  	}
   358  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1))
   359  	var stop uint32
   360  	for i := 0; i < P; i++ {
   361  		go func() {
   362  			for atomic.LoadUint32(&stop) == 0 {
   363  				preempt()
   364  			}
   365  		}()
   366  	}
   367  	for i := 0; i < N; i++ {
   368  		runtime.Gosched()
   369  		runtime.GC()
   370  	}
   371  	atomic.StoreUint32(&stop, 1)
   372  }
   373  
   374  func TestAsyncPreempt(t *testing.T) {
   375  	if !runtime.PreemptMSupported {
   376  		t.Skip("asynchronous preemption not supported on this platform")
   377  	}
   378  	output := runTestProg(t, "testprog", "AsyncPreempt")
   379  	want := "OK\n"
   380  	if output != want {
   381  		t.Fatalf("want %s, got %s\n", want, output)
   382  	}
   383  }
   384  
   385  func TestGCFairness(t *testing.T) {
   386  	output := runTestProg(t, "testprog", "GCFairness")
   387  	want := "OK\n"
   388  	if output != want {
   389  		t.Fatalf("want %s, got %s\n", want, output)
   390  	}
   391  }
   392  
   393  func TestGCFairness2(t *testing.T) {
   394  	output := runTestProg(t, "testprog", "GCFairness2")
   395  	want := "OK\n"
   396  	if output != want {
   397  		t.Fatalf("want %s, got %s\n", want, output)
   398  	}
   399  }
   400  
   401  func TestNumGoroutine(t *testing.T) {
   402  	output := runTestProg(t, "testprog", "NumGoroutine")
   403  	want := "1\n"
   404  	if output != want {
   405  		t.Fatalf("want %q, got %q", want, output)
   406  	}
   407  
   408  	buf := make([]byte, 1<<20)
   409  
   410  	// Try up to 10 times for a match before giving up.
   411  	// This is a fundamentally racy check but it's important
   412  	// to notice if NumGoroutine and Stack are _always_ out of sync.
   413  	for i := 0; ; i++ {
   414  		// Give goroutines about to exit a chance to exit.
   415  		// The NumGoroutine and Stack below need to see
   416  		// the same state of the world, so anything we can do
   417  		// to keep it quiet is good.
   418  		runtime.Gosched()
   419  
   420  		n := runtime.NumGoroutine()
   421  		buf = buf[:runtime.Stack(buf, true)]
   422  
   423  		// To avoid double-counting "goroutine" in "goroutine $m [running]:"
   424  		// and "created by $func in goroutine $n", remove the latter
   425  		output := strings.ReplaceAll(string(buf), "in goroutine", "")
   426  		nstk := strings.Count(output, "goroutine ")
   427  		if n == nstk {
   428  			break
   429  		}
   430  		if i >= 10 {
   431  			t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump: %s", n, nstk, buf)
   432  		}
   433  	}
   434  }
   435  
   436  func TestPingPongHog(t *testing.T) {
   437  	if runtime.GOARCH == "wasm" {
   438  		t.Skip("no preemption on wasm yet")
   439  	}
   440  	if testing.Short() {
   441  		t.Skip("skipping in -short mode")
   442  	}
   443  	if race.Enabled {
   444  		// The race detector randomizes the scheduler,
   445  		// which causes this test to fail (#38266).
   446  		t.Skip("skipping in -race mode")
   447  	}
   448  
   449  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
   450  	done := make(chan bool)
   451  	hogChan, lightChan := make(chan bool), make(chan bool)
   452  	hogCount, lightCount := 0, 0
   453  
   454  	run := func(limit int, counter *int, wake chan bool) {
   455  		for {
   456  			select {
   457  			case <-done:
   458  				return
   459  
   460  			case <-wake:
   461  				for i := 0; i < limit; i++ {
   462  					*counter++
   463  				}
   464  				wake <- true
   465  			}
   466  		}
   467  	}
   468  
   469  	// Start two co-scheduled hog goroutines.
   470  	for i := 0; i < 2; i++ {
   471  		go run(1e6, &hogCount, hogChan)
   472  	}
   473  
   474  	// Start two co-scheduled light goroutines.
   475  	for i := 0; i < 2; i++ {
   476  		go run(1e3, &lightCount, lightChan)
   477  	}
   478  
   479  	// Start goroutine pairs and wait for a few preemption rounds.
   480  	hogChan <- true
   481  	lightChan <- true
   482  	time.Sleep(100 * time.Millisecond)
   483  	close(done)
   484  	<-hogChan
   485  	<-lightChan
   486  
   487  	// Check that hogCount and lightCount are within a factor of
   488  	// 20, which indicates that both pairs of goroutines handed off
   489  	// the P within a time-slice to their buddy. We can use a
   490  	// fairly large factor here to make this robust: if the
   491  	// scheduler isn't working right, the gap should be ~1000X
   492  	// (was 5, increased to 20, see issue 52207).
   493  	const factor = 20
   494  	if hogCount/factor > lightCount || lightCount/factor > hogCount {
   495  		t.Fatalf("want hogCount/lightCount in [%v, %v]; got %d/%d = %g", 1.0/factor, factor, hogCount, lightCount, float64(hogCount)/float64(lightCount))
   496  	}
   497  }
   498  
   499  func BenchmarkPingPongHog(b *testing.B) {
   500  	if b.N == 0 {
   501  		return
   502  	}
   503  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
   504  
   505  	// Create a CPU hog
   506  	stop, done := make(chan bool), make(chan bool)
   507  	go func() {
   508  		for {
   509  			select {
   510  			case <-stop:
   511  				done <- true
   512  				return
   513  			default:
   514  			}
   515  		}
   516  	}()
   517  
   518  	// Ping-pong b.N times
   519  	ping, pong := make(chan bool), make(chan bool)
   520  	go func() {
   521  		for j := 0; j < b.N; j++ {
   522  			pong <- <-ping
   523  		}
   524  		close(stop)
   525  		done <- true
   526  	}()
   527  	go func() {
   528  		for i := 0; i < b.N; i++ {
   529  			ping <- <-pong
   530  		}
   531  		done <- true
   532  	}()
   533  	b.ResetTimer()
   534  	ping <- true // Start ping-pong
   535  	<-stop
   536  	b.StopTimer()
   537  	<-ping // Let last ponger exit
   538  	<-done // Make sure goroutines exit
   539  	<-done
   540  	<-done
   541  }
   542  
   543  var padData [128]uint64
   544  
   545  func stackGrowthRecursive(i int) {
   546  	var pad [128]uint64
   547  	pad = padData
   548  	for j := range pad {
   549  		if pad[j] != 0 {
   550  			return
   551  		}
   552  	}
   553  	if i != 0 {
   554  		stackGrowthRecursive(i - 1)
   555  	}
   556  }
   557  
   558  func TestPreemptSplitBig(t *testing.T) {
   559  	if testing.Short() {
   560  		t.Skip("skipping in -short mode")
   561  	}
   562  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
   563  	stop := make(chan int)
   564  	go big(stop)
   565  	for i := 0; i < 3; i++ {
   566  		time.Sleep(10 * time.Microsecond) // let big start running
   567  		runtime.GC()
   568  	}
   569  	close(stop)
   570  }
   571  
   572  func big(stop chan int) int {
   573  	n := 0
   574  	for {
   575  		// delay so that gc is sure to have asked for a preemption
   576  		for i := 0; i < 1e9; i++ {
   577  			n++
   578  		}
   579  
   580  		// call bigframe, which used to miss the preemption in its prologue.
   581  		bigframe(stop)
   582  
   583  		// check if we've been asked to stop.
   584  		select {
   585  		case <-stop:
   586  			return n
   587  		}
   588  	}
   589  }
   590  
   591  func bigframe(stop chan int) int {
   592  	// not splitting the stack will overflow.
   593  	// small will notice that it needs a stack split and will
   594  	// catch the overflow.
   595  	var x [8192]byte
   596  	return small(stop, &x)
   597  }
   598  
   599  func small(stop chan int, x *[8192]byte) int {
   600  	for i := range x {
   601  		x[i] = byte(i)
   602  	}
   603  	sum := 0
   604  	for i := range x {
   605  		sum += int(x[i])
   606  	}
   607  
   608  	// keep small from being a leaf function, which might
   609  	// make it not do any stack check at all.
   610  	nonleaf(stop)
   611  
   612  	return sum
   613  }
   614  
   615  func nonleaf(stop chan int) bool {
   616  	// do something that won't be inlined:
   617  	select {
   618  	case <-stop:
   619  		return true
   620  	default:
   621  		return false
   622  	}
   623  }
   624  
   625  func TestSchedLocalQueue(t *testing.T) {
   626  	runtime.RunSchedLocalQueueTest()
   627  }
   628  
   629  func TestSchedLocalQueueSteal(t *testing.T) {
   630  	runtime.RunSchedLocalQueueStealTest()
   631  }
   632  
   633  func TestSchedLocalQueueEmpty(t *testing.T) {
   634  	if runtime.NumCPU() == 1 {
   635  		// Takes too long and does not trigger the race.
   636  		t.Skip("skipping on uniprocessor")
   637  	}
   638  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
   639  
   640  	// If runtime triggers a forced GC during this test then it will deadlock,
   641  	// since the goroutines can't be stopped/preempted during spin wait.
   642  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   643  	// SetGCPercent waits until the mark phase is over, but the runtime
   644  	// also preempts at the start of the sweep phase, so make sure that's
   645  	// done too. See #45867.
   646  	runtime.GC()
   647  
   648  	iters := int(1e5)
   649  	if testing.Short() {
   650  		iters = 1e2
   651  	}
   652  	runtime.RunSchedLocalQueueEmptyTest(iters)
   653  }
   654  
   655  func benchmarkStackGrowth(b *testing.B, rec int) {
   656  	b.RunParallel(func(pb *testing.PB) {
   657  		for pb.Next() {
   658  			stackGrowthRecursive(rec)
   659  		}
   660  	})
   661  }
   662  
   663  func BenchmarkStackGrowth(b *testing.B) {
   664  	benchmarkStackGrowth(b, 10)
   665  }
   666  
   667  func BenchmarkStackGrowthDeep(b *testing.B) {
   668  	benchmarkStackGrowth(b, 1024)
   669  }
   670  
   671  func BenchmarkCreateGoroutines(b *testing.B) {
   672  	benchmarkCreateGoroutines(b, 1)
   673  }
   674  
   675  func BenchmarkCreateGoroutinesParallel(b *testing.B) {
   676  	benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
   677  }
   678  
   679  func benchmarkCreateGoroutines(b *testing.B, procs int) {
   680  	c := make(chan bool)
   681  	var f func(n int)
   682  	f = func(n int) {
   683  		if n == 0 {
   684  			c <- true
   685  			return
   686  		}
   687  		go f(n - 1)
   688  	}
   689  	for i := 0; i < procs; i++ {
   690  		go f(b.N / procs)
   691  	}
   692  	for i := 0; i < procs; i++ {
   693  		<-c
   694  	}
   695  }
   696  
   697  func BenchmarkCreateGoroutinesCapture(b *testing.B) {
   698  	b.ReportAllocs()
   699  	for i := 0; i < b.N; i++ {
   700  		const N = 4
   701  		var wg sync.WaitGroup
   702  		wg.Add(N)
   703  		for i := 0; i < N; i++ {
   704  			go func() {
   705  				if i >= N {
   706  					b.Logf("bad") // just to capture b
   707  				}
   708  				wg.Done()
   709  			}()
   710  		}
   711  		wg.Wait()
   712  	}
   713  }
   714  
   715  // warmupScheduler ensures the scheduler has at least targetThreadCount threads
   716  // in its thread pool.
   717  func warmupScheduler(targetThreadCount int) {
   718  	var wg sync.WaitGroup
   719  	var count int32
   720  	for i := 0; i < targetThreadCount; i++ {
   721  		wg.Add(1)
   722  		go func() {
   723  			atomic.AddInt32(&count, 1)
   724  			for atomic.LoadInt32(&count) < int32(targetThreadCount) {
   725  				// spin until all threads started
   726  			}
   727  
   728  			// spin a bit more to ensure they are all running on separate CPUs.
   729  			doWork(time.Millisecond)
   730  			wg.Done()
   731  		}()
   732  	}
   733  	wg.Wait()
   734  }
   735  
   736  func doWork(dur time.Duration) {
   737  	start := time.Now()
   738  	for time.Since(start) < dur {
   739  	}
   740  }
   741  
   742  // BenchmarkCreateGoroutinesSingle creates many goroutines, all from a single
   743  // producer (the main benchmark goroutine).
   744  //
   745  // Compared to BenchmarkCreateGoroutines, this causes different behavior in the
   746  // scheduler because Ms are much more likely to need to steal work from the
   747  // main P rather than having work in the local run queue.
   748  func BenchmarkCreateGoroutinesSingle(b *testing.B) {
   749  	// Since we are interested in stealing behavior, warm the scheduler to
   750  	// get all the Ps running first.
   751  	warmupScheduler(runtime.GOMAXPROCS(0))
   752  	b.ResetTimer()
   753  
   754  	var wg sync.WaitGroup
   755  	wg.Add(b.N)
   756  	for i := 0; i < b.N; i++ {
   757  		go func() {
   758  			wg.Done()
   759  		}()
   760  	}
   761  	wg.Wait()
   762  }
   763  
   764  func BenchmarkClosureCall(b *testing.B) {
   765  	sum := 0
   766  	off1 := 1
   767  	for i := 0; i < b.N; i++ {
   768  		off2 := 2
   769  		func() {
   770  			sum += i + off1 + off2
   771  		}()
   772  	}
   773  	_ = sum
   774  }
   775  
   776  func benchmarkWakeupParallel(b *testing.B, spin func(time.Duration)) {
   777  	if runtime.GOMAXPROCS(0) == 1 {
   778  		b.Skip("skipping: GOMAXPROCS=1")
   779  	}
   780  
   781  	wakeDelay := 5 * time.Microsecond
   782  	for _, delay := range []time.Duration{
   783  		0,
   784  		1 * time.Microsecond,
   785  		2 * time.Microsecond,
   786  		5 * time.Microsecond,
   787  		10 * time.Microsecond,
   788  		20 * time.Microsecond,
   789  		50 * time.Microsecond,
   790  		100 * time.Microsecond,
   791  	} {
   792  		b.Run(delay.String(), func(b *testing.B) {
   793  			if b.N == 0 {
   794  				return
   795  			}
   796  			// Start two goroutines, which alternate between being
   797  			// sender and receiver in the following protocol:
   798  			//
   799  			// - The receiver spins for `delay` and then does a
   800  			// blocking receive on a channel.
   801  			//
   802  			// - The sender spins for `delay+wakeDelay` and then
   803  			// sends to the same channel. (The addition of
   804  			// `wakeDelay` improves the probability that the
   805  			// receiver will be blocking when the send occurs when
   806  			// the goroutines execute in parallel.)
   807  			//
   808  			// In each iteration of the benchmark, each goroutine
   809  			// acts once as sender and once as receiver, so each
   810  			// goroutine spins for delay twice.
   811  			//
   812  			// BenchmarkWakeupParallel is used to estimate how
   813  			// efficiently the scheduler parallelizes goroutines in
   814  			// the presence of blocking:
   815  			//
   816  			// - If both goroutines are executed on the same core,
   817  			// an increase in delay by N will increase the time per
   818  			// iteration by 4*N, because all 4 delays are
   819  			// serialized.
   820  			//
   821  			// - Otherwise, an increase in delay by N will increase
   822  			// the time per iteration by 2*N, and the time per
   823  			// iteration is 2 * (runtime overhead + chan
   824  			// send/receive pair + delay + wakeDelay). This allows
   825  			// the runtime overhead, including the time it takes
   826  			// for the unblocked goroutine to be scheduled, to be
   827  			// estimated.
   828  			ping, pong := make(chan struct{}), make(chan struct{})
   829  			start := make(chan struct{})
   830  			done := make(chan struct{})
   831  			go func() {
   832  				<-start
   833  				for i := 0; i < b.N; i++ {
   834  					// sender
   835  					spin(delay + wakeDelay)
   836  					ping <- struct{}{}
   837  					// receiver
   838  					spin(delay)
   839  					<-pong
   840  				}
   841  				done <- struct{}{}
   842  			}()
   843  			go func() {
   844  				for i := 0; i < b.N; i++ {
   845  					// receiver
   846  					spin(delay)
   847  					<-ping
   848  					// sender
   849  					spin(delay + wakeDelay)
   850  					pong <- struct{}{}
   851  				}
   852  				done <- struct{}{}
   853  			}()
   854  			b.ResetTimer()
   855  			start <- struct{}{}
   856  			<-done
   857  			<-done
   858  		})
   859  	}
   860  }
   861  
   862  func BenchmarkWakeupParallelSpinning(b *testing.B) {
   863  	benchmarkWakeupParallel(b, func(d time.Duration) {
   864  		end := time.Now().Add(d)
   865  		for time.Now().Before(end) {
   866  			// do nothing
   867  		}
   868  	})
   869  }
   870  
   871  // sysNanosleep is defined by OS-specific files (such as runtime_linux_test.go)
   872  // to sleep for the given duration. If nil, dependent tests are skipped.
   873  // The implementation should invoke a blocking system call and not
   874  // call time.Sleep, which would deschedule the goroutine.
   875  var sysNanosleep func(d time.Duration)
   876  
   877  func BenchmarkWakeupParallelSyscall(b *testing.B) {
   878  	if sysNanosleep == nil {
   879  		b.Skipf("skipping on %v; sysNanosleep not defined", runtime.GOOS)
   880  	}
   881  	benchmarkWakeupParallel(b, func(d time.Duration) {
   882  		sysNanosleep(d)
   883  	})
   884  }
   885  
   886  type Matrix [][]float64
   887  
   888  func BenchmarkMatmult(b *testing.B) {
   889  	b.StopTimer()
   890  	// matmult is O(N**3) but testing expects O(b.N),
   891  	// so we need to take cube root of b.N
   892  	n := int(math.Cbrt(float64(b.N))) + 1
   893  	A := makeMatrix(n)
   894  	B := makeMatrix(n)
   895  	C := makeMatrix(n)
   896  	b.StartTimer()
   897  	matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
   898  }
   899  
   900  func makeMatrix(n int) Matrix {
   901  	m := make(Matrix, n)
   902  	for i := 0; i < n; i++ {
   903  		m[i] = make([]float64, n)
   904  		for j := 0; j < n; j++ {
   905  			m[i][j] = float64(i*n + j)
   906  		}
   907  	}
   908  	return m
   909  }
   910  
   911  func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
   912  	di := i1 - i0
   913  	dj := j1 - j0
   914  	dk := k1 - k0
   915  	if di >= dj && di >= dk && di >= threshold {
   916  		// divide in two by y axis
   917  		mi := i0 + di/2
   918  		done1 := make(chan struct{}, 1)
   919  		go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
   920  		matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
   921  		<-done1
   922  	} else if dj >= dk && dj >= threshold {
   923  		// divide in two by x axis
   924  		mj := j0 + dj/2
   925  		done1 := make(chan struct{}, 1)
   926  		go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
   927  		matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
   928  		<-done1
   929  	} else if dk >= threshold {
   930  		// divide in two by "k" axis
   931  		// deliberately not parallel because of data races
   932  		mk := k0 + dk/2
   933  		matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
   934  		matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
   935  	} else {
   936  		// the matrices are small enough, compute directly
   937  		for i := i0; i < i1; i++ {
   938  			for j := j0; j < j1; j++ {
   939  				for k := k0; k < k1; k++ {
   940  					C[i][j] += A[i][k] * B[k][j]
   941  				}
   942  			}
   943  		}
   944  	}
   945  	if done != nil {
   946  		done <- struct{}{}
   947  	}
   948  }
   949  
   950  func TestStealOrder(t *testing.T) {
   951  	runtime.RunStealOrderTest()
   952  }
   953  
   954  func TestLockOSThreadNesting(t *testing.T) {
   955  	if runtime.GOARCH == "wasm" {
   956  		t.Skip("no threads on wasm yet")
   957  	}
   958  
   959  	go func() {
   960  		e, i := runtime.LockOSCounts()
   961  		if e != 0 || i != 0 {
   962  			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
   963  			return
   964  		}
   965  		runtime.LockOSThread()
   966  		runtime.LockOSThread()
   967  		runtime.UnlockOSThread()
   968  		e, i = runtime.LockOSCounts()
   969  		if e != 1 || i != 0 {
   970  			t.Errorf("want locked counts 1, 0; got %d, %d", e, i)
   971  			return
   972  		}
   973  		runtime.UnlockOSThread()
   974  		e, i = runtime.LockOSCounts()
   975  		if e != 0 || i != 0 {
   976  			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
   977  			return
   978  		}
   979  	}()
   980  }
   981  
   982  func TestLockOSThreadExit(t *testing.T) {
   983  	testLockOSThreadExit(t, "testprog")
   984  }
   985  
   986  func testLockOSThreadExit(t *testing.T, prog string) {
   987  	output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1")
   988  	want := "OK\n"
   989  	if output != want {
   990  		t.Errorf("want %q, got %q", want, output)
   991  	}
   992  
   993  	output = runTestProg(t, prog, "LockOSThreadAlt")
   994  	if output != want {
   995  		t.Errorf("want %q, got %q", want, output)
   996  	}
   997  }
   998  
   999  func TestLockOSThreadAvoidsStatePropagation(t *testing.T) {
  1000  	want := "OK\n"
  1001  	skip := "unshare not permitted\n"
  1002  	output := runTestProg(t, "testprog", "LockOSThreadAvoidsStatePropagation", "GOMAXPROCS=1")
  1003  	if output == skip {
  1004  		t.Skip("unshare syscall not permitted on this system")
  1005  	} else if output != want {
  1006  		t.Errorf("want %q, got %q", want, output)
  1007  	}
  1008  }
  1009  
  1010  func TestLockOSThreadTemplateThreadRace(t *testing.T) {
  1011  	testenv.MustHaveGoRun(t)
  1012  
  1013  	exe, err := buildTestProg(t, "testprog")
  1014  	if err != nil {
  1015  		t.Fatal(err)
  1016  	}
  1017  
  1018  	iterations := 100
  1019  	if testing.Short() {
  1020  		// Reduce run time to ~100ms, with much lower probability of
  1021  		// catching issues.
  1022  		iterations = 5
  1023  	}
  1024  	for i := 0; i < iterations; i++ {
  1025  		want := "OK\n"
  1026  		output := runBuiltTestProg(t, exe, "LockOSThreadTemplateThreadRace")
  1027  		if output != want {
  1028  			t.Fatalf("run %d: want %q, got %q", i, want, output)
  1029  		}
  1030  	}
  1031  }
  1032  
  1033  func TestLockOSThreadVgetrandom(t *testing.T) {
  1034  	if runtime.GOOS != "linux" {
  1035  		t.Skipf("vgetrandom only relevant on Linux")
  1036  	}
  1037  	output := runTestProg(t, "testprog", "LockOSThreadVgetrandom")
  1038  	want := "OK\n"
  1039  	if output != want {
  1040  		t.Errorf("want %q, got %q", want, output)
  1041  	}
  1042  }
  1043  
  1044  // fakeSyscall emulates a system call.
  1045  //
  1046  //go:nosplit
  1047  func fakeSyscall(duration time.Duration) {
  1048  	runtime.Entersyscall()
  1049  	for start := runtime.Nanotime(); runtime.Nanotime()-start < int64(duration); {
  1050  	}
  1051  	runtime.Exitsyscall()
  1052  }
  1053  
  1054  // Check that a goroutine will be preempted if it is calling short system calls.
  1055  func testPreemptionAfterSyscall(t *testing.T, syscallDuration time.Duration) {
  1056  	if runtime.GOARCH == "wasm" {
  1057  		t.Skip("no preemption on wasm yet")
  1058  	}
  1059  
  1060  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
  1061  
  1062  	iterations := 10
  1063  	if testing.Short() {
  1064  		iterations = 1
  1065  	}
  1066  	const (
  1067  		maxDuration = 5 * time.Second
  1068  		nroutines   = 8
  1069  	)
  1070  
  1071  	for i := 0; i < iterations; i++ {
  1072  		c := make(chan bool, nroutines)
  1073  		stop := uint32(0)
  1074  
  1075  		start := time.Now()
  1076  		for g := 0; g < nroutines; g++ {
  1077  			go func(stop *uint32) {
  1078  				c <- true
  1079  				for atomic.LoadUint32(stop) == 0 {
  1080  					fakeSyscall(syscallDuration)
  1081  				}
  1082  				c <- true
  1083  			}(&stop)
  1084  		}
  1085  		// wait until all goroutines have started.
  1086  		for g := 0; g < nroutines; g++ {
  1087  			<-c
  1088  		}
  1089  		atomic.StoreUint32(&stop, 1)
  1090  		// wait until all goroutines have finished.
  1091  		for g := 0; g < nroutines; g++ {
  1092  			<-c
  1093  		}
  1094  		duration := time.Since(start)
  1095  
  1096  		if duration > maxDuration {
  1097  			t.Errorf("timeout exceeded: %v (%v)", duration, maxDuration)
  1098  		}
  1099  	}
  1100  }
  1101  
  1102  func TestPreemptionAfterSyscall(t *testing.T) {
  1103  	if runtime.GOOS == "plan9" {
  1104  		testenv.SkipFlaky(t, 41015)
  1105  	}
  1106  
  1107  	for _, i := range []time.Duration{10, 100, 1000} {
  1108  		d := i * time.Microsecond
  1109  		t.Run(fmt.Sprint(d), func(t *testing.T) {
  1110  			testPreemptionAfterSyscall(t, d)
  1111  		})
  1112  	}
  1113  }
  1114  
  1115  func TestGetgThreadSwitch(t *testing.T) {
  1116  	runtime.RunGetgThreadSwitchTest()
  1117  }
  1118  
  1119  // TestNetpollBreak tests that netpollBreak can break a netpoll.
  1120  // This test is not particularly safe since the call to netpoll
  1121  // will pick up any stray files that are ready, but it should work
  1122  // OK as long it is not run in parallel.
  1123  func TestNetpollBreak(t *testing.T) {
  1124  	if runtime.GOMAXPROCS(0) == 1 {
  1125  		t.Skip("skipping: GOMAXPROCS=1")
  1126  	}
  1127  
  1128  	// Make sure that netpoll is initialized.
  1129  	runtime.NetpollGenericInit()
  1130  
  1131  	start := time.Now()
  1132  	c := make(chan bool, 2)
  1133  	go func() {
  1134  		c <- true
  1135  		runtime.Netpoll(10 * time.Second.Nanoseconds())
  1136  		c <- true
  1137  	}()
  1138  	<-c
  1139  	// Loop because the break might get eaten by the scheduler.
  1140  	// Break twice to break both the netpoll we started and the
  1141  	// scheduler netpoll.
  1142  loop:
  1143  	for {
  1144  		runtime.Usleep(100)
  1145  		runtime.NetpollBreak()
  1146  		runtime.NetpollBreak()
  1147  		select {
  1148  		case <-c:
  1149  			break loop
  1150  		default:
  1151  		}
  1152  	}
  1153  	if dur := time.Since(start); dur > 5*time.Second {
  1154  		t.Errorf("netpollBreak did not interrupt netpoll: slept for: %v", dur)
  1155  	}
  1156  }
  1157  
  1158  // TestBigGOMAXPROCS tests that setting GOMAXPROCS to a large value
  1159  // doesn't cause a crash at startup. See issue 38474.
  1160  func TestBigGOMAXPROCS(t *testing.T) {
  1161  	t.Parallel()
  1162  	output := runTestProg(t, "testprog", "NonexistentTest", "GOMAXPROCS=1024")
  1163  	// Ignore error conditions on small machines.
  1164  	for _, errstr := range []string{
  1165  		"failed to create new OS thread",
  1166  		"cannot allocate memory",
  1167  	} {
  1168  		if strings.Contains(output, errstr) {
  1169  			t.Skipf("failed to create 1024 threads")
  1170  		}
  1171  	}
  1172  	if !strings.Contains(output, "unknown function: NonexistentTest") {
  1173  		t.Errorf("output:\n%s\nwanted:\nunknown function: NonexistentTest", output)
  1174  	}
  1175  }
  1176  
  1177  type goroutineState struct {
  1178  	G trace.GoID     // This goroutine.
  1179  	P trace.ProcID   // Most recent P this goroutine ran on.
  1180  	M trace.ThreadID // Most recent M this goroutine ran on.
  1181  }
  1182  
  1183  func newGoroutineState(g trace.GoID) *goroutineState {
  1184  	return &goroutineState{
  1185  		G: g,
  1186  		P: trace.NoProc,
  1187  		M: trace.NoThread,
  1188  	}
  1189  }
  1190  
  1191  // TestTraceSTW verifies that goroutines continue running on the same M and P
  1192  // after a STW.
  1193  func TestTraceSTW(t *testing.T) {
  1194  	// Across STW, the runtime attempts to keep goroutines running on the
  1195  	// same P and the P running on the same M. It does this by keeping
  1196  	// goroutines in the P's local runq, and remembering which M the P ran
  1197  	// on before STW and preferring that M when restarting.
  1198  	//
  1199  	// This test verifies that affinity by analyzing a trace of testprog
  1200  	// TraceSTW.
  1201  	//
  1202  	// The affinity across STW is best-effort, so have to allow some
  1203  	// failure rate, thus we test many times and ensure the error rate is
  1204  	// low.
  1205  	//
  1206  	// The expected affinity can fail for a variety of reasons. The most
  1207  	// obvious is that while procresize assigns Ps back to their original
  1208  	// M, startTheWorldWithSema calls wakep to start a spinning M. The
  1209  	// spinning M may steal a goroutine from another P if that P is too
  1210  	// slow to start.
  1211  
  1212  	if testing.Short() {
  1213  		t.Skip("skipping in -short mode")
  1214  	}
  1215  
  1216  	if runtime.NumCPU() < 4 {
  1217  		t.Skip("This test sets GOMAXPROCS=4 and wants to avoid thread descheduling as much as possible. Skip on machines with less than 4 CPUs")
  1218  	}
  1219  
  1220  	const runs = 50
  1221  
  1222  	var errors int
  1223  	for i := range runs {
  1224  		err := runTestTracesSTW(t, i, "TraceSTW", "stop-the-world (read mem stats)")
  1225  		if err != nil {
  1226  			t.Logf("Run %d failed: %v", i, err)
  1227  			errors++
  1228  		}
  1229  	}
  1230  
  1231  	pct := float64(errors) / float64(runs)
  1232  	t.Logf("Errors: %d/%d = %f%%", errors, runs, 100*pct)
  1233  	if pct > 0.25 {
  1234  		t.Errorf("Error rate too high")
  1235  	}
  1236  }
  1237  
  1238  // TestTraceGCSTW verifies that goroutines continue running on the same M and P
  1239  // after a GC STW.
  1240  func TestTraceGCSTW(t *testing.T) {
  1241  	// Very similar to TestTraceSTW, but using a STW that starts the GC.
  1242  	// When the GC starts, the background GC mark workers start running,
  1243  	// which provide an additional source of disturbance to the scheduler.
  1244  	//
  1245  	// procresize assigns GC workers to previously-idle Ps to avoid
  1246  	// changing what the previously-running Ps are doing.
  1247  
  1248  	if testing.Short() {
  1249  		t.Skip("skipping in -short mode")
  1250  	}
  1251  
  1252  	if runtime.NumCPU() < 8 {
  1253  		t.Skip("This test sets GOMAXPROCS=8 and wants to avoid thread descheduling as much as possible. Skip on machines with less than 8 CPUs")
  1254  	}
  1255  
  1256  	const runs = 50
  1257  
  1258  	var errors int
  1259  	for i := range runs {
  1260  		err := runTestTracesSTW(t, i, "TraceGCSTW", "stop-the-world (GC sweep termination)")
  1261  		if err != nil {
  1262  			t.Logf("Run %d failed: %v", i, err)
  1263  			errors++
  1264  		}
  1265  	}
  1266  
  1267  	pct := float64(errors) / float64(runs)
  1268  	t.Logf("Errors: %d/%d = %f%%", errors, runs, 100*pct)
  1269  	if pct > 0.25 {
  1270  		t.Errorf("Error rate too high")
  1271  	}
  1272  }
  1273  
  1274  func runTestTracesSTW(t *testing.T, run int, name, stwType string) (err error) {
  1275  	t.Logf("Run %d", run)
  1276  
  1277  	// By default, TSAN sleeps for 1s at exit to allow background
  1278  	// goroutines to race. This slows down execution for this test far too
  1279  	// much, since we are running 50 iterations, so disable the sleep.
  1280  	//
  1281  	// Outside of race mode, GORACE does nothing.
  1282  	buf := []byte(runTestProg(t, "testprog", name, "GORACE=atexit_sleep_ms=0"))
  1283  
  1284  	// We locally "fail" the run (return an error) if the trace exhibits
  1285  	// unwanted scheduling. i.e., the target goroutines did not remain on
  1286  	// the same P/M.
  1287  	//
  1288  	// We fail the entire test (t.Fatal) for other cases that should never
  1289  	// occur, such as a trace parse error.
  1290  	defer func() {
  1291  		if err != nil || t.Failed() {
  1292  			testtrace.Dump(t, fmt.Sprintf("Test%s-run%d", name, run), []byte(buf), false)
  1293  		}
  1294  	}()
  1295  
  1296  	br, err := trace.NewReader(bytes.NewReader(buf))
  1297  	if err != nil {
  1298  		t.Fatalf("NewReader got err %v want nil", err)
  1299  	}
  1300  
  1301  	var targetGoroutines []*goroutineState
  1302  	findGoroutine := func(goid trace.GoID) *goroutineState {
  1303  		for _, gs := range targetGoroutines {
  1304  			if gs.G == goid {
  1305  				return gs
  1306  			}
  1307  		}
  1308  		return nil
  1309  	}
  1310  	findProc := func(pid trace.ProcID) *goroutineState {
  1311  		for _, gs := range targetGoroutines {
  1312  			if gs.P == pid {
  1313  				return gs
  1314  			}
  1315  		}
  1316  		return nil
  1317  	}
  1318  
  1319  	// 1. Find the goroutine IDs for the target goroutines. This will be in
  1320  	// the StateTransition from NotExist.
  1321  	//
  1322  	// 2. Once found, track which M and P the target goroutines run on until...
  1323  	//
  1324  	// 3. Look for the first STW after the "TraceSTW" "start" log message,
  1325  	// where we commit the target goroutines' "before" M and P.
  1326  	//
  1327  	// N.B. We must do (1) and (2) together because the first target
  1328  	// goroutine may start running before the second is created.
  1329  	var startLogSeen bool
  1330  	var stwSeen bool
  1331  findStart:
  1332  	for {
  1333  		ev, err := br.ReadEvent()
  1334  		if err == io.EOF {
  1335  			// Reached the end of the trace without finding case (3).
  1336  			t.Fatalf("Trace missing start log message")
  1337  		}
  1338  		if err != nil {
  1339  			t.Fatalf("ReadEvent got err %v want nil", err)
  1340  		}
  1341  		t.Logf("Event: %s", ev.String())
  1342  
  1343  		switch ev.Kind() {
  1344  		case trace.EventStateTransition:
  1345  			st := ev.StateTransition()
  1346  			if st.Resource.Kind != trace.ResourceGoroutine {
  1347  				continue
  1348  			}
  1349  
  1350  			goid := st.Resource.Goroutine()
  1351  			from, to := st.Goroutine()
  1352  
  1353  			// Potentially case (1): Goroutine creation.
  1354  			if from == trace.GoNotExist {
  1355  				for sf := range st.Stack.Frames() {
  1356  					if sf.Func == "main.traceSTWTarget" {
  1357  						targetGoroutines = append(targetGoroutines, newGoroutineState(goid))
  1358  						t.Logf("Identified target goroutine id %d", goid)
  1359  					}
  1360  
  1361  					// Always break, the goroutine entrypoint is always the
  1362  					// first frame.
  1363  					break
  1364  				}
  1365  			}
  1366  
  1367  			// Potentially case (2): Goroutine running.
  1368  			if to == trace.GoRunning {
  1369  				gs := findGoroutine(goid)
  1370  				if gs == nil {
  1371  					continue
  1372  				}
  1373  				gs.P = ev.Proc()
  1374  				gs.M = ev.Thread()
  1375  				t.Logf("G %d running on P %d M %d", gs.G, gs.P, gs.M)
  1376  			}
  1377  		case trace.EventLog:
  1378  			// Potentially case (3): Start log event.
  1379  			log := ev.Log()
  1380  			if log.Category != "TraceSTW" {
  1381  				continue
  1382  			}
  1383  			if log.Message != "start" {
  1384  				t.Fatalf("Log message got %s want start", log.Message)
  1385  			}
  1386  
  1387  			// Found start point, move on to next stage.
  1388  			t.Logf("Found start message")
  1389  			startLogSeen = true
  1390  		case trace.EventRangeBegin:
  1391  			if !startLogSeen {
  1392  				// Ignore spurious STW before we expect.
  1393  				continue
  1394  			}
  1395  
  1396  			r := ev.Range()
  1397  			if r.Name == stwType {
  1398  				t.Logf("Found STW")
  1399  				stwSeen = true
  1400  				break findStart
  1401  			}
  1402  		}
  1403  	}
  1404  
  1405  	if !stwSeen {
  1406  		t.Fatal("Can't find STW in the test trace")
  1407  	}
  1408  
  1409  	t.Log("Target goroutines:")
  1410  	for _, gs := range targetGoroutines {
  1411  		t.Logf("%+v", gs)
  1412  	}
  1413  
  1414  	if len(targetGoroutines) != 2 {
  1415  		t.Fatalf("len(targetGoroutines) got %d want 2", len(targetGoroutines))
  1416  	}
  1417  
  1418  	for _, gs := range targetGoroutines {
  1419  		if gs.P == trace.NoProc {
  1420  			t.Fatalf("Goroutine %+v not running on a P", gs)
  1421  		}
  1422  		if gs.M == trace.NoThread {
  1423  			t.Fatalf("Goroutine %+v not running on an M", gs)
  1424  		}
  1425  	}
  1426  
  1427  	// The test continues until we see the "end" log message.
  1428  	//
  1429  	// What we want to observe is that the target goroutines run only on
  1430  	// the original P and M.
  1431  	//
  1432  	// They will be stopped by STW [1], but should resume on the original P
  1433  	// and M.
  1434  	//
  1435  	// However, this is best effort. For example, startTheWorld wakep's a
  1436  	// spinning M. If the original M is slow to restart (e.g., due to poor
  1437  	// kernel scheduling), the spinning M may legally steal the goroutine
  1438  	// and run it instead.
  1439  	//
  1440  	// In practice, we see this occur frequently on builders, likely
  1441  	// because they are overcommitted on CPU. Thus, we instead check
  1442  	// slightly more constrained properties:
  1443  	// - The original P must run on the original M (if it runs at all).
  1444  	// - The original P must run the original G before anything else,
  1445  	//   unless that G has already run elsewhere.
  1446  	//
  1447  	// This allows a spinning M to steal the G from a slow-to-start M, but
  1448  	// does not allow the original P to just flat out run something
  1449  	// completely different from expected.
  1450  	//
  1451  	// Note this is still somewhat racy: the spinning M may steal the
  1452  	// target G, but before it marks the target G as running, the original
  1453  	// P runs an alternative G. This test will fail that case, even though
  1454  	// it is legitimate. We allow that failure because such a race should
  1455  	// be very rare, particularly because the test process usually has no
  1456  	// other runnable goroutines.
  1457  	//
  1458  	// [1] This is slightly fragile because there is a small window between
  1459  	// the "start" log and actual STW during which the target goroutines
  1460  	// could legitimately migrate.
  1461  	var pRunning []trace.ProcID
  1462  	var gRunning []trace.GoID
  1463  findEnd:
  1464  	for {
  1465  		ev, err := br.ReadEvent()
  1466  		if err == io.EOF {
  1467  			break
  1468  		}
  1469  		if err != nil {
  1470  			t.Fatalf("ReadEvent got err %v want nil", err)
  1471  		}
  1472  		t.Logf("Event: %s", ev.String())
  1473  
  1474  		switch ev.Kind() {
  1475  		case trace.EventStateTransition:
  1476  			st := ev.StateTransition()
  1477  			switch st.Resource.Kind {
  1478  			case trace.ResourceProc:
  1479  				p := st.Resource.Proc()
  1480  				_, to := st.Proc()
  1481  
  1482  				// Proc running. Ensure it didn't migrate.
  1483  				if to == trace.ProcRunning {
  1484  					gs := findProc(p)
  1485  					if gs == nil {
  1486  						continue
  1487  					}
  1488  
  1489  					if slices.Contains(pRunning, p) {
  1490  						// Only check the first
  1491  						// transition to running.
  1492  						// Afterwards it is free to
  1493  						// migrate anywhere.
  1494  						continue
  1495  					}
  1496  					pRunning = append(pRunning, p)
  1497  
  1498  					m := ev.Thread()
  1499  					if m != gs.M {
  1500  						t.Logf("Proc %d running on M %d want M %d", p, m, gs.M)
  1501  						return fmt.Errorf("P did not remain on M")
  1502  					}
  1503  				}
  1504  			case trace.ResourceGoroutine:
  1505  				goid := st.Resource.Goroutine()
  1506  				_, to := st.Goroutine()
  1507  
  1508  				// Goroutine running. Ensure it didn't migrate.
  1509  				if to == trace.GoRunning {
  1510  					p := ev.Proc()
  1511  					m := ev.Thread()
  1512  
  1513  					gs := findGoroutine(goid)
  1514  					if gs == nil {
  1515  						// This isn't a target
  1516  						// goroutine. Is it a target P?
  1517  						// That shouldn't run anything
  1518  						// other than the target G.
  1519  						gs = findProc(p)
  1520  						if gs == nil {
  1521  							continue
  1522  						}
  1523  
  1524  						if slices.Contains(gRunning, gs.G) {
  1525  							// This P's target G ran elsewhere. This probably
  1526  							// means that this P was slow to start, so
  1527  							// another P stole it. That isn't ideal, but
  1528  							// we'll allow it.
  1529  							continue
  1530  						}
  1531  
  1532  						t.Logf("Goroutine %d running on P %d M %d want this P to run G %d", goid, p, m, gs.G)
  1533  						return fmt.Errorf("P ran incorrect goroutine")
  1534  					}
  1535  
  1536  					if !slices.Contains(gRunning, goid) {
  1537  						gRunning = append(gRunning, goid)
  1538  					}
  1539  
  1540  					if p != gs.P || m != gs.M {
  1541  						t.Logf("Goroutine %d running on P %d M %d want P %d M %d", goid, p, m, gs.P, gs.M)
  1542  						// We don't want this to occur,
  1543  						// but allow it for cases of
  1544  						// bad kernel scheduling. See
  1545  						// "The test continues" comment
  1546  						// above.
  1547  					}
  1548  				}
  1549  			}
  1550  		case trace.EventLog:
  1551  			// Potentially end log event.
  1552  			log := ev.Log()
  1553  			if log.Category != "TraceSTW" {
  1554  				continue
  1555  			}
  1556  			if log.Message != "end" {
  1557  				t.Fatalf("Log message got %s want end", log.Message)
  1558  			}
  1559  
  1560  			// Found end point.
  1561  			t.Logf("Found end message")
  1562  			break findEnd
  1563  		}
  1564  	}
  1565  
  1566  	return nil
  1567  }
  1568  
  1569  func TestMexitSTW(t *testing.T) {
  1570  	got := runTestProg(t, "testprog", "mexitSTW")
  1571  	want := "OK\n"
  1572  	if got != want {
  1573  		t.Fatalf("expected %q, but got:\n%s", want, got)
  1574  	}
  1575  }
  1576  

View as plain text