Skip to content

Commit

Permalink
test(tm2/pkg/cmap): add benchmarks to show true impact of contention (g…
Browse files Browse the repository at this point in the history
…nolang#3540)

The Go standard library's sync.Map is touted as great for cases with
high load and is commonly known knowledge but the benchmark that I am
committing shows otherwise that for this library's usage, it is so much
more expensive hence this benchmark will avoid someone committing
sync.Map without seeing the true implications.

```shell
$ benchstat map_w_mutex.txt stdlib_sync_map.txt
name                               old time/op    new time/op    delta
CMapConcurrentInsertsDeletesHas-8     1.72s ±11%     1.92s ± 3%   +11.66%  (p=0.000 n=10+9)
CMapHas-8                             109ns ± 9%     118ns ± 3%    +8.26%  (p=0.002 n=10+8)

name                               old alloc/op   new alloc/op   delta
CMapConcurrentInsertsDeletesHas-8    1.18GB ± 2%    3.21GB ± 3%  +172.09%  (p=0.000 n=10+10)
CMapHas-8                             16.0B ± 0%     16.0B ± 0%      ~     (all equal)

name                               old allocs/op  new allocs/op  delta
CMapConcurrentInsertsDeletesHas-8      824k ± 0%     4433k ± 0%  +437.89%  (p=0.000 n=10+10)
CMapHas-8                              2.00 ± 0%      1.60 ±38%      ~     (p=0.065 n=9+10)
```

Updates gnolang#3505
  • Loading branch information
odeke-em authored Jan 31, 2025
1 parent 7992a29 commit c24f69f
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions tm2/pkg/cmap/cmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package cmap

import (
"fmt"
"runtime"
"strings"
"sync"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -56,6 +58,61 @@ func TestContains(t *testing.T) {
assert.Nil(t, cmap.Get("key2"))
}

var sink any = nil

func BenchmarkCMapConcurrentInsertsDeletesHas(b *testing.B) {
cm := NewCMap()
keys := make([]string, 100000)
for i := range keys {
keys[i] = fmt.Sprintf("key%d", i)
}
b.ResetTimer()

for i := 0; i < b.N; i++ {
var wg sync.WaitGroup
semaCh := make(chan bool)
nCPU := runtime.NumCPU()
for j := 0; j < nCPU; j++ {
wg.Add(1)
go func() {
defer wg.Done()

// Make sure that all the goroutines run at the
// exact same time for true concurrent tests.
<-semaCh

for i, key := range keys {
if (j+i)%2 == 0 {
cm.Has(key)
} else {
cm.Set(key, j)
}
_ = cm.Size()
if (i+1)%3 == 0 {
cm.Delete(key)
}

if (i+1)%327 == 0 {
cm.Clear()
}
_ = cm.Size()
_ = cm.Keys()
}
_ = cm.Values()
}()
}
close(semaCh)
wg.Wait()

sink = semaCh
}

if sink == nil {
b.Fatal("Benchmark did not run!")
}
sink = nil
}

func BenchmarkCMapHas(b *testing.B) {
m := NewCMap()
for i := 0; i < 1000; i++ {
Expand Down

0 comments on commit c24f69f

Please sign in to comment.