blob: 4ded218d2d8d0c27e9efe6953f69d83e79b1ac67 [file] [log] [blame]
Brent Austinba3052e2015-04-21 16:08:23 -07001// 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
5package sync_test
6
7import (
8 . "sync"
9 "sync/atomic"
10 "testing"
11)
12
13func 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++ {
Dan Willemsend2797482017-07-26 13:13:13 -070019 go func() {
Brent Austinba3052e2015-04-21 16:08:23 -070020 wg1.Done()
21 wg2.Wait()
22 exited <- true
Dan Willemsend2797482017-07-26 13:13:13 -070023 }()
Brent Austinba3052e2015-04-21 16:08:23 -070024 }
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 // Will block if barrier fails to unlock someone.
36 }
37}
38
39func TestWaitGroup(t *testing.T) {
40 wg1 := &WaitGroup{}
41 wg2 := &WaitGroup{}
42
43 // Run the same test a few times to ensure barrier is in a proper state.
44 for i := 0; i != 8; i++ {
45 testWaitGroup(t, wg1, wg2)
46 }
47}
48
49func 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
63func TestWaitGroupRace(t *testing.T) {
64 // Run this test for about 1ms.
65 for i := 0; i < 1000; i++ {
66 wg := &WaitGroup{}
67 n := new(int32)
68 // spawn goroutine 1
69 wg.Add(1)
70 go func() {
71 atomic.AddInt32(n, 1)
72 wg.Done()
73 }()
74 // spawn goroutine 2
75 wg.Add(1)
76 go func() {
77 atomic.AddInt32(n, 1)
78 wg.Done()
79 }()
80 // Wait for goroutine 1 and 2
81 wg.Wait()
82 if atomic.LoadInt32(n) != 2 {
83 t.Fatal("Spurious wakeup from Wait")
84 }
85 }
86}
87
Dan Willemsen09eb3b12015-09-16 14:34:17 -070088func 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
Brent Austinba3052e2015-04-21 16:08:23 -0700101func 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
116func 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
132func BenchmarkWaitGroupAddDone(b *testing.B) {
133 benchmarkWaitGroupAddDone(b, 0)
134}
135
136func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
137 benchmarkWaitGroupAddDone(b, 100)
138}
139
140func 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
155func BenchmarkWaitGroupWait(b *testing.B) {
156 benchmarkWaitGroupWait(b, 0)
157}
158
159func BenchmarkWaitGroupWaitWork(b *testing.B) {
160 benchmarkWaitGroupWait(b, 100)
161}
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700162
163func 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}