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  }