Source file
src/sync/rwmutex_test.go
1
2
3
4
5
6
7 package sync_test
8
9 import (
10 "fmt"
11 "runtime"
12 . "sync"
13 "sync/atomic"
14 "testing"
15 )
16
17
18
19
20 func parallelReader(m *RWMutex, clocked, cunlock, cdone chan bool) {
21 m.RLock()
22 clocked <- true
23 <-cunlock
24 m.RUnlock()
25 cdone <- true
26 }
27
28 func doTestParallelReaders(numReaders, gomaxprocs int) {
29 runtime.GOMAXPROCS(gomaxprocs)
30 var m RWMutex
31 clocked := make(chan bool)
32 cunlock := make(chan bool)
33 cdone := make(chan bool)
34 for i := 0; i < numReaders; i++ {
35 go parallelReader(&m, clocked, cunlock, cdone)
36 }
37
38 for i := 0; i < numReaders; i++ {
39 <-clocked
40 }
41 for i := 0; i < numReaders; i++ {
42 cunlock <- true
43 }
44
45 for i := 0; i < numReaders; i++ {
46 <-cdone
47 }
48 }
49
50 func TestParallelReaders(t *testing.T) {
51 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
52 doTestParallelReaders(1, 4)
53 doTestParallelReaders(3, 4)
54 doTestParallelReaders(4, 2)
55 }
56
57 func reader(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
58 for i := 0; i < num_iterations; i++ {
59 rwm.RLock()
60 n := atomic.AddInt32(activity, 1)
61 if n < 1 || n >= 10000 {
62 rwm.RUnlock()
63 panic(fmt.Sprintf("wlock(%d)\n", n))
64 }
65 for i := 0; i < 100; i++ {
66 }
67 atomic.AddInt32(activity, -1)
68 rwm.RUnlock()
69 }
70 cdone <- true
71 }
72
73 func writer(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) {
74 for i := 0; i < num_iterations; i++ {
75 rwm.Lock()
76 n := atomic.AddInt32(activity, 10000)
77 if n != 10000 {
78 rwm.Unlock()
79 panic(fmt.Sprintf("wlock(%d)\n", n))
80 }
81 for i := 0; i < 100; i++ {
82 }
83 atomic.AddInt32(activity, -10000)
84 rwm.Unlock()
85 }
86 cdone <- true
87 }
88
89 func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
90 runtime.GOMAXPROCS(gomaxprocs)
91
92 var activity int32
93 var rwm RWMutex
94 cdone := make(chan bool)
95 go writer(&rwm, num_iterations, &activity, cdone)
96 var i int
97 for i = 0; i < numReaders/2; i++ {
98 go reader(&rwm, num_iterations, &activity, cdone)
99 }
100 go writer(&rwm, num_iterations, &activity, cdone)
101 for ; i < numReaders; i++ {
102 go reader(&rwm, num_iterations, &activity, cdone)
103 }
104
105 for i := 0; i < 2+numReaders; i++ {
106 <-cdone
107 }
108 }
109
110 func TestRWMutex(t *testing.T) {
111 var m RWMutex
112
113 m.Lock()
114 if m.TryLock() {
115 t.Fatalf("TryLock succeeded with mutex locked")
116 }
117 if m.TryRLock() {
118 t.Fatalf("TryRLock succeeded with mutex locked")
119 }
120 m.Unlock()
121
122 if !m.TryLock() {
123 t.Fatalf("TryLock failed with mutex unlocked")
124 }
125 m.Unlock()
126
127 if !m.TryRLock() {
128 t.Fatalf("TryRLock failed with mutex unlocked")
129 }
130 if !m.TryRLock() {
131 t.Fatalf("TryRLock failed with mutex rlocked")
132 }
133 if m.TryLock() {
134 t.Fatalf("TryLock succeeded with mutex rlocked")
135 }
136 m.RUnlock()
137 m.RUnlock()
138
139 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
140 n := 1000
141 if testing.Short() {
142 n = 5
143 }
144 HammerRWMutex(1, 1, n)
145 HammerRWMutex(1, 3, n)
146 HammerRWMutex(1, 10, n)
147 HammerRWMutex(4, 1, n)
148 HammerRWMutex(4, 3, n)
149 HammerRWMutex(4, 10, n)
150 HammerRWMutex(10, 1, n)
151 HammerRWMutex(10, 3, n)
152 HammerRWMutex(10, 10, n)
153 HammerRWMutex(10, 5, n)
154 }
155
156 func TestRLocker(t *testing.T) {
157 var wl RWMutex
158 var rl Locker
159 wlocked := make(chan bool, 1)
160 rlocked := make(chan bool, 1)
161 rl = wl.RLocker()
162 n := 10
163 go func() {
164 for i := 0; i < n; i++ {
165 rl.Lock()
166 rl.Lock()
167 rlocked <- true
168 wl.Lock()
169 wlocked <- true
170 }
171 }()
172 for i := 0; i < n; i++ {
173 <-rlocked
174 rl.Unlock()
175 select {
176 case <-wlocked:
177 t.Fatal("RLocker() didn't read-lock it")
178 default:
179 }
180 rl.Unlock()
181 <-wlocked
182 select {
183 case <-rlocked:
184 t.Fatal("RLocker() didn't respect the write lock")
185 default:
186 }
187 wl.Unlock()
188 }
189 }
190
191 func BenchmarkRWMutexUncontended(b *testing.B) {
192 type PaddedRWMutex struct {
193 RWMutex
194 pad [32]uint32
195 }
196 b.RunParallel(func(pb *testing.PB) {
197 var rwm PaddedRWMutex
198 for pb.Next() {
199 rwm.RLock()
200 rwm.RLock()
201 rwm.RUnlock()
202 rwm.RUnlock()
203 rwm.Lock()
204 rwm.Unlock()
205 }
206 })
207 }
208
209 func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
210 var rwm RWMutex
211 b.RunParallel(func(pb *testing.PB) {
212 foo := 0
213 for pb.Next() {
214 foo++
215 if foo%writeRatio == 0 {
216 rwm.Lock()
217 rwm.Unlock()
218 } else {
219 rwm.RLock()
220 for i := 0; i != localWork; i += 1 {
221 foo *= 2
222 foo /= 2
223 }
224 rwm.RUnlock()
225 }
226 }
227 _ = foo
228 })
229 }
230
231 func BenchmarkRWMutexWrite100(b *testing.B) {
232 benchmarkRWMutex(b, 0, 100)
233 }
234
235 func BenchmarkRWMutexWrite10(b *testing.B) {
236 benchmarkRWMutex(b, 0, 10)
237 }
238
239 func BenchmarkRWMutexWorkWrite100(b *testing.B) {
240 benchmarkRWMutex(b, 100, 100)
241 }
242
243 func BenchmarkRWMutexWorkWrite10(b *testing.B) {
244 benchmarkRWMutex(b, 100, 10)
245 }
246
View as plain text