eq2go/internal/common/benchmark_test.go

210 lines
4.5 KiB
Go

package common
import (
"fmt"
"math/rand"
"testing"
)
// testItem implements Identifiable for benchmarking
type testItem struct {
id int32
name string
value int32
flag bool
}
func (t *testItem) GetID() int32 { return t.id }
// BenchmarkMasterListOperations benchmarks the generic MasterList
func BenchmarkMasterListOperations(b *testing.B) {
// Create master list with test data
ml := NewMasterList[int32, *testItem]()
const numItems = 10000
// Pre-populate
b.StopTimer()
for i := 0; i < numItems; i++ {
item := &testItem{
id: int32(i + 1),
name: fmt.Sprintf("Item %d", i+1),
value: int32(rand.Intn(100)),
flag: rand.Intn(2) == 1,
}
ml.Add(item)
}
b.StartTimer()
b.Run("Get", func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
id := int32(rand.Intn(numItems) + 1)
_ = ml.Get(id)
}
})
})
b.Run("Filter_10Percent", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ml.Filter(func(item *testItem) bool {
return item.value < 10 // ~10% match
})
}
})
b.Run("Filter_50Percent", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ml.Filter(func(item *testItem) bool {
return item.value < 50 // ~50% match
})
}
})
b.Run("Filter_90Percent", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ml.Filter(func(item *testItem) bool {
return item.value < 90 // ~90% match
})
}
})
b.Run("Count_10Percent", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ml.Count(func(item *testItem) bool {
return item.value < 10
})
}
})
b.Run("Count_50Percent", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ml.Count(func(item *testItem) bool {
return item.value < 50
})
}
})
b.Run("Find", func(b *testing.B) {
for i := 0; i < b.N; i++ {
targetValue := int32(rand.Intn(100))
_, _ = ml.Find(func(item *testItem) bool {
return item.value == targetValue
})
}
})
b.Run("ForEach", func(b *testing.B) {
for i := 0; i < b.N; i++ {
ml.ForEach(func(id int32, item *testItem) {
_ = item.value + 1 // Minimal work
})
}
})
b.Run("WithReadLock", func(b *testing.B) {
for i := 0; i < b.N; i++ {
ml.WithReadLock(func(items map[int32]*testItem) {
count := 0
for _, item := range items {
if item.value < 50 {
count++
}
}
_ = count
})
}
})
b.Run("FilterWithCapacity_Accurate", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = ml.FilterWithCapacity(func(item *testItem) bool {
return item.value < 50
}, 5000) // Accurate estimate: 50% of 10k = 5k
}
})
b.Run("FilterInto_Reuse", func(b *testing.B) {
var reusableSlice []*testItem
for i := 0; i < b.N; i++ {
reusableSlice = ml.FilterInto(func(item *testItem) bool {
return item.value < 50
}, reusableSlice)
}
})
b.Run("CountAndFilter_Combined", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = ml.CountAndFilter(func(item *testItem) bool {
return item.value < 50
})
}
})
}
// BenchmarkMemoryAllocations tests allocation patterns
func BenchmarkMemoryAllocations(b *testing.B) {
ml := NewMasterList[int32, *testItem]()
const numItems = 1000
// Pre-populate
for i := 0; i < numItems; i++ {
item := &testItem{
id: int32(i + 1),
name: fmt.Sprintf("Item %d", i+1),
value: int32(rand.Intn(100)),
flag: rand.Intn(2) == 1,
}
ml.Add(item)
}
b.Run("Filter_Allocations", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = ml.Filter(func(item *testItem) bool {
return item.value < 50
})
}
})
b.Run("GetAll_Allocations", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = ml.GetAll()
}
})
b.Run("GetAllSlice_Allocations", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = ml.GetAllSlice()
}
})
b.Run("FilterWithCapacity_Allocations", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = ml.FilterWithCapacity(func(item *testItem) bool {
return item.value < 50
}, 500) // Accurate capacity estimate
}
})
b.Run("FilterInto_Allocations", func(b *testing.B) {
b.ReportAllocs()
reusableSlice := make([]*testItem, 0, 600) // Pre-sized
for i := 0; i < b.N; i++ {
reusableSlice = ml.FilterInto(func(item *testItem) bool {
return item.value < 50
}, reusableSlice)
}
})
b.Run("CountAndFilter_Allocations", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = ml.CountAndFilter(func(item *testItem) bool {
return item.value < 50
})
}
})
}