github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/runtime/rwmutex_test.go (about) 1 // Copyright 2017 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 // This is a copy of sync/rwmutex_test.go rewritten to test the 8 // runtime rwmutex. 9 10 package runtime_test 11 12 import ( 13 "fmt" 14 . "runtime" 15 "runtime/debug" 16 "sync/atomic" 17 "testing" 18 ) 19 20 func parallelReader(m *RWMutex, clocked chan bool, cunlock *uint32, cdone chan bool) { 21 m.RLock() 22 clocked <- true 23 for atomic.LoadUint32(cunlock) == 0 { 24 } 25 m.RUnlock() 26 cdone <- true 27 } 28 29 func doTestParallelReaders(numReaders int) { 30 GOMAXPROCS(numReaders + 1) 31 var m RWMutex 32 clocked := make(chan bool, numReaders) 33 var cunlock uint32 34 cdone := make(chan bool) 35 for i := 0; i < numReaders; i++ { 36 go parallelReader(&m, clocked, &cunlock, cdone) 37 } 38 // Wait for all parallel RLock()s to succeed. 39 for i := 0; i < numReaders; i++ { 40 <-clocked 41 } 42 atomic.StoreUint32(&cunlock, 1) 43 // Wait for the goroutines to finish. 44 for i := 0; i < numReaders; i++ { 45 <-cdone 46 } 47 } 48 49 func TestParallelRWMutexReaders(t *testing.T) { 50 if GOARCH == "wasm" { 51 t.Skip("wasm has no threads yet") 52 } 53 defer GOMAXPROCS(GOMAXPROCS(-1)) 54 // If runtime triggers a forced GC during this test then it will deadlock, 55 // since the goroutines can't be stopped/preempted. 56 // Disable GC for this test (see issue #10958). 57 defer debug.SetGCPercent(debug.SetGCPercent(-1)) 58 doTestParallelReaders(1) 59 doTestParallelReaders(3) 60 doTestParallelReaders(4) 61 } 62 63 func reader(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) { 64 for i := 0; i < num_iterations; i++ { 65 rwm.RLock() 66 n := atomic.AddInt32(activity, 1) 67 if n < 1 || n >= 10000 { 68 panic(fmt.Sprintf("wlock(%d)\n", n)) 69 } 70 for i := 0; i < 100; i++ { 71 } 72 atomic.AddInt32(activity, -1) 73 rwm.RUnlock() 74 } 75 cdone <- true 76 } 77 78 func writer(rwm *RWMutex, num_iterations int, activity *int32, cdone chan bool) { 79 for i := 0; i < num_iterations; i++ { 80 rwm.Lock() 81 n := atomic.AddInt32(activity, 10000) 82 if n != 10000 { 83 panic(fmt.Sprintf("wlock(%d)\n", n)) 84 } 85 for i := 0; i < 100; i++ { 86 } 87 atomic.AddInt32(activity, -10000) 88 rwm.Unlock() 89 } 90 cdone <- true 91 } 92 93 func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) { 94 GOMAXPROCS(gomaxprocs) 95 // Number of active readers + 10000 * number of active writers. 96 var activity int32 97 var rwm RWMutex 98 cdone := make(chan bool) 99 go writer(&rwm, num_iterations, &activity, cdone) 100 var i int 101 for i = 0; i < numReaders/2; i++ { 102 go reader(&rwm, num_iterations, &activity, cdone) 103 } 104 go writer(&rwm, num_iterations, &activity, cdone) 105 for ; i < numReaders; i++ { 106 go reader(&rwm, num_iterations, &activity, cdone) 107 } 108 // Wait for the 2 writers and all readers to finish. 109 for i := 0; i < 2+numReaders; i++ { 110 <-cdone 111 } 112 } 113 114 func TestRWMutex(t *testing.T) { 115 defer GOMAXPROCS(GOMAXPROCS(-1)) 116 n := 1000 117 if testing.Short() { 118 n = 5 119 } 120 HammerRWMutex(1, 1, n) 121 HammerRWMutex(1, 3, n) 122 HammerRWMutex(1, 10, n) 123 HammerRWMutex(4, 1, n) 124 HammerRWMutex(4, 3, n) 125 HammerRWMutex(4, 10, n) 126 HammerRWMutex(10, 1, n) 127 HammerRWMutex(10, 3, n) 128 HammerRWMutex(10, 10, n) 129 HammerRWMutex(10, 5, n) 130 } 131 132 func BenchmarkRWMutexUncontended(b *testing.B) { 133 type PaddedRWMutex struct { 134 RWMutex 135 pad [32]uint32 136 } 137 b.RunParallel(func(pb *testing.PB) { 138 var rwm PaddedRWMutex 139 for pb.Next() { 140 rwm.RLock() 141 rwm.RLock() 142 rwm.RUnlock() 143 rwm.RUnlock() 144 rwm.Lock() 145 rwm.Unlock() 146 } 147 }) 148 } 149 150 func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) { 151 var rwm RWMutex 152 b.RunParallel(func(pb *testing.PB) { 153 foo := 0 154 for pb.Next() { 155 foo++ 156 if foo%writeRatio == 0 { 157 rwm.Lock() 158 rwm.Unlock() 159 } else { 160 rwm.RLock() 161 for i := 0; i != localWork; i += 1 { 162 foo *= 2 163 foo /= 2 164 } 165 rwm.RUnlock() 166 } 167 } 168 _ = foo 169 }) 170 } 171 172 func BenchmarkRWMutexWrite100(b *testing.B) { 173 benchmarkRWMutex(b, 0, 100) 174 } 175 176 func BenchmarkRWMutexWrite10(b *testing.B) { 177 benchmarkRWMutex(b, 0, 10) 178 } 179 180 func BenchmarkRWMutexWorkWrite100(b *testing.B) { 181 benchmarkRWMutex(b, 100, 100) 182 } 183 184 func BenchmarkRWMutexWorkWrite10(b *testing.B) { 185 benchmarkRWMutex(b, 100, 10) 186 }