Files
UnrealEngine/Engine/Source/Developer/TraceInsights/Private/Insights/LoadingProfiler/Tracks/LoadingTimingTrack.cpp
2025-05-18 13:04:45 +08:00

305 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LoadingTimingTrack.h"
// TraceServices
#include "TraceServices/Containers/Timelines.h"
#include "TraceServices/Model/AnalysisSession.h"
#include "TraceServices/Model/LoadTimeProfiler.h"
// TraceInsightsCore
#include "InsightsCore/Common/TimeUtils.h"
#include "InsightsCore/Filter/ViewModels/FilterConfigurator.h"
#include "InsightsCore/Filter/ViewModels/Filters.h"
// TraceInsights
#include "Insights/InsightsManager.h"
#include "Insights/LoadingProfiler/ViewModels/LoadingSharedState.h"
#include "Insights/ViewModels/TimingEvent.h"
#include "Insights/ViewModels/TimingEventSearch.h"
#include "Insights/ViewModels/TimingTrackViewport.h"
#include "Insights/ViewModels/TooltipDrawState.h"
#define LOCTEXT_NAMESPACE "UE::Insights::LoadingProfiler"
namespace UE::Insights::LoadingProfiler
{
////////////////////////////////////////////////////////////////////////////////////////////////////
INSIGHTS_IMPLEMENT_RTTI(FLoadingTimingTrack)
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLoadingTimingTrack::BuildDrawState(ITimingEventsTrackDrawStateBuilder& Builder, const ITimingTrackUpdateContext& Context)
{
TSharedPtr<const TraceServices::IAnalysisSession> Session = FInsightsManager::Get()->GetSession();
if (Session.IsValid() && TraceServices::ReadLoadTimeProfilerProvider(*Session.Get()))
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
const TraceServices::ILoadTimeProfilerProvider& LoadTimeProfilerProvider = *TraceServices::ReadLoadTimeProfilerProvider(*Session.Get());
const FTimingTrackViewport& Viewport = Context.GetViewport();
LoadTimeProfilerProvider.ReadTimeline(TimelineIndex, [this, &Builder, &Viewport](const TraceServices::ILoadTimeProfilerProvider::CpuTimeline& Timeline)
{
if (FTimingEventsTrack::bUseDownSampling)
{
const double SecondsPerPixel = 1.0 / Viewport.GetScaleX();
Timeline.EnumerateEventsDownSampled(Viewport.GetStartTime(), Viewport.GetEndTime(), SecondsPerPixel, [this, &Builder](double StartTime, double EndTime, uint32 Depth, const TraceServices::FLoadTimeProfilerCpuEvent& Event)
{
if (Event.Package)
{
const TCHAR* Name = SharedState.GetEventName(Depth, Event);
const uint64 Type = static_cast<uint64>(Event.EventType);
const uint32 Color = 0;
Builder.AddEvent(StartTime, EndTime, Depth, Name, Type, Color);
}
return TraceServices::EEventEnumerate::Continue;
});
}
else
{
Timeline.EnumerateEvents(Viewport.GetStartTime(), Viewport.GetEndTime(), [this, &Builder](double StartTime, double EndTime, uint32 Depth, const TraceServices::FLoadTimeProfilerCpuEvent& Event)
{
if (Event.Package)
{
const TCHAR* Name = SharedState.GetEventName(Depth, Event);
const uint64 Type = static_cast<uint64>(Event.EventType);
const uint32 Color = 0;
Builder.AddEvent(StartTime, EndTime, Depth, Name, Type, Color);
}
return TraceServices::EEventEnumerate::Continue;
});
}
});
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLoadingTimingTrack::BuildFilteredDrawState(ITimingEventsTrackDrawStateBuilder& Builder, const ITimingTrackUpdateContext& Context)
{
if (HasCustomFilter())
{
using EFilterField = UE::Insights::EFilterField;
UE::Insights::FFilterContext FilterConfiguratorContext;
FilterConfiguratorContext.SetReturnValueForUnsetFilters(false);
FilterConfiguratorContext.AddFilterData<double>(static_cast<int32>(EFilterField::StartTime), 0.0f);
FilterConfiguratorContext.AddFilterData<double>(static_cast<int32>(EFilterField::EndTime), 0.0f);
FilterConfiguratorContext.AddFilterData<double>(static_cast<int32>(EFilterField::Duration), 0.0f);
FilterConfiguratorContext.AddFilterData<FString>(static_cast<int32>(EFilterField::TrackName), this->GetName());
TSharedPtr<const TraceServices::IAnalysisSession> Session = FInsightsManager::Get()->GetSession();
if (Session.IsValid() && TraceServices::ReadLoadTimeProfilerProvider(*Session.Get()))
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
const TraceServices::ILoadTimeProfilerProvider& LoadTimeProfilerProvider = *TraceServices::ReadLoadTimeProfilerProvider(*Session.Get());
const FTimingTrackViewport& Viewport = Context.GetViewport();
LoadTimeProfilerProvider.ReadTimeline(TimelineIndex, [this, &Builder, &Viewport, &FilterConfiguratorContext](const TraceServices::ILoadTimeProfilerProvider::CpuTimeline& Timeline)
{
Timeline.EnumerateEvents(Viewport.GetStartTime(), Viewport.GetEndTime(), [this, &Builder, &FilterConfiguratorContext](double StartTime, double EndTime, uint32 Depth, const TraceServices::FLoadTimeProfilerCpuEvent& Event)
{
if (Event.Package)
{
FilterConfiguratorContext.SetFilterData<double>(static_cast<int32>(EFilterField::StartTime), StartTime);
FilterConfiguratorContext.SetFilterData<double>(static_cast<int32>(EFilterField::EndTime), EndTime);
FilterConfiguratorContext.SetFilterData<double>(static_cast<int32>(EFilterField::Duration), EndTime - StartTime);
if (FilterConfigurator->ApplyFilters(FilterConfiguratorContext))
{
const TCHAR* Name = SharedState.GetEventName(Depth, Event);
const uint64 Type = static_cast<uint64>(Event.EventType);
const uint32 Color = 0;
Builder.AddEvent(StartTime, EndTime, Depth, Name, Type, Color);
}
}
return TraceServices::EEventEnumerate::Continue;
});
});
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLoadingTimingTrack::InitTooltip(FTooltipDrawState& InOutTooltip, const ITimingEvent& InTooltipEvent) const
{
if (InTooltipEvent.CheckTrack(this) && InTooltipEvent.Is<FTimingEvent>())
{
const FTimingEvent& TooltipEvent = InTooltipEvent.As<FTimingEvent>();
auto MatchEvent = [&TooltipEvent](double InStartTime, double InEndTime, uint32 InDepth)
{
return InDepth == TooltipEvent.GetDepth()
&& InStartTime == TooltipEvent.GetStartTime()
&& InEndTime == TooltipEvent.GetEndTime();
};
FTimingEventSearchParameters SearchParameters(TooltipEvent.GetStartTime(), TooltipEvent.GetEndTime(), ETimingEventSearchFlags::StopAtFirstMatch, MatchEvent);
FindLoadTimeProfilerCpuEvent(SearchParameters, [this, &InOutTooltip, &TooltipEvent](double InFoundStartTime, double InFoundEndTime, uint32 InFoundDepth, const TraceServices::FLoadTimeProfilerCpuEvent& InFoundEvent)
{
InOutTooltip.ResetContent();
InOutTooltip.AddTitle(SharedState.GetEventName(TooltipEvent.GetDepth(), InFoundEvent));
const TraceServices::FPackageExportInfo* Export = InFoundEvent.Export;
const TraceServices::FPackageInfo* Package = InFoundEvent.Export ? InFoundEvent.Export->Package : InFoundEvent.Package;
InOutTooltip.AddNameValueTextLine(TEXT("Duration:"), UE::Insights::FormatTimeAuto(TooltipEvent.GetDuration()));
InOutTooltip.AddNameValueTextLine(TEXT("Depth:"), FString::Printf(TEXT("%d"), TooltipEvent.GetDepth()));
if (Package)
{
InOutTooltip.AddNameValueTextLine(TEXT("Package Name:"), Package->Name);
InOutTooltip.AddNameValueTextLine(TEXT("Header Size:"), FString::Printf(TEXT("%s bytes"), *FText::AsNumber(Package->Summary.TotalHeaderSize).ToString()));
InOutTooltip.AddNameValueTextLine(TEXT("Package Summary:"), FString::Printf(TEXT("%d imports, %d exports"), Package->Summary.ImportCount, Package->Summary.ExportCount));
InOutTooltip.AddNameValueTextLine(TEXT("Request Priority:"), FString::Printf(TEXT("%d"), Package->Summary.Priority));
if (!Export)
{
InOutTooltip.AddNameValueTextLine(TEXT("Event:"), TEXT("ProcessPackageSummary"));
}
}
if (Export)
{
InOutTooltip.AddNameValueTextLine(TEXT("Event:"), FString::Printf(TEXT("%s"), TraceServices::GetLoadTimeProfilerObjectEventTypeString(InFoundEvent.EventType)));
InOutTooltip.AddNameValueTextLine(TEXT("Export Class:"), Export->Class ? Export->Class->Name : TEXT("N/A"));
InOutTooltip.AddNameValueTextLine(TEXT("Serial Size:"), FString::Printf(TEXT("%s bytes"), *FText::AsNumber(Export->SerialSize).ToString()));
}
InOutTooltip.UpdateLayout();
});
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
const TSharedPtr<const ITimingEvent> FLoadingTimingTrack::SearchEvent(const FTimingEventSearchParameters& InSearchParameters) const
{
TSharedPtr<const ITimingEvent> FoundEvent;
FindLoadTimeProfilerCpuEvent(InSearchParameters, [this, &FoundEvent](double InFoundStartTime, double InFoundEndTime, uint32 InFoundDepth, const TraceServices::FLoadTimeProfilerCpuEvent& InFoundEvent)
{
FoundEvent = MakeShared<FTimingEvent>(SharedThis(this), InFoundStartTime, InFoundEndTime, InFoundDepth);
});
return FoundEvent;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool FLoadingTimingTrack::FindLoadTimeProfilerCpuEvent(const FTimingEventSearchParameters& InParameters, TFunctionRef<void(double, double, uint32, const TraceServices::FLoadTimeProfilerCpuEvent&)> InFoundPredicate) const
{
using EFilterField = UE::Insights::EFilterField;
UE::Insights::FFilterContext FilterConfiguratorContext;
FilterConfiguratorContext.SetReturnValueForUnsetFilters(false);
FilterConfiguratorContext.AddFilterData<double>(static_cast<int32>(EFilterField::StartTime), 0.0f);
FilterConfiguratorContext.AddFilterData<double>(static_cast<int32>(EFilterField::EndTime), 0.0f);
FilterConfiguratorContext.AddFilterData<double>(static_cast<int32>(EFilterField::Duration), 0.0f);
FilterConfiguratorContext.AddFilterData<FString>(static_cast<int32>(EFilterField::TrackName), this->GetName());
return TTimingEventSearch<TraceServices::FLoadTimeProfilerCpuEvent>::Search(
InParameters,
[this](TTimingEventSearch<TraceServices::FLoadTimeProfilerCpuEvent>::FContext& InContext)
{
TSharedPtr<const TraceServices::IAnalysisSession> Session = FInsightsManager::Get()->GetSession();
if (Session.IsValid())
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
if (TraceServices::ReadLoadTimeProfilerProvider(*Session.Get()))
{
const TraceServices::ILoadTimeProfilerProvider& LoadTimeProfilerProvider = *TraceServices::ReadLoadTimeProfilerProvider(*Session.Get());
LoadTimeProfilerProvider.ReadTimeline(TimelineIndex, [&InContext](const TraceServices::ILoadTimeProfilerProvider::CpuTimeline& Timeline)
{
auto Callback = [&InContext](double EventStartTime, double EventEndTime, uint32 EventDepth, const TraceServices::FLoadTimeProfilerCpuEvent& Event)
{
if (Event.Package)
{
InContext.Check(EventStartTime, EventEndTime, EventDepth, Event);
return InContext.ShouldContinueSearching() ? TraceServices::EEventEnumerate::Continue : TraceServices::EEventEnumerate::Stop;
}
else
{
return TraceServices::EEventEnumerate::Continue;
}
};
if (InContext.GetParameters().SearchDirection == FTimingEventSearchParameters::ESearchDirection::Forward)
{
Timeline.EnumerateEvents(InContext.GetParameters().StartTime, InContext.GetParameters().EndTime, Callback);
}
else
{
Timeline.EnumerateEventsBackwards(InContext.GetParameters().EndTime, InContext.GetParameters().StartTime, Callback);
}
});
}
}
},
[&FilterConfiguratorContext, &InParameters](double EventStartTime, double EventEndTime, uint32 EventDepth, const TraceServices::FLoadTimeProfilerCpuEvent& Event)
{
if (!InParameters.FilterExecutor.IsValid())
{
return true;
}
TSharedPtr<const TraceServices::IAnalysisSession> Session = FInsightsManager::Get()->GetSession();
if (Session.IsValid())
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
if (TraceServices::ReadLoadTimeProfilerProvider(*Session.Get()))
{
FilterConfiguratorContext.SetFilterData<double>(static_cast<int32>(EFilterField::StartTime), EventStartTime);
FilterConfiguratorContext.SetFilterData<double>(static_cast<int32>(EFilterField::EndTime), EventEndTime);
FilterConfiguratorContext.SetFilterData<double>(static_cast<int32>(EFilterField::Duration), EventEndTime - EventStartTime);
return InParameters.FilterExecutor->ApplyFilters(FilterConfiguratorContext);
}
}
return false;
},
[&InFoundPredicate](double InFoundStartTime, double InFoundEndTime, uint32 InFoundDepth, const TraceServices::FLoadTimeProfilerCpuEvent& InEvent)
{
InFoundPredicate(InFoundStartTime, InFoundEndTime, InFoundDepth, InEvent);
},
TTimingEventSearch<TraceServices::FLoadTimeProfilerCpuEvent>::NoMatch);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool FLoadingTimingTrack::HasCustomFilter() const
{
return FilterConfigurator.IsValid() && !FilterConfigurator->IsEmpty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLoadingTimingTrack::SetFilterConfigurator(TSharedPtr<UE::Insights::FFilterConfigurator> InFilterConfigurator)
{
if (FilterConfigurator != InFilterConfigurator)
{
FilterConfigurator = InFilterConfigurator;
SetDirtyFlag();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace UE::Insights::LoadingProfiler
#undef LOCTEXT_NAMESPACE