github.com/songzhibin97/gkit@v1.2.13/sys/syncx/rwmutex_test.go (about) 1 package syncx 2 3 import ( 4 "fmt" 5 "github.com/songzhibin97/gkit/sys/fastrand" 6 "sync" 7 "testing" 8 ) 9 10 func BenchmarkRWMutex100Read(b *testing.B) { 11 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 12 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 13 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 0) 14 }) 15 16 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 17 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 0) 18 }) 19 } 20 } 21 22 func BenchmarkRWMutex1Write99Read(b *testing.B) { 23 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 24 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 25 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 1) 26 }) 27 28 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 29 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 1) 30 }) 31 } 32 } 33 34 func BenchmarkRWMutex10Write90Read(b *testing.B) { 35 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 36 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 37 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 10) 38 }) 39 40 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 41 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 10) 42 }) 43 } 44 } 45 46 func BenchmarkRWMutex50Write50Read(b *testing.B) { 47 for nWorker := 1; nWorker <= 256; nWorker <<= 2 { 48 b.Run(fmt.Sprintf("syncx-%d", nWorker), func(b *testing.B) { 49 benchmarkSyncxRWMutexNWriteNRead(b, nWorker, 50) 50 }) 51 52 b.Run(fmt.Sprintf("sync-%d", nWorker), func(b *testing.B) { 53 benchmarkSyncRWMutexNWriteNRead(b, nWorker, 50) 54 }) 55 } 56 } 57 58 func benchmarkSyncRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) { 59 var res int // A mock resource we contention for 60 61 var mu sync.RWMutex 62 mu.Lock() 63 64 var wg sync.WaitGroup 65 wg.Add(nWorker) 66 67 n := b.N 68 quota := n / nWorker 69 70 for g := nWorker; g > 0; g-- { 71 // Comuse remaining quota 72 if g == 1 { 73 quota = n 74 } 75 go func(quota int) { 76 for i := 0; i < quota; i++ { 77 if fastrand.Intn(100) > nWrite-1 { 78 mu.RLock() 79 _ = res 80 mu.RUnlock() 81 } else { 82 mu.Lock() 83 res++ 84 mu.Unlock() 85 } 86 } 87 wg.Done() 88 }(quota) 89 90 n -= quota 91 } 92 93 if n != 0 { 94 b.Fatalf("Incorrect quota assignments: %v remaining", n) 95 } 96 97 b.ResetTimer() 98 mu.Unlock() 99 wg.Wait() 100 } 101 102 func benchmarkSyncxRWMutexNWriteNRead(b *testing.B, nWorker, nWrite int) { 103 var res int // A mock resource we contention for 104 105 mu := NewRWMutex() 106 mu.Lock() 107 108 var wg sync.WaitGroup 109 wg.Add(nWorker) 110 111 n := b.N 112 quota := n / nWorker 113 114 for g := nWorker; g > 0; g-- { 115 // Comuse remaining quota 116 if g == 1 { 117 quota = n 118 } 119 go func(quota int) { 120 rmu := mu.RLocker() 121 for i := 0; i < quota; i++ { 122 if fastrand.Intn(100) > nWrite-1 { 123 rmu.Lock() 124 _ = res 125 rmu.Unlock() 126 } else { 127 mu.Lock() 128 res++ 129 mu.Unlock() 130 } 131 } 132 wg.Done() 133 }(quota) 134 135 n -= quota 136 } 137 138 if n != 0 { 139 b.Fatalf("Incorrect quota assignments: %v remaining", n) 140 } 141 142 b.ResetTimer() 143 mu.Unlock() 144 wg.Wait() 145 }