package groups import ( "fmt" "math/rand" "sync/atomic" "testing" "time" ) // Mock implementations for benchmarking use the existing mock entities from groups_test.go // Helper functions for creating test data // createTestEntity creates a mock entity for benchmarking func createTestEntity(id int32, name string, isPlayer bool) *mockEntity { entity := createMockEntity(id, name, isPlayer) // Randomize some properties for more realistic benchmarking entity.level = int8(rand.Intn(80) + 1) entity.class = int8(rand.Intn(25) + 1) entity.race = int8(rand.Intn(18) + 1) entity.hp = int32(rand.Intn(5000) + 1000) entity.maxHP = int32(rand.Intn(5000) + 1000) entity.power = int32(rand.Intn(3000) + 500) entity.maxPower = int32(rand.Intn(3000) + 500) entity.isBot = !isPlayer && rand.Intn(2) == 1 entity.isNPC = !isPlayer && rand.Intn(2) == 0 entity.zone = &mockZone{ zoneID: int32(rand.Intn(100) + 1), instanceID: int32(rand.Intn(10)), zoneName: fmt.Sprintf("Zone %d", rand.Intn(100)+1), } return entity } // createTestGroup creates a group with test data for benchmarking func createTestGroup(b *testing.B, groupID int32, memberCount int) *Group { b.Helper() group := NewGroup(groupID, nil, nil) // Add test members for i := 0; i < memberCount; i++ { entity := createTestEntity( int32(i+1), fmt.Sprintf("Player%d", i+1), true, ) isLeader := (i == 0) err := group.AddMember(entity, isLeader) if err != nil { b.Fatalf("Failed to add member to group: %v", err) } } return group } // BenchmarkGroupCreation measures group creation performance func BenchmarkGroupCreation(b *testing.B) { b.Run("NewGroup", func(b *testing.B) { for i := 0; i < b.N; i++ { group := NewGroup(int32(i+1), nil, nil) group.Disband() // Clean up background goroutine } }) b.Run("NewGroupWithOptions", func(b *testing.B) { options := DefaultGroupOptions() for i := 0; i < b.N; i++ { group := NewGroup(int32(i+1), &options, nil) group.Disband() // Clean up background goroutine } }) b.Run("NewGroupParallel", func(b *testing.B) { var idCounter int64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { id := atomic.AddInt64(&idCounter, 1) group := NewGroup(int32(id), nil, nil) group.Disband() // Clean up background goroutine } }) }) } // BenchmarkGroupMemberOperations measures member management performance func BenchmarkGroupMemberOperations(b *testing.B) { group := createTestGroup(b, 1001, 3) defer group.Disband() // Clean up background goroutine b.Run("AddMember", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { // Create a new group for each iteration to avoid full group testGroup := NewGroup(int32(i+1000), nil, nil) entity := createTestEntity(int32(i+1), fmt.Sprintf("BenchPlayer%d", i), true) testGroup.AddMember(entity, false) testGroup.Disband() // Clean up background goroutine } }) b.Run("GetSize", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetSize() } }) }) b.Run("GetMembers", func(b *testing.B) { for i := 0; i < b.N; i++ { _ = group.GetMembers() } }) b.Run("GetLeaderName", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetLeaderName() } }) }) b.Run("UpdateGroupMemberInfo", func(b *testing.B) { members := group.GetMembers() if len(members) == 0 { b.Skip("No members to update") } for i := 0; i < b.N; i++ { member := members[i%len(members)] if member.Member != nil { group.UpdateGroupMemberInfo(member.Member, false) } } }) } // BenchmarkGroupOptions measures group options performance func BenchmarkGroupOptions(b *testing.B) { group := createTestGroup(b, 1001, 3) defer group.Disband() // Clean up background goroutine b.Run("GetGroupOptions", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetGroupOptions() } }) }) b.Run("SetGroupOptions", func(b *testing.B) { options := DefaultGroupOptions() for i := 0; i < b.N; i++ { options.LootMethod = int8(i % 4) group.SetGroupOptions(&options) } }) b.Run("GetLastLooterIndex", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetLastLooterIndex() } }) }) b.Run("SetNextLooterIndex", func(b *testing.B) { for i := 0; i < b.N; i++ { group.SetNextLooterIndex(int8(i % 6)) } }) } // BenchmarkGroupRaidOperations measures raid functionality performance func BenchmarkGroupRaidOperations(b *testing.B) { group := createTestGroup(b, 1001, 6) defer group.Disband() // Clean up background goroutine // Setup some raid groups raidGroups := []int32{1001, 1002, 1003, 1004} group.ReplaceRaidGroups(raidGroups) b.Run("GetRaidGroups", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetRaidGroups() } }) }) b.Run("IsGroupRaid", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.IsGroupRaid() } }) }) b.Run("IsInRaidGroup", func(b *testing.B) { for i := 0; i < b.N; i++ { targetID := int32((i % 4) + 1001) _ = group.IsInRaidGroup(targetID, false) } }) b.Run("AddGroupToRaid", func(b *testing.B) { for i := 0; i < b.N; i++ { // Cycle through a limited set of group IDs to avoid infinite growth groupID := int32(2000 + (i % 10)) group.AddGroupToRaid(groupID) } }) b.Run("ReplaceRaidGroups", func(b *testing.B) { newGroups := []int32{2001, 2002, 2003} for i := 0; i < b.N; i++ { group.ReplaceRaidGroups(newGroups) } }) b.Run("ClearGroupRaid", func(b *testing.B) { for i := 0; i < b.N; i++ { group.ClearGroupRaid() // Re-add groups for next iteration group.ReplaceRaidGroups(raidGroups) } }) } // BenchmarkGroupMessaging measures messaging performance func BenchmarkGroupMessaging(b *testing.B) { group := createTestGroup(b, 1001, 6) defer group.Disband() // Clean up background goroutine b.Run("SimpleGroupMessage", func(b *testing.B) { for i := 0; i < b.N; i++ { group.SimpleGroupMessage(fmt.Sprintf("Benchmark message %d", i)) } }) b.Run("SendGroupMessage", func(b *testing.B) { for i := 0; i < b.N; i++ { group.SendGroupMessage(GROUP_MESSAGE_TYPE_SYSTEM, fmt.Sprintf("System message %d", i)) } }) b.Run("GroupChatMessageFromName", func(b *testing.B) { for i := 0; i < b.N; i++ { group.GroupChatMessageFromName( fmt.Sprintf("Player%d", i%6+1), 0, fmt.Sprintf("Chat message %d", i), CHANNEL_GROUP_CHAT, ) } }) } // BenchmarkGroupState measures group state operations func BenchmarkGroupState(b *testing.B) { group := createTestGroup(b, 1001, 6) defer group.Disband() // Clean up background goroutine b.Run("GetID", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetID() } }) }) b.Run("IsDisbanded", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.IsDisbanded() } }) }) b.Run("GetCreatedTime", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetCreatedTime() } }) }) b.Run("GetLastActivity", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = group.GetLastActivity() } }) }) } // BenchmarkMasterListOperations measures master list performance func BenchmarkMasterListOperations(b *testing.B) { ml := NewMasterList() // Pre-populate with groups const numGroups = 1000 groups := make([]*Group, numGroups) b.StopTimer() for i := 0; i < numGroups; i++ { groups[i] = createTestGroup(b, int32(i+1), rand.Intn(6)+1) ml.AddGroup(groups[i]) } // Cleanup all groups when benchmark is done defer func() { for _, group := range groups { if group != nil { group.Disband() } } }() b.StartTimer() b.Run("GetGroup", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { id := int32(rand.Intn(numGroups) + 1) _ = ml.GetGroup(id) } }) }) b.Run("AddGroup", func(b *testing.B) { startID := int32(numGroups + 1) var addedGroups []*Group b.ResetTimer() for i := 0; i < b.N; i++ { group := createTestGroup(b, startID+int32(i), 3) ml.AddGroup(group) addedGroups = append(addedGroups, group) } // Cleanup added groups for _, group := range addedGroups { group.Disband() } }) b.Run("GetAllGroups", func(b *testing.B) { for i := 0; i < b.N; i++ { _ = ml.GetAllGroups() } }) b.Run("GetActiveGroups", func(b *testing.B) { for i := 0; i < b.N; i++ { _ = ml.GetActiveGroups() } }) b.Run("GetGroupsByZone", func(b *testing.B) { for i := 0; i < b.N; i++ { zoneID := int32(rand.Intn(100) + 1) _ = ml.GetGroupsByZone(zoneID) } }) b.Run("GetGroupsBySize", func(b *testing.B) { for i := 0; i < b.N; i++ { size := int32(rand.Intn(6) + 1) _ = ml.GetGroupsBySize(size) } }) b.Run("GetRaidGroups", func(b *testing.B) { for i := 0; i < b.N; i++ { _ = ml.GetRaidGroups() } }) b.Run("GetGroupStatistics", func(b *testing.B) { for i := 0; i < b.N; i++ { _ = ml.GetGroupStatistics() } }) } // BenchmarkManagerOperations measures manager performance func BenchmarkManagerOperations(b *testing.B) { config := GroupManagerConfig{ MaxGroups: 1000, InviteTimeout: 30 * time.Second, UpdateInterval: 1 * time.Second, BuffUpdateInterval: 5 * time.Second, EnableStatistics: true, } manager := NewManager(config, nil) // Pre-populate with groups b.StopTimer() for i := 0; i < 100; i++ { leader := createTestEntity(int32(i+1), fmt.Sprintf("Leader%d", i+1), true) manager.NewGroup(leader, nil, 0) } b.StartTimer() b.Run("NewGroup", func(b *testing.B) { startID := int32(1000) for i := 0; i < b.N; i++ { leader := createTestEntity(startID+int32(i), fmt.Sprintf("BenchLeader%d", i), true) _, err := manager.NewGroup(leader, nil, 0) if err != nil { b.Fatalf("Failed to create group: %v", err) } } }) b.Run("GetGroup", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { groupID := int32(rand.Intn(100) + 1) _ = manager.GetGroup(groupID) } }) }) b.Run("IsGroupIDValid", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { groupID := int32(rand.Intn(100) + 1) _ = manager.IsGroupIDValid(groupID) } }) }) b.Run("GetGroupCount", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = manager.GetGroupCount() } }) }) b.Run("GetAllGroups", func(b *testing.B) { for i := 0; i < b.N; i++ { _ = manager.GetAllGroups() } }) b.Run("GetStats", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = manager.GetStats() } }) }) } // BenchmarkInviteSystem measures invitation system performance func BenchmarkInviteSystem(b *testing.B) { config := GroupManagerConfig{ InviteTimeout: 30 * time.Second, EnableStatistics: true, } manager := NewManager(config, nil) b.Run("AddInvite", func(b *testing.B) { for i := 0; i < b.N; i++ { leader := createTestEntity(int32(i+1), fmt.Sprintf("Leader%d", i+1), true) member := createTestEntity(int32(i+1001), fmt.Sprintf("Member%d", i+1), true) manager.AddInvite(leader, member) } }) b.Run("HasPendingInvite", func(b *testing.B) { // Add some invites first for i := 0; i < 100; i++ { leader := createTestEntity(int32(i+1), fmt.Sprintf("TestLeader%d", i+1), true) member := createTestEntity(int32(i+2001), fmt.Sprintf("TestMember%d", i+1), true) manager.AddInvite(leader, member) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { member := createTestEntity(int32(rand.Intn(100)+2001), fmt.Sprintf("TestMember%d", rand.Intn(100)+1), true) _ = manager.HasPendingInvite(member) } }) }) b.Run("Invite", func(b *testing.B) { for i := 0; i < b.N; i++ { leader := createTestEntity(int32(i+3001), fmt.Sprintf("InviteLeader%d", i+1), true) member := createTestEntity(int32(i+4001), fmt.Sprintf("InviteMember%d", i+1), true) _ = manager.Invite(leader, member) } }) b.Run("DeclineInvite", func(b *testing.B) { // Add invites to decline for i := 0; i < b.N; i++ { leader := createTestEntity(int32(i+5001), fmt.Sprintf("DeclineLeader%d", i+1), true) member := createTestEntity(int32(i+6001), fmt.Sprintf("DeclineMember%d", i+1), true) manager.AddInvite(leader, member) manager.DeclineInvite(member) } }) } // BenchmarkConcurrentOperations measures concurrent access performance func BenchmarkConcurrentOperations(b *testing.B) { config := GroupManagerConfig{ MaxGroups: 1000, EnableStatistics: true, } manager := NewManager(config, nil) // Pre-populate for i := 0; i < 50; i++ { leader := createTestEntity(int32(i+1), fmt.Sprintf("ConcurrentLeader%d", i+1), true) manager.NewGroup(leader, nil, 0) } b.Run("ConcurrentGroupAccess", func(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { groupID := int32(rand.Intn(50) + 1) switch rand.Intn(4) { case 0: _ = manager.GetGroup(groupID) case 1: _ = manager.GetGroupSize(groupID) case 2: _ = manager.IsGroupIDValid(groupID) case 3: member := createTestEntity(int32(rand.Intn(1000)+10000), "ConcurrentMember", true) manager.AddGroupMember(groupID, member, false) } } }) }) b.Run("ConcurrentInviteOperations", func(b *testing.B) { var counter int64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { i := atomic.AddInt64(&counter, 1) leader := createTestEntity(int32(i+20000), fmt.Sprintf("ConcurrentInviteLeader%d", i), true) member := createTestEntity(int32(i+30000), fmt.Sprintf("ConcurrentInviteMember%d", i), true) switch rand.Intn(3) { case 0: manager.AddInvite(leader, member) case 1: _ = manager.HasPendingInvite(member) case 2: manager.DeclineInvite(member) } } }) }) } // BenchmarkMemoryAllocation measures memory allocation patterns func BenchmarkMemoryAllocation(b *testing.B) { b.Run("GroupAllocation", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { group := NewGroup(int32(i+1), nil, nil) group.Disband() // Clean up background goroutine } }) b.Run("MasterListAllocation", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { ml := NewMasterList() _ = ml } }) b.Run("ManagerAllocation", func(b *testing.B) { config := GroupManagerConfig{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { manager := NewManager(config, nil) _ = manager } }) b.Run("GroupMemberInfoAllocation", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { gmi := &GroupMemberInfo{ GroupID: int32(i + 1), Name: fmt.Sprintf("Member%d", i+1), Zone: "TestZone", HPCurrent: 1000, HPMax: 1000, PowerCurrent: 500, PowerMax: 500, LevelCurrent: 50, LevelMax: 80, RaceID: 1, ClassID: 1, Leader: false, IsClient: true, JoinTime: time.Now(), LastUpdate: time.Now(), } _ = gmi } }) } // BenchmarkComparisonWithOldSystem provides comparison benchmarks func BenchmarkComparisonWithOldSystem(b *testing.B) { ml := NewMasterList() const numGroups = 1000 // Setup b.StopTimer() groups := make([]*Group, numGroups) for i := 0; i < numGroups; i++ { groups[i] = createTestGroup(b, int32(i+1), rand.Intn(6)+1) ml.AddGroup(groups[i]) } // Cleanup all groups when benchmark is done defer func() { for _, group := range groups { if group != nil { group.Disband() } } }() b.StartTimer() b.Run("ModernizedGroupLookup", func(b *testing.B) { // Modern generic-based lookup b.RunParallel(func(pb *testing.PB) { for pb.Next() { id := int32(rand.Intn(numGroups) + 1) _ = ml.GetGroup(id) } }) }) b.Run("ModernizedGroupFiltering", func(b *testing.B) { // Modern filter-based operations for i := 0; i < b.N; i++ { _ = ml.GetActiveGroups() } }) b.Run("ModernizedGroupStatistics", func(b *testing.B) { // Modern statistics computation for i := 0; i < b.N; i++ { _ = ml.GetGroupStatistics() } }) }