eq2go/internal/ground_spawn/benchmark_test.go

563 lines
12 KiB
Go

package ground_spawn
import (
"testing"
)
// Mock implementations are in test_utils.go
// Benchmark GroundSpawn operations
func BenchmarkGroundSpawn(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 10,
AttemptsPerHarvest: 2,
RandomizeHeading: true,
Location: SpawnLocation{
X: 100.0, Y: 200.0, Z: 300.0, Heading: 45.0, GridID: 1,
},
Name: "Benchmark Node",
Description: "A benchmark harvestable node",
}
gs := NewGroundSpawn(config)
b.Run("GetNumberHarvests", func(b *testing.B) {
for b.Loop() {
_ = gs.GetNumberHarvests()
}
})
b.Run("SetNumberHarvests", func(b *testing.B) {
b.ResetTimer()
for i := 0; b.Loop(); i++ {
gs.SetNumberHarvests(int8(i % 10))
}
})
b.Run("GetCollectionSkill", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = gs.GetCollectionSkill()
}
})
b.Run("SetCollectionSkill", func(b *testing.B) {
skills := []string{SkillGathering, SkillMining, SkillFishing, SkillTrapping}
b.ResetTimer()
for i := 0; b.Loop(); i++ {
gs.SetCollectionSkill(skills[i%len(skills)])
}
})
b.Run("IsAvailable", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = gs.IsAvailable()
}
})
b.Run("IsDepleted", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = gs.IsDepleted()
}
})
b.Run("GetHarvestMessageName", func(b *testing.B) {
b.ResetTimer()
for i := 0; b.Loop(); i++ {
_ = gs.GetHarvestMessageName(i%2 == 0, i%4 == 0)
}
})
b.Run("GetHarvestSpellType", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = gs.GetHarvestSpellType()
}
})
b.Run("Copy", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
copy := gs.Copy()
_ = copy
}
})
b.Run("Respawn", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
gs.Respawn()
}
})
}
// Benchmark Manager operations
func BenchmarkManager(b *testing.B) {
manager := NewManager(nil, &mockLogger{})
// Pre-populate with ground spawns
for i := int32(1); i <= 100; i++ {
config := GroundSpawnConfig{
GroundSpawnID: i,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
Heading: float32(i * 45), GridID: 1,
},
Name: "Benchmark Node",
Description: "Benchmark node",
}
gs := manager.CreateGroundSpawn(config)
_ = gs
}
b.Run("GetGroundSpawn", func(b *testing.B) {
b.ResetTimer()
for i := 0; b.Loop(); i++ {
spawnID := int32((i % 100) + 1)
_ = manager.GetGroundSpawn(spawnID)
}
})
b.Run("CreateGroundSpawn", func(b *testing.B) {
b.ResetTimer()
for i := 0; b.Loop(); i++ {
config := GroundSpawnConfig{
GroundSpawnID: int32(2000 + i),
CollectionSkill: SkillMining,
NumberHarvests: 3,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i), Y: float32(i * 2), Z: float32(i * 3),
Heading: 0, GridID: 1,
},
Name: "New Node",
Description: "New benchmark node",
}
_ = manager.CreateGroundSpawn(config)
}
})
b.Run("GetGroundSpawnsByZone", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = manager.GetGroundSpawnsByZone(1)
}
})
b.Run("GetGroundSpawnCount", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = manager.GetGroundSpawnCount()
}
})
b.Run("GetActiveGroundSpawns", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = manager.GetActiveGroundSpawns()
}
})
b.Run("GetDepletedGroundSpawns", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = manager.GetDepletedGroundSpawns()
}
})
b.Run("GetStatistics", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
_ = manager.GetStatistics()
}
})
b.Run("ResetStatistics", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
manager.ResetStatistics()
}
})
b.Run("ProcessRespawns", func(b *testing.B) {
b.ResetTimer()
for b.Loop() {
manager.ProcessRespawns()
}
})
}
// Benchmark concurrent operations
func BenchmarkConcurrentOperations(b *testing.B) {
b.Run("GroundSpawnConcurrentReads", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 10,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Concurrent Node",
Description: "Concurrent benchmark node",
}
gs := NewGroundSpawn(config)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
switch i % 4 {
case 0:
_ = gs.GetNumberHarvests()
case 1:
_ = gs.GetCollectionSkill()
case 2:
_ = gs.IsAvailable()
case 3:
_ = gs.GetHarvestSpellType()
}
i++
}
})
})
b.Run("GroundSpawnConcurrentWrites", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 10,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Concurrent Node",
Description: "Concurrent benchmark node",
}
gs := NewGroundSpawn(config)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
switch i % 3 {
case 0:
gs.SetNumberHarvests(int8(i % 10))
case 1:
gs.SetCollectionSkill(SkillMining)
case 2:
gs.SetRandomizeHeading(i%2 == 0)
}
i++
}
})
})
b.Run("ManagerConcurrentOperations", func(b *testing.B) {
manager := NewManager(nil, &mockLogger{})
// Pre-populate
for i := int32(1); i <= 10; i++ {
config := GroundSpawnConfig{
GroundSpawnID: i,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
Heading: 0, GridID: 1,
},
Name: "Manager Node",
Description: "Manager benchmark node",
}
manager.CreateGroundSpawn(config)
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
spawnID := int32((i % 10) + 1)
switch i % 5 {
case 0:
_ = manager.GetGroundSpawn(spawnID)
case 1:
_ = manager.GetGroundSpawnsByZone(1)
case 2:
_ = manager.GetStatistics()
case 3:
_ = manager.GetActiveGroundSpawns()
case 4:
manager.ProcessRespawns()
}
i++
}
})
})
}
// Memory allocation benchmarks
func BenchmarkMemoryAllocations(b *testing.B) {
b.Run("GroundSpawnCreation", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Memory Test Node",
Description: "Memory test node",
}
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = NewGroundSpawn(config)
}
})
b.Run("ManagerCreation", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = NewManager(nil, &mockLogger{})
}
})
b.Run("GroundSpawnCopy", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Copy Test Node",
Description: "Copy test node",
}
gs := NewGroundSpawn(config)
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = gs.Copy()
}
})
b.Run("StatisticsGeneration", func(b *testing.B) {
manager := NewManager(nil, &mockLogger{})
// Add some data for meaningful statistics
for i := int32(1); i <= 10; i++ {
config := GroundSpawnConfig{
GroundSpawnID: i,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
Heading: 0, GridID: 1,
},
Name: "Stats Node",
Description: "Stats test node",
}
manager.CreateGroundSpawn(config)
}
// Add some harvest statistics
manager.mutex.Lock()
manager.totalHarvests = 1000
manager.successfulHarvests = 850
manager.rareItemsHarvested = 50
manager.skillUpsGenerated = 200
manager.harvestsBySkill[SkillGathering] = 600
manager.harvestsBySkill[SkillMining] = 400
manager.mutex.Unlock()
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = manager.GetStatistics()
}
})
}
// Contention benchmarks
func BenchmarkContention(b *testing.B) {
b.Run("HighContentionReads", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 10,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Contention Node",
Description: "Contention test node",
}
gs := NewGroundSpawn(config)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = gs.GetNumberHarvests()
}
})
})
b.Run("HighContentionWrites", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 10,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Contention Node",
Description: "Contention test node",
}
gs := NewGroundSpawn(config)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
gs.SetNumberHarvests(int8(i % 10))
i++
}
})
})
b.Run("MixedReadWrite", func(b *testing.B) {
config := GroundSpawnConfig{
GroundSpawnID: 1,
CollectionSkill: SkillGathering,
NumberHarvests: 10,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
},
Name: "Mixed Node",
Description: "Mixed operations test node",
}
gs := NewGroundSpawn(config)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
if i%10 == 0 {
// 10% writes
gs.SetNumberHarvests(int8(i % 5))
} else {
// 90% reads
_ = gs.GetNumberHarvests()
}
i++
}
})
})
b.Run("ManagerHighContention", func(b *testing.B) {
manager := NewManager(nil, &mockLogger{})
// Pre-populate
for i := int32(1); i <= 5; i++ {
config := GroundSpawnConfig{
GroundSpawnID: i,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
Heading: 0, GridID: 1,
},
Name: "Contention Node",
Description: "Manager contention test",
}
manager.CreateGroundSpawn(config)
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = manager.GetGroundSpawn(1)
}
})
})
}
// Scalability benchmarks
func BenchmarkScalability(b *testing.B) {
sizes := []int{10, 100, 1000}
for _, size := range sizes {
b.Run("GroundSpawnLookup_"+string(rune(size)), func(b *testing.B) {
manager := NewManager(nil, &mockLogger{})
// Pre-populate with varying sizes
for i := int32(1); i <= int32(size); i++ {
config := GroundSpawnConfig{
GroundSpawnID: i,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
Heading: 0, GridID: 1,
},
Name: "Scale Node",
Description: "Scalability test node",
}
manager.CreateGroundSpawn(config)
}
b.ResetTimer()
for i := 0; b.Loop(); i++ {
spawnID := int32((i % size) + 1)
_ = manager.GetGroundSpawn(spawnID)
}
})
}
for _, size := range sizes {
b.Run("ZoneLookup_"+string(rune(size)), func(b *testing.B) {
manager := NewManager(nil, &mockLogger{})
// Pre-populate with varying sizes
for i := int32(1); i <= int32(size); i++ {
config := GroundSpawnConfig{
GroundSpawnID: i,
CollectionSkill: SkillGathering,
NumberHarvests: 5,
AttemptsPerHarvest: 1,
Location: SpawnLocation{
X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
Heading: 0, GridID: 1,
},
Name: "Zone Node",
Description: "Zone scalability test",
}
manager.CreateGroundSpawn(config)
}
b.ResetTimer()
for b.Loop() {
_ = manager.GetGroundSpawnsByZone(1)
}
})
}
}