...

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  	"fmt"
		 9  	"internal/race"
		10  	"internal/testenv"
		11  	"math"
		12  	"net"
		13  	"runtime"
		14  	"runtime/debug"
		15  	"strings"
		16  	"sync"
		17  	"sync/atomic"
		18  	"syscall"
		19  	"testing"
		20  	"time"
		21  )
		22  
		23  var stop = make(chan bool, 1)
		24  
		25  func perpetuumMobile() {
		26  	select {
		27  	case <-stop:
		28  	default:
		29  		go perpetuumMobile()
		30  	}
		31  }
		32  
		33  func TestStopTheWorldDeadlock(t *testing.T) {
		34  	if runtime.GOARCH == "wasm" {
		35  		t.Skip("no preemption on wasm yet")
		36  	}
		37  	if testing.Short() {
		38  		t.Skip("skipping during short test")
		39  	}
		40  	maxprocs := runtime.GOMAXPROCS(3)
		41  	compl := make(chan bool, 2)
		42  	go func() {
		43  		for i := 0; i != 1000; i += 1 {
		44  			runtime.GC()
		45  		}
		46  		compl <- true
		47  	}()
		48  	go func() {
		49  		for i := 0; i != 1000; i += 1 {
		50  			runtime.GOMAXPROCS(3)
		51  		}
		52  		compl <- true
		53  	}()
		54  	go perpetuumMobile()
		55  	<-compl
		56  	<-compl
		57  	stop <- true
		58  	runtime.GOMAXPROCS(maxprocs)
		59  }
		60  
		61  func TestYieldProgress(t *testing.T) {
		62  	testYieldProgress(false)
		63  }
		64  
		65  func TestYieldLockedProgress(t *testing.T) {
		66  	testYieldProgress(true)
		67  }
		68  
		69  func testYieldProgress(locked bool) {
		70  	c := make(chan bool)
		71  	cack := make(chan bool)
		72  	go func() {
		73  		if locked {
		74  			runtime.LockOSThread()
		75  		}
		76  		for {
		77  			select {
		78  			case <-c:
		79  				cack <- true
		80  				return
		81  			default:
		82  				runtime.Gosched()
		83  			}
		84  		}
		85  	}()
		86  	time.Sleep(10 * time.Millisecond)
		87  	c <- true
		88  	<-cack
		89  }
		90  
		91  func TestYieldLocked(t *testing.T) {
		92  	const N = 10
		93  	c := make(chan bool)
		94  	go func() {
		95  		runtime.LockOSThread()
		96  		for i := 0; i < N; i++ {
		97  			runtime.Gosched()
		98  			time.Sleep(time.Millisecond)
		99  		}
	 100  		c <- true
	 101  		// runtime.UnlockOSThread() is deliberately omitted
	 102  	}()
	 103  	<-c
	 104  }
	 105  
	 106  func TestGoroutineParallelism(t *testing.T) {
	 107  	if runtime.NumCPU() == 1 {
	 108  		// Takes too long, too easy to deadlock, etc.
	 109  		t.Skip("skipping on uniprocessor")
	 110  	}
	 111  	P := 4
	 112  	N := 10
	 113  	if testing.Short() {
	 114  		P = 3
	 115  		N = 3
	 116  	}
	 117  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
	 118  	// If runtime triggers a forced GC during this test then it will deadlock,
	 119  	// since the goroutines can't be stopped/preempted.
	 120  	// Disable GC for this test (see issue #10958).
	 121  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
	 122  	for try := 0; try < N; try++ {
	 123  		done := make(chan bool)
	 124  		x := uint32(0)
	 125  		for p := 0; p < P; p++ {
	 126  			// Test that all P goroutines are scheduled at the same time
	 127  			go func(p int) {
	 128  				for i := 0; i < 3; i++ {
	 129  					expected := uint32(P*i + p)
	 130  					for atomic.LoadUint32(&x) != expected {
	 131  					}
	 132  					atomic.StoreUint32(&x, expected+1)
	 133  				}
	 134  				done <- true
	 135  			}(p)
	 136  		}
	 137  		for p := 0; p < P; p++ {
	 138  			<-done
	 139  		}
	 140  	}
	 141  }
	 142  
	 143  // Test that all runnable goroutines are scheduled at the same time.
	 144  func TestGoroutineParallelism2(t *testing.T) {
	 145  	//testGoroutineParallelism2(t, false, false)
	 146  	testGoroutineParallelism2(t, true, false)
	 147  	testGoroutineParallelism2(t, false, true)
	 148  	testGoroutineParallelism2(t, true, true)
	 149  }
	 150  
	 151  func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
	 152  	if runtime.NumCPU() == 1 {
	 153  		// Takes too long, too easy to deadlock, etc.
	 154  		t.Skip("skipping on uniprocessor")
	 155  	}
	 156  	P := 4
	 157  	N := 10
	 158  	if testing.Short() {
	 159  		N = 3
	 160  	}
	 161  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
	 162  	// If runtime triggers a forced GC during this test then it will deadlock,
	 163  	// since the goroutines can't be stopped/preempted.
	 164  	// Disable GC for this test (see issue #10958).
	 165  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
	 166  	for try := 0; try < N; try++ {
	 167  		if load {
	 168  			// Create P goroutines and wait until they all run.
	 169  			// When we run the actual test below, worker threads
	 170  			// running the goroutines will start parking.
	 171  			done := make(chan bool)
	 172  			x := uint32(0)
	 173  			for p := 0; p < P; p++ {
	 174  				go func() {
	 175  					if atomic.AddUint32(&x, 1) == uint32(P) {
	 176  						done <- true
	 177  						return
	 178  					}
	 179  					for atomic.LoadUint32(&x) != uint32(P) {
	 180  					}
	 181  				}()
	 182  			}
	 183  			<-done
	 184  		}
	 185  		if netpoll {
	 186  			// Enable netpoller, affects schedler behavior.
	 187  			laddr := "localhost:0"
	 188  			if runtime.GOOS == "android" {
	 189  				// On some Android devices, there are no records for localhost,
	 190  				// see https://golang.org/issues/14486.
	 191  				// Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
	 192  				laddr = "127.0.0.1:0"
	 193  			}
	 194  			ln, err := net.Listen("tcp", laddr)
	 195  			if err != nil {
	 196  				defer ln.Close() // yup, defer in a loop
	 197  			}
	 198  		}
	 199  		done := make(chan bool)
	 200  		x := uint32(0)
	 201  		// Spawn P goroutines in a nested fashion just to differ from TestGoroutineParallelism.
	 202  		for p := 0; p < P/2; p++ {
	 203  			go func(p int) {
	 204  				for p2 := 0; p2 < 2; p2++ {
	 205  					go func(p2 int) {
	 206  						for i := 0; i < 3; i++ {
	 207  							expected := uint32(P*i + p*2 + p2)
	 208  							for atomic.LoadUint32(&x) != expected {
	 209  							}
	 210  							atomic.StoreUint32(&x, expected+1)
	 211  						}
	 212  						done <- true
	 213  					}(p2)
	 214  				}
	 215  			}(p)
	 216  		}
	 217  		for p := 0; p < P; p++ {
	 218  			<-done
	 219  		}
	 220  	}
	 221  }
	 222  
	 223  func TestBlockLocked(t *testing.T) {
	 224  	const N = 10
	 225  	c := make(chan bool)
	 226  	go func() {
	 227  		runtime.LockOSThread()
	 228  		for i := 0; i < N; i++ {
	 229  			c <- true
	 230  		}
	 231  		runtime.UnlockOSThread()
	 232  	}()
	 233  	for i := 0; i < N; i++ {
	 234  		<-c
	 235  	}
	 236  }
	 237  
	 238  func TestTimerFairness(t *testing.T) {
	 239  	if runtime.GOARCH == "wasm" {
	 240  		t.Skip("no preemption on wasm yet")
	 241  	}
	 242  
	 243  	done := make(chan bool)
	 244  	c := make(chan bool)
	 245  	for i := 0; i < 2; i++ {
	 246  		go func() {
	 247  			for {
	 248  				select {
	 249  				case c <- true:
	 250  				case <-done:
	 251  					return
	 252  				}
	 253  			}
	 254  		}()
	 255  	}
	 256  
	 257  	timer := time.After(20 * time.Millisecond)
	 258  	for {
	 259  		select {
	 260  		case <-c:
	 261  		case <-timer:
	 262  			close(done)
	 263  			return
	 264  		}
	 265  	}
	 266  }
	 267  
	 268  func TestTimerFairness2(t *testing.T) {
	 269  	if runtime.GOARCH == "wasm" {
	 270  		t.Skip("no preemption on wasm yet")
	 271  	}
	 272  
	 273  	done := make(chan bool)
	 274  	c := make(chan bool)
	 275  	for i := 0; i < 2; i++ {
	 276  		go func() {
	 277  			timer := time.After(20 * time.Millisecond)
	 278  			var buf [1]byte
	 279  			for {
	 280  				syscall.Read(0, buf[0:0])
	 281  				select {
	 282  				case c <- true:
	 283  				case <-c:
	 284  				case <-timer:
	 285  					done <- true
	 286  					return
	 287  				}
	 288  			}
	 289  		}()
	 290  	}
	 291  	<-done
	 292  	<-done
	 293  }
	 294  
	 295  // The function is used to test preemption at split stack checks.
	 296  // Declaring a var avoids inlining at the call site.
	 297  var preempt = func() int {
	 298  	var a [128]int
	 299  	sum := 0
	 300  	for _, v := range a {
	 301  		sum += v
	 302  	}
	 303  	return sum
	 304  }
	 305  
	 306  func TestPreemption(t *testing.T) {
	 307  	if runtime.GOARCH == "wasm" {
	 308  		t.Skip("no preemption on wasm yet")
	 309  	}
	 310  
	 311  	// Test that goroutines are preempted at function calls.
	 312  	N := 5
	 313  	if testing.Short() {
	 314  		N = 2
	 315  	}
	 316  	c := make(chan bool)
	 317  	var x uint32
	 318  	for g := 0; g < 2; g++ {
	 319  		go func(g int) {
	 320  			for i := 0; i < N; i++ {
	 321  				for atomic.LoadUint32(&x) != uint32(g) {
	 322  					preempt()
	 323  				}
	 324  				atomic.StoreUint32(&x, uint32(1-g))
	 325  			}
	 326  			c <- true
	 327  		}(g)
	 328  	}
	 329  	<-c
	 330  	<-c
	 331  }
	 332  
	 333  func TestPreemptionGC(t *testing.T) {
	 334  	if runtime.GOARCH == "wasm" {
	 335  		t.Skip("no preemption on wasm yet")
	 336  	}
	 337  
	 338  	// Test that pending GC preempts running goroutines.
	 339  	P := 5
	 340  	N := 10
	 341  	if testing.Short() {
	 342  		P = 3
	 343  		N = 2
	 344  	}
	 345  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1))
	 346  	var stop uint32
	 347  	for i := 0; i < P; i++ {
	 348  		go func() {
	 349  			for atomic.LoadUint32(&stop) == 0 {
	 350  				preempt()
	 351  			}
	 352  		}()
	 353  	}
	 354  	for i := 0; i < N; i++ {
	 355  		runtime.Gosched()
	 356  		runtime.GC()
	 357  	}
	 358  	atomic.StoreUint32(&stop, 1)
	 359  }
	 360  
	 361  func TestAsyncPreempt(t *testing.T) {
	 362  	if !runtime.PreemptMSupported {
	 363  		t.Skip("asynchronous preemption not supported on this platform")
	 364  	}
	 365  	output := runTestProg(t, "testprog", "AsyncPreempt")
	 366  	want := "OK\n"
	 367  	if output != want {
	 368  		t.Fatalf("want %s, got %s\n", want, output)
	 369  	}
	 370  }
	 371  
	 372  func TestGCFairness(t *testing.T) {
	 373  	output := runTestProg(t, "testprog", "GCFairness")
	 374  	want := "OK\n"
	 375  	if output != want {
	 376  		t.Fatalf("want %s, got %s\n", want, output)
	 377  	}
	 378  }
	 379  
	 380  func TestGCFairness2(t *testing.T) {
	 381  	output := runTestProg(t, "testprog", "GCFairness2")
	 382  	want := "OK\n"
	 383  	if output != want {
	 384  		t.Fatalf("want %s, got %s\n", want, output)
	 385  	}
	 386  }
	 387  
	 388  func TestNumGoroutine(t *testing.T) {
	 389  	output := runTestProg(t, "testprog", "NumGoroutine")
	 390  	want := "1\n"
	 391  	if output != want {
	 392  		t.Fatalf("want %q, got %q", want, output)
	 393  	}
	 394  
	 395  	buf := make([]byte, 1<<20)
	 396  
	 397  	// Try up to 10 times for a match before giving up.
	 398  	// This is a fundamentally racy check but it's important
	 399  	// to notice if NumGoroutine and Stack are _always_ out of sync.
	 400  	for i := 0; ; i++ {
	 401  		// Give goroutines about to exit a chance to exit.
	 402  		// The NumGoroutine and Stack below need to see
	 403  		// the same state of the world, so anything we can do
	 404  		// to keep it quiet is good.
	 405  		runtime.Gosched()
	 406  
	 407  		n := runtime.NumGoroutine()
	 408  		buf = buf[:runtime.Stack(buf, true)]
	 409  
	 410  		nstk := strings.Count(string(buf), "goroutine ")
	 411  		if n == nstk {
	 412  			break
	 413  		}
	 414  		if i >= 10 {
	 415  			t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump: %s", n, nstk, buf)
	 416  		}
	 417  	}
	 418  }
	 419  
	 420  func TestPingPongHog(t *testing.T) {
	 421  	if runtime.GOARCH == "wasm" {
	 422  		t.Skip("no preemption on wasm yet")
	 423  	}
	 424  	if testing.Short() {
	 425  		t.Skip("skipping in -short mode")
	 426  	}
	 427  	if race.Enabled {
	 428  		// The race detector randomizes the scheduler,
	 429  		// which causes this test to fail (#38266).
	 430  		t.Skip("skipping in -race mode")
	 431  	}
	 432  
	 433  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
	 434  	done := make(chan bool)
	 435  	hogChan, lightChan := make(chan bool), make(chan bool)
	 436  	hogCount, lightCount := 0, 0
	 437  
	 438  	run := func(limit int, counter *int, wake chan bool) {
	 439  		for {
	 440  			select {
	 441  			case <-done:
	 442  				return
	 443  
	 444  			case <-wake:
	 445  				for i := 0; i < limit; i++ {
	 446  					*counter++
	 447  				}
	 448  				wake <- true
	 449  			}
	 450  		}
	 451  	}
	 452  
	 453  	// Start two co-scheduled hog goroutines.
	 454  	for i := 0; i < 2; i++ {
	 455  		go run(1e6, &hogCount, hogChan)
	 456  	}
	 457  
	 458  	// Start two co-scheduled light goroutines.
	 459  	for i := 0; i < 2; i++ {
	 460  		go run(1e3, &lightCount, lightChan)
	 461  	}
	 462  
	 463  	// Start goroutine pairs and wait for a few preemption rounds.
	 464  	hogChan <- true
	 465  	lightChan <- true
	 466  	time.Sleep(100 * time.Millisecond)
	 467  	close(done)
	 468  	<-hogChan
	 469  	<-lightChan
	 470  
	 471  	// Check that hogCount and lightCount are within a factor of
	 472  	// 5, which indicates that both pairs of goroutines handed off
	 473  	// the P within a time-slice to their buddy. We can use a
	 474  	// fairly large factor here to make this robust: if the
	 475  	// scheduler isn't working right, the gap should be ~1000X.
	 476  	const factor = 5
	 477  	if hogCount > lightCount*factor || lightCount > hogCount*factor {
	 478  		t.Fatalf("want hogCount/lightCount in [%v, %v]; got %d/%d = %g", 1.0/factor, factor, hogCount, lightCount, float64(hogCount)/float64(lightCount))
	 479  	}
	 480  }
	 481  
	 482  func BenchmarkPingPongHog(b *testing.B) {
	 483  	if b.N == 0 {
	 484  		return
	 485  	}
	 486  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
	 487  
	 488  	// Create a CPU hog
	 489  	stop, done := make(chan bool), make(chan bool)
	 490  	go func() {
	 491  		for {
	 492  			select {
	 493  			case <-stop:
	 494  				done <- true
	 495  				return
	 496  			default:
	 497  			}
	 498  		}
	 499  	}()
	 500  
	 501  	// Ping-pong b.N times
	 502  	ping, pong := make(chan bool), make(chan bool)
	 503  	go func() {
	 504  		for j := 0; j < b.N; j++ {
	 505  			pong <- <-ping
	 506  		}
	 507  		close(stop)
	 508  		done <- true
	 509  	}()
	 510  	go func() {
	 511  		for i := 0; i < b.N; i++ {
	 512  			ping <- <-pong
	 513  		}
	 514  		done <- true
	 515  	}()
	 516  	b.ResetTimer()
	 517  	ping <- true // Start ping-pong
	 518  	<-stop
	 519  	b.StopTimer()
	 520  	<-ping // Let last ponger exit
	 521  	<-done // Make sure goroutines exit
	 522  	<-done
	 523  	<-done
	 524  }
	 525  
	 526  var padData [128]uint64
	 527  
	 528  func stackGrowthRecursive(i int) {
	 529  	var pad [128]uint64
	 530  	pad = padData
	 531  	for j := range pad {
	 532  		if pad[j] != 0 {
	 533  			return
	 534  		}
	 535  	}
	 536  	if i != 0 {
	 537  		stackGrowthRecursive(i - 1)
	 538  	}
	 539  }
	 540  
	 541  func TestPreemptSplitBig(t *testing.T) {
	 542  	if testing.Short() {
	 543  		t.Skip("skipping in -short mode")
	 544  	}
	 545  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	 546  	stop := make(chan int)
	 547  	go big(stop)
	 548  	for i := 0; i < 3; i++ {
	 549  		time.Sleep(10 * time.Microsecond) // let big start running
	 550  		runtime.GC()
	 551  	}
	 552  	close(stop)
	 553  }
	 554  
	 555  func big(stop chan int) int {
	 556  	n := 0
	 557  	for {
	 558  		// delay so that gc is sure to have asked for a preemption
	 559  		for i := 0; i < 1e9; i++ {
	 560  			n++
	 561  		}
	 562  
	 563  		// call bigframe, which used to miss the preemption in its prologue.
	 564  		bigframe(stop)
	 565  
	 566  		// check if we've been asked to stop.
	 567  		select {
	 568  		case <-stop:
	 569  			return n
	 570  		}
	 571  	}
	 572  }
	 573  
	 574  func bigframe(stop chan int) int {
	 575  	// not splitting the stack will overflow.
	 576  	// small will notice that it needs a stack split and will
	 577  	// catch the overflow.
	 578  	var x [8192]byte
	 579  	return small(stop, &x)
	 580  }
	 581  
	 582  func small(stop chan int, x *[8192]byte) int {
	 583  	for i := range x {
	 584  		x[i] = byte(i)
	 585  	}
	 586  	sum := 0
	 587  	for i := range x {
	 588  		sum += int(x[i])
	 589  	}
	 590  
	 591  	// keep small from being a leaf function, which might
	 592  	// make it not do any stack check at all.
	 593  	nonleaf(stop)
	 594  
	 595  	return sum
	 596  }
	 597  
	 598  func nonleaf(stop chan int) bool {
	 599  	// do something that won't be inlined:
	 600  	select {
	 601  	case <-stop:
	 602  		return true
	 603  	default:
	 604  		return false
	 605  	}
	 606  }
	 607  
	 608  func TestSchedLocalQueue(t *testing.T) {
	 609  	runtime.RunSchedLocalQueueTest()
	 610  }
	 611  
	 612  func TestSchedLocalQueueSteal(t *testing.T) {
	 613  	runtime.RunSchedLocalQueueStealTest()
	 614  }
	 615  
	 616  func TestSchedLocalQueueEmpty(t *testing.T) {
	 617  	if runtime.NumCPU() == 1 {
	 618  		// Takes too long and does not trigger the race.
	 619  		t.Skip("skipping on uniprocessor")
	 620  	}
	 621  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
	 622  
	 623  	// If runtime triggers a forced GC during this test then it will deadlock,
	 624  	// since the goroutines can't be stopped/preempted during spin wait.
	 625  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
	 626  
	 627  	iters := int(1e5)
	 628  	if testing.Short() {
	 629  		iters = 1e2
	 630  	}
	 631  	runtime.RunSchedLocalQueueEmptyTest(iters)
	 632  }
	 633  
	 634  func benchmarkStackGrowth(b *testing.B, rec int) {
	 635  	b.RunParallel(func(pb *testing.PB) {
	 636  		for pb.Next() {
	 637  			stackGrowthRecursive(rec)
	 638  		}
	 639  	})
	 640  }
	 641  
	 642  func BenchmarkStackGrowth(b *testing.B) {
	 643  	benchmarkStackGrowth(b, 10)
	 644  }
	 645  
	 646  func BenchmarkStackGrowthDeep(b *testing.B) {
	 647  	benchmarkStackGrowth(b, 1024)
	 648  }
	 649  
	 650  func BenchmarkCreateGoroutines(b *testing.B) {
	 651  	benchmarkCreateGoroutines(b, 1)
	 652  }
	 653  
	 654  func BenchmarkCreateGoroutinesParallel(b *testing.B) {
	 655  	benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
	 656  }
	 657  
	 658  func benchmarkCreateGoroutines(b *testing.B, procs int) {
	 659  	c := make(chan bool)
	 660  	var f func(n int)
	 661  	f = func(n int) {
	 662  		if n == 0 {
	 663  			c <- true
	 664  			return
	 665  		}
	 666  		go f(n - 1)
	 667  	}
	 668  	for i := 0; i < procs; i++ {
	 669  		go f(b.N / procs)
	 670  	}
	 671  	for i := 0; i < procs; i++ {
	 672  		<-c
	 673  	}
	 674  }
	 675  
	 676  func BenchmarkCreateGoroutinesCapture(b *testing.B) {
	 677  	b.ReportAllocs()
	 678  	for i := 0; i < b.N; i++ {
	 679  		const N = 4
	 680  		var wg sync.WaitGroup
	 681  		wg.Add(N)
	 682  		for i := 0; i < N; i++ {
	 683  			i := i
	 684  			go func() {
	 685  				if i >= N {
	 686  					b.Logf("bad") // just to capture b
	 687  				}
	 688  				wg.Done()
	 689  			}()
	 690  		}
	 691  		wg.Wait()
	 692  	}
	 693  }
	 694  
	 695  // warmupScheduler ensures the scheduler has at least targetThreadCount threads
	 696  // in its thread pool.
	 697  func warmupScheduler(targetThreadCount int) {
	 698  	var wg sync.WaitGroup
	 699  	var count int32
	 700  	for i := 0; i < targetThreadCount; i++ {
	 701  		wg.Add(1)
	 702  		go func() {
	 703  			atomic.AddInt32(&count, 1)
	 704  			for atomic.LoadInt32(&count) < int32(targetThreadCount) {
	 705  				// spin until all threads started
	 706  			}
	 707  
	 708  			// spin a bit more to ensure they are all running on separate CPUs.
	 709  			doWork(time.Millisecond)
	 710  			wg.Done()
	 711  		}()
	 712  	}
	 713  	wg.Wait()
	 714  }
	 715  
	 716  func doWork(dur time.Duration) {
	 717  	start := time.Now()
	 718  	for time.Since(start) < dur {
	 719  	}
	 720  }
	 721  
	 722  // BenchmarkCreateGoroutinesSingle creates many goroutines, all from a single
	 723  // producer (the main benchmark goroutine).
	 724  //
	 725  // Compared to BenchmarkCreateGoroutines, this causes different behavior in the
	 726  // scheduler because Ms are much more likely to need to steal work from the
	 727  // main P rather than having work in the local run queue.
	 728  func BenchmarkCreateGoroutinesSingle(b *testing.B) {
	 729  	// Since we are interested in stealing behavior, warm the scheduler to
	 730  	// get all the Ps running first.
	 731  	warmupScheduler(runtime.GOMAXPROCS(0))
	 732  	b.ResetTimer()
	 733  
	 734  	var wg sync.WaitGroup
	 735  	wg.Add(b.N)
	 736  	for i := 0; i < b.N; i++ {
	 737  		go func() {
	 738  			wg.Done()
	 739  		}()
	 740  	}
	 741  	wg.Wait()
	 742  }
	 743  
	 744  func BenchmarkClosureCall(b *testing.B) {
	 745  	sum := 0
	 746  	off1 := 1
	 747  	for i := 0; i < b.N; i++ {
	 748  		off2 := 2
	 749  		func() {
	 750  			sum += i + off1 + off2
	 751  		}()
	 752  	}
	 753  	_ = sum
	 754  }
	 755  
	 756  func benchmarkWakeupParallel(b *testing.B, spin func(time.Duration)) {
	 757  	if runtime.GOMAXPROCS(0) == 1 {
	 758  		b.Skip("skipping: GOMAXPROCS=1")
	 759  	}
	 760  
	 761  	wakeDelay := 5 * time.Microsecond
	 762  	for _, delay := range []time.Duration{
	 763  		0,
	 764  		1 * time.Microsecond,
	 765  		2 * time.Microsecond,
	 766  		5 * time.Microsecond,
	 767  		10 * time.Microsecond,
	 768  		20 * time.Microsecond,
	 769  		50 * time.Microsecond,
	 770  		100 * time.Microsecond,
	 771  	} {
	 772  		b.Run(delay.String(), func(b *testing.B) {
	 773  			if b.N == 0 {
	 774  				return
	 775  			}
	 776  			// Start two goroutines, which alternate between being
	 777  			// sender and receiver in the following protocol:
	 778  			//
	 779  			// - The receiver spins for `delay` and then does a
	 780  			// blocking receive on a channel.
	 781  			//
	 782  			// - The sender spins for `delay+wakeDelay` and then
	 783  			// sends to the same channel. (The addition of
	 784  			// `wakeDelay` improves the probability that the
	 785  			// receiver will be blocking when the send occurs when
	 786  			// the goroutines execute in parallel.)
	 787  			//
	 788  			// In each iteration of the benchmark, each goroutine
	 789  			// acts once as sender and once as receiver, so each
	 790  			// goroutine spins for delay twice.
	 791  			//
	 792  			// BenchmarkWakeupParallel is used to estimate how
	 793  			// efficiently the scheduler parallelizes goroutines in
	 794  			// the presence of blocking:
	 795  			//
	 796  			// - If both goroutines are executed on the same core,
	 797  			// an increase in delay by N will increase the time per
	 798  			// iteration by 4*N, because all 4 delays are
	 799  			// serialized.
	 800  			//
	 801  			// - Otherwise, an increase in delay by N will increase
	 802  			// the time per iteration by 2*N, and the time per
	 803  			// iteration is 2 * (runtime overhead + chan
	 804  			// send/receive pair + delay + wakeDelay). This allows
	 805  			// the runtime overhead, including the time it takes
	 806  			// for the unblocked goroutine to be scheduled, to be
	 807  			// estimated.
	 808  			ping, pong := make(chan struct{}), make(chan struct{})
	 809  			start := make(chan struct{})
	 810  			done := make(chan struct{})
	 811  			go func() {
	 812  				<-start
	 813  				for i := 0; i < b.N; i++ {
	 814  					// sender
	 815  					spin(delay + wakeDelay)
	 816  					ping <- struct{}{}
	 817  					// receiver
	 818  					spin(delay)
	 819  					<-pong
	 820  				}
	 821  				done <- struct{}{}
	 822  			}()
	 823  			go func() {
	 824  				for i := 0; i < b.N; i++ {
	 825  					// receiver
	 826  					spin(delay)
	 827  					<-ping
	 828  					// sender
	 829  					spin(delay + wakeDelay)
	 830  					pong <- struct{}{}
	 831  				}
	 832  				done <- struct{}{}
	 833  			}()
	 834  			b.ResetTimer()
	 835  			start <- struct{}{}
	 836  			<-done
	 837  			<-done
	 838  		})
	 839  	}
	 840  }
	 841  
	 842  func BenchmarkWakeupParallelSpinning(b *testing.B) {
	 843  	benchmarkWakeupParallel(b, func(d time.Duration) {
	 844  		end := time.Now().Add(d)
	 845  		for time.Now().Before(end) {
	 846  			// do nothing
	 847  		}
	 848  	})
	 849  }
	 850  
	 851  // sysNanosleep is defined by OS-specific files (such as runtime_linux_test.go)
	 852  // to sleep for the given duration. If nil, dependent tests are skipped.
	 853  // The implementation should invoke a blocking system call and not
	 854  // call time.Sleep, which would deschedule the goroutine.
	 855  var sysNanosleep func(d time.Duration)
	 856  
	 857  func BenchmarkWakeupParallelSyscall(b *testing.B) {
	 858  	if sysNanosleep == nil {
	 859  		b.Skipf("skipping on %v; sysNanosleep not defined", runtime.GOOS)
	 860  	}
	 861  	benchmarkWakeupParallel(b, func(d time.Duration) {
	 862  		sysNanosleep(d)
	 863  	})
	 864  }
	 865  
	 866  type Matrix [][]float64
	 867  
	 868  func BenchmarkMatmult(b *testing.B) {
	 869  	b.StopTimer()
	 870  	// matmult is O(N**3) but testing expects O(b.N),
	 871  	// so we need to take cube root of b.N
	 872  	n := int(math.Cbrt(float64(b.N))) + 1
	 873  	A := makeMatrix(n)
	 874  	B := makeMatrix(n)
	 875  	C := makeMatrix(n)
	 876  	b.StartTimer()
	 877  	matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
	 878  }
	 879  
	 880  func makeMatrix(n int) Matrix {
	 881  	m := make(Matrix, n)
	 882  	for i := 0; i < n; i++ {
	 883  		m[i] = make([]float64, n)
	 884  		for j := 0; j < n; j++ {
	 885  			m[i][j] = float64(i*n + j)
	 886  		}
	 887  	}
	 888  	return m
	 889  }
	 890  
	 891  func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
	 892  	di := i1 - i0
	 893  	dj := j1 - j0
	 894  	dk := k1 - k0
	 895  	if di >= dj && di >= dk && di >= threshold {
	 896  		// divide in two by y axis
	 897  		mi := i0 + di/2
	 898  		done1 := make(chan struct{}, 1)
	 899  		go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
	 900  		matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
	 901  		<-done1
	 902  	} else if dj >= dk && dj >= threshold {
	 903  		// divide in two by x axis
	 904  		mj := j0 + dj/2
	 905  		done1 := make(chan struct{}, 1)
	 906  		go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
	 907  		matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
	 908  		<-done1
	 909  	} else if dk >= threshold {
	 910  		// divide in two by "k" axis
	 911  		// deliberately not parallel because of data races
	 912  		mk := k0 + dk/2
	 913  		matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
	 914  		matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
	 915  	} else {
	 916  		// the matrices are small enough, compute directly
	 917  		for i := i0; i < i1; i++ {
	 918  			for j := j0; j < j1; j++ {
	 919  				for k := k0; k < k1; k++ {
	 920  					C[i][j] += A[i][k] * B[k][j]
	 921  				}
	 922  			}
	 923  		}
	 924  	}
	 925  	if done != nil {
	 926  		done <- struct{}{}
	 927  	}
	 928  }
	 929  
	 930  func TestStealOrder(t *testing.T) {
	 931  	runtime.RunStealOrderTest()
	 932  }
	 933  
	 934  func TestLockOSThreadNesting(t *testing.T) {
	 935  	if runtime.GOARCH == "wasm" {
	 936  		t.Skip("no threads on wasm yet")
	 937  	}
	 938  
	 939  	go func() {
	 940  		e, i := runtime.LockOSCounts()
	 941  		if e != 0 || i != 0 {
	 942  			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
	 943  			return
	 944  		}
	 945  		runtime.LockOSThread()
	 946  		runtime.LockOSThread()
	 947  		runtime.UnlockOSThread()
	 948  		e, i = runtime.LockOSCounts()
	 949  		if e != 1 || i != 0 {
	 950  			t.Errorf("want locked counts 1, 0; got %d, %d", e, i)
	 951  			return
	 952  		}
	 953  		runtime.UnlockOSThread()
	 954  		e, i = runtime.LockOSCounts()
	 955  		if e != 0 || i != 0 {
	 956  			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
	 957  			return
	 958  		}
	 959  	}()
	 960  }
	 961  
	 962  func TestLockOSThreadExit(t *testing.T) {
	 963  	testLockOSThreadExit(t, "testprog")
	 964  }
	 965  
	 966  func testLockOSThreadExit(t *testing.T, prog string) {
	 967  	output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1")
	 968  	want := "OK\n"
	 969  	if output != want {
	 970  		t.Errorf("want %q, got %q", want, output)
	 971  	}
	 972  
	 973  	output = runTestProg(t, prog, "LockOSThreadAlt")
	 974  	if output != want {
	 975  		t.Errorf("want %q, got %q", want, output)
	 976  	}
	 977  }
	 978  
	 979  func TestLockOSThreadAvoidsStatePropagation(t *testing.T) {
	 980  	want := "OK\n"
	 981  	skip := "unshare not permitted\n"
	 982  	output := runTestProg(t, "testprog", "LockOSThreadAvoidsStatePropagation", "GOMAXPROCS=1")
	 983  	if output == skip {
	 984  		t.Skip("unshare syscall not permitted on this system")
	 985  	} else if output != want {
	 986  		t.Errorf("want %q, got %q", want, output)
	 987  	}
	 988  }
	 989  
	 990  func TestLockOSThreadTemplateThreadRace(t *testing.T) {
	 991  	testenv.MustHaveGoRun(t)
	 992  
	 993  	exe, err := buildTestProg(t, "testprog")
	 994  	if err != nil {
	 995  		t.Fatal(err)
	 996  	}
	 997  
	 998  	iterations := 100
	 999  	if testing.Short() {
	1000  		// Reduce run time to ~100ms, with much lower probability of
	1001  		// catching issues.
	1002  		iterations = 5
	1003  	}
	1004  	for i := 0; i < iterations; i++ {
	1005  		want := "OK\n"
	1006  		output := runBuiltTestProg(t, exe, "LockOSThreadTemplateThreadRace")
	1007  		if output != want {
	1008  			t.Fatalf("run %d: want %q, got %q", i, want, output)
	1009  		}
	1010  	}
	1011  }
	1012  
	1013  // fakeSyscall emulates a system call.
	1014  //go:nosplit
	1015  func fakeSyscall(duration time.Duration) {
	1016  	runtime.Entersyscall()
	1017  	for start := runtime.Nanotime(); runtime.Nanotime()-start < int64(duration); {
	1018  	}
	1019  	runtime.Exitsyscall()
	1020  }
	1021  
	1022  // Check that a goroutine will be preempted if it is calling short system calls.
	1023  func testPreemptionAfterSyscall(t *testing.T, syscallDuration time.Duration) {
	1024  	if runtime.GOARCH == "wasm" {
	1025  		t.Skip("no preemption on wasm yet")
	1026  	}
	1027  
	1028  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	1029  
	1030  	interations := 10
	1031  	if testing.Short() {
	1032  		interations = 1
	1033  	}
	1034  	const (
	1035  		maxDuration = 3 * time.Second
	1036  		nroutines	 = 8
	1037  	)
	1038  
	1039  	for i := 0; i < interations; i++ {
	1040  		c := make(chan bool, nroutines)
	1041  		stop := uint32(0)
	1042  
	1043  		start := time.Now()
	1044  		for g := 0; g < nroutines; g++ {
	1045  			go func(stop *uint32) {
	1046  				c <- true
	1047  				for atomic.LoadUint32(stop) == 0 {
	1048  					fakeSyscall(syscallDuration)
	1049  				}
	1050  				c <- true
	1051  			}(&stop)
	1052  		}
	1053  		// wait until all goroutines have started.
	1054  		for g := 0; g < nroutines; g++ {
	1055  			<-c
	1056  		}
	1057  		atomic.StoreUint32(&stop, 1)
	1058  		// wait until all goroutines have finished.
	1059  		for g := 0; g < nroutines; g++ {
	1060  			<-c
	1061  		}
	1062  		duration := time.Since(start)
	1063  
	1064  		if duration > maxDuration {
	1065  			t.Errorf("timeout exceeded: %v (%v)", duration, maxDuration)
	1066  		}
	1067  	}
	1068  }
	1069  
	1070  func TestPreemptionAfterSyscall(t *testing.T) {
	1071  	for _, i := range []time.Duration{10, 100, 1000} {
	1072  		d := i * time.Microsecond
	1073  		t.Run(fmt.Sprint(d), func(t *testing.T) {
	1074  			testPreemptionAfterSyscall(t, d)
	1075  		})
	1076  	}
	1077  }
	1078  
	1079  func TestGetgThreadSwitch(t *testing.T) {
	1080  	runtime.RunGetgThreadSwitchTest()
	1081  }
	1082  
	1083  // TestNetpollBreak tests that netpollBreak can break a netpoll.
	1084  // This test is not particularly safe since the call to netpoll
	1085  // will pick up any stray files that are ready, but it should work
	1086  // OK as long it is not run in parallel.
	1087  func TestNetpollBreak(t *testing.T) {
	1088  	if runtime.GOMAXPROCS(0) == 1 {
	1089  		t.Skip("skipping: GOMAXPROCS=1")
	1090  	}
	1091  
	1092  	// Make sure that netpoll is initialized.
	1093  	runtime.NetpollGenericInit()
	1094  
	1095  	start := time.Now()
	1096  	c := make(chan bool, 2)
	1097  	go func() {
	1098  		c <- true
	1099  		runtime.Netpoll(10 * time.Second.Nanoseconds())
	1100  		c <- true
	1101  	}()
	1102  	<-c
	1103  	// Loop because the break might get eaten by the scheduler.
	1104  	// Break twice to break both the netpoll we started and the
	1105  	// scheduler netpoll.
	1106  loop:
	1107  	for {
	1108  		runtime.Usleep(100)
	1109  		runtime.NetpollBreak()
	1110  		runtime.NetpollBreak()
	1111  		select {
	1112  		case <-c:
	1113  			break loop
	1114  		default:
	1115  		}
	1116  	}
	1117  	if dur := time.Since(start); dur > 5*time.Second {
	1118  		t.Errorf("netpollBreak did not interrupt netpoll: slept for: %v", dur)
	1119  	}
	1120  }
	1121  
	1122  // TestBigGOMAXPROCS tests that setting GOMAXPROCS to a large value
	1123  // doesn't cause a crash at startup. See issue 38474.
	1124  func TestBigGOMAXPROCS(t *testing.T) {
	1125  	t.Parallel()
	1126  	output := runTestProg(t, "testprog", "NonexistentTest", "GOMAXPROCS=1024")
	1127  	// Ignore error conditions on small machines.
	1128  	for _, errstr := range []string{
	1129  		"failed to create new OS thread",
	1130  		"cannot allocate memory",
	1131  	} {
	1132  		if strings.Contains(output, errstr) {
	1133  			t.Skipf("failed to create 1024 threads")
	1134  		}
	1135  	}
	1136  	if !strings.Contains(output, "unknown function: NonexistentTest") {
	1137  		t.Errorf("output:\n%s\nwanted:\nunknown function: NonexistentTest", output)
	1138  	}
	1139  }
	1140  

View as plain text