github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/benchmark/primitives/safe_config_selector_test.go (about) 1 /* 2 * 3 * Copyright 2017 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 19 // Benchmark options for safe config selector type. 20 21 package primitives_test 22 23 import ( 24 "sync" 25 "sync/atomic" 26 "testing" 27 "time" 28 "unsafe" 29 ) 30 31 type safeUpdaterAtomicAndCounter struct { 32 ptr unsafe.Pointer // *countingFunc 33 } 34 35 type countingFunc struct { 36 mu sync.RWMutex 37 f func() 38 } 39 40 func (s *safeUpdaterAtomicAndCounter) call() { 41 cfPtr := atomic.LoadPointer(&s.ptr) 42 var cf *countingFunc 43 for { 44 cf = (*countingFunc)(cfPtr) 45 cf.mu.RLock() 46 cfPtr2 := atomic.LoadPointer(&s.ptr) 47 if cfPtr == cfPtr2 { 48 // Use cf with confidence! 49 break 50 } 51 // cf changed; try to use the new one instead, because the old one is 52 // no longer valid to use. 53 cf.mu.RUnlock() 54 cfPtr = cfPtr2 55 } 56 defer cf.mu.RUnlock() 57 cf.f() 58 } 59 60 func (s *safeUpdaterAtomicAndCounter) update(f func()) { 61 newCF := &countingFunc{f: f} 62 oldCFPtr := atomic.SwapPointer(&s.ptr, unsafe.Pointer(newCF)) 63 if oldCFPtr == nil { 64 return 65 } 66 (*countingFunc)(oldCFPtr).mu.Lock() 67 (*countingFunc)(oldCFPtr).mu.Unlock() //lint:ignore SA2001 necessary to unlock after locking to unblock any RLocks 68 } 69 70 type safeUpdaterRWMutex struct { 71 mu sync.RWMutex 72 f func() 73 } 74 75 func (s *safeUpdaterRWMutex) call() { 76 s.mu.RLock() 77 defer s.mu.RUnlock() 78 s.f() 79 } 80 81 func (s *safeUpdaterRWMutex) update(f func()) { 82 s.mu.Lock() 83 defer s.mu.Unlock() 84 s.f = f 85 } 86 87 type updater interface { 88 call() 89 update(f func()) 90 } 91 92 func benchmarkSafeUpdater(b *testing.B, u updater) { 93 t := time.NewTicker(time.Second) 94 go func() { 95 for range t.C { 96 u.update(func() {}) 97 } 98 }() 99 b.RunParallel(func(pb *testing.PB) { 100 u.update(func() {}) 101 for pb.Next() { 102 u.call() 103 } 104 }) 105 t.Stop() 106 } 107 108 func BenchmarkSafeUpdaterAtomicAndCounter(b *testing.B) { 109 benchmarkSafeUpdater(b, &safeUpdaterAtomicAndCounter{}) 110 } 111 112 func BenchmarkSafeUpdaterRWMutex(b *testing.B) { 113 benchmarkSafeUpdater(b, &safeUpdaterRWMutex{}) 114 }