507 lines
12 KiB
Go
507 lines
12 KiB
Go
package entity
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// BenchmarkEntityCreation measures entity creation performance
|
|
func BenchmarkEntityCreation(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
entity := NewEntity()
|
|
_ = entity
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkEntityCombatState measures combat state operations
|
|
func BenchmarkEntityCombatState(b *testing.B) {
|
|
entity := NewEntity()
|
|
|
|
b.Run("Sequential", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
entity.SetInCombat(true)
|
|
_ = entity.IsInCombat()
|
|
entity.SetInCombat(false)
|
|
}
|
|
})
|
|
|
|
b.Run("Parallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
entity.SetInCombat(true)
|
|
_ = entity.IsInCombat()
|
|
entity.SetInCombat(false)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkEntityCastingState measures casting state operations
|
|
func BenchmarkEntityCastingState(b *testing.B) {
|
|
entity := NewEntity()
|
|
|
|
b.Run("Sequential", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
entity.SetCasting(true)
|
|
_ = entity.IsCasting()
|
|
entity.SetCasting(false)
|
|
}
|
|
})
|
|
|
|
b.Run("Parallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
entity.SetCasting(true)
|
|
_ = entity.IsCasting()
|
|
entity.SetCasting(false)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkEntityStatCalculations measures stat calculation performance
|
|
func BenchmarkEntityStatCalculations(b *testing.B) {
|
|
entity := NewEntity()
|
|
info := entity.GetInfoStruct()
|
|
|
|
// Set up some base stats
|
|
info.SetStr(100.0)
|
|
info.SetSta(100.0)
|
|
info.SetAgi(100.0)
|
|
info.SetWis(100.0)
|
|
info.SetIntel(100.0)
|
|
|
|
b.Run("GetStats", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = entity.GetStr()
|
|
_ = entity.GetSta()
|
|
_ = entity.GetAgi()
|
|
_ = entity.GetWis()
|
|
_ = entity.GetIntel()
|
|
}
|
|
})
|
|
|
|
b.Run("GetStatsParallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_ = entity.GetStr()
|
|
_ = entity.GetSta()
|
|
_ = entity.GetAgi()
|
|
_ = entity.GetWis()
|
|
_ = entity.GetIntel()
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("GetPrimaryStat", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = entity.GetPrimaryStat()
|
|
}
|
|
})
|
|
|
|
b.Run("CalculateBonuses", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
entity.CalculateBonuses()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkEntitySpellEffects measures spell effect operations
|
|
func BenchmarkEntitySpellEffects(b *testing.B) {
|
|
entity := NewEntity()
|
|
|
|
b.Run("AddRemoveSpellEffect", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
spellID := int32(i + 1000)
|
|
entity.AddSpellEffect(spellID, 123, 30.0)
|
|
entity.RemoveSpellEffect(spellID)
|
|
}
|
|
})
|
|
|
|
b.Run("AddRemoveSpellEffectParallel", func(b *testing.B) {
|
|
var counter int64
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
spellID := int32(counter + 1000)
|
|
counter++
|
|
entity.AddSpellEffect(spellID, 123, 30.0)
|
|
entity.RemoveSpellEffect(spellID)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkEntityMaintainedSpells measures maintained spell operations
|
|
func BenchmarkEntityMaintainedSpells(b *testing.B) {
|
|
entity := NewEntity()
|
|
info := entity.GetInfoStruct()
|
|
info.SetMaxConcentration(1000) // Large pool for benchmarking
|
|
|
|
b.Run("AddRemoveMaintainedSpell", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
spellID := int32(i + 2000)
|
|
if entity.AddMaintainedSpell("Benchmark Spell", spellID, 60.0, 1) {
|
|
entity.RemoveMaintainedSpell(spellID)
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("AddRemoveMaintainedSpellParallel", func(b *testing.B) {
|
|
var counter int64
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
spellID := int32(counter + 2000)
|
|
counter++
|
|
if entity.AddMaintainedSpell("Benchmark Spell", spellID, 60.0, 1) {
|
|
entity.RemoveMaintainedSpell(spellID)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkInfoStructBasicOps measures basic InfoStruct operations
|
|
func BenchmarkInfoStructBasicOps(b *testing.B) {
|
|
info := NewInfoStruct()
|
|
|
|
b.Run("SetGetName", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
info.SetName("BenchmarkCharacter")
|
|
_ = info.GetName()
|
|
}
|
|
})
|
|
|
|
b.Run("SetGetNameParallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
info.SetName("BenchmarkCharacter")
|
|
_ = info.GetName()
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("SetGetLevel", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
info.SetLevel(int16(i % 100))
|
|
_ = info.GetLevel()
|
|
}
|
|
})
|
|
|
|
b.Run("SetGetStats", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
val := float32(i % 1000)
|
|
info.SetStr(val)
|
|
info.SetSta(val)
|
|
info.SetAgi(val)
|
|
info.SetWis(val)
|
|
info.SetIntel(val)
|
|
|
|
_ = info.GetStr()
|
|
_ = info.GetSta()
|
|
_ = info.GetAgi()
|
|
_ = info.GetWis()
|
|
_ = info.GetIntel()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkInfoStructConcentration measures concentration operations
|
|
func BenchmarkInfoStructConcentration(b *testing.B) {
|
|
info := NewInfoStruct()
|
|
info.SetMaxConcentration(1000)
|
|
|
|
b.Run("AddRemoveConcentration", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
amount := int16(i%10 + 1)
|
|
if info.AddConcentration(amount) {
|
|
info.RemoveConcentration(amount)
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("AddRemoveConcentrationParallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
amount := int16(1) // Use small amount to reduce contention
|
|
if info.AddConcentration(amount) {
|
|
info.RemoveConcentration(amount)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkInfoStructCoins measures coin operations
|
|
func BenchmarkInfoStructCoins(b *testing.B) {
|
|
info := NewInfoStruct()
|
|
|
|
b.Run("AddRemoveCoins", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
amount := int32(i%10000 + 1)
|
|
info.AddCoins(amount)
|
|
info.RemoveCoins(amount / 2)
|
|
}
|
|
})
|
|
|
|
b.Run("AddRemoveCoinsParallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
amount := int32(100)
|
|
info.AddCoins(amount)
|
|
info.RemoveCoins(amount / 2)
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("GetCoins", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = info.GetCoins()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkInfoStructResistances measures resistance operations
|
|
func BenchmarkInfoStructResistances(b *testing.B) {
|
|
info := NewInfoStruct()
|
|
resistTypes := []string{"heat", "cold", "magic", "mental", "divine", "disease", "poison"}
|
|
|
|
b.Run("SetGetResistances", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
resistType := resistTypes[i%len(resistTypes)]
|
|
value := int16(i % 100)
|
|
info.SetResistance(resistType, value)
|
|
_ = info.GetResistance(resistType)
|
|
}
|
|
})
|
|
|
|
b.Run("SetGetResistancesParallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
resistType := resistTypes[rand.Intn(len(resistTypes))]
|
|
value := int16(rand.Intn(100))
|
|
info.SetResistance(resistType, value)
|
|
_ = info.GetResistance(resistType)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkInfoStructClone measures clone operations
|
|
func BenchmarkInfoStructClone(b *testing.B) {
|
|
info := NewInfoStruct()
|
|
|
|
// Set up some state to clone
|
|
info.SetName("Original Character")
|
|
info.SetLevel(50)
|
|
info.SetStr(100.0)
|
|
info.SetSta(120.0)
|
|
info.SetAgi(90.0)
|
|
info.SetWis(110.0)
|
|
info.SetIntel(105.0)
|
|
info.AddConcentration(5)
|
|
info.AddCoins(50000)
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
clone := info.Clone()
|
|
_ = clone
|
|
}
|
|
}
|
|
|
|
// BenchmarkEntityPetManagement measures pet management operations
|
|
func BenchmarkEntityPetManagement(b *testing.B) {
|
|
entity := NewEntity()
|
|
|
|
b.Run("SetGetPet", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
pet := NewEntity()
|
|
entity.SetPet(pet)
|
|
_ = entity.GetPet()
|
|
entity.SetPet(nil)
|
|
}
|
|
})
|
|
|
|
b.Run("SetGetPetParallel", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
pet := NewEntity()
|
|
entity.SetPet(pet)
|
|
_ = entity.GetPet()
|
|
entity.SetPet(nil)
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("AllPetTypes", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
pet := NewEntity()
|
|
|
|
entity.SetPet(pet)
|
|
_ = entity.GetPet()
|
|
|
|
entity.SetCharmedPet(pet)
|
|
_ = entity.GetCharmedPet()
|
|
|
|
entity.SetDeityPet(pet)
|
|
_ = entity.GetDeityPet()
|
|
|
|
entity.SetCosmeticPet(pet)
|
|
_ = entity.GetCosmeticPet()
|
|
|
|
// Clear all pets
|
|
entity.SetPet(nil)
|
|
entity.SetCharmedPet(nil)
|
|
entity.SetDeityPet(nil)
|
|
entity.SetCosmeticPet(nil)
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkConcurrentWorkload simulates a realistic concurrent workload
|
|
func BenchmarkConcurrentWorkload(b *testing.B) {
|
|
numEntities := 100
|
|
entities := make([]*Entity, numEntities)
|
|
|
|
// Create entities
|
|
for i := 0; i < numEntities; i++ {
|
|
entities[i] = NewEntity()
|
|
info := entities[i].GetInfoStruct()
|
|
info.SetMaxConcentration(50)
|
|
info.SetName("Entity" + string(rune('A'+i%26)))
|
|
info.SetLevel(int16(i%100 + 1))
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
b.Run("MixedOperations", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
entityIdx := rand.Intn(numEntities)
|
|
entity := entities[entityIdx]
|
|
|
|
switch rand.Intn(10) {
|
|
case 0, 1: // Combat state changes (20%)
|
|
entity.SetInCombat(rand.Intn(2) == 1)
|
|
_ = entity.IsInCombat()
|
|
case 2, 3: // Stat reads (20%)
|
|
_ = entity.GetStr()
|
|
_ = entity.GetSta()
|
|
_ = entity.GetPrimaryStat()
|
|
case 4: // Spell effects (10%)
|
|
spellID := int32(rand.Intn(1000) + 10000)
|
|
entity.AddSpellEffect(spellID, int32(entityIdx), 30.0)
|
|
entity.RemoveSpellEffect(spellID)
|
|
case 5: // Maintained spells (10%)
|
|
spellID := int32(rand.Intn(100) + 20000)
|
|
if entity.AddMaintainedSpell("Workload Spell", spellID, 60.0, 1) {
|
|
entity.RemoveMaintainedSpell(spellID)
|
|
}
|
|
case 6, 7: // InfoStruct operations (20%)
|
|
info := entity.GetInfoStruct()
|
|
info.SetStr(float32(rand.Intn(200) + 50))
|
|
_ = info.GetStr()
|
|
case 8: // Coin operations (10%)
|
|
info := entity.GetInfoStruct()
|
|
info.AddCoins(int32(rand.Intn(1000)))
|
|
_ = info.GetCoins()
|
|
case 9: // Resistance operations (10%)
|
|
info := entity.GetInfoStruct()
|
|
resistTypes := []string{"heat", "cold", "magic", "mental"}
|
|
resistType := resistTypes[rand.Intn(len(resistTypes))]
|
|
info.SetResistance(resistType, int16(rand.Intn(100)))
|
|
_ = info.GetResistance(resistType)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkMemoryAllocation measures memory allocation patterns
|
|
func BenchmarkMemoryAllocation(b *testing.B) {
|
|
b.Run("EntityAllocation", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
entity := NewEntity()
|
|
_ = entity
|
|
}
|
|
})
|
|
|
|
b.Run("InfoStructAllocation", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
info := NewInfoStruct()
|
|
_ = info
|
|
}
|
|
})
|
|
|
|
b.Run("CloneAllocation", func(b *testing.B) {
|
|
info := NewInfoStruct()
|
|
info.SetName("Test")
|
|
info.SetLevel(50)
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
clone := info.Clone()
|
|
_ = clone
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkContention measures performance under high contention
|
|
func BenchmarkContention(b *testing.B) {
|
|
entity := NewEntity()
|
|
info := entity.GetInfoStruct()
|
|
info.SetMaxConcentration(10) // Low limit to create contention
|
|
|
|
b.Run("HighContentionConcentration", func(b *testing.B) {
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
if info.AddConcentration(1) {
|
|
// Hold for a brief moment to increase contention
|
|
time.Sleep(time.Nanosecond)
|
|
info.RemoveConcentration(1)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("HighContentionSpellEffects", func(b *testing.B) {
|
|
var spellCounter int64
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
spellID := int32(spellCounter % 100) // Reuse spell IDs to create contention
|
|
spellCounter++
|
|
entity.AddSpellEffect(spellID, 123, 30.0)
|
|
entity.RemoveSpellEffect(spellID)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// BenchmarkScalability tests performance as load increases
|
|
func BenchmarkScalability(b *testing.B) {
|
|
goroutineCounts := []int{1, 2, 4, 8, 16, 32, 64}
|
|
|
|
for _, numGoroutines := range goroutineCounts {
|
|
b.Run(fmt.Sprintf("Goroutines_%d", numGoroutines), func(b *testing.B) {
|
|
entity := NewEntity()
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
entity.SetInCombat(true)
|
|
_ = entity.IsInCombat()
|
|
entity.SetInCombat(false)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|