git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/concurrentmap/concurrent_map_bench_test.go (about)

     1  package concurrentmap
     2  
     3  import (
     4  	"strconv"
     5  	"sync"
     6  	"testing"
     7  )
     8  
     9  type Integer int
    10  
    11  func (i Integer) String() string {
    12  	return strconv.Itoa(int(i))
    13  }
    14  
    15  func BenchmarkItems(b *testing.B) {
    16  	m := New[Animal]()
    17  
    18  	// Insert 100 elements.
    19  	for i := 0; i < 10000; i++ {
    20  		m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
    21  	}
    22  	for i := 0; i < b.N; i++ {
    23  		m.Items()
    24  	}
    25  }
    26  
    27  func BenchmarkItemsInteger(b *testing.B) {
    28  	m := NewStringer[Integer, Animal]()
    29  
    30  	// Insert 100 elements.
    31  	for i := 0; i < 10000; i++ {
    32  		m.Set((Integer)(i), Animal{strconv.Itoa(i)})
    33  	}
    34  	for i := 0; i < b.N; i++ {
    35  		m.Items()
    36  	}
    37  }
    38  func directSharding(key uint32) uint32 {
    39  	return key
    40  }
    41  
    42  func BenchmarkItemsInt(b *testing.B) {
    43  	m := NewWithCustomShardingFunction[uint32, Animal](directSharding)
    44  
    45  	// Insert 100 elements.
    46  	for i := 0; i < 10000; i++ {
    47  		m.Set((uint32)(i), Animal{strconv.Itoa(i)})
    48  	}
    49  	for i := 0; i < b.N; i++ {
    50  		m.Items()
    51  	}
    52  }
    53  
    54  func BenchmarkMarshalJson(b *testing.B) {
    55  	m := New[Animal]()
    56  
    57  	// Insert 100 elements.
    58  	for i := 0; i < 10000; i++ {
    59  		m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
    60  	}
    61  	for i := 0; i < b.N; i++ {
    62  		_, err := m.MarshalJSON()
    63  		if err != nil {
    64  			b.FailNow()
    65  		}
    66  	}
    67  }
    68  
    69  func BenchmarkStrconv(b *testing.B) {
    70  	for i := 0; i < b.N; i++ {
    71  		strconv.Itoa(i)
    72  	}
    73  }
    74  
    75  func BenchmarkSingleInsertAbsent(b *testing.B) {
    76  	m := New[string]()
    77  	b.ResetTimer()
    78  	for i := 0; i < b.N; i++ {
    79  		m.Set(strconv.Itoa(i), "value")
    80  	}
    81  }
    82  
    83  func BenchmarkSingleInsertAbsentSyncMap(b *testing.B) {
    84  	var m sync.Map
    85  	b.ResetTimer()
    86  	for i := 0; i < b.N; i++ {
    87  		m.Store(strconv.Itoa(i), "value")
    88  	}
    89  }
    90  
    91  func BenchmarkSingleInsertPresent(b *testing.B) {
    92  	m := New[string]()
    93  	m.Set("key", "value")
    94  	b.ResetTimer()
    95  	for i := 0; i < b.N; i++ {
    96  		m.Set("key", "value")
    97  	}
    98  }
    99  
   100  func BenchmarkSingleInsertPresentSyncMap(b *testing.B) {
   101  	var m sync.Map
   102  	m.Store("key", "value")
   103  	b.ResetTimer()
   104  	for i := 0; i < b.N; i++ {
   105  		m.Store("key", "value")
   106  	}
   107  }
   108  
   109  func benchmarkMultiInsertDifferent(b *testing.B) {
   110  	m := New[string]()
   111  	finished := make(chan struct{}, b.N)
   112  	_, set := GetSet(m, finished)
   113  	b.ResetTimer()
   114  	for i := 0; i < b.N; i++ {
   115  		go set(strconv.Itoa(i), "value")
   116  	}
   117  	for i := 0; i < b.N; i++ {
   118  		<-finished
   119  	}
   120  }
   121  
   122  func BenchmarkMultiInsertDifferentSyncMap(b *testing.B) {
   123  	var m sync.Map
   124  	finished := make(chan struct{}, b.N)
   125  	_, set := GetSetSyncMap[string, string](&m, finished)
   126  
   127  	b.ResetTimer()
   128  	for i := 0; i < b.N; i++ {
   129  		go set(strconv.Itoa(i), "value")
   130  	}
   131  	for i := 0; i < b.N; i++ {
   132  		<-finished
   133  	}
   134  }
   135  
   136  func BenchmarkMultiInsertDifferent_1_Shard(b *testing.B) {
   137  	runWithShards(benchmarkMultiInsertDifferent, b, 1)
   138  }
   139  func BenchmarkMultiInsertDifferent_16_Shard(b *testing.B) {
   140  	runWithShards(benchmarkMultiInsertDifferent, b, 16)
   141  }
   142  func BenchmarkMultiInsertDifferent_32_Shard(b *testing.B) {
   143  	runWithShards(benchmarkMultiInsertDifferent, b, 32)
   144  }
   145  func BenchmarkMultiInsertDifferent_256_Shard(b *testing.B) {
   146  	runWithShards(benchmarkMultiGetSetDifferent, b, 256)
   147  }
   148  
   149  func BenchmarkMultiInsertSame(b *testing.B) {
   150  	m := New[string]()
   151  	finished := make(chan struct{}, b.N)
   152  	_, set := GetSet(m, finished)
   153  	m.Set("key", "value")
   154  	b.ResetTimer()
   155  	for i := 0; i < b.N; i++ {
   156  		go set("key", "value")
   157  	}
   158  	for i := 0; i < b.N; i++ {
   159  		<-finished
   160  	}
   161  }
   162  
   163  func BenchmarkMultiInsertSameSyncMap(b *testing.B) {
   164  	var m sync.Map
   165  	finished := make(chan struct{}, b.N)
   166  	_, set := GetSetSyncMap[string, string](&m, finished)
   167  	m.Store("key", "value")
   168  	b.ResetTimer()
   169  	for i := 0; i < b.N; i++ {
   170  		go set("key", "value")
   171  	}
   172  	for i := 0; i < b.N; i++ {
   173  		<-finished
   174  	}
   175  }
   176  
   177  func BenchmarkMultiGetSame(b *testing.B) {
   178  	m := New[string]()
   179  	finished := make(chan struct{}, b.N)
   180  	get, _ := GetSet(m, finished)
   181  	m.Set("key", "value")
   182  	b.ResetTimer()
   183  	for i := 0; i < b.N; i++ {
   184  		go get("key", "value")
   185  	}
   186  	for i := 0; i < b.N; i++ {
   187  		<-finished
   188  	}
   189  }
   190  
   191  func BenchmarkMultiGetSameSyncMap(b *testing.B) {
   192  	var m sync.Map
   193  	finished := make(chan struct{}, b.N)
   194  	get, _ := GetSetSyncMap[string, string](&m, finished)
   195  	m.Store("key", "value")
   196  	b.ResetTimer()
   197  	for i := 0; i < b.N; i++ {
   198  		go get("key", "value")
   199  	}
   200  	for i := 0; i < b.N; i++ {
   201  		<-finished
   202  	}
   203  }
   204  
   205  func benchmarkMultiGetSetDifferent(b *testing.B) {
   206  	m := New[string]()
   207  	finished := make(chan struct{}, 2*b.N)
   208  	get, set := GetSet(m, finished)
   209  	m.Set("-1", "value")
   210  	b.ResetTimer()
   211  	for i := 0; i < b.N; i++ {
   212  		go set(strconv.Itoa(i-1), "value")
   213  		go get(strconv.Itoa(i), "value")
   214  	}
   215  	for i := 0; i < 2*b.N; i++ {
   216  		<-finished
   217  	}
   218  }
   219  
   220  func BenchmarkMultiGetSetDifferentSyncMap(b *testing.B) {
   221  	var m sync.Map
   222  	finished := make(chan struct{}, 2*b.N)
   223  	get, set := GetSetSyncMap[string, string](&m, finished)
   224  	m.Store("-1", "value")
   225  	b.ResetTimer()
   226  	for i := 0; i < b.N; i++ {
   227  		go set(strconv.Itoa(i-1), "value")
   228  		go get(strconv.Itoa(i), "value")
   229  	}
   230  	for i := 0; i < 2*b.N; i++ {
   231  		<-finished
   232  	}
   233  }
   234  
   235  func BenchmarkMultiGetSetDifferent_1_Shard(b *testing.B) {
   236  	runWithShards(benchmarkMultiGetSetDifferent, b, 1)
   237  }
   238  func BenchmarkMultiGetSetDifferent_16_Shard(b *testing.B) {
   239  	runWithShards(benchmarkMultiGetSetDifferent, b, 16)
   240  }
   241  func BenchmarkMultiGetSetDifferent_32_Shard(b *testing.B) {
   242  	runWithShards(benchmarkMultiGetSetDifferent, b, 32)
   243  }
   244  func BenchmarkMultiGetSetDifferent_256_Shard(b *testing.B) {
   245  	runWithShards(benchmarkMultiGetSetDifferent, b, 256)
   246  }
   247  
   248  func benchmarkMultiGetSetBlock(b *testing.B) {
   249  	m := New[string]()
   250  	finished := make(chan struct{}, 2*b.N)
   251  	get, set := GetSet(m, finished)
   252  	for i := 0; i < b.N; i++ {
   253  		m.Set(strconv.Itoa(i%100), "value")
   254  	}
   255  	b.ResetTimer()
   256  	for i := 0; i < b.N; i++ {
   257  		go set(strconv.Itoa(i%100), "value")
   258  		go get(strconv.Itoa(i%100), "value")
   259  	}
   260  	for i := 0; i < 2*b.N; i++ {
   261  		<-finished
   262  	}
   263  }
   264  
   265  func BenchmarkMultiGetSetBlockSyncMap(b *testing.B) {
   266  	var m sync.Map
   267  	finished := make(chan struct{}, 2*b.N)
   268  	get, set := GetSetSyncMap[string, string](&m, finished)
   269  	for i := 0; i < b.N; i++ {
   270  		m.Store(strconv.Itoa(i%100), "value")
   271  	}
   272  	b.ResetTimer()
   273  	for i := 0; i < b.N; i++ {
   274  		go set(strconv.Itoa(i%100), "value")
   275  		go get(strconv.Itoa(i%100), "value")
   276  	}
   277  	for i := 0; i < 2*b.N; i++ {
   278  		<-finished
   279  	}
   280  }
   281  
   282  func BenchmarkMultiGetSetBlock_1_Shard(b *testing.B) {
   283  	runWithShards(benchmarkMultiGetSetBlock, b, 1)
   284  }
   285  func BenchmarkMultiGetSetBlock_16_Shard(b *testing.B) {
   286  	runWithShards(benchmarkMultiGetSetBlock, b, 16)
   287  }
   288  func BenchmarkMultiGetSetBlock_32_Shard(b *testing.B) {
   289  	runWithShards(benchmarkMultiGetSetBlock, b, 32)
   290  }
   291  func BenchmarkMultiGetSetBlock_256_Shard(b *testing.B) {
   292  	runWithShards(benchmarkMultiGetSetBlock, b, 256)
   293  }
   294  
   295  func GetSet[K comparable, V any](m ConcurrentMap[K, V], finished chan struct{}) (set func(key K, value V), get func(key K, value V)) {
   296  	return func(key K, value V) {
   297  			for i := 0; i < 10; i++ {
   298  				m.Get(key)
   299  			}
   300  			finished <- struct{}{}
   301  		}, func(key K, value V) {
   302  			for i := 0; i < 10; i++ {
   303  				m.Set(key, value)
   304  			}
   305  			finished <- struct{}{}
   306  		}
   307  }
   308  
   309  func GetSetSyncMap[K comparable, V any](m *sync.Map, finished chan struct{}) (get func(key K, value V), set func(key K, value V)) {
   310  	get = func(key K, value V) {
   311  		for i := 0; i < 10; i++ {
   312  			m.Load(key)
   313  		}
   314  		finished <- struct{}{}
   315  	}
   316  	set = func(key K, value V) {
   317  		for i := 0; i < 10; i++ {
   318  			m.Store(key, value)
   319  		}
   320  		finished <- struct{}{}
   321  	}
   322  	return
   323  }
   324  
   325  func runWithShards(bench func(b *testing.B), b *testing.B, shardsCount int) {
   326  	oldShardsCount := SHARD_COUNT
   327  	SHARD_COUNT = shardsCount
   328  	bench(b)
   329  	SHARD_COUNT = oldShardsCount
   330  }
   331  
   332  func BenchmarkKeys(b *testing.B) {
   333  	m := New[Animal]()
   334  
   335  	// Insert 100 elements.
   336  	for i := 0; i < 10000; i++ {
   337  		m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
   338  	}
   339  	for i := 0; i < b.N; i++ {
   340  		m.Keys()
   341  	}
   342  }