Source file
src/runtime/chan_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "internal/testenv"
9 "math"
10 "runtime"
11 "sync"
12 "sync/atomic"
13 "testing"
14 "time"
15 )
16
17 func TestChan(t *testing.T) {
18 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
19 N := 200
20 if testing.Short() {
21 N = 20
22 }
23 for chanCap := 0; chanCap < N; chanCap++ {
24 {
25
26 c := make(chan int, chanCap)
27 recv1 := false
28 go func() {
29 _ = <-c
30 recv1 = true
31 }()
32 recv2 := false
33 go func() {
34 _, _ = <-c
35 recv2 = true
36 }()
37 time.Sleep(time.Millisecond)
38 if recv1 || recv2 {
39 t.Fatalf("chan[%d]: receive from empty chan", chanCap)
40 }
41
42 select {
43 case _ = <-c:
44 t.Fatalf("chan[%d]: receive from empty chan", chanCap)
45 default:
46 }
47 select {
48 case _, _ = <-c:
49 t.Fatalf("chan[%d]: receive from empty chan", chanCap)
50 default:
51 }
52 c <- 0
53 c <- 0
54 }
55
56 {
57
58 c := make(chan int, chanCap)
59 for i := 0; i < chanCap; i++ {
60 c <- i
61 }
62 sent := uint32(0)
63 go func() {
64 c <- 0
65 atomic.StoreUint32(&sent, 1)
66 }()
67 time.Sleep(time.Millisecond)
68 if atomic.LoadUint32(&sent) != 0 {
69 t.Fatalf("chan[%d]: send to full chan", chanCap)
70 }
71
72 select {
73 case c <- 0:
74 t.Fatalf("chan[%d]: send to full chan", chanCap)
75 default:
76 }
77 <-c
78 }
79
80 {
81
82 c := make(chan int, chanCap)
83 for i := 0; i < chanCap; i++ {
84 c <- i
85 }
86 close(c)
87 for i := 0; i < chanCap; i++ {
88 v := <-c
89 if v != i {
90 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
91 }
92 }
93 if v := <-c; v != 0 {
94 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0)
95 }
96 if v, ok := <-c; v != 0 || ok {
97 t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false)
98 }
99 }
100
101 {
102
103 c := make(chan int, chanCap)
104 done := make(chan bool)
105 go func() {
106 v, ok := <-c
107 done <- v == 0 && ok == false
108 }()
109 time.Sleep(time.Millisecond)
110 close(c)
111 if !<-done {
112 t.Fatalf("chan[%d]: received non zero from closed chan", chanCap)
113 }
114 }
115
116 {
117
118
119 c := make(chan int, chanCap)
120 go func() {
121 for i := 0; i < 100; i++ {
122 c <- i
123 }
124 }()
125 for i := 0; i < 100; i++ {
126 v := <-c
127 if v != i {
128 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
129 }
130 }
131
132
133 go func() {
134 for i := 0; i < 100; i++ {
135 c <- i
136 }
137 }()
138 for i := 0; i < 100; i++ {
139 v, ok := <-c
140 if !ok {
141 t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i)
142 }
143 if v != i {
144 t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
145 }
146 }
147
148
149
150 const P = 4
151 const L = 1000
152 for p := 0; p < P; p++ {
153 go func() {
154 for i := 0; i < L; i++ {
155 c <- i
156 }
157 }()
158 }
159 done := make(chan map[int]int)
160 for p := 0; p < P; p++ {
161 go func() {
162 recv := make(map[int]int)
163 for i := 0; i < L; i++ {
164 v := <-c
165 recv[v] = recv[v] + 1
166 }
167 done <- recv
168 }()
169 }
170 recv := make(map[int]int)
171 for p := 0; p < P; p++ {
172 for k, v := range <-done {
173 recv[k] = recv[k] + v
174 }
175 }
176 if len(recv) != L {
177 t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L)
178 }
179 for _, v := range recv {
180 if v != P {
181 t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P)
182 }
183 }
184 }
185
186 {
187
188 c := make(chan int, chanCap)
189 if len(c) != 0 || cap(c) != chanCap {
190 t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c))
191 }
192 for i := 0; i < chanCap; i++ {
193 c <- i
194 }
195 if len(c) != chanCap || cap(c) != chanCap {
196 t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c))
197 }
198 }
199
200 }
201 }
202
203 func TestNonblockRecvRace(t *testing.T) {
204 n := 10000
205 if testing.Short() {
206 n = 100
207 }
208 for i := 0; i < n; i++ {
209 c := make(chan int, 1)
210 c <- 1
211 go func() {
212 select {
213 case <-c:
214 default:
215 t.Error("chan is not ready")
216 }
217 }()
218 close(c)
219 <-c
220 if t.Failed() {
221 return
222 }
223 }
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 func TestNonblockSelectRace(t *testing.T) {
241 n := 100000
242 if testing.Short() {
243 n = 1000
244 }
245 done := make(chan bool, 1)
246 for i := 0; i < n; i++ {
247 c1 := make(chan int, 1)
248 c2 := make(chan int, 1)
249 c1 <- 1
250 go func() {
251 select {
252 case <-c1:
253 case <-c2:
254 default:
255 done <- false
256 return
257 }
258 done <- true
259 }()
260 c2 <- 1
261 select {
262 case <-c1:
263 default:
264 }
265 if !<-done {
266 t.Fatal("no chan is ready")
267 }
268 }
269 }
270
271
272 func TestNonblockSelectRace2(t *testing.T) {
273 n := 100000
274 if testing.Short() {
275 n = 1000
276 }
277 done := make(chan bool, 1)
278 for i := 0; i < n; i++ {
279 c1 := make(chan int, 1)
280 c2 := make(chan int)
281 c1 <- 1
282 go func() {
283 select {
284 case <-c1:
285 case <-c2:
286 default:
287 done <- false
288 return
289 }
290 done <- true
291 }()
292 close(c2)
293 select {
294 case <-c1:
295 default:
296 }
297 if !<-done {
298 t.Fatal("no chan is ready")
299 }
300 }
301 }
302
303 func TestSelfSelect(t *testing.T) {
304
305
306 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
307 for _, chanCap := range []int{0, 10} {
308 var wg sync.WaitGroup
309 wg.Add(2)
310 c := make(chan int, chanCap)
311 for p := 0; p < 2; p++ {
312 go func() {
313 defer wg.Done()
314 for i := 0; i < 1000; i++ {
315 if p == 0 || i%2 == 0 {
316 select {
317 case c <- p:
318 case v := <-c:
319 if chanCap == 0 && v == p {
320 t.Errorf("self receive")
321 return
322 }
323 }
324 } else {
325 select {
326 case v := <-c:
327 if chanCap == 0 && v == p {
328 t.Errorf("self receive")
329 return
330 }
331 case c <- p:
332 }
333 }
334 }
335 }()
336 }
337 wg.Wait()
338 }
339 }
340
341 func TestSelectStress(t *testing.T) {
342 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10))
343 var c [4]chan int
344 c[0] = make(chan int)
345 c[1] = make(chan int)
346 c[2] = make(chan int, 2)
347 c[3] = make(chan int, 3)
348 N := int(1e5)
349 if testing.Short() {
350 N /= 10
351 }
352
353
354
355
356
357
358 var wg sync.WaitGroup
359 wg.Add(10)
360 for k := 0; k < 4; k++ {
361 go func() {
362 for i := 0; i < N; i++ {
363 c[k] <- 0
364 }
365 wg.Done()
366 }()
367 go func() {
368 for i := 0; i < N; i++ {
369 <-c[k]
370 }
371 wg.Done()
372 }()
373 }
374 go func() {
375 var n [4]int
376 c1 := c
377 for i := 0; i < 4*N; i++ {
378 select {
379 case c1[3] <- 0:
380 n[3]++
381 if n[3] == N {
382 c1[3] = nil
383 }
384 case c1[2] <- 0:
385 n[2]++
386 if n[2] == N {
387 c1[2] = nil
388 }
389 case c1[0] <- 0:
390 n[0]++
391 if n[0] == N {
392 c1[0] = nil
393 }
394 case c1[1] <- 0:
395 n[1]++
396 if n[1] == N {
397 c1[1] = nil
398 }
399 }
400 }
401 wg.Done()
402 }()
403 go func() {
404 var n [4]int
405 c1 := c
406 for i := 0; i < 4*N; i++ {
407 select {
408 case <-c1[0]:
409 n[0]++
410 if n[0] == N {
411 c1[0] = nil
412 }
413 case <-c1[1]:
414 n[1]++
415 if n[1] == N {
416 c1[1] = nil
417 }
418 case <-c1[2]:
419 n[2]++
420 if n[2] == N {
421 c1[2] = nil
422 }
423 case <-c1[3]:
424 n[3]++
425 if n[3] == N {
426 c1[3] = nil
427 }
428 }
429 }
430 wg.Done()
431 }()
432 wg.Wait()
433 }
434
435 func TestSelectFairness(t *testing.T) {
436 const trials = 10000
437 if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
438 testenv.SkipFlaky(t, 22047)
439 }
440 c1 := make(chan byte, trials+1)
441 c2 := make(chan byte, trials+1)
442 for i := 0; i < trials+1; i++ {
443 c1 <- 1
444 c2 <- 2
445 }
446 c3 := make(chan byte)
447 c4 := make(chan byte)
448 out := make(chan byte)
449 done := make(chan byte)
450 var wg sync.WaitGroup
451 wg.Add(1)
452 go func() {
453 defer wg.Done()
454 for {
455 var b byte
456 select {
457 case b = <-c3:
458 case b = <-c4:
459 case b = <-c1:
460 case b = <-c2:
461 }
462 select {
463 case out <- b:
464 case <-done:
465 return
466 }
467 }
468 }()
469 cnt1, cnt2 := 0, 0
470 for i := 0; i < trials; i++ {
471 switch b := <-out; b {
472 case 1:
473 cnt1++
474 case 2:
475 cnt2++
476 default:
477 t.Fatalf("unexpected value %d on channel", b)
478 }
479 }
480
481
482
483
484
485 const mean = trials * 0.5
486 const variance = trials * 0.5 * (1 - 0.5)
487 stddev := math.Sqrt(variance)
488 if math.Abs(float64(cnt1-mean)) > 10*stddev {
489 t.Errorf("unfair select: in %d trials, results were %d, %d", trials, cnt1, cnt2)
490 }
491 close(done)
492 wg.Wait()
493 }
494
495 func TestChanSendInterface(t *testing.T) {
496 type mt struct{}
497 m := &mt{}
498 c := make(chan any, 1)
499 c <- m
500 select {
501 case c <- m:
502 default:
503 }
504 select {
505 case c <- m:
506 case c <- &mt{}:
507 default:
508 }
509 }
510
511 func TestPseudoRandomSend(t *testing.T) {
512 n := 100
513 for _, chanCap := range []int{0, n} {
514 c := make(chan int, chanCap)
515 l := make([]int, n)
516 var m sync.Mutex
517 m.Lock()
518 go func() {
519 for i := 0; i < n; i++ {
520 runtime.Gosched()
521 l[i] = <-c
522 }
523 m.Unlock()
524 }()
525 for i := 0; i < n; i++ {
526 select {
527 case c <- 1:
528 case c <- 0:
529 }
530 }
531 m.Lock()
532 n0 := 0
533 n1 := 0
534 for _, i := range l {
535 n0 += (i + 1) % 2
536 n1 += i
537 }
538 if n0 <= n/10 || n1 <= n/10 {
539 t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap)
540 }
541 }
542 }
543
544 func TestMultiConsumer(t *testing.T) {
545 const nwork = 23
546 const niter = 271828
547
548 pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31}
549
550 q := make(chan int, nwork*3)
551 r := make(chan int, nwork*3)
552
553
554 var wg sync.WaitGroup
555 for i := 0; i < nwork; i++ {
556 wg.Add(1)
557 go func(w int) {
558 for v := range q {
559
560 if pn[w%len(pn)] == v {
561 runtime.Gosched()
562 }
563 r <- v
564 }
565 wg.Done()
566 }(i)
567 }
568
569
570 expect := 0
571 go func() {
572 for i := 0; i < niter; i++ {
573 v := pn[i%len(pn)]
574 expect += v
575 q <- v
576 }
577 close(q)
578 wg.Wait()
579 close(r)
580 }()
581
582
583 n := 0
584 s := 0
585 for v := range r {
586 n++
587 s += v
588 }
589 if n != niter || s != expect {
590 t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)",
591 expect, s, niter, n)
592 }
593 }
594
595 func TestShrinkStackDuringBlockedSend(t *testing.T) {
596
597
598
599
600 const n = 10
601 c := make(chan int)
602 done := make(chan struct{})
603
604 go func() {
605 for i := 0; i < n; i++ {
606 c <- i
607
608 stackGrowthRecursive(20)
609 }
610 done <- struct{}{}
611 }()
612
613 for i := 0; i < n; i++ {
614 x := <-c
615 if x != i {
616 t.Errorf("bad channel read: want %d, got %d", i, x)
617 }
618
619
620 time.Sleep(1 * time.Millisecond)
621
622 runtime.GC()
623 }
624 <-done
625 }
626
627 func TestNoShrinkStackWhileParking(t *testing.T) {
628 if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm64" {
629 testenv.SkipFlaky(t, 49382)
630 }
631 if runtime.GOOS == "openbsd" {
632 testenv.SkipFlaky(t, 51482)
633 }
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652 const n = 10
653 send := func(c chan<- int, done chan struct{}) {
654 for i := 0; i < n; i++ {
655 c <- i
656
657
658
659
660
661
662 stackGrowthRecursive(20)
663 }
664 done <- struct{}{}
665 }
666 recv := func(c <-chan int, done chan struct{}) {
667 for i := 0; i < n; i++ {
668
669
670 time.Sleep(10 * time.Microsecond)
671 <-c
672 }
673 done <- struct{}{}
674 }
675 for i := 0; i < n*20; i++ {
676 c := make(chan int)
677 done := make(chan struct{})
678 go recv(c, done)
679 go send(c, done)
680
681
682
683 time.Sleep(50 * time.Microsecond)
684 runtime.GC()
685 <-done
686 <-done
687 }
688 }
689
690 func TestSelectDuplicateChannel(t *testing.T) {
691
692
693 c := make(chan int)
694 d := make(chan int)
695 e := make(chan int)
696
697
698 go func() {
699 select {
700 case <-c:
701 case <-c:
702 case <-d:
703 }
704 e <- 9
705 }()
706 time.Sleep(time.Millisecond)
707
708
709 go func() {
710 <-c
711 }()
712 time.Sleep(time.Millisecond)
713
714 d <- 7
715 <-e
716 c <- 8
717 }
718
719 func TestSelectStackAdjust(t *testing.T) {
720
721
722 c := make(chan *int)
723 d := make(chan *int)
724 ready1 := make(chan bool)
725 ready2 := make(chan bool)
726
727 f := func(ready chan bool, dup bool) {
728
729 stackGrowthRecursive((10 << 10) / (128 * 8))
730
731
732 ready <- true
733
734 val := 42
735 var cx *int
736 cx = &val
737
738 var c2 chan *int
739 var d2 chan *int
740 if dup {
741 c2 = c
742 d2 = d
743 }
744
745
746 select {
747 case cx = <-c:
748 case <-c2:
749 case <-d:
750 case <-d2:
751 }
752
753
754 if cx != &val {
755 t.Error("cx no longer points to val")
756 } else if val != 42 {
757 t.Error("val changed")
758 } else {
759 *cx = 43
760 if val != 43 {
761 t.Error("changing *cx failed to change val")
762 }
763 }
764 ready <- true
765 }
766
767 go f(ready1, false)
768 go f(ready2, true)
769
770
771 <-ready1
772 <-ready2
773 time.Sleep(10 * time.Millisecond)
774
775
776 runtime.GC()
777
778
779 close(d)
780 <-ready1
781 <-ready2
782 }
783
784 type struct0 struct{}
785
786 func BenchmarkMakeChan(b *testing.B) {
787 b.Run("Byte", func(b *testing.B) {
788 var x chan byte
789 for i := 0; i < b.N; i++ {
790 x = make(chan byte, 8)
791 }
792 close(x)
793 })
794 b.Run("Int", func(b *testing.B) {
795 var x chan int
796 for i := 0; i < b.N; i++ {
797 x = make(chan int, 8)
798 }
799 close(x)
800 })
801 b.Run("Ptr", func(b *testing.B) {
802 var x chan *byte
803 for i := 0; i < b.N; i++ {
804 x = make(chan *byte, 8)
805 }
806 close(x)
807 })
808 b.Run("Struct", func(b *testing.B) {
809 b.Run("0", func(b *testing.B) {
810 var x chan struct0
811 for i := 0; i < b.N; i++ {
812 x = make(chan struct0, 8)
813 }
814 close(x)
815 })
816 b.Run("32", func(b *testing.B) {
817 var x chan struct32
818 for i := 0; i < b.N; i++ {
819 x = make(chan struct32, 8)
820 }
821 close(x)
822 })
823 b.Run("40", func(b *testing.B) {
824 var x chan struct40
825 for i := 0; i < b.N; i++ {
826 x = make(chan struct40, 8)
827 }
828 close(x)
829 })
830 })
831 }
832
833 func BenchmarkChanNonblocking(b *testing.B) {
834 myc := make(chan int)
835 b.RunParallel(func(pb *testing.PB) {
836 for pb.Next() {
837 select {
838 case <-myc:
839 default:
840 }
841 }
842 })
843 }
844
845 func BenchmarkSelectUncontended(b *testing.B) {
846 b.RunParallel(func(pb *testing.PB) {
847 myc1 := make(chan int, 1)
848 myc2 := make(chan int, 1)
849 myc1 <- 0
850 for pb.Next() {
851 select {
852 case <-myc1:
853 myc2 <- 0
854 case <-myc2:
855 myc1 <- 0
856 }
857 }
858 })
859 }
860
861 func BenchmarkSelectSyncContended(b *testing.B) {
862 myc1 := make(chan int)
863 myc2 := make(chan int)
864 myc3 := make(chan int)
865 done := make(chan int)
866 b.RunParallel(func(pb *testing.PB) {
867 go func() {
868 for {
869 select {
870 case myc1 <- 0:
871 case myc2 <- 0:
872 case myc3 <- 0:
873 case <-done:
874 return
875 }
876 }
877 }()
878 for pb.Next() {
879 select {
880 case <-myc1:
881 case <-myc2:
882 case <-myc3:
883 }
884 }
885 })
886 close(done)
887 }
888
889 func BenchmarkSelectAsyncContended(b *testing.B) {
890 procs := runtime.GOMAXPROCS(0)
891 myc1 := make(chan int, procs)
892 myc2 := make(chan int, procs)
893 b.RunParallel(func(pb *testing.PB) {
894 myc1 <- 0
895 for pb.Next() {
896 select {
897 case <-myc1:
898 myc2 <- 0
899 case <-myc2:
900 myc1 <- 0
901 }
902 }
903 })
904 }
905
906 func BenchmarkSelectNonblock(b *testing.B) {
907 myc1 := make(chan int)
908 myc2 := make(chan int)
909 myc3 := make(chan int, 1)
910 myc4 := make(chan int, 1)
911 b.RunParallel(func(pb *testing.PB) {
912 for pb.Next() {
913 select {
914 case <-myc1:
915 default:
916 }
917 select {
918 case myc2 <- 0:
919 default:
920 }
921 select {
922 case <-myc3:
923 default:
924 }
925 select {
926 case myc4 <- 0:
927 default:
928 }
929 }
930 })
931 }
932
933 func BenchmarkChanUncontended(b *testing.B) {
934 const C = 100
935 b.RunParallel(func(pb *testing.PB) {
936 myc := make(chan int, C)
937 for pb.Next() {
938 for i := 0; i < C; i++ {
939 myc <- 0
940 }
941 for i := 0; i < C; i++ {
942 <-myc
943 }
944 }
945 })
946 }
947
948 func BenchmarkChanContended(b *testing.B) {
949 const C = 100
950 myc := make(chan int, C*runtime.GOMAXPROCS(0))
951 b.RunParallel(func(pb *testing.PB) {
952 for pb.Next() {
953 for i := 0; i < C; i++ {
954 myc <- 0
955 }
956 for i := 0; i < C; i++ {
957 <-myc
958 }
959 }
960 })
961 }
962
963 func benchmarkChanSync(b *testing.B, work int) {
964 const CallsPerSched = 1000
965 procs := 2
966 N := int32(b.N / CallsPerSched / procs * procs)
967 c := make(chan bool, procs)
968 myc := make(chan int)
969 for p := 0; p < procs; p++ {
970 go func() {
971 for {
972 i := atomic.AddInt32(&N, -1)
973 if i < 0 {
974 break
975 }
976 for g := 0; g < CallsPerSched; g++ {
977 if i%2 == 0 {
978 <-myc
979 localWork(work)
980 myc <- 0
981 localWork(work)
982 } else {
983 myc <- 0
984 localWork(work)
985 <-myc
986 localWork(work)
987 }
988 }
989 }
990 c <- true
991 }()
992 }
993 for p := 0; p < procs; p++ {
994 <-c
995 }
996 }
997
998 func BenchmarkChanSync(b *testing.B) {
999 benchmarkChanSync(b, 0)
1000 }
1001
1002 func BenchmarkChanSyncWork(b *testing.B) {
1003 benchmarkChanSync(b, 1000)
1004 }
1005
1006 func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
1007 const CallsPerSched = 1000
1008 procs := runtime.GOMAXPROCS(-1)
1009 N := int32(b.N / CallsPerSched)
1010 c := make(chan bool, 2*procs)
1011 myc := make(chan int, chanSize)
1012 for p := 0; p < procs; p++ {
1013 go func() {
1014 foo := 0
1015 for atomic.AddInt32(&N, -1) >= 0 {
1016 for g := 0; g < CallsPerSched; g++ {
1017 for i := 0; i < localWork; i++ {
1018 foo *= 2
1019 foo /= 2
1020 }
1021 myc <- 1
1022 }
1023 }
1024 myc <- 0
1025 c <- foo == 42
1026 }()
1027 go func() {
1028 foo := 0
1029 for {
1030 v := <-myc
1031 if v == 0 {
1032 break
1033 }
1034 for i := 0; i < localWork; i++ {
1035 foo *= 2
1036 foo /= 2
1037 }
1038 }
1039 c <- foo == 42
1040 }()
1041 }
1042 for p := 0; p < procs; p++ {
1043 <-c
1044 <-c
1045 }
1046 }
1047
1048 func BenchmarkChanProdCons0(b *testing.B) {
1049 benchmarkChanProdCons(b, 0, 0)
1050 }
1051
1052 func BenchmarkChanProdCons10(b *testing.B) {
1053 benchmarkChanProdCons(b, 10, 0)
1054 }
1055
1056 func BenchmarkChanProdCons100(b *testing.B) {
1057 benchmarkChanProdCons(b, 100, 0)
1058 }
1059
1060 func BenchmarkChanProdConsWork0(b *testing.B) {
1061 benchmarkChanProdCons(b, 0, 100)
1062 }
1063
1064 func BenchmarkChanProdConsWork10(b *testing.B) {
1065 benchmarkChanProdCons(b, 10, 100)
1066 }
1067
1068 func BenchmarkChanProdConsWork100(b *testing.B) {
1069 benchmarkChanProdCons(b, 100, 100)
1070 }
1071
1072 func BenchmarkSelectProdCons(b *testing.B) {
1073 const CallsPerSched = 1000
1074 procs := runtime.GOMAXPROCS(-1)
1075 N := int32(b.N / CallsPerSched)
1076 c := make(chan bool, 2*procs)
1077 myc := make(chan int, 128)
1078 myclose := make(chan bool)
1079 for p := 0; p < procs; p++ {
1080 go func() {
1081
1082 foo := 0
1083
1084 mytimer := time.After(time.Hour)
1085 for atomic.AddInt32(&N, -1) >= 0 {
1086 for g := 0; g < CallsPerSched; g++ {
1087
1088 for i := 0; i < 100; i++ {
1089 foo *= 2
1090 foo /= 2
1091 }
1092 select {
1093 case myc <- 1:
1094 case <-mytimer:
1095 case <-myclose:
1096 }
1097 }
1098 }
1099 myc <- 0
1100 c <- foo == 42
1101 }()
1102 go func() {
1103
1104 foo := 0
1105
1106 mytimer := time.After(time.Hour)
1107 loop:
1108 for {
1109 select {
1110 case v := <-myc:
1111 if v == 0 {
1112 break loop
1113 }
1114 case <-mytimer:
1115 case <-myclose:
1116 }
1117
1118 for i := 0; i < 100; i++ {
1119 foo *= 2
1120 foo /= 2
1121 }
1122 }
1123 c <- foo == 42
1124 }()
1125 }
1126 for p := 0; p < procs; p++ {
1127 <-c
1128 <-c
1129 }
1130 }
1131
1132 func BenchmarkReceiveDataFromClosedChan(b *testing.B) {
1133 count := b.N
1134 ch := make(chan struct{}, count)
1135 for i := 0; i < count; i++ {
1136 ch <- struct{}{}
1137 }
1138 close(ch)
1139
1140 b.ResetTimer()
1141 for range ch {
1142 }
1143 }
1144
1145 func BenchmarkChanCreation(b *testing.B) {
1146 b.RunParallel(func(pb *testing.PB) {
1147 for pb.Next() {
1148 myc := make(chan int, 1)
1149 myc <- 0
1150 <-myc
1151 }
1152 })
1153 }
1154
1155 func BenchmarkChanSem(b *testing.B) {
1156 type Empty struct{}
1157 myc := make(chan Empty, runtime.GOMAXPROCS(0))
1158 b.RunParallel(func(pb *testing.PB) {
1159 for pb.Next() {
1160 myc <- Empty{}
1161 <-myc
1162 }
1163 })
1164 }
1165
1166 func BenchmarkChanPopular(b *testing.B) {
1167 const n = 1000
1168 c := make(chan bool)
1169 var a []chan bool
1170 var wg sync.WaitGroup
1171 wg.Add(n)
1172 for j := 0; j < n; j++ {
1173 d := make(chan bool)
1174 a = append(a, d)
1175 go func() {
1176 for i := 0; i < b.N; i++ {
1177 select {
1178 case <-c:
1179 case <-d:
1180 }
1181 }
1182 wg.Done()
1183 }()
1184 }
1185 for i := 0; i < b.N; i++ {
1186 for _, d := range a {
1187 d <- true
1188 }
1189 }
1190 wg.Wait()
1191 }
1192
1193 func BenchmarkChanClosed(b *testing.B) {
1194 c := make(chan struct{})
1195 close(c)
1196 b.RunParallel(func(pb *testing.PB) {
1197 for pb.Next() {
1198 select {
1199 case <-c:
1200 default:
1201 b.Error("Unreachable")
1202 }
1203 }
1204 })
1205 }
1206
1207 var (
1208 alwaysFalse = false
1209 workSink = 0
1210 )
1211
1212 func localWork(w int) {
1213 foo := 0
1214 for i := 0; i < w; i++ {
1215 foo /= (foo + 1)
1216 }
1217 if alwaysFalse {
1218 workSink += foo
1219 }
1220 }
1221
View as plain text