123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- /*
- *
- * Copyright 2019 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package primitives_test
- import (
- "sync"
- "sync/atomic"
- "testing"
- )
- type incrementUint64Map interface {
- increment(string)
- result(string) uint64
- }
- type mapWithLock struct {
- mu sync.Mutex
- m map[string]uint64
- }
- func newMapWithLock() incrementUint64Map {
- return &mapWithLock{
- m: make(map[string]uint64),
- }
- }
- func (mwl *mapWithLock) increment(c string) {
- mwl.mu.Lock()
- mwl.m[c]++
- mwl.mu.Unlock()
- }
- func (mwl *mapWithLock) result(c string) uint64 {
- return mwl.m[c]
- }
- type mapWithAtomicFastpath struct {
- mu sync.RWMutex
- m map[string]*uint64
- }
- func newMapWithAtomicFastpath() incrementUint64Map {
- return &mapWithAtomicFastpath{
- m: make(map[string]*uint64),
- }
- }
- func (mwaf *mapWithAtomicFastpath) increment(c string) {
- mwaf.mu.RLock()
- if p, ok := mwaf.m[c]; ok {
- atomic.AddUint64(p, 1)
- mwaf.mu.RUnlock()
- return
- }
- mwaf.mu.RUnlock()
- mwaf.mu.Lock()
- if p, ok := mwaf.m[c]; ok {
- atomic.AddUint64(p, 1)
- mwaf.mu.Unlock()
- return
- }
- var temp uint64 = 1
- mwaf.m[c] = &temp
- mwaf.mu.Unlock()
- }
- func (mwaf *mapWithAtomicFastpath) result(c string) uint64 {
- return atomic.LoadUint64(mwaf.m[c])
- }
- type mapWithSyncMap struct {
- m sync.Map
- }
- func newMapWithSyncMap() incrementUint64Map {
- return &mapWithSyncMap{}
- }
- func (mwsm *mapWithSyncMap) increment(c string) {
- p, ok := mwsm.m.Load(c)
- if !ok {
- tp := new(uint64)
- p, _ = mwsm.m.LoadOrStore(c, tp)
- }
- atomic.AddUint64(p.(*uint64), 1)
- }
- func (mwsm *mapWithSyncMap) result(c string) uint64 {
- p, _ := mwsm.m.Load(c)
- return atomic.LoadUint64(p.(*uint64))
- }
- func benchmarkIncrementUint64Map(b *testing.B, f func() incrementUint64Map) {
- const cat = "cat"
- benches := []struct {
- name string
- goroutineCount int
- }{
- {
- name: " 1",
- goroutineCount: 1,
- },
- {
- name: " 10",
- goroutineCount: 10,
- },
- {
- name: " 100",
- goroutineCount: 100,
- },
- {
- name: "1000",
- goroutineCount: 1000,
- },
- }
- for _, bb := range benches {
- b.Run(bb.name, func(b *testing.B) {
- m := f()
- var wg sync.WaitGroup
- wg.Add(bb.goroutineCount)
- b.ResetTimer()
- for i := 0; i < bb.goroutineCount; i++ {
- go func() {
- for j := 0; j < b.N; j++ {
- m.increment(cat)
- }
- wg.Done()
- }()
- }
- wg.Wait()
- b.StopTimer()
- if m.result(cat) != uint64(bb.goroutineCount*b.N) {
- b.Fatalf("result is %d, want %d", m.result(cat), b.N)
- }
- })
- }
- }
- func BenchmarkMapWithSyncMutexContetion(b *testing.B) {
- benchmarkIncrementUint64Map(b, newMapWithLock)
- }
- func BenchmarkMapWithAtomicFastpath(b *testing.B) {
- benchmarkIncrementUint64Map(b, newMapWithAtomicFastpath)
- }
- func BenchmarkMapWithSyncMap(b *testing.B) {
- benchmarkIncrementUint64Map(b, newMapWithSyncMap)
- }
|