// Copyright Epic Games, Inc. All Rights Reserved. #include "MassEntityTrace.h" #if UE_MASS_TRACE_ENABLED #include "MassArchetypeData.h" #include "MassEntityTypes.h" #include "MassEntityQuery.h" #include "MassEntityUtils.h" #include "MassProcessor.h" #include "MassDebugger.h" #include "Trace/Trace.inl" #include "TraceFilter.h" UE_TRACE_CHANNEL_DEFINE(MassChannel); UE_TRACE_EVENT_BEGIN(MassTrace, MassPhaseBegin) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(UE::Trace::WideString, PhaseName) UE_TRACE_EVENT_FIELD(uint64, PhaseId) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassPhaseEnd) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(UE::Trace::WideString, PhaseName) UE_TRACE_EVENT_FIELD(uint64, PhaseId) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, RegisterMassArchetype) UE_TRACE_EVENT_FIELD(uint64, ArchetypeID) UE_TRACE_EVENT_FIELD(uint64[], Fragments) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, RegisterMassFragment) UE_TRACE_EVENT_FIELD(uint64, FragmentId) UE_TRACE_EVENT_FIELD(UE::Trace::WideString, FragmentName) UE_TRACE_EVENT_FIELD(uint32, FragmentSize) UE_TRACE_EVENT_FIELD(uint8, FragmentType) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassPhaseExecutionBegin) UE_TRACE_EVENT_FIELD(uint64, PhaseId) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassPhaseExecutionEnd) UE_TRACE_EVENT_FIELD(uint64, PhaseId) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassExecuteChunk) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, ChunkId) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_FIELD(int32, EntityCount) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassExecuteChunkEnd) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, ChunkId) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassBulkAddEntity) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64[], Entities) UE_TRACE_EVENT_FIELD(uint64[], ArchetypeIDs) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassBulkEntityDestroyed) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64[], Entities) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, MassEntityMoved) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, Entity) UE_TRACE_EVENT_FIELD(uint64, NewArchetypeID) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, QueryCreated) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_FIELD(UE::Trace::WideString, Name) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, QueryDestroyed) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, QueryRegisteredToProcessor) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_FIELD(uint64, ProcessorID) UE_TRACE_EVENT_FIELD(UE::Trace::WideString, ProcessorName) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, QueryArchetypeAdded) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_FIELD(uint64, ArchetypeID) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, QueryForEachStarted) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_END() UE_TRACE_EVENT_BEGIN(MassTrace, QueryForEachComplete) UE_TRACE_EVENT_FIELD(uint64, Cycle) UE_TRACE_EVENT_FIELD(uint64, QueryID) UE_TRACE_EVENT_FIELD(int32, ArchetypeCount) UE_TRACE_EVENT_FIELD(int32, ChunkCount) UE_TRACE_EVENT_FIELD(int32, EntityCount) UE_TRACE_EVENT_END() enum class FFragmentType : uint8 { Unknown = 0, Fragment, Tag, SharedFragment }; void FMassTrace::QueryCreated(const FMassEntityQuery* Query) { UE_TRACE_LOG(MassTrace, QueryCreated, MassChannel) << QueryCreated.Cycle(FPlatformTime::Cycles64()) << QueryCreated.QueryID(reinterpret_cast(Query)); } void FMassTrace::QueryDestroyed(const FMassEntityQuery* Query) { UE_TRACE_LOG(MassTrace, QueryDestroyed, MassChannel) << QueryDestroyed.Cycle(FPlatformTime::Cycles64()) << QueryDestroyed.QueryID(reinterpret_cast(Query)); } void FMassTrace::QueryRegisteredToProcessor(const FMassEntityQuery* Query, TNotNull Processor) { UE_TRACE_LOG(MassTrace, QueryRegisteredToProcessor, MassChannel) << QueryRegisteredToProcessor.QueryID(reinterpret_cast(Query)) << QueryRegisteredToProcessor.ProcessorID(reinterpret_cast((const UMassProcessor*)(Processor))) << QueryRegisteredToProcessor.ProcessorName(*Processor->GetProcessorName()); } void FMassTrace::QueryArchetypeAdded(const FMassEntityQuery* Query, const FMassArchetypeHandle& Archetype) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { uint64 ArchetypeID = reinterpret_cast(FMassArchetypeHelper::ArchetypeDataFromHandle(Archetype)); UE_TRACE_LOG(MassTrace, QueryArchetypeAdded, MassChannel) << QueryArchetypeAdded.QueryID(reinterpret_cast(Query)) << QueryArchetypeAdded.ArchetypeID(ArchetypeID); } } FMassTrace::FScopedQueryForEachTrace::FScopedQueryForEachTrace(const FMassEntityQuery* InQuery) : Query(InQuery) , ArchetypeCount(0) , ChunkCount(0) , EntityCount(0) { UE_TRACE_LOG(MassTrace, QueryForEachStarted, MassChannel) << QueryForEachStarted.Cycle(FPlatformTime::Cycles64()) << QueryForEachStarted.QueryID(reinterpret_cast(Query)); } FMassTrace::FScopedQueryForEachTrace::~FScopedQueryForEachTrace() { UE_TRACE_LOG(MassTrace, QueryForEachComplete, MassChannel) << QueryForEachComplete.Cycle(FPlatformTime::Cycles64()) << QueryForEachComplete.QueryID(reinterpret_cast(Query)) << QueryForEachComplete.ArchetypeCount(ArchetypeCount) << QueryForEachComplete.ChunkCount(ChunkCount) << QueryForEachComplete.EntityCount(EntityCount); } void FMassTrace::FScopedQueryForEachTrace::ReportArchetype(const FMassArchetypeData& Archetype) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { ++ArchetypeCount; ChunkCount += Archetype.GetChunkCount(); EntityCount += Archetype.GetNumEntities(); } } void FMassTrace::OutputRegisterFragment(const UScriptStruct* Struct) { const uint64 FragmentId = reinterpret_cast(Struct); const FFragmentType FragmentType = [](const UScriptStruct* Struct) { if (Struct->IsChildOf()) { return FFragmentType::Fragment; } else if (Struct->IsChildOf()) { return FFragmentType::Tag; } else if (Struct->IsChildOf()) { return FFragmentType::SharedFragment; } else { return FFragmentType::Unknown; } }(Struct); UE_TRACE_LOG(MassTrace, RegisterMassFragment, MassChannel) << RegisterMassFragment.FragmentId(FragmentId) << RegisterMassFragment.FragmentName(*Struct->GetName()) << RegisterMassFragment.FragmentSize(Struct->GetStructureSize()) << RegisterMassFragment.FragmentType(static_cast(FragmentType)); } void FMassTrace::OnPhaseBegin(uint64 PhaseId) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const FString EnumName = StaticEnum()->GetNameStringByValue(PhaseId); OutputBeginPhaseRegion(*EnumName); } } void FMassTrace::OnPhaseEnd(uint64 PhaseId) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const FString EnumName = StaticEnum()->GetNameStringByValue(PhaseId); OutputEndPhaseRegion(*EnumName); } } uint64 FMassTrace::OutputRegisterArchetype(uint64 ArchetypeID, const FMassArchetypeCompositionDescriptor& CompositionDescriptor) { TArray FragmentsScratch; FragmentsScratch.Reserve(CompositionDescriptor.Fragments.CountStoredTypes() + CompositionDescriptor.Tags.CountStoredTypes()); auto FragmentIterator = CompositionDescriptor.Fragments.GetIndexIterator(); while (FragmentIterator) { const UScriptStruct* FragmentStruct = CompositionDescriptor.Fragments.GetTypeAtIndex(*FragmentIterator); OutputRegisterFragment(FragmentStruct); // TODO Should have utility function to go from UScriptStruct to the fragment ID FragmentsScratch.Add(reinterpret_cast(FragmentStruct)); ++FragmentIterator; } auto TagIterator = CompositionDescriptor.Tags.GetIndexIterator(); while (TagIterator) { const UScriptStruct* FragmentStruct = CompositionDescriptor.Tags.GetTypeAtIndex(*TagIterator); { OutputRegisterFragment(FragmentStruct); } // TODO Should have utility function to go from UScriptStruct to the fragment ID FragmentsScratch.Add(reinterpret_cast(FragmentStruct)); ++TagIterator; } UE_TRACE_LOG(MassTrace, RegisterMassArchetype, MassChannel) << RegisterMassArchetype.ArchetypeID(ArchetypeID) << RegisterMassArchetype.Fragments(FragmentsScratch.GetData(), FragmentsScratch.Num()); return ArchetypeID; } uint64 FMassTrace::RegisterArchetype(const FMassArchetypeHandle& ArchetypeHandle) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const FMassArchetypeCompositionDescriptor& CompositionDescriptor = FMassDebugger::GetArchetypeComposition(ArchetypeHandle); const uint64 ArchetypeID = FMassDebugger::GetArchetypeTraceID(ArchetypeHandle); return OutputRegisterArchetype(ArchetypeID, CompositionDescriptor); } return 0; } uint64 FMassTrace::RegisterArchetype(const FMassArchetypeData& Data) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const FMassArchetypeCompositionDescriptor& CompositionDescriptor = Data.GetCompositionDescriptor(); const uint64 ArchetypeID = FMassDebugger::GetArchetypeTraceID(Data); return OutputRegisterArchetype(ArchetypeID, CompositionDescriptor); } return 0; } void FMassTrace::RegisterFragment(const UScriptStruct* Struct) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { OutputRegisterFragment(Struct); } } void FMassTrace::EntityCreated(FMassEntityHandle Entity, const FMassArchetypeData& Archetype) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const uint64 Cycle = FPlatformTime::Cycles64(); const uint64 EntityAsU64 = Entity.AsNumber(); const uint64 ArchetypeID = FMassDebugger::GetArchetypeTraceID(Archetype); UE_TRACE_LOG(MassTrace, MassBulkAddEntity, MassChannel) << MassBulkAddEntity.Cycle(Cycle) << MassBulkAddEntity.Entities(&EntityAsU64, 1) << MassBulkAddEntity.ArchetypeIDs(&ArchetypeID, 1); } } void FMassTrace::EntityMoved(FMassEntityHandle Entity, const FMassArchetypeData& NewArchetype) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const uint64 Cycle = FPlatformTime::Cycles64(); const uint64 EntityAsU64 = Entity.AsNumber(); UE_TRACE_LOG(MassTrace, MassEntityMoved, MassChannel) << MassEntityMoved.Cycle(Cycle) << MassEntityMoved.Entity(EntityAsU64) << MassEntityMoved.NewArchetypeID(FMassDebugger::GetArchetypeTraceID(NewArchetype)); } } void FMassTrace::EntityDestroyed(FMassEntityHandle Entity) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const uint64 Cycle = FPlatformTime::Cycles64(); const uint64 EntityAsU64 = Entity.AsNumber(); UE_TRACE_LOG(MassTrace, MassBulkEntityDestroyed, MassChannel) << MassBulkEntityDestroyed.Cycle(Cycle) << MassBulkEntityDestroyed.Entities(&EntityAsU64, 1); } } void FMassTrace::EntitiesDestroyed(TConstArrayView Entities) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const uint64 Cycle = FPlatformTime::Cycles64(); TConstArrayView EntitiesAsU64( reinterpret_cast(Entities.GetData()), Entities.Num()); UE_TRACE_LOG(MassTrace, MassBulkEntityDestroyed, MassChannel) << MassBulkEntityDestroyed.Cycle(Cycle) << MassBulkEntityDestroyed.Entities(EntitiesAsU64.GetData(), EntitiesAsU64.Num()); } } uint64_t FMassTrace::OutputBeginPhaseWithID(const TCHAR* PhaseName) { if (UE_TRACE_CHANNELEXPR_IS_ENABLED(MassChannel)) { const uint64 PhaseId = FPlatformTime::Cycles64(); UE_TRACE_LOG(MassTrace, MassPhaseBegin, MassChannel) << MassPhaseBegin.Cycle(FPlatformTime::Cycles64()) << MassPhaseBegin.PhaseName(PhaseName) << MassPhaseBegin.PhaseId(PhaseId); return PhaseId; } return 0; } void FMassTrace::OutputBeginPhaseRegion(const TCHAR* PhaseName) { UE_TRACE_LOG(MassTrace, MassPhaseBegin, MassChannel) << MassPhaseBegin.Cycle(FPlatformTime::Cycles64()) << MassPhaseBegin.PhaseName(PhaseName) << MassPhaseBegin.PhaseId(0); } void FMassTrace::OutputEndPhaseRegion(const TCHAR* PhaseName) { UE_TRACE_LOG(MassTrace, MassPhaseEnd, MassChannel) << MassPhaseEnd.Cycle(FPlatformTime::Cycles64()) << MassPhaseEnd.PhaseName(PhaseName) << MassPhaseEnd.PhaseId(0); } void FMassTrace::OutputEndPhaseRegion(uint64 PhaseId) { UE_TRACE_LOG(MassTrace, MassPhaseEnd, MassChannel) << MassPhaseEnd.Cycle(FPlatformTime::Cycles64()) << MassPhaseEnd.PhaseId(PhaseId); } #endif //UE_MASS_TRACE_ENABLED