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  }