github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/sync/rwmutex_test.go (about) 1 // Copyright 2009 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 // GOMAXPROCS=10 go test 6 7 package sync_test 8 9 import ( 10 "fmt" 11 "runtime" 12 . "sync" 13 "sync/atomic" 14 "testing" 15 ) 16 17 // There is a modified copy of this file in runtime/rwmutex_test.go. 18 // If you make any changes here, see if you should make them there. 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 // Wait for all parallel RLock()s to succeed. 38 for i := 0; i < numReaders; i++ { 39 <-clocked 40 } 41 for i := 0; i < numReaders; i++ { 42 cunlock <- true 43 } 44 // Wait for the goroutines to finish. 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 // Number of active readers + 10000 * number of active writers. 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 // Wait for the 2 writers and all readers to finish. 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 }