2019-12-26 15:32:37 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
2019-06-03 15:32:00 -04:00
|
|
|
|
|
|
|
|
#include "TraceServices/Model/LoadTimeProfiler.h"
|
|
|
|
|
#include "Model/LoadTimeProfilerPrivate.h"
|
|
|
|
|
#include "AnalysisServicePrivate.h"
|
|
|
|
|
#include "Common/TimelineStatistics.h"
|
|
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
namespace TraceServices
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
FLoadTimeProfilerProvider::FLoaderFrameCounter::FLoaderFrameCounter(ELoaderFrameCounterType InType, const TPagedArray<FLoaderFrame>& InFrames)
|
|
|
|
|
: Frames(InFrames)
|
|
|
|
|
, Type(InType)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TCHAR* FLoadTimeProfilerProvider::FLoaderFrameCounter::GetName() const
|
|
|
|
|
{
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
case LoaderFrameCounterType_IoDispatcherThroughput:
|
|
|
|
|
return TEXT("AssetLoading/IoDispatcher/Throughput");
|
|
|
|
|
case LoaderFrameCounterType_LoaderThroughput:
|
|
|
|
|
return TEXT("AssetLoading/AsyncLoading/Throughput");
|
|
|
|
|
}
|
|
|
|
|
check(false);
|
|
|
|
|
return TEXT("");
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 10:57:43 -05:00
|
|
|
const TCHAR* FLoadTimeProfilerProvider::FLoaderFrameCounter::GetGroup() const
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
const TCHAR* FLoadTimeProfilerProvider::FLoaderFrameCounter::GetDescription() const
|
|
|
|
|
{
|
|
|
|
|
return TEXT("N/A");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FLoadTimeProfilerProvider::FLoaderFrameCounter::IsFloatingPoint() const
|
|
|
|
|
{
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
case LoaderFrameCounterType_IoDispatcherThroughput:
|
|
|
|
|
case LoaderFrameCounterType_LoaderThroughput:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ECounterDisplayHint FLoadTimeProfilerProvider::FLoaderFrameCounter::GetDisplayHint() const
|
|
|
|
|
{
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
case LoaderFrameCounterType_IoDispatcherThroughput:
|
|
|
|
|
case LoaderFrameCounterType_LoaderThroughput:
|
|
|
|
|
return CounterDisplayHint_Memory;
|
|
|
|
|
}
|
|
|
|
|
return CounterDisplayHint_None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FLoadTimeProfilerProvider::FLoaderFrameCounter::EnumerateValues(double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef<void(double, int64)> Callback) const
|
|
|
|
|
{
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FLoadTimeProfilerProvider::FLoaderFrameCounter::EnumerateFloatValues(double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef<void(double, double)> Callback) const
|
|
|
|
|
{
|
|
|
|
|
if (Frames.Num() == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int32 FirstFrameIndex = FMath::Max(0, int32(FMath::RoundToZero(IntervalStart / FLoadTimeProfilerProvider::LoaderFrameLength)) - 1);
|
|
|
|
|
int32 LastFrameIndex = FMath::Min(int32(Frames.Num()) - 1, int32(FMath::RoundToZero(IntervalEnd / FLoadTimeProfilerProvider::LoaderFrameLength)) + 1);
|
|
|
|
|
for (int32 FrameIndex = FirstFrameIndex; FrameIndex <= LastFrameIndex; ++FrameIndex)
|
|
|
|
|
{
|
|
|
|
|
double Time = (FrameIndex + 0.5) * FLoadTimeProfilerProvider::LoaderFrameLength;
|
|
|
|
|
if (bIncludeExternalBounds || (IntervalStart <= Time && Time <= IntervalEnd))
|
|
|
|
|
{
|
|
|
|
|
const FLoaderFrame& Frame = Frames[FrameIndex];
|
|
|
|
|
switch (Type)
|
|
|
|
|
{
|
|
|
|
|
case LoaderFrameCounterType_LoaderThroughput:
|
|
|
|
|
Callback(Time, double(Frame.HeaderLoadedBytes + Frame.ExportLoadedBytes) / FLoadTimeProfilerProvider::LoaderFrameLength);
|
|
|
|
|
break;
|
|
|
|
|
case LoaderFrameCounterType_IoDispatcherThroughput:
|
|
|
|
|
Callback(Time, double(Frame.IoDispatcherReadBytes) / FLoadTimeProfilerProvider::LoaderFrameLength);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FLoadTimeProfilerProvider::FLoadTimeProfilerProvider(IAnalysisSession& InSession, ICounterProvider& InCounterProvider)
|
2019-06-03 15:32:00 -04:00
|
|
|
: Session(InSession)
|
2019-11-25 12:03:09 -05:00
|
|
|
, CounterProvider(InCounterProvider)
|
|
|
|
|
, ClassInfos(Session.GetLinearAllocator(), 16384)
|
|
|
|
|
, Requests(Session.GetLinearAllocator(), 16384)
|
|
|
|
|
, Packages(Session.GetLinearAllocator(), 16384)
|
|
|
|
|
, PackageLoads(Session.GetLinearAllocator(), 16384)
|
|
|
|
|
, IoDispatcherBatches(Session.GetLinearAllocator(), 16384)
|
|
|
|
|
, Exports(Session.GetLinearAllocator(), 16384)
|
2019-10-03 16:26:48 -04:00
|
|
|
, RequestsTable(Requests)
|
2019-11-25 12:03:09 -05:00
|
|
|
, Frames(Session.GetLinearAllocator(), 4096)
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
2019-11-15 08:26:38 -05:00
|
|
|
RequestsTable.EditLayout().
|
|
|
|
|
AddColumn(&FLoadRequest::Name, TEXT("Name")).
|
|
|
|
|
AddColumn(&FLoadRequest::ThreadId, TEXT("ThreadId")).
|
2021-05-21 03:11:46 -04:00
|
|
|
AddColumn(&FLoadRequest::StartTime, TEXT("StartTime"), TableColumnDisplayHint_Time).
|
|
|
|
|
AddColumn(&FLoadRequest::EndTime, TEXT("EndTime"), TableColumnDisplayHint_Time).
|
2019-11-15 08:26:38 -05:00
|
|
|
AddColumn<int32>(
|
|
|
|
|
[](const FLoadRequest& Row)
|
|
|
|
|
{
|
|
|
|
|
return Row.Packages.Num();
|
2020-06-23 18:40:00 -04:00
|
|
|
},
|
2021-05-21 03:11:46 -04:00
|
|
|
TEXT("PackageCount"),
|
|
|
|
|
TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FLoadTimeProfilerProvider::PackageSizeSum, TEXT("Size"), TableColumnDisplayHint_Memory | TableColumnDisplayHint_Summable).
|
2019-11-15 08:26:38 -05:00
|
|
|
AddColumn<const TCHAR*>(
|
|
|
|
|
[](const FLoadRequest& Row)
|
|
|
|
|
{
|
|
|
|
|
return Row.Packages.Num() ? Row.Packages[0]->Name : TEXT("N/A");
|
|
|
|
|
},
|
|
|
|
|
TEXT("FirstPackage"));
|
|
|
|
|
|
|
|
|
|
AggregatedStatsTableLayout.
|
|
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Name, TEXT("Name")).
|
2021-05-21 03:11:46 -04:00
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Count, TEXT("Count"), TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Total, TEXT("Total"), TableColumnDisplayHint_Time | TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Min, TEXT("Min"), TableColumnDisplayHint_Time).
|
|
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Max, TEXT("Max"), TableColumnDisplayHint_Time).
|
|
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Average, TEXT("Avg"), TableColumnDisplayHint_Time).
|
|
|
|
|
AddColumn(&FLoadTimeProfilerAggregatedStats::Median, TEXT("Med"), TableColumnDisplayHint_Time);
|
2019-11-15 08:26:38 -05:00
|
|
|
|
|
|
|
|
PackagesTableLayout.
|
|
|
|
|
AddColumn<const TCHAR*>([](const FPackagesTableRow& Row)
|
|
|
|
|
{
|
|
|
|
|
return Row.PackageInfo->Name;
|
|
|
|
|
},
|
|
|
|
|
TEXT("Package")).
|
2021-05-21 03:11:46 -04:00
|
|
|
AddColumn(&FPackagesTableRow::SerializedHeaderSize, TEXT("SerializedHeaderSize"), TableColumnDisplayHint_Memory | TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FPackagesTableRow::SerializedExportsCount, TEXT("SerializedExportsCount"), TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FPackagesTableRow::SerializedExportsSize, TEXT("SerializedExportsSize"), TableColumnDisplayHint_Memory | TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FPackagesTableRow::MainThreadTime, TEXT("MainThreadTime"), TableColumnDisplayHint_Time | TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FPackagesTableRow::AsyncLoadingThreadTime, TEXT("AsyncLoadingThreadTime"), TableColumnDisplayHint_Time | TableColumnDisplayHint_Summable);
|
2019-11-15 08:26:38 -05:00
|
|
|
|
|
|
|
|
ExportsTableLayout.
|
|
|
|
|
AddColumn<const TCHAR*>([](const FExportsTableRow& Row)
|
|
|
|
|
{
|
|
|
|
|
return Row.ExportInfo->Package ? Row.ExportInfo->Package->Name : TEXT("[unknown]");
|
|
|
|
|
},
|
|
|
|
|
TEXT("Package")).
|
|
|
|
|
AddColumn<const TCHAR*>([](const FExportsTableRow& Row)
|
|
|
|
|
{
|
|
|
|
|
return Row.ExportInfo->Class ? Row.ExportInfo->Class->Name : TEXT("[unknown]");
|
|
|
|
|
},
|
|
|
|
|
TEXT("Class")).
|
|
|
|
|
AddColumn<const TCHAR*>([](const FExportsTableRow& Row)
|
|
|
|
|
{
|
|
|
|
|
return GetLoadTimeProfilerObjectEventTypeString(Row.EventType);
|
|
|
|
|
},
|
|
|
|
|
TEXT("EventType")).
|
2021-05-21 03:11:46 -04:00
|
|
|
AddColumn(&FExportsTableRow::SerializedSize, TEXT("SerializedSize"), TableColumnDisplayHint_Memory | TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FExportsTableRow::MainThreadTime, TEXT("MainThreadTime"), TableColumnDisplayHint_Time | TableColumnDisplayHint_Summable).
|
|
|
|
|
AddColumn(&FExportsTableRow::AsyncLoadingThreadTime, TEXT("AsyncLoadingThreadTime"), TableColumnDisplayHint_Time | TableColumnDisplayHint_Summable);
|
2019-06-03 15:32:00 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
bool FLoadTimeProfilerProvider::GetCpuThreadTimelineIndex(uint32 ThreadId, uint32& OutTimelineIndex) const
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
2020-06-23 18:40:00 -04:00
|
|
|
Session.ReadAccessCheck();
|
2019-11-25 12:03:09 -05:00
|
|
|
const uint32* FindTimelineIndex = CpuTimelinesThreadMap.Find(ThreadId);
|
|
|
|
|
if (FindTimelineIndex)
|
|
|
|
|
{
|
|
|
|
|
OutTimelineIndex = *FindTimelineIndex;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-06-03 15:32:00 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
bool FLoadTimeProfilerProvider::ReadTimeline(uint32 Index, TFunctionRef<void(const CpuTimeline &)> Callback) const
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
|
|
|
|
Session.ReadAccessCheck();
|
2019-11-25 12:03:09 -05:00
|
|
|
if (Index >= uint32(CpuTimelines.Num()))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Callback(*CpuTimelines[Index]);
|
|
|
|
|
return true;
|
2019-06-03 15:32:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ITable<FLoadTimeProfilerAggregatedStats>* FLoadTimeProfilerProvider::CreateEventAggregation(double IntervalStart, double IntervalEnd) const
|
|
|
|
|
{
|
|
|
|
|
TArray<const CpuTimelineInternal*> Timelines;
|
2019-11-25 12:03:09 -05:00
|
|
|
for (const TSharedRef<CpuTimelineInternal>& Timeline : CpuTimelines)
|
|
|
|
|
{
|
|
|
|
|
Timelines.Add(&Timeline.Get());
|
|
|
|
|
}
|
2019-06-03 15:32:00 -04:00
|
|
|
|
|
|
|
|
auto BucketMapper = [](const FLoadTimeProfilerCpuEvent& Event)
|
|
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
return Event.Package;
|
2019-06-03 15:32:00 -04:00
|
|
|
};
|
2019-11-25 12:03:09 -05:00
|
|
|
TMap<const FPackageInfo*, FAggregatedTimingStats> Aggregation;
|
2019-06-03 15:32:00 -04:00
|
|
|
FTimelineStatistics::CreateAggregation(Timelines, BucketMapper, IntervalStart, IntervalEnd, Aggregation);
|
2019-11-15 08:26:38 -05:00
|
|
|
TTable<FLoadTimeProfilerAggregatedStats>* Table = new TTable<FLoadTimeProfilerAggregatedStats>(AggregatedStatsTableLayout);
|
2019-06-03 15:32:00 -04:00
|
|
|
for (const auto& KV : Aggregation)
|
|
|
|
|
{
|
|
|
|
|
FLoadTimeProfilerAggregatedStats& Row = Table->AddRow();
|
2019-11-25 12:03:09 -05:00
|
|
|
Row.Name = KV.Key ? KV.Key->Name : TEXT("[unknown]");
|
2019-06-03 15:32:00 -04:00
|
|
|
const FAggregatedTimingStats& Stats = KV.Value;
|
|
|
|
|
Row.Count = Stats.InstanceCount;
|
|
|
|
|
Row.Total = Stats.TotalExclusiveTime;
|
|
|
|
|
Row.Min = Stats.MinExclusiveTime;
|
|
|
|
|
Row.Max = Stats.MaxExclusiveTime;
|
|
|
|
|
Row.Average = Stats.AverageExclusiveTime;
|
|
|
|
|
Row.Median = Stats.MedianExclusiveTime;
|
|
|
|
|
}
|
|
|
|
|
return Table;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ITable<FLoadTimeProfilerAggregatedStats>* FLoadTimeProfilerProvider::CreateObjectTypeAggregation(double IntervalStart, double IntervalEnd) const
|
|
|
|
|
{
|
|
|
|
|
TArray<const CpuTimelineInternal*> Timelines;
|
2019-11-25 12:03:09 -05:00
|
|
|
for (const TSharedRef<CpuTimelineInternal>& Timeline : CpuTimelines)
|
|
|
|
|
{
|
|
|
|
|
Timelines.Add(&Timeline.Get());
|
|
|
|
|
}
|
2019-06-03 15:32:00 -04:00
|
|
|
|
|
|
|
|
auto BucketMapper = [](const FLoadTimeProfilerCpuEvent& Event) -> const FClassInfo*
|
|
|
|
|
{
|
|
|
|
|
return Event.Export ? Event.Export->Class : nullptr;
|
|
|
|
|
};
|
2020-11-13 05:29:37 -04:00
|
|
|
TMap<const FClassInfo*, FAggregatedTimingStats> Aggregation;
|
2019-06-03 15:32:00 -04:00
|
|
|
FTimelineStatistics::CreateAggregation(Timelines, BucketMapper, IntervalStart, IntervalEnd, Aggregation);
|
2019-11-15 08:26:38 -05:00
|
|
|
TTable<FLoadTimeProfilerAggregatedStats>* Table = new TTable<FLoadTimeProfilerAggregatedStats>(AggregatedStatsTableLayout);
|
2019-06-03 15:32:00 -04:00
|
|
|
for (const auto& KV : Aggregation)
|
|
|
|
|
{
|
|
|
|
|
const FClassInfo* ClassInfo = KV.Key;
|
|
|
|
|
if (ClassInfo)
|
|
|
|
|
{
|
|
|
|
|
FLoadTimeProfilerAggregatedStats& Row = Table->AddRow();
|
|
|
|
|
const FAggregatedTimingStats& Stats = KV.Value;
|
|
|
|
|
Row.Name = ClassInfo->Name;
|
|
|
|
|
Row.Count = Stats.InstanceCount;
|
|
|
|
|
Row.Total = Stats.TotalExclusiveTime;
|
|
|
|
|
Row.Min = Stats.MinExclusiveTime;
|
|
|
|
|
Row.Max = Stats.MaxExclusiveTime;
|
|
|
|
|
Row.Average = Stats.AverageExclusiveTime;
|
|
|
|
|
Row.Median = Stats.MedianExclusiveTime;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Table;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-03 16:26:48 -04:00
|
|
|
ITable<FPackagesTableRow>* FLoadTimeProfilerProvider::CreatePackageDetailsTable(double IntervalStart, double IntervalEnd) const
|
|
|
|
|
{
|
2019-11-15 08:26:38 -05:00
|
|
|
TTable<FPackagesTableRow>* Table = new TTable<FPackagesTableRow>(PackagesTableLayout);
|
2019-10-03 16:26:48 -04:00
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
TMap<const FPackageInfo*, FPackagesTableRow*> PackagesMap;
|
2019-10-03 16:26:48 -04:00
|
|
|
|
|
|
|
|
auto FindRow = [Table, &PackagesMap](const FLoadTimeProfilerCpuEvent& Event) -> FPackagesTableRow*
|
|
|
|
|
{
|
|
|
|
|
if (Event.Package)
|
|
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
FPackagesTableRow** FindIt = PackagesMap.Find(Event.Package);
|
2019-10-03 16:26:48 -04:00
|
|
|
FPackagesTableRow* Row = nullptr;
|
|
|
|
|
if (!FindIt)
|
|
|
|
|
{
|
|
|
|
|
Row = &Table->AddRow();
|
|
|
|
|
Row->PackageInfo = Event.Package;
|
2019-11-25 12:03:09 -05:00
|
|
|
PackagesMap.Add(Event.Package, Row);
|
2019-10-03 16:26:48 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Row = *FindIt;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
if (Event.Export && Event.EventType == LoadTimeProfilerObjectEventType_Serialize)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
|
|
|
|
++Row->SerializedExportsCount;
|
|
|
|
|
Row->SerializedExportsSize += Event.Export->SerialSize;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
Row->SerializedHeaderSize = Event.Package->Summary.TotalHeaderSize;
|
2019-10-03 16:26:48 -04:00
|
|
|
|
|
|
|
|
return Row;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
for (int32 TimelineIndex = 0, TimelineCount = CpuTimelines.Num(); TimelineIndex < TimelineCount; ++TimelineIndex)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
CpuTimelines[TimelineIndex]->EnumerateEvents(IntervalStart, IntervalEnd, [Table, &PackagesMap, FindRow, TimelineIndex](double StartTime, double EndTime, uint32, const FLoadTimeProfilerCpuEvent& Event)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
FPackagesTableRow* Row = FindRow(Event);
|
|
|
|
|
if (Row)
|
|
|
|
|
{
|
|
|
|
|
if (TimelineIndex == 0)
|
|
|
|
|
{
|
|
|
|
|
Row->MainThreadTime += EndTime - StartTime; // TODO: Should be exclusive time
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Row->AsyncLoadingThreadTime += EndTime - StartTime; // TODO: Should be exclusive time
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-13 05:29:37 -04:00
|
|
|
return EEventEnumerate::Continue;
|
2019-11-25 12:03:09 -05:00
|
|
|
});
|
|
|
|
|
}
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2019-10-03 16:26:48 -04:00
|
|
|
return Table;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ITable<FExportsTableRow>* FLoadTimeProfilerProvider::CreateExportDetailsTable(double IntervalStart, double IntervalEnd) const
|
|
|
|
|
{
|
2019-11-15 08:26:38 -05:00
|
|
|
TTable<FExportsTableRow>* Table = new TTable<FExportsTableRow>(ExportsTableLayout);
|
2019-10-03 16:26:48 -04:00
|
|
|
|
|
|
|
|
TMap<TTuple<const FPackageExportInfo*, ELoadTimeProfilerObjectEventType>, FExportsTableRow*> ExportsMap;
|
|
|
|
|
|
|
|
|
|
auto FindRow = [Table, &ExportsMap](const FLoadTimeProfilerCpuEvent& Event) -> FExportsTableRow*
|
|
|
|
|
{
|
|
|
|
|
if (Event.Export)
|
|
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
auto Key = MakeTuple(Event.Export, Event.EventType);
|
2019-10-03 16:26:48 -04:00
|
|
|
FExportsTableRow** FindIt = ExportsMap.Find(Key);
|
|
|
|
|
FExportsTableRow* Row = nullptr;
|
|
|
|
|
if (!FindIt)
|
|
|
|
|
{
|
|
|
|
|
Row = &Table->AddRow();
|
|
|
|
|
Row->ExportInfo = Event.Export;
|
2019-11-25 12:03:09 -05:00
|
|
|
Row->EventType = Event.EventType;
|
2019-10-03 16:26:48 -04:00
|
|
|
ExportsMap.Add(Key, Row);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Row = *FindIt;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
if (Event.EventType == LoadTimeProfilerObjectEventType_Serialize)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
|
|
|
|
Row->SerializedSize += Event.Export->SerialSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Row;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
for (int32 TimelineIndex = 0, TimelineCount = CpuTimelines.Num(); TimelineIndex < TimelineCount; ++TimelineIndex)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
CpuTimelines[TimelineIndex]->EnumerateEvents(IntervalStart, IntervalEnd, [Table, &ExportsMap, FindRow, TimelineIndex](double StartTime, double EndTime, uint32, const FLoadTimeProfilerCpuEvent& Event)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
FExportsTableRow* Row = FindRow(Event);
|
|
|
|
|
if (Row)
|
|
|
|
|
{
|
|
|
|
|
if (TimelineIndex == 0)
|
|
|
|
|
{
|
|
|
|
|
Row->MainThreadTime += EndTime - StartTime; // TODO: Should be exclusive time
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Row->AsyncLoadingThreadTime += EndTime - StartTime; // TODO: Should be exclusive time
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-13 05:29:37 -04:00
|
|
|
return EEventEnumerate::Continue;
|
2019-11-25 12:03:09 -05:00
|
|
|
});
|
|
|
|
|
}
|
2019-10-03 16:26:48 -04:00
|
|
|
return Table;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
const FClassInfo& FLoadTimeProfilerProvider::AddClassInfo(const TCHAR* ClassName)
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
FClassInfo& ClassInfo = ClassInfos.PushBack();
|
|
|
|
|
ClassInfo.Name = Session.StoreString(ClassName);
|
|
|
|
|
return ClassInfo;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
FLoadRequest& FLoadTimeProfilerProvider::CreateRequest()
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
FLoadRequest& RequestInfo = Requests.PushBack();
|
|
|
|
|
return RequestInfo;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 06:41:39 -04:00
|
|
|
FPackageInfo& FLoadTimeProfilerProvider::CreatePackage()
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
uint32 PackageId = Packages.Num();
|
|
|
|
|
FPackageInfo& Package = Packages.PushBack();
|
|
|
|
|
Package.Id = PackageId;
|
|
|
|
|
return Package;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
void FLoadTimeProfilerProvider::DistributeBytesAcrossFrames(uint64 ByteCount, double StartTime, double EndTime, uint64 FLoaderFrame::* FrameVariable)
|
|
|
|
|
{
|
|
|
|
|
uint64 OriginalByteCount = ByteCount;
|
|
|
|
|
|
|
|
|
|
int32 BeginFrameIndex = int32(FMath::RoundToZero(StartTime / LoaderFrameLength));
|
|
|
|
|
int32 EndFrameIndex = int32(FMath::RoundToZero(EndTime / LoaderFrameLength));
|
|
|
|
|
while (Frames.Num() <= EndFrameIndex + 1)
|
|
|
|
|
{
|
|
|
|
|
Frames.PushBack();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BeginFrameIndex == EndFrameIndex)
|
|
|
|
|
{
|
|
|
|
|
FLoaderFrame& Frame = Frames[BeginFrameIndex];
|
|
|
|
|
Frame.*FrameVariable += ByteCount;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
double TotalTime = EndTime - StartTime;
|
|
|
|
|
double TimeInFirstFrame = (BeginFrameIndex + 1) * LoaderFrameLength - StartTime;
|
|
|
|
|
check(TimeInFirstFrame >= 0.0);
|
|
|
|
|
uint64 BytesInFirstFrame = uint64(FMath::RoundToZero(TimeInFirstFrame / TotalTime * ByteCount));
|
|
|
|
|
Frames[BeginFrameIndex].*FrameVariable += BytesInFirstFrame;
|
|
|
|
|
|
|
|
|
|
uint64 TotalDistributed = BytesInFirstFrame;
|
|
|
|
|
|
|
|
|
|
double TimeInLastFrame = EndTime - EndFrameIndex * LoaderFrameLength;
|
|
|
|
|
check(TimeInLastFrame >= 0.0);
|
|
|
|
|
uint64 BytesInLastFrame = uint64(FMath::RoundToZero(TimeInLastFrame / TotalTime * ByteCount));
|
|
|
|
|
|
|
|
|
|
check(BytesInFirstFrame + BytesInLastFrame <= ByteCount);
|
|
|
|
|
ByteCount -= BytesInFirstFrame + BytesInLastFrame;
|
|
|
|
|
|
|
|
|
|
int32 FullFramesLeft = EndFrameIndex - BeginFrameIndex - 1;
|
|
|
|
|
for (int32 FrameIndex = BeginFrameIndex + 1; FrameIndex < EndFrameIndex; ++FrameIndex)
|
|
|
|
|
{
|
|
|
|
|
uint64 BytesInFrame = ByteCount / FullFramesLeft;
|
|
|
|
|
Frames[FrameIndex].*FrameVariable += BytesInFrame;
|
|
|
|
|
|
|
|
|
|
TotalDistributed += BytesInFrame;
|
|
|
|
|
|
|
|
|
|
ByteCount -= BytesInFrame;
|
|
|
|
|
--FullFramesLeft;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BytesInLastFrame += ByteCount;
|
|
|
|
|
Frames[EndFrameIndex].*FrameVariable += BytesInLastFrame;
|
|
|
|
|
TotalDistributed += BytesInLastFrame;
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
check(TotalDistributed == OriginalByteCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64 FLoadTimeProfilerProvider::BeginLoadPackage(const FPackageInfo& PackageInfo, double Time)
|
|
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
CreateCounters();
|
|
|
|
|
|
|
|
|
|
LoadingPackagesCounter->AddValue(Time, int64(1));
|
|
|
|
|
|
|
|
|
|
uint64 LoadHandle = PackageLoads.Num();
|
|
|
|
|
FPackageLoad& PackageLoad = PackageLoads.PushBack();
|
|
|
|
|
PackageLoad.Package = &PackageInfo;
|
|
|
|
|
PackageLoad.StartTime = Time;
|
|
|
|
|
return LoadHandle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FLoadTimeProfilerProvider::EndLoadPackage(uint64 LoadHandle, double Time)
|
|
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
FPackageLoad& PackageLoad = PackageLoads[LoadHandle];
|
|
|
|
|
PackageLoad.EndTime = Time;
|
|
|
|
|
check(PackageLoad.EndTime >= PackageLoad.StartTime);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
DistributeBytesAcrossFrames(PackageLoad.Package->Summary.TotalHeaderSize, PackageLoad.StartTime, PackageLoad.EndTime, &FLoaderFrame::HeaderLoadedBytes);
|
|
|
|
|
DistributeBytesAcrossFrames(PackageLoad.Package->TotalExportsSerialSize, PackageLoad.StartTime, PackageLoad.EndTime, &FLoaderFrame::ExportLoadedBytes);
|
|
|
|
|
|
|
|
|
|
TotalLoaderBytesLoadedCounter->AddValue(Time, int64(PackageLoad.Package->Summary.TotalHeaderSize + PackageLoad.Package->TotalExportsSerialSize));
|
|
|
|
|
LoadingPackagesCounter->AddValue(Time, int64(-1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64 FLoadTimeProfilerProvider::BeginIoDispatcherBatch(uint64 BatchId, double Time)
|
|
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
CreateCounters();
|
|
|
|
|
|
|
|
|
|
ActiveIoDispatcherBatchesCounter->AddValue(Time, int64(1));
|
|
|
|
|
|
|
|
|
|
uint64 BatchHandle = IoDispatcherBatches.Num();
|
|
|
|
|
|
|
|
|
|
FIoDispatcherBatch& Batch = IoDispatcherBatches.PushBack();
|
|
|
|
|
Batch.StartTime = Time;
|
|
|
|
|
|
|
|
|
|
return BatchHandle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FLoadTimeProfilerProvider::EndIoDispatcherBatch(uint64 BatchHandle, double Time, uint64 TotalSize)
|
|
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
FIoDispatcherBatch& Batch = IoDispatcherBatches[BatchHandle];
|
|
|
|
|
Batch.EndTime = Time;
|
|
|
|
|
Batch.TotalSize = TotalSize;
|
|
|
|
|
|
|
|
|
|
check(Batch.EndTime >= Batch.StartTime);
|
|
|
|
|
|
|
|
|
|
DistributeBytesAcrossFrames(Batch.TotalSize, Batch.StartTime, Batch.EndTime, &FLoaderFrame::IoDispatcherReadBytes);
|
|
|
|
|
|
|
|
|
|
TotalIoDispatcherBytesReadCounter->AddValue(Time, int64(Batch.TotalSize));
|
|
|
|
|
ActiveIoDispatcherBatchesCounter->AddValue(Time, int64(-1));
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
FPackageExportInfo& FLoadTimeProfilerProvider::CreateExport()
|
2019-06-03 15:32:00 -04:00
|
|
|
{
|
|
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
|
|
|
|
uint32 ExportId = Exports.Num();
|
|
|
|
|
FPackageExportInfo& Export = Exports.PushBack();
|
|
|
|
|
Export.Id = ExportId;
|
|
|
|
|
return Export;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
FLoadTimeProfilerProvider::CpuTimelineInternal& FLoadTimeProfilerProvider::EditCpuTimeline(uint32 ThreadId)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2020-06-23 18:40:00 -04:00
|
|
|
Session.WriteAccessCheck();
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
uint32* FindTimelineIndex = CpuTimelinesThreadMap.Find(ThreadId);
|
|
|
|
|
if (FindTimelineIndex)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
return CpuTimelines[*FindTimelineIndex].Get();
|
2019-10-03 16:26:48 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TSharedRef<CpuTimelineInternal> Timeline = MakeShared<CpuTimelineInternal>(Session.GetLinearAllocator());
|
2019-11-25 12:03:09 -05:00
|
|
|
uint32 TimelineIndex = CpuTimelines.Num();
|
|
|
|
|
CpuTimelinesThreadMap.Add(ThreadId, TimelineIndex);
|
|
|
|
|
CpuTimelines.Add(Timeline);
|
2019-10-03 16:26:48 -04:00
|
|
|
return Timeline.Get();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64 FLoadTimeProfilerProvider::PackageSizeSum(const FLoadRequest& Row)
|
|
|
|
|
{
|
|
|
|
|
uint64 Sum = 0;
|
|
|
|
|
for (const FPackageInfo* Package : Row.Packages)
|
|
|
|
|
{
|
|
|
|
|
Sum += Package->Summary.TotalHeaderSize;
|
|
|
|
|
for (const FPackageExportInfo* Export : Package->Exports)
|
|
|
|
|
{
|
|
|
|
|
Sum += Export->SerialSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Sum;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
void FLoadTimeProfilerProvider::CreateCounters()
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
if (!bHasCreatedCounters)
|
2019-10-03 16:26:48 -04:00
|
|
|
{
|
2019-11-25 12:03:09 -05:00
|
|
|
for (int32 CounterType = 0; CounterType < FLoaderFrameCounter::LoaderFrameCounterType_Count; ++CounterType)
|
|
|
|
|
{
|
|
|
|
|
CounterProvider.AddCounter(new FLoaderFrameCounter(FLoaderFrameCounter::ELoaderFrameCounterType(CounterType), Frames));
|
|
|
|
|
}
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2019-11-25 12:03:09 -05:00
|
|
|
ActiveIoDispatcherBatchesCounter = CounterProvider.CreateCounter();
|
|
|
|
|
ActiveIoDispatcherBatchesCounter->SetName(TEXT("AssetLoading/IoDispatcher/ActiveBatches"));
|
|
|
|
|
|
|
|
|
|
TotalIoDispatcherBytesReadCounter = CounterProvider.CreateCounter();
|
|
|
|
|
TotalIoDispatcherBytesReadCounter->SetName(TEXT("AssetLoading/IoDispatcher/TotalBytesRead"));
|
|
|
|
|
TotalIoDispatcherBytesReadCounter->SetDisplayHint(CounterDisplayHint_Memory);
|
|
|
|
|
|
|
|
|
|
LoadingPackagesCounter = CounterProvider.CreateCounter();
|
|
|
|
|
LoadingPackagesCounter->SetName(TEXT("AssetLoading/AsyncLoading/ActiveLoadingPackages"));
|
|
|
|
|
|
|
|
|
|
TotalLoaderBytesLoadedCounter = CounterProvider.CreateCounter();
|
|
|
|
|
TotalLoaderBytesLoadedCounter->SetName(TEXT("AssetLoading/AsyncLoading/TotalBytesLoaded"));
|
|
|
|
|
TotalLoaderBytesLoadedCounter->SetDisplayHint(CounterDisplayHint_Memory);
|
|
|
|
|
|
|
|
|
|
bHasCreatedCounters = true;
|
2019-10-03 16:26:48 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TCHAR* GetLoadTimeProfilerObjectEventTypeString(ELoadTimeProfilerObjectEventType EventType)
|
|
|
|
|
{
|
|
|
|
|
switch (EventType)
|
|
|
|
|
{
|
|
|
|
|
case LoadTimeProfilerObjectEventType_Create:
|
|
|
|
|
return TEXT("Create");
|
|
|
|
|
case LoadTimeProfilerObjectEventType_Serialize:
|
|
|
|
|
return TEXT("Serialize");
|
|
|
|
|
case LoadTimeProfilerObjectEventType_PostLoad:
|
|
|
|
|
return TEXT("PostLoad");
|
|
|
|
|
case LoadTimeProfilerObjectEventType_None:
|
|
|
|
|
return TEXT("None");
|
|
|
|
|
}
|
|
|
|
|
return TEXT("[invalid]");
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-13 05:29:37 -04:00
|
|
|
} // namespace TraceServices
|