Files
yoan stamant 05bc614a8e [StateTreeDebugger]
- Added trace event for Phase (Push + Pop) to make it easier to recreate the event hierarchy when analyzing the traces.
- Merged enums EStateTreeTraceInstanceEventType and EStateTreeTraceNodeEventType to EStateTreeTraceEventType which is mainly a list of verbs that could be reused for different events (States, Instances, Tasks, etc.)
- EStateTreeUpdatePhase is no longer used as flags and reduced to uint8
- Phase events are stacked when producing traces and sent only if meaningful events (Task, State, Transition, etc.) are sent during their scope. This is to avoid sending useless events when the StateTree is ticked without any changes
#rnx
#rb mikko.mononen
#preflight 6474a5e62e05bcc3309d093e

[CL 25663847 by yoan stamant in ue5-main branch]
2023-05-29 10:13:21 -04:00

119 lines
3.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#if WITH_STATETREE_DEBUGGER
#include "Debugger/StateTreeTraceProvider.h"
#include "StateTreeTypes.h"
#include "Debugger/StateTreeDebugger.h"
FName FStateTreeTraceProvider::ProviderName("StateTreeDebuggerProvider");
#define LOCTEXT_NAMESPACE "StateTreeDebuggerProvider"
FStateTreeTraceProvider::FStateTreeTraceProvider(TraceServices::IAnalysisSession& InSession)
: Session(InSession)
{
}
bool FStateTreeTraceProvider::ReadTimelines(const FStateTreeInstanceDebugId InstanceId, const TFunctionRef<void(const FStateTreeInstanceDebugId ProcessedInstanceId, const FEventsTimeline&)> Callback) const
{
Session.ReadAccessCheck();
// Read specific timeline if specified
if (InstanceId.IsValid())
{
const uint32* IndexPtr = InstanceIdToDebuggerEntryTimelines.Find(InstanceId);
if (IndexPtr != nullptr && EventsTimelines.IsValidIndex(*IndexPtr))
{
Callback(InstanceId, *EventsTimelines[*IndexPtr]);
return true;
}
}
else
{
for(auto It = InstanceIdToDebuggerEntryTimelines.CreateConstIterator(); It; ++It)
{
if (EventsTimelines.IsValidIndex(It.Value()))
{
Callback(It.Key(), *EventsTimelines[It.Value()]);
}
}
return EventsTimelines.Num() > 0;
}
return false;
}
bool FStateTreeTraceProvider::ReadTimelines(const UStateTree& StateTree, TFunctionRef<void(const FStateTreeInstanceDebugId ProcessedInstanceId, const FEventsTimeline&)> Callback) const
{
Session.ReadAccessCheck();
for (auto It = InstanceIdToDebuggerEntryTimelines.CreateConstIterator(); It; ++It)
{
check(EventsTimelines.IsValidIndex(It.Value()));
check(Descriptors.Num() == EventsTimelines.Num());
if (Descriptors[It.Value()].StateTree == &StateTree)
{
Callback(Descriptors[It.Value()].Id, *EventsTimelines[It.Value()]);
}
}
return EventsTimelines.Num() > 0;
}
void FStateTreeTraceProvider::AppendEvent(const FStateTreeInstanceDebugId InInstanceId, const double InTime, const FStateTreeTraceEventVariantType& InEvent)
{
Session.WriteAccessCheck();
// It is currently possible to receive events from an instance without receiving event `EStateTreeTraceEventType::Push` first
// (i.e. traces were activated after the statetree instance execution was started).
// We plan to buffer the Instance events (Started/Stopped) to address this but for now we ignore events related to that instance.
if (const uint32* IndexPtr = InstanceIdToDebuggerEntryTimelines.Find(InInstanceId))
{
EventsTimelines[*IndexPtr]->AppendEvent(InTime, InEvent);
}
Session.UpdateDurationSeconds(InTime);
}
void FStateTreeTraceProvider::AppendInstanceEvent(
const UStateTree* InStateTree,
const FStateTreeInstanceDebugId InInstanceId,
const TCHAR* InInstanceName,
const double InTime,
const double InWorldRecordingTime,
const EStateTreeTraceEventType InEventType)
{
if (InEventType == EStateTreeTraceEventType::Push)
{
Descriptors.Emplace(InStateTree, InInstanceId, InInstanceName, TRange<double>(InWorldRecordingTime, std::numeric_limits<double>::max()));
check(InstanceIdToDebuggerEntryTimelines.Find(InInstanceId) == nullptr);
InstanceIdToDebuggerEntryTimelines.Add(InInstanceId, EventsTimelines.Num());
EventsTimelines.Emplace(MakeShared<TraceServices::TPointTimeline<FStateTreeTraceEventVariantType>>(Session.GetLinearAllocator()));
}
else if (InEventType == EStateTreeTraceEventType::Pop)
{
// Process only if timeline can be found. See details in AppendEvent comment.
if (const uint32* Index = InstanceIdToDebuggerEntryTimelines.Find(InInstanceId))
{
check(Descriptors.IsValidIndex(*Index));
Descriptors[*Index].Lifetime.SetUpperBound(InWorldRecordingTime);
}
}
Session.UpdateDurationSeconds(InTime);
}
void FStateTreeTraceProvider::GetInstances(TArray<UE::StateTreeDebugger::FInstanceDescriptor>& OutInstances) const
{
OutInstances = Descriptors;
}
#undef LOCTEXT_NAMESPACE
#endif // WITH_STATETREE_DEBUGGER