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