305 lines
13 KiB
C++
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
|