github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/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 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1)) 112 n := 1000 113 if testing.Short() { 114 n = 5 115 } 116 HammerRWMutex(1, 1, n) 117 HammerRWMutex(1, 3, n) 118 HammerRWMutex(1, 10, n) 119 HammerRWMutex(4, 1, n) 120 HammerRWMutex(4, 3, n) 121 HammerRWMutex(4, 10, n) 122 HammerRWMutex(10, 1, n) 123 HammerRWMutex(10, 3, n) 124 HammerRWMutex(10, 10, n) 125 HammerRWMutex(10, 5, n) 126 } 127 128 func TestRLocker(t *testing.T) { 129 var wl RWMutex 130 var rl Locker 131 wlocked := make(chan bool, 1) 132 rlocked := make(chan bool, 1) 133 rl = wl.RLocker() 134 n := 10 135 go func() { 136 for i := 0; i < n; i++ { 137 rl.Lock() 138 rl.Lock() 139 rlocked <- true 140 wl.Lock() 141 wlocked <- true 142 } 143 }() 144 for i := 0; i < n; i++ { 145 <-rlocked 146 rl.Unlock() 147 select { 148 case <-wlocked: 149 t.Fatal("RLocker() didn't read-lock it") 150 default: 151 } 152 rl.Unlock() 153 <-wlocked 154 select { 155 case <-rlocked: 156 t.Fatal("RLocker() didn't respect the write lock") 157 default: 158 } 159 wl.Unlock() 160 } 161 } 162 163 func BenchmarkRWMutexUncontended(b *testing.B) { 164 type PaddedRWMutex struct { 165 RWMutex 166 pad [32]uint32 167 } 168 b.RunParallel(func(pb *testing.PB) { 169 var rwm PaddedRWMutex 170 for pb.Next() { 171 rwm.RLock() 172 rwm.RLock() 173 rwm.RUnlock() 174 rwm.RUnlock() 175 rwm.Lock() 176 rwm.Unlock() 177 } 178 }) 179 } 180 181 func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) { 182 var rwm RWMutex 183 b.RunParallel(func(pb *testing.PB) { 184 foo := 0 185 for pb.Next() { 186 foo++ 187 if foo%writeRatio == 0 { 188 rwm.Lock() 189 rwm.Unlock() 190 } else { 191 rwm.RLock() 192 for i := 0; i != localWork; i += 1 { 193 foo *= 2 194 foo /= 2 195 } 196 rwm.RUnlock() 197 } 198 } 199 _ = foo 200 }) 201 } 202 203 func BenchmarkRWMutexWrite100(b *testing.B) { 204 benchmarkRWMutex(b, 0, 100) 205 } 206 207 func BenchmarkRWMutexWrite10(b *testing.B) { 208 benchmarkRWMutex(b, 0, 10) 209 } 210 211 func BenchmarkRWMutexWorkWrite100(b *testing.B) { 212 benchmarkRWMutex(b, 100, 100) 213 } 214 215 func BenchmarkRWMutexWorkWrite10(b *testing.B) { 216 benchmarkRWMutex(b, 100, 10) 217 }