github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/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 const CallsPerSched = 1000 164 procs := runtime.GOMAXPROCS(-1) 165 N := int32(b.N / CallsPerSched) 166 c := make(chan bool, procs) 167 for p := 0; p < procs; p++ { 168 go func() { 169 var rwm PaddedRWMutex 170 for atomic.AddInt32(&N, -1) >= 0 { 171 runtime.Gosched() 172 for g := 0; g < CallsPerSched; g++ { 173 rwm.RLock() 174 rwm.RLock() 175 rwm.RUnlock() 176 rwm.RUnlock() 177 rwm.Lock() 178 rwm.Unlock() 179 } 180 } 181 c <- true 182 }() 183 } 184 for p := 0; p < procs; p++ { 185 <-c 186 } 187 } 188 189 func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) { 190 const CallsPerSched = 1000 191 procs := runtime.GOMAXPROCS(-1) 192 N := int32(b.N / CallsPerSched) 193 c := make(chan bool, procs) 194 var rwm RWMutex 195 for p := 0; p < procs; p++ { 196 go func() { 197 foo := 0 198 for atomic.AddInt32(&N, -1) >= 0 { 199 runtime.Gosched() 200 for g := 0; g < CallsPerSched; g++ { 201 foo++ 202 if foo%writeRatio == 0 { 203 rwm.Lock() 204 rwm.Unlock() 205 } else { 206 rwm.RLock() 207 for i := 0; i != localWork; i += 1 { 208 foo *= 2 209 foo /= 2 210 } 211 rwm.RUnlock() 212 } 213 } 214 } 215 c <- foo == 42 216 }() 217 } 218 for p := 0; p < procs; p++ { 219 <-c 220 } 221 } 222 223 func BenchmarkRWMutexWrite100(b *testing.B) { 224 benchmarkRWMutex(b, 0, 100) 225 } 226 227 func BenchmarkRWMutexWrite10(b *testing.B) { 228 benchmarkRWMutex(b, 0, 10) 229 } 230 231 func BenchmarkRWMutexWorkWrite100(b *testing.B) { 232 benchmarkRWMutex(b, 100, 100) 233 } 234 235 func BenchmarkRWMutexWorkWrite10(b *testing.B) { 236 benchmarkRWMutex(b, 100, 10) 237 }