Repository: puzpuzpuz/xsync
Pull request #81 (2022-11-02 17:07:42)

Report throughput in benchmarks
Also removes map debug output from benchmark runs. The output can be seen in verbose test output now.


Patch:
diff --git a/map.go b/map.go
index 7a95b9f..f6f46ad 100644
--- a/map.go
+++ b/map.go
@@ -5,6 +5,7 @@ import (
 	"hash/maphash"
 	"math"
 	"runtime"
+	"strings"
 	"sync"
 	"sync/atomic"
 	"unsafe"
@@ -713,20 +714,22 @@ type mapStats struct {
 	TotalShrinks int64
 }
 
-func (s *mapStats) Print() {
-	fmt.Println("---")
-	fmt.Printf("RootBuckets:  %d\n", s.RootBuckets)
-	fmt.Printf("TotalBuckets: %d\n", s.TotalBuckets)
-	fmt.Printf("EmptyBuckets: %d\n", s.EmptyBuckets)
-	fmt.Printf("Capacity:     %d\n", s.Capacity)
-	fmt.Printf("Size:         %d\n", s.Size)
-	fmt.Printf("Counter:      %d\n", s.Counter)
-	fmt.Printf("CounterLen:   %d\n", s.CounterLen)
-	fmt.Printf("MinEntries:   %d\n", s.MinEntries)
-	fmt.Printf("MaxEntries:   %d\n", s.MaxEntries)
-	fmt.Printf("TotalGrowths: %d\n", s.TotalGrowths)
-	fmt.Printf("TotalShrinks: %d\n", s.TotalShrinks)
-	fmt.Println("---")
+func (s *mapStats) ToString() string {
+	var sb strings.Builder
+	sb.WriteString("\n---\n")
+	sb.WriteString(fmt.Sprintf("RootBuckets:  %d\n", s.RootBuckets))
+	sb.WriteString(fmt.Sprintf("TotalBuckets: %d\n", s.TotalBuckets))
+	sb.WriteString(fmt.Sprintf("EmptyBuckets: %d\n", s.EmptyBuckets))
+	sb.WriteString(fmt.Sprintf("Capacity:     %d\n", s.Capacity))
+	sb.WriteString(fmt.Sprintf("Size:         %d\n", s.Size))
+	sb.WriteString(fmt.Sprintf("Counter:      %d\n", s.Counter))
+	sb.WriteString(fmt.Sprintf("CounterLen:   %d\n", s.CounterLen))
+	sb.WriteString(fmt.Sprintf("MinEntries:   %d\n", s.MinEntries))
+	sb.WriteString(fmt.Sprintf("MaxEntries:   %d\n", s.MaxEntries))
+	sb.WriteString(fmt.Sprintf("TotalGrowths: %d\n", s.TotalGrowths))
+	sb.WriteString(fmt.Sprintf("TotalShrinks: %d\n", s.TotalShrinks))
+	sb.WriteString("---\n")
+	return sb.String()
 }
 
 // O(N) operation; use for debug purposes only


Test patch:
diff --git a/counter_test.go b/counter_test.go
index 7f2faee..d715ca6 100644
--- a/counter_test.go
+++ b/counter_test.go
@@ -84,7 +84,7 @@ func TestCounterParallelIncrementors(t *testing.T) {
 
 func benchmarkCounter(b *testing.B, writeRatio int) {
 	c := NewCounter()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			foo++
@@ -104,7 +104,7 @@ func BenchmarkCounter(b *testing.B) {
 
 func benchmarkAtomicInt64(b *testing.B, writeRatio int) {
 	var c int64
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			foo++
diff --git a/map_test.go b/map_test.go
index 1785c13..5c848f5 100644
--- a/map_test.go
+++ b/map_test.go
@@ -41,6 +41,14 @@ func init() {
 	}
 }
 
+func runParallel(b *testing.B, benchFn func(pb *testing.PB)) {
+	b.ResetTimer()
+	start := time.Now()
+	b.RunParallel(benchFn)
+	opsPerSec := float64(b.N) * float64(time.Second) / float64(time.Since(start).Nanoseconds())
+	b.ReportMetric(opsPerSec, "ops/s")
+}
+
 func TestMap_BucketStructSize(t *testing.T) {
 	size := unsafe.Sizeof(BucketPadded{})
 	if size != 64 {
@@ -551,7 +559,8 @@ func TestMapResize(t *testing.T) {
 		t.Fatalf("zero total shrinks expected: %d", stats.TotalShrinks)
 	}
 	// This is useful when debugging table resize and occupancy.
-	stats.Print()
+	// Use -v flag to see the output.
+	t.Log(stats.ToString())
 
 	for i := 0; i < numEntries; i++ {
 		m.Delete(strconv.Itoa(i))
@@ -570,7 +579,7 @@ func TestMapResize(t *testing.T) {
 	if stats.TotalShrinks == 0 {
 		t.Fatalf("non-zero total shrinks expected: %d", stats.TotalShrinks)
 	}
-	stats.Print()
+	t.Log(stats.ToString())
 }
 
 func TestMapResize_CounterLenLimit(t *testing.T) {
@@ -1081,8 +1090,7 @@ func benchmarkMap(
 	deleteFn func(k string),
 	readPercentage int,
 ) {
-	b.ResetTimer()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		// convert percent to permille to support 99% case
 		storeThreshold := 10 * readPercentage
 		deleteThreshold := 10*readPercentage + ((1000 - 10*readPercentage) / 2)
@@ -1105,8 +1113,7 @@ func BenchmarkMapRange(b *testing.B) {
 	for i := 0; i < benchmarkNumEntries; i++ {
 		m.Store(benchmarkKeys[i], i)
 	}
-	b.ResetTimer()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			m.Range(func(key string, value interface{}) bool {
@@ -1126,8 +1133,7 @@ func BenchmarkMapRangeStandard(b *testing.B) {
 	for i := 0; i < benchmarkNumEntries; i++ {
 		m.Store(benchmarkKeys[i], i)
 	}
-	b.ResetTimer()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			m.Range(func(key interface{}, value interface{}) bool {
diff --git a/mapof_test.go b/mapof_test.go
index 01734e3..956cbc2 100644
--- a/mapof_test.go
+++ b/mapof_test.go
@@ -651,7 +651,8 @@ func TestMapOfResize(t *testing.T) {
 		t.Fatalf("zero total shrinks expected: %d", stats.TotalShrinks)
 	}
 	// This is useful when debugging table resize and occupancy.
-	stats.Print()
+	// Use -v flag to see the output.
+	t.Log(stats.ToString())
 
 	for i := 0; i < numEntries; i++ {
 		m.Delete(strconv.Itoa(i))
@@ -670,7 +671,7 @@ func TestMapOfResize(t *testing.T) {
 	if stats.TotalShrinks == 0 {
 		t.Fatalf("non-zero total shrinks expected: %d", stats.TotalShrinks)
 	}
-	stats.Print()
+	t.Log(stats.ToString())
 }
 
 func TestMapOfResize_CounterLenLimit(t *testing.T) {
@@ -1004,8 +1005,7 @@ func benchmarkMapOfStringKeys(
 	deleteFn func(k string),
 	readPercentage int,
 ) {
-	b.ResetTimer()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		// convert percent to permille to support 99% case
 		storeThreshold := 10 * readPercentage
 		deleteThreshold := 10*readPercentage + ((1000 - 10*readPercentage) / 2)
@@ -1116,8 +1116,7 @@ func benchmarkMapOfIntegerKeys(
 	deleteFn func(k int),
 	readPercentage int,
 ) {
-	b.ResetTimer()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		// convert percent to permille to support 99% case
 		storeThreshold := 10 * readPercentage
 		deleteThreshold := 10*readPercentage + ((1000 - 10*readPercentage) / 2)
@@ -1140,8 +1139,7 @@ func BenchmarkMapOfRange(b *testing.B) {
 	for i := 0; i < benchmarkNumEntries; i++ {
 		m.Store(benchmarkKeys[i], i)
 	}
-	b.ResetTimer()
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			m.Range(func(key string, value int) bool {
diff --git a/rbmutex_test.go b/rbmutex_test.go
index a551294..cb96f4c 100644
--- a/rbmutex_test.go
+++ b/rbmutex_test.go
@@ -135,7 +135,7 @@ func TestRBMutex(t *testing.T) {
 func benchmarkRBMutex(b *testing.B, parallelism, localWork, writeRatio int) {
 	mu := NewRBMutex()
 	b.SetParallelism(parallelism)
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			foo++
@@ -198,7 +198,7 @@ func BenchmarkRBMutexWorkWrite1000(b *testing.B) {
 func benchmarkRWMutex(b *testing.B, parallelism, localWork, writeRatio int) {
 	var mu sync.RWMutex
 	b.SetParallelism(parallelism)
-	b.RunParallel(func(pb *testing.PB) {
+	runParallel(b, func(pb *testing.PB) {
 		foo := 0
 		for pb.Next() {
 			foo++