Source file
src/sync/waitgroup_test.go
1
2
3
4
5 package sync_test
6
7 import (
8 . "sync"
9 "sync/atomic"
10 "testing"
11 )
12
13 func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
14 n := 16
15 wg1.Add(n)
16 wg2.Add(n)
17 exited := make(chan bool, n)
18 for i := 0; i != n; i++ {
19 go func() {
20 wg1.Done()
21 wg2.Wait()
22 exited <- true
23 }()
24 }
25 wg1.Wait()
26 for i := 0; i != n; i++ {
27 select {
28 case <-exited:
29 t.Fatal("WaitGroup released group too soon")
30 default:
31 }
32 wg2.Done()
33 }
34 for i := 0; i != n; i++ {
35 <-exited
36 }
37 }
38
39 func TestWaitGroup(t *testing.T) {
40 wg1 := &WaitGroup{}
41 wg2 := &WaitGroup{}
42
43
44 for i := 0; i != 8; i++ {
45 testWaitGroup(t, wg1, wg2)
46 }
47 }
48
49 func TestWaitGroupMisuse(t *testing.T) {
50 defer func() {
51 err := recover()
52 if err != "sync: negative WaitGroup counter" {
53 t.Fatalf("Unexpected panic: %#v", err)
54 }
55 }()
56 wg := &WaitGroup{}
57 wg.Add(1)
58 wg.Done()
59 wg.Done()
60 t.Fatal("Should panic")
61 }
62
63 func TestWaitGroupRace(t *testing.T) {
64
65 for i := 0; i < 1000; i++ {
66 wg := &WaitGroup{}
67 n := new(int32)
68
69 wg.Add(1)
70 go func() {
71 atomic.AddInt32(n, 1)
72 wg.Done()
73 }()
74
75 wg.Add(1)
76 go func() {
77 atomic.AddInt32(n, 1)
78 wg.Done()
79 }()
80
81 wg.Wait()
82 if atomic.LoadInt32(n) != 2 {
83 t.Fatal("Spurious wakeup from Wait")
84 }
85 }
86 }
87
88 func TestWaitGroupAlign(t *testing.T) {
89 type X struct {
90 x byte
91 wg WaitGroup
92 }
93 var x X
94 x.wg.Add(1)
95 go func(x *X) {
96 x.wg.Done()
97 }(&x)
98 x.wg.Wait()
99 }
100
101 func BenchmarkWaitGroupUncontended(b *testing.B) {
102 type PaddedWaitGroup struct {
103 WaitGroup
104 pad [128]uint8
105 }
106 b.RunParallel(func(pb *testing.PB) {
107 var wg PaddedWaitGroup
108 for pb.Next() {
109 wg.Add(1)
110 wg.Done()
111 wg.Wait()
112 }
113 })
114 }
115
116 func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
117 var wg WaitGroup
118 b.RunParallel(func(pb *testing.PB) {
119 foo := 0
120 for pb.Next() {
121 wg.Add(1)
122 for i := 0; i < localWork; i++ {
123 foo *= 2
124 foo /= 2
125 }
126 wg.Done()
127 }
128 _ = foo
129 })
130 }
131
132 func BenchmarkWaitGroupAddDone(b *testing.B) {
133 benchmarkWaitGroupAddDone(b, 0)
134 }
135
136 func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
137 benchmarkWaitGroupAddDone(b, 100)
138 }
139
140 func benchmarkWaitGroupWait(b *testing.B, localWork int) {
141 var wg WaitGroup
142 b.RunParallel(func(pb *testing.PB) {
143 foo := 0
144 for pb.Next() {
145 wg.Wait()
146 for i := 0; i < localWork; i++ {
147 foo *= 2
148 foo /= 2
149 }
150 }
151 _ = foo
152 })
153 }
154
155 func BenchmarkWaitGroupWait(b *testing.B) {
156 benchmarkWaitGroupWait(b, 0)
157 }
158
159 func BenchmarkWaitGroupWaitWork(b *testing.B) {
160 benchmarkWaitGroupWait(b, 100)
161 }
162
163 func BenchmarkWaitGroupActuallyWait(b *testing.B) {
164 b.ReportAllocs()
165 b.RunParallel(func(pb *testing.PB) {
166 for pb.Next() {
167 var wg WaitGroup
168 wg.Add(1)
169 go func() {
170 wg.Done()
171 }()
172 wg.Wait()
173 }
174 })
175 }
176
View as plain text