406 lines
10 KiB
Go
406 lines
10 KiB
Go
package alt_advancement
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"sync"
|
|
"testing"
|
|
|
|
"eq2emu/internal/database"
|
|
)
|
|
|
|
// Global shared master list for benchmarks to avoid repeated setup
|
|
var (
|
|
sharedAltAdvancementMasterList *MasterList
|
|
sharedAltAdvancements []*AltAdvancement
|
|
altAdvancementSetupOnce sync.Once
|
|
)
|
|
|
|
// setupSharedAltAdvancementMasterList creates the shared master list once
|
|
func setupSharedAltAdvancementMasterList(b *testing.B) {
|
|
altAdvancementSetupOnce.Do(func() {
|
|
// Create test database
|
|
db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create test database: %v", err)
|
|
}
|
|
|
|
sharedAltAdvancementMasterList = NewMasterList()
|
|
|
|
// Pre-populate with alternate advancements for realistic testing
|
|
const numAltAdvancements = 1000
|
|
sharedAltAdvancements = make([]*AltAdvancement, numAltAdvancements)
|
|
|
|
groups := []int8{AA_CLASS, AA_SUBCLASS, AA_SHADOW, AA_HEROIC, AA_TRADESKILL, AA_PRESTIGE}
|
|
classes := []int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} // 0 = universal, 1-10 = specific classes
|
|
|
|
for i := range numAltAdvancements {
|
|
sharedAltAdvancements[i] = New(db)
|
|
sharedAltAdvancements[i].NodeID = int32(i + 1)
|
|
sharedAltAdvancements[i].SpellID = int32(i + 1)
|
|
sharedAltAdvancements[i].Name = fmt.Sprintf("Alt Advancement %d", i+1)
|
|
sharedAltAdvancements[i].Group = groups[i%len(groups)]
|
|
sharedAltAdvancements[i].ClassReq = classes[i%len(classes)]
|
|
sharedAltAdvancements[i].MinLevel = int8(rand.Intn(50) + 1)
|
|
sharedAltAdvancements[i].RankCost = int8(rand.Intn(5) + 1)
|
|
sharedAltAdvancements[i].MaxRank = int8(rand.Intn(10) + 1)
|
|
sharedAltAdvancements[i].Col = int8(rand.Intn(11))
|
|
sharedAltAdvancements[i].Row = int8(rand.Intn(16))
|
|
|
|
sharedAltAdvancementMasterList.AddAltAdvancement(sharedAltAdvancements[i])
|
|
}
|
|
})
|
|
}
|
|
|
|
// createTestAltAdvancement creates an alternate advancement for benchmarking
|
|
func createTestAltAdvancement(b *testing.B, id int32) *AltAdvancement {
|
|
b.Helper()
|
|
|
|
// Use nil database for benchmarking in-memory operations
|
|
aa := New(nil)
|
|
aa.NodeID = id
|
|
aa.SpellID = id
|
|
aa.Name = fmt.Sprintf("Benchmark AA %d", id)
|
|
aa.Group = []int8{AA_CLASS, AA_SUBCLASS, AA_SHADOW, AA_HEROIC}[id%4]
|
|
aa.ClassReq = int8((id % 10) + 1)
|
|
aa.MinLevel = int8((id % 50) + 1)
|
|
aa.RankCost = int8(rand.Intn(5) + 1)
|
|
aa.MaxRank = int8(rand.Intn(10) + 1)
|
|
aa.Col = int8(rand.Intn(11))
|
|
aa.Row = int8(rand.Intn(16))
|
|
|
|
return aa
|
|
}
|
|
|
|
// BenchmarkAltAdvancementCreation measures alternate advancement creation performance
|
|
func BenchmarkAltAdvancementCreation(b *testing.B) {
|
|
db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
b.Run("Sequential", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
aa := New(db)
|
|
aa.NodeID = int32(i)
|
|
aa.SpellID = int32(i)
|
|
aa.Name = fmt.Sprintf("AA %d", i)
|
|
_ = aa
|
|
}
|
|
})
|
|
|
|
b.Run("Parallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
id := int32(0)
|
|
for pb.Next() {
|
|
aa := New(db)
|
|
aa.NodeID = id
|
|
aa.SpellID = id
|
|
aa.Name = fmt.Sprintf("AA %d", id)
|
|
id++
|
|
_ = aa
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkAltAdvancementOperations measures individual alternate advancement operations
|
|
func BenchmarkAltAdvancementOperations(b *testing.B) {
|
|
aa := createTestAltAdvancement(b, 1001)
|
|
|
|
b.Run("GetID", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = aa.GetID()
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("IsNew", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = aa.IsNew()
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("Clone", func(b *testing.B) {
|
|
for b.Loop() {
|
|
_ = aa.Clone()
|
|
}
|
|
})
|
|
|
|
b.Run("IsValid", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = aa.IsValid()
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkMasterListOperations measures master list performance
|
|
func BenchmarkMasterListOperations(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
|
|
b.Run("GetAltAdvancement", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
id := int32(rand.Intn(1000) + 1)
|
|
_ = ml.GetAltAdvancement(id)
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("AddAltAdvancement", func(b *testing.B) {
|
|
// Create a separate master list for add operations
|
|
addML := NewMasterList()
|
|
startID := int32(10000)
|
|
// Pre-create AAs to measure just the Add operation
|
|
aasToAdd := make([]*AltAdvancement, b.N)
|
|
for i := 0; i < b.N; i++ {
|
|
aasToAdd[i] = createTestAltAdvancement(b, startID+int32(i))
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
addML.AddAltAdvancement(aasToAdd[i])
|
|
}
|
|
})
|
|
|
|
b.Run("GetAltAdvancementsByGroup", func(b *testing.B) {
|
|
groups := []int8{AA_CLASS, AA_SUBCLASS, AA_SHADOW, AA_HEROIC, AA_TRADESKILL, AA_PRESTIGE}
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
group := groups[rand.Intn(len(groups))]
|
|
_ = ml.GetAltAdvancementsByGroup(group)
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("GetAltAdvancementsByClass", func(b *testing.B) {
|
|
classes := []int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
class := classes[rand.Intn(len(classes))]
|
|
_ = ml.GetAltAdvancementsByClass(class)
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("GetAltAdvancementsByLevel", func(b *testing.B) {
|
|
for b.Loop() {
|
|
level := int8(rand.Intn(50) + 1)
|
|
_ = ml.GetAltAdvancementsByLevel(level)
|
|
}
|
|
})
|
|
|
|
b.Run("GetAltAdvancementsByGroupAndClass", func(b *testing.B) {
|
|
groups := []int8{AA_CLASS, AA_SUBCLASS, AA_SHADOW, AA_HEROIC}
|
|
classes := []int8{1, 2, 3, 4, 5}
|
|
for b.Loop() {
|
|
group := groups[rand.Intn(len(groups))]
|
|
class := classes[rand.Intn(len(classes))]
|
|
_ = ml.GetAltAdvancementsByGroupAndClass(group, class)
|
|
}
|
|
})
|
|
|
|
b.Run("GetGroups", func(b *testing.B) {
|
|
for b.Loop() {
|
|
_ = ml.GetGroups()
|
|
}
|
|
})
|
|
|
|
b.Run("GetClasses", func(b *testing.B) {
|
|
for b.Loop() {
|
|
_ = ml.GetClasses()
|
|
}
|
|
})
|
|
|
|
b.Run("Size", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = ml.Size()
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkConcurrentOperations tests mixed workload performance
|
|
func BenchmarkConcurrentOperations(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
|
|
b.Run("MixedOperations", func(b *testing.B) {
|
|
groups := []int8{AA_CLASS, AA_SUBCLASS, AA_SHADOW, AA_HEROIC, AA_TRADESKILL, AA_PRESTIGE}
|
|
classes := []int8{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
switch rand.Intn(8) {
|
|
case 0:
|
|
id := int32(rand.Intn(1000) + 1)
|
|
_ = ml.GetAltAdvancement(id)
|
|
case 1:
|
|
group := groups[rand.Intn(len(groups))]
|
|
_ = ml.GetAltAdvancementsByGroup(group)
|
|
case 2:
|
|
class := classes[rand.Intn(len(classes))]
|
|
_ = ml.GetAltAdvancementsByClass(class)
|
|
case 3:
|
|
level := int8(rand.Intn(50) + 1)
|
|
_ = ml.GetAltAdvancementsByLevel(level)
|
|
case 4:
|
|
group := groups[rand.Intn(len(groups))]
|
|
class := classes[rand.Intn(len(classes))]
|
|
_ = ml.GetAltAdvancementsByGroupAndClass(group, class)
|
|
case 5:
|
|
_ = ml.GetGroups()
|
|
case 6:
|
|
_ = ml.GetClasses()
|
|
case 7:
|
|
_ = ml.Size()
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkMemoryAllocation measures memory allocation patterns
|
|
func BenchmarkMemoryAllocation(b *testing.B) {
|
|
db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
b.Run("AltAdvancementAllocation", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
aa := New(db)
|
|
aa.NodeID = int32(i)
|
|
aa.SpellID = int32(i)
|
|
aa.Name = fmt.Sprintf("AA %d", i)
|
|
_ = aa
|
|
}
|
|
})
|
|
|
|
b.Run("MasterListAllocation", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for b.Loop() {
|
|
ml := NewMasterList()
|
|
_ = ml
|
|
}
|
|
})
|
|
|
|
b.Run("AddAltAdvancement_Allocations", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
ml := NewMasterList()
|
|
for i := 0; i < b.N; i++ {
|
|
aa := createTestAltAdvancement(b, int32(i+1))
|
|
ml.AddAltAdvancement(aa)
|
|
}
|
|
})
|
|
|
|
b.Run("GetAltAdvancementsByGroup_Allocations", func(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for b.Loop() {
|
|
_ = ml.GetAltAdvancementsByGroup(AA_CLASS)
|
|
}
|
|
})
|
|
|
|
b.Run("GetGroups_Allocations", func(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for b.Loop() {
|
|
_ = ml.GetGroups()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkUpdateOperations measures update performance
|
|
func BenchmarkUpdateOperations(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
|
|
b.Run("UpdateAltAdvancement", func(b *testing.B) {
|
|
// Create AAs to update
|
|
updateAAs := make([]*AltAdvancement, b.N)
|
|
for i := 0; i < b.N; i++ {
|
|
updateAAs[i] = createTestAltAdvancement(b, int32((i%1000)+1))
|
|
updateAAs[i].Name = "Updated Name"
|
|
updateAAs[i].Group = AA_SUBCLASS
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = ml.UpdateAltAdvancement(updateAAs[i])
|
|
}
|
|
})
|
|
|
|
b.Run("RemoveAltAdvancement", func(b *testing.B) {
|
|
// Create a separate master list for removal testing
|
|
removeML := NewMasterList()
|
|
|
|
// Add AAs to remove
|
|
for i := 0; i < b.N; i++ {
|
|
aa := createTestAltAdvancement(b, int32(i+1))
|
|
removeML.AddAltAdvancement(aa)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
removeML.RemoveAltAdvancement(int32(i + 1))
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkValidation measures validation performance
|
|
func BenchmarkValidation(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
|
|
b.Run("ValidateAll", func(b *testing.B) {
|
|
for b.Loop() {
|
|
_ = ml.ValidateAll()
|
|
}
|
|
})
|
|
|
|
b.Run("IndividualValidation", func(b *testing.B) {
|
|
aa := createTestAltAdvancement(b, 1001)
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = aa.IsValid()
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkCloneOperations measures cloning performance
|
|
func BenchmarkCloneOperations(b *testing.B) {
|
|
setupSharedAltAdvancementMasterList(b)
|
|
ml := sharedAltAdvancementMasterList
|
|
|
|
b.Run("GetAltAdvancementClone", func(b *testing.B) {
|
|
for b.Loop() {
|
|
id := int32(rand.Intn(1000) + 1)
|
|
_ = ml.GetAltAdvancementClone(id)
|
|
}
|
|
})
|
|
|
|
b.Run("DirectClone", func(b *testing.B) {
|
|
aa := createTestAltAdvancement(b, 1001)
|
|
for b.Loop() {
|
|
_ = aa.Clone()
|
|
}
|
|
})
|
|
}
|