github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/lang/syncx/rwmutex_test.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package syncx 16 17 import ( 18 "fmt" 19 "sync" 20 "testing" 21 22 "github.com/bytedance/gopkg/lang/fastrand" 23 ) 24 25 func BenchmarkRWMutex100Read(b *testing.B) { 26 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 27 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 28 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 0) 29 }) 30 31 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 32 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 0) 33 }) 34 } 35 } 36 37 func BenchmarkRWMutex1Write99Read(b *testing.B) { 38 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 39 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 40 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 1) 41 }) 42 43 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 44 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 1) 45 }) 46 } 47 } 48 49 func BenchmarkRWMutex10Write90Read(b *testing.B) { 50 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 51 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 52 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 10) 53 }) 54 55 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 56 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 10) 57 }) 58 } 59 } 60 61 func BenchmarkRWMutex50Write50Read(b *testing.B) { 62 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 63 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 64 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 50) 65 }) 66 67 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 68 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 50) 69 }) 70 } 71 } 72 73 func benchmarkSyncRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) { 74 var res int // A mock resource we contention for 75 76 var mu sync.RWMutex 77 mu.Lock() 78 79 var wg sync.WaitGroup 80 wg.Add(nWorker) 81 82 n := b.N 83 quota := n / nWorker 84 85 for g := nWorker; g > 0; g-- { 86 // Comuse remaining quota 87 if g == 1 { 88 quota = n 89 } 90 go func(quota int) { 91 for i := 0; i < quota; i++ { 92 if fastrand.Intn(100) > nWrite-1 { 93 mu.RLock() 94 _ = res 95 mu.RUnlock() 96 } else { 97 mu.Lock() 98 res++ 99 mu.Unlock() 100 } 101 } 102 wg.Done() 103 }(quota) 104 105 n -= quota 106 } 107 108 if n != 0 { 109 b.Fatalf("Incorrect quota assignments: %v remaining", n) 110 } 111 112 b.ResetTimer() 113 mu.Unlock() 114 wg.Wait() 115 } 116 117 func benchmarkSyncxRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) { 118 var res int // A mock resource we contention for 119 120 mu := NewRWMutex() 121 mu.Lock() 122 123 var wg sync.WaitGroup 124 wg.Add(nWorker) 125 126 n := b.N 127 quota := n / nWorker 128 129 for g := nWorker; g > 0; g-- { 130 // Comuse remaining quota 131 if g == 1 { 132 quota = n 133 } 134 go func(quota int) { 135 rmu := mu.RLocker() 136 for i := 0; i < quota; i++ { 137 if fastrand.Intn(100) > nWrite-1 { 138 rmu.Lock() 139 _ = res 140 rmu.Unlock() 141 } else { 142 mu.Lock() 143 res++ 144 mu.Unlock() 145 } 146 } 147 wg.Done() 148 }(quota) 149 150 n -= quota 151 } 152 153 if n != 0 { 154 b.Fatalf("Incorrect quota assignments: %v remaining", n) 155 } 156 157 b.ResetTimer() 158 mu.Unlock() 159 wg.Wait() 160 }