gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/benchmark/primitives/syncmap_test.go (about) 1 /* 2 * 3 * Copyright 2019 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package primitives_test 19 20 import ( 21 "sync" 22 "sync/atomic" 23 "testing" 24 ) 25 26 type incrementUint64Map interface { 27 increment(string) 28 result(string) uint64 29 } 30 31 type mapWithLock struct { 32 mu sync.Mutex 33 m map[string]uint64 34 } 35 36 func newMapWithLock() incrementUint64Map { 37 return &mapWithLock{ 38 m: make(map[string]uint64), 39 } 40 } 41 42 func (mwl *mapWithLock) increment(c string) { 43 mwl.mu.Lock() 44 mwl.m[c]++ 45 mwl.mu.Unlock() 46 } 47 48 func (mwl *mapWithLock) result(c string) uint64 { 49 return mwl.m[c] 50 } 51 52 type mapWithAtomicFastpath struct { 53 mu sync.RWMutex 54 m map[string]*uint64 55 } 56 57 func newMapWithAtomicFastpath() incrementUint64Map { 58 return &mapWithAtomicFastpath{ 59 m: make(map[string]*uint64), 60 } 61 } 62 63 func (mwaf *mapWithAtomicFastpath) increment(c string) { 64 mwaf.mu.RLock() 65 if p, ok := mwaf.m[c]; ok { 66 atomic.AddUint64(p, 1) 67 mwaf.mu.RUnlock() 68 return 69 } 70 mwaf.mu.RUnlock() 71 72 mwaf.mu.Lock() 73 if p, ok := mwaf.m[c]; ok { 74 atomic.AddUint64(p, 1) 75 mwaf.mu.Unlock() 76 return 77 } 78 var temp uint64 = 1 79 mwaf.m[c] = &temp 80 mwaf.mu.Unlock() 81 } 82 83 func (mwaf *mapWithAtomicFastpath) result(c string) uint64 { 84 return atomic.LoadUint64(mwaf.m[c]) 85 } 86 87 type mapWithSyncMap struct { 88 m sync.Map 89 } 90 91 func newMapWithSyncMap() incrementUint64Map { 92 return &mapWithSyncMap{} 93 } 94 95 func (mwsm *mapWithSyncMap) increment(c string) { 96 p, ok := mwsm.m.Load(c) 97 if !ok { 98 tp := new(uint64) 99 p, _ = mwsm.m.LoadOrStore(c, tp) 100 } 101 atomic.AddUint64(p.(*uint64), 1) 102 } 103 104 func (mwsm *mapWithSyncMap) result(c string) uint64 { 105 p, _ := mwsm.m.Load(c) 106 return atomic.LoadUint64(p.(*uint64)) 107 } 108 109 func benchmarkIncrementUint64Map(b *testing.B, f func() incrementUint64Map) { 110 const cat = "cat" 111 benches := []struct { 112 name string 113 goroutineCount int 114 }{ 115 { 116 name: " 1", 117 goroutineCount: 1, 118 }, 119 { 120 name: " 10", 121 goroutineCount: 10, 122 }, 123 { 124 name: " 100", 125 goroutineCount: 100, 126 }, 127 { 128 name: "1000", 129 goroutineCount: 1000, 130 }, 131 } 132 for _, bb := range benches { 133 b.Run(bb.name, func(b *testing.B) { 134 m := f() 135 var wg sync.WaitGroup 136 wg.Add(bb.goroutineCount) 137 b.ResetTimer() 138 for i := 0; i < bb.goroutineCount; i++ { 139 go func() { 140 for j := 0; j < b.N; j++ { 141 m.increment(cat) 142 } 143 wg.Done() 144 }() 145 } 146 wg.Wait() 147 b.StopTimer() 148 if m.result(cat) != uint64(bb.goroutineCount*b.N) { 149 b.Fatalf("result is %d, want %d", m.result(cat), b.N) 150 } 151 }) 152 } 153 } 154 155 func BenchmarkMapWithSyncMutexContetion(b *testing.B) { 156 benchmarkIncrementUint64Map(b, newMapWithLock) 157 } 158 159 func BenchmarkMapWithAtomicFastpath(b *testing.B) { 160 benchmarkIncrementUint64Map(b, newMapWithAtomicFastpath) 161 } 162 163 func BenchmarkMapWithSyncMap(b *testing.B) { 164 benchmarkIncrementUint64Map(b, newMapWithSyncMap) 165 }