github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/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 func parallelReader(m *RWMutex, clocked, cunlock, cdone chan bool) { 18 m.RLock() 19 clocked <- true 20 <-cunlock 21 m.RUnlock() 22 cdone <- true 23 } 24 25 func doTestParallelReaders(numReaders, gomaxprocs int) { 26 runtime.GOMAXPROCS(gomaxprocs) 27 var m RWMutex 28 clocked := make(chan bool) 29 cunlock := make(chan bool) 30 cdone := make(chan bool) 31 for i := 0; i < numReaders; i++ { 32 go parallelReader(&m, clocked, cunlock, cdone) 33 } 34 // Wait for all parallel RLock()s to succeed. 35 for i := 0; i < numReaders; i++ { 36 <-clocked 37 } 38 for i := 0; i < numReaders; i++ { 39 cunlock <- true 40 } 41 // Wait for the goroutines to finish. 42 for i := 0; i < numReaders; i++ { 43 <-cdone 44 } 45 } 46 47 func TestParallelReaders(t *testing.T) { 48 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1)) 49 doTestParallelReaders(1, 4) 50 doTestParallelReaders(3, 4) 51 doTestParallelReaders(4, 2) 52 } 53 54 func reader(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) { 55 for i := 0; i < num_iterations; i++ { 56 rwm.RLock() 57 n := atomic.AddInt32(activity, 1) 58 if n < 1 || n >= 10000 { 59 panic(fmt.Sprintf("wlock(%d)\n", n)) 60 } 61 for i := 0; i < 100; i++ { 62 } 63 atomic.AddInt32(activity, -1) 64 rwm.RUnlock() 65 } 66 cdone <- true 67 } 68 69 func writer(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) { 70 for i := 0; i < num_iterations; i++ { 71 rwm.Lock() 72 n := atomic.AddInt32(activity, 10000) 73 if n != 10000 { 74 panic(fmt.Sprintf("wlock(%d)\n", n)) 75 } 76 for i := 0; i < 100; i++ { 77 } 78 atomic.AddInt32(activity, -10000) 79 rwm.Unlock() 80 } 81 cdone <- true 82 } 83 84 func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) { 85 runtime.GOMAXPROCS(gomaxprocs) 86 // Number of active readers + 10000 * number of active writers. 87 var activity int32 88 var rwm RWMutex 89 cdone := make(chan bool) 90 go writer(&rwm, num_iterations, &activity, cdone) 91 var i int 92 for i = 0; i < numReaders/2; i++ { 93 go reader(&rwm, num_iterations, &activity, cdone) 94 } 95 go writer(&rwm, num_iterations, &activity, cdone) 96 for ; i < numReaders; i++ { 97 go reader(&rwm, num_iterations, &activity, cdone) 98 } 99 // Wait for the 2 writers and all readers to finish. 100 for i := 0; i < 2+numReaders; i++ { 101 <-cdone 102 } 103 } 104 105 func TestRWMutex(t *testing.T) { 106 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1)) 107 n := 1000 108 if testing.Short() { 109 n = 5 110 } 111 HammerRWMutex(1, 1, n) 112 HammerRWMutex(1, 3, n) 113 HammerRWMutex(1, 10, n) 114 HammerRWMutex(4, 1, n) 115 HammerRWMutex(4, 3, n) 116 HammerRWMutex(4, 10, n) 117 HammerRWMutex(10, 1, n) 118 HammerRWMutex(10, 3, n) 119 HammerRWMutex(10, 10, n) 120 HammerRWMutex(10, 5, n) 121 } 122 123 func TestRLocker(t *testing.T) { 124 var wl RWMutex 125 var rl Locker 126 wlocked := make(chan bool, 1) 127 rlocked := make(chan bool, 1) 128 rl = wl.RLocker() 129 n := 10 130 go func() { 131 for i := 0; i < n; i++ { 132 rl.Lock() 133 rl.Lock() 134 rlocked <- true 135 wl.Lock() 136 wlocked <- true 137 } 138 }() 139 for i := 0; i < n; i++ { 140 <-rlocked 141 rl.Unlock() 142 select { 143 case <-wlocked: 144 t.Fatal("RLocker() didn't read-lock it") 145 default: 146 } 147 rl.Unlock() 148 <-wlocked 149 select { 150 case <-rlocked: 151 t.Fatal("RLocker() didn't respect the write lock") 152 default: 153 } 154 wl.Unlock() 155 } 156 } 157 158 func BenchmarkRWMutexUncontended(b *testing.B) { 159 type PaddedRWMutex struct { 160 RWMutex 161 pad [32]uint32 162 } 163 b.RunParallel(func(pb *testing.PB) { 164 var rwm PaddedRWMutex 165 for pb.Next() { 166 rwm.RLock() 167 rwm.RLock() 168 rwm.RUnlock() 169 rwm.RUnlock() 170 rwm.Lock() 171 rwm.Unlock() 172 } 173 }) 174 } 175 176 func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) { 177 var rwm RWMutex 178 b.RunParallel(func(pb *testing.PB) { 179 foo := 0 180 for pb.Next() { 181 foo++ 182 if foo%writeRatio == 0 { 183 rwm.Lock() 184 rwm.Unlock() 185 } else { 186 rwm.RLock() 187 for i := 0; i != localWork; i += 1 { 188 foo *= 2 189 foo /= 2 190 } 191 rwm.RUnlock() 192 } 193 } 194 _ = foo 195 }) 196 } 197 198 func BenchmarkRWMutexWrite100(b *testing.B) { 199 benchmarkRWMutex(b, 0, 100) 200 } 201 202 func BenchmarkRWMutexWrite10(b *testing.B) { 203 benchmarkRWMutex(b, 0, 10) 204 } 205 206 func BenchmarkRWMutexWorkWrite100(b *testing.B) { 207 benchmarkRWMutex(b, 100, 100) 208 } 209 210 func BenchmarkRWMutexWorkWrite10(b *testing.B) { 211 benchmarkRWMutex(b, 100, 10) 212 }