Files
UnrealEngine/Engine/Source/Developer/Profiler/Private/ProfilerDataSource.cpp
2025-05-18 13:04:45 +08:00

574 lines
23 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ProfilerDataSource.h"
#if STATS
#include "Containers/MapBuilder.h"
#include "ProfilerStream.h"
#include "ProfilerDataProvider.h"
#include "ProfilerSession.h"
#define LOCTEXT_NAMESPACE "ProfilerDataSource"
/*-----------------------------------------------------------------------------
FGraphDataSource
-----------------------------------------------------------------------------*/
const int32 FTimeAccuracy::_FPS008 = 8;
const int32 FTimeAccuracy::_FPS015 = 15;
const int32 FTimeAccuracy::_FPS030 = 30;
const int32 FTimeAccuracy::_FPS060 = 60;
const int32 FTimeAccuracy::_FPS120 = 120;
/*-----------------------------------------------------------------------------
FGraphDataSource
-----------------------------------------------------------------------------*/
FGraphDataSource::FGraphDataSource( const TSharedRef<FProfilerSession>& InProfilerSession, const uint32 InStatID )
: FGraphDataSourceDescription( InStatID )
, ThisCachedDataByIndex()
, ThisCachedDataByTime( FTimeAccuracy::FPS060 )
, ProfilerSession( InProfilerSession )
{
const TSharedRef<FProfilerStatMetaData> MetaData = ProfilerSession->GetMetaData();
const FProfilerStat& Stat = MetaData->GetStatByID(InStatID);
const FProfilerGroup& Group = Stat.OwningGroup();
Initialize( Stat.Name().GetPlainNameString(), Group.Name().GetPlainNameString(), Stat.Type(), ProfilerSession->GetCreationTime() );
switch( GetSampleType() )
{
case EProfilerSampleTypes::Memory:
{
// By default we show memory data as KBs.
Scale = 1.0f / 1024.0f;
break;
}
default:
{
Scale = 1.0f;
}
}
}
const TGraphDataType FGraphDataSource::GetUncachedValueFromIndex( const uint32 FrameIndex ) const
{
check( FrameIndex < ProfilerSession->GetDataProvider()->GetNumFrames() );
double Result = 0.0;
// Hierarchical samples are stored in different location.
// We skip hierarchical samples to ignore misleading recursion which would be counted twice etc.
if (GetSampleType() == EProfilerSampleTypes::HierarchicalTime)
{
const TMap<uint32, FInclusiveTime>& InclusiveAggregates = ProfilerSession->GetInclusiveAggregateStackStats( FrameIndex );
const FInclusiveTime* InclusiveTime = InclusiveAggregates.Find( GetStatID() );
if (InclusiveTime)
{
Result = ProfilerSession->GetMetaData()->ConvertCyclesToMS( InclusiveTime->DurationCycles ) * Scale;
}
}
else
{
const TSharedRef<IDataProvider> DataProvider = ProfilerSession->GetDataProvider();
const FIntPoint& IndicesForFrame = DataProvider->GetSamplesIndicesForFrame( FrameIndex );
const uint32 SampleStartIndex = IndicesForFrame.X;
const uint32 SampleEndIndex = IndicesForFrame.Y;
const FProfilerSampleArray& Collection = DataProvider->GetCollection();
for (uint32 SampleIndex = SampleStartIndex; SampleIndex < SampleEndIndex; SampleIndex++)
{
const FProfilerSample& ProfilerSample = Collection[SampleIndex];
const bool bValidStat = ProfilerSample.StatID() == GetStatID();
if (bValidStat)
{
Result += ProfilerSample.GetDoubleValue() * Scale;
}
}
}
return (TGraphDataType)Result;
}
const TGraphDataType FGraphDataSource::GetUncachedValueFromTimeRange( const float StartTimeMS, const float EndTimeMS ) const
{
const TSharedRef<IDataProvider> DataProvider = ProfilerSession->GetDataProvider();
const FIntPoint IndicesForFrame = DataProvider->GetClosestSamplesIndicesForTime( StartTimeMS, EndTimeMS );
const uint32 StartFrameIndex = IndicesForFrame.X;
const uint32 EndFrameIndex = IndicesForFrame.Y;
TGraphDataType ResultMax = (TGraphDataType)MIN_int32;
// Iterate through all frames and calculate the maximum value.
for( uint32 FrameIndex = StartFrameIndex; FrameIndex < EndFrameIndex; ++FrameIndex )
{
const TGraphDataType DataSourceValue = const_cast<FGraphDataSource*>(this)->GetValueFromIndex( FrameIndex );
ResultMax = FMath::Max( ResultMax, DataSourceValue );
}
return (TGraphDataType)ResultMax;
}
const uint32 FGraphDataSource::GetNumFrames() const
{
return ProfilerSession->GetDataProvider()->GetNumFrames();
}
const float FGraphDataSource::GetTotalTimeMS() const
{
return static_cast<float>(ProfilerSession->GetDataProvider()->GetTotalTimeMS());
}
const TSharedRef<IDataProvider> FGraphDataSource::GetDataProvider() const
{
return ProfilerSession->GetDataProvider();
}
const FProfilerAggregatedStat* FGraphDataSource::GetAggregatedStat() const
{
return ProfilerSession->GetAggregatedStat( StatID );
}
const FGuid FGraphDataSource::GetSessionInstanceID() const
{
return ProfilerSession->GetInstanceID();
}
/*-----------------------------------------------------------------------------
FCombinedGraphDataSource
-----------------------------------------------------------------------------*/
FCombinedGraphDataSource::FCombinedGraphDataSource( const uint32 InStatID, const FTimeAccuracy::Type InTimeAccuracy )
: FGraphDataSourceDescription( InStatID )
, ThisCachedDataByTime( InTimeAccuracy )
{
}
const FVector FCombinedGraphDataSource::GetUncachedValueFromTimeRange( const float StartTimeMS, const float EndTimeMS ) const
{
// X=Min, Y=Max, Z=Avg
FVector3f AggregatedValue( (TGraphDataType)MAX_int32, (TGraphDataType)MIN_int32, 0.0f );
const uint32 NumSources = GraphDataSources.Num();
const float InvNumSources = 1.0f / (float)NumSources;
for( auto It = GetSourcesIterator(); It; ++It )
{
const TSharedRef<const FGraphDataSource>& GraphDataSource = It.Value();
const float DataSourceValue = GraphDataSource->GetValueFromTimeRange( StartTimeMS, EndTimeMS );
AggregatedValue.X = FMath::Min( AggregatedValue.X, DataSourceValue );
AggregatedValue.Y = FMath::Max( AggregatedValue.Y, DataSourceValue );
AggregatedValue.Z += DataSourceValue;
}
AggregatedValue.Z *= InvNumSources;
return (FVector)AggregatedValue;
}
void FCombinedGraphDataSource::GetStartIndicesFromTimeRange( const float StartTimeMS, const float EndTimeMS, TMap<FGuid,uint32>& out_StartIndices ) const
{
for( auto It = GetSourcesIterator(); It; ++It )
{
const TSharedRef<const FGraphDataSource>& GraphDataSource = It.Value();
const FIntPoint IndicesForFrame = GraphDataSource->GetDataProvider()->GetClosestSamplesIndicesForTime( StartTimeMS, EndTimeMS );
const uint32 StartFrameIndex = IndicesForFrame.X;
const uint32 EndFrameIndex = IndicesForFrame.Y;
uint32 FrameIndex = 0;
float MaxFrameTime = 0.0f;
// Iterate through all frames and find the highest frame time.
for( uint32 InnerFrameIndex = StartFrameIndex; InnerFrameIndex < EndFrameIndex; ++InnerFrameIndex )
{
const float InnerFrameTime = GraphDataSource->GetDataProvider()->GetFrameTimeMS( InnerFrameIndex );
if( InnerFrameTime > MaxFrameTime )
{
MaxFrameTime = InnerFrameTime;
FrameIndex = InnerFrameIndex;
}
}
if( MaxFrameTime > 0.0f )
{
out_StartIndices.Add( GraphDataSource->GetSessionInstanceID(), FrameIndex );
}
}
}
/*-----------------------------------------------------------------------------
FEventGraphData
-----------------------------------------------------------------------------*/
//namespace NEventGraphSample {
FName FEventGraphConsts::RootEvent = TEXT("RootEvent");
FName FEventGraphConsts::Self = TEXT("Self");
FName FEventGraphConsts::FakeRoot = TEXT("FakeRoot");
/*-----------------------------------------------------------------------------
FEventGraphSample
-----------------------------------------------------------------------------*/
FEventProperty FEventGraphSample::Properties[ (uint32)EEventPropertyIndex::InvalidOrMax ] =
{
// Properties
FEventProperty( EEventPropertyIndex::StatName, TEXT( "StatName" ), STRUCT_OFFSET( FEventGraphSample, _StatName ), EEventPropertyFormatters::Name ),
FEventProperty( EEventPropertyIndex::InclusiveTimeMS, TEXT( "InclusiveTimeMS" ), STRUCT_OFFSET( FEventGraphSample, _InclusiveTimeMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::InclusiveTimePct, TEXT( "InclusiveTimePct" ), STRUCT_OFFSET( FEventGraphSample, _InclusiveTimePct ), EEventPropertyFormatters::TimePct ),
FEventProperty( EEventPropertyIndex::ExclusiveTimeMS, TEXT( "ExclusiveTimeMS" ), STRUCT_OFFSET( FEventGraphSample, _ExclusiveTimeMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::ExclusiveTimePct, TEXT( "ExclusiveTimePct" ), STRUCT_OFFSET( FEventGraphSample, _ExclusiveTimePct ), EEventPropertyFormatters::TimePct ),
FEventProperty( EEventPropertyIndex::NumCallsPerFrame, TEXT( "NumCallsPerFrame" ), STRUCT_OFFSET( FEventGraphSample, _NumCallsPerFrame ), EEventPropertyFormatters::Number ),
// Special none property
FEventProperty( EEventPropertyIndex::None, NAME_None, INDEX_NONE, EEventPropertyFormatters::Name ),
FEventProperty( EEventPropertyIndex::MinInclusiveTimeMS, TEXT( "MinInclusiveTimeMS" ), STRUCT_OFFSET( FEventGraphSample, _MinInclusiveTimeMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::MaxInclusiveTimeMS, TEXT( "MaxInclusiveTimeMS" ), STRUCT_OFFSET( FEventGraphSample, _MaxInclusiveTimeMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::AvgInclusiveTimeMS, TEXT( "AvgInclusiveTimeMS" ), STRUCT_OFFSET( FEventGraphSample, _AvgInclusiveTimeMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::MinNumCallsPerFrame, TEXT( "MinNumCallsPerFrame" ), STRUCT_OFFSET( FEventGraphSample, _MinNumCallsPerFrame ), EEventPropertyFormatters::Number ),
FEventProperty( EEventPropertyIndex::MaxNumCallsPerFrame, TEXT( "MaxNumCallsPerFrame" ), STRUCT_OFFSET( FEventGraphSample, _MaxNumCallsPerFrame ), EEventPropertyFormatters::Number ),
FEventProperty( EEventPropertyIndex::AvgNumCallsPerFrame, TEXT( "AvgNumCallsPerFrame" ), STRUCT_OFFSET( FEventGraphSample, _AvgNumCallsPerFrame ), EEventPropertyFormatters::Number ),
FEventProperty( EEventPropertyIndex::ThreadName, TEXT( "ThreadName" ), STRUCT_OFFSET( FEventGraphSample, _ThreadName ), EEventPropertyFormatters::Name ),
FEventProperty( EEventPropertyIndex::ThreadDurationMS, TEXT( "ThreadDurationMS" ), STRUCT_OFFSET( FEventGraphSample, _ThreadDurationMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::FrameDurationMS, TEXT( "FrameDurationMS" ), STRUCT_OFFSET( FEventGraphSample, _FrameDurationMS ), EEventPropertyFormatters::TimeMS ),
FEventProperty( EEventPropertyIndex::ThreadPct, TEXT( "ThreadPct" ), STRUCT_OFFSET( FEventGraphSample, _ThreadPct ), EEventPropertyFormatters::TimePct ),
FEventProperty( EEventPropertyIndex::FramePct, TEXT( "FramePct" ), STRUCT_OFFSET( FEventGraphSample, _FramePct ), EEventPropertyFormatters::TimePct ),
FEventProperty( EEventPropertyIndex::ThreadToFramePct, TEXT( "ThreadToFramePct" ), STRUCT_OFFSET( FEventGraphSample, _ThreadToFramePct ), EEventPropertyFormatters::TimePct ),
FEventProperty( EEventPropertyIndex::GroupName, TEXT( "GroupName" ), STRUCT_OFFSET( FEventGraphSample, _GroupName ), EEventPropertyFormatters::Name ),
// Booleans
FEventProperty(EEventPropertyIndex::bIsHotPath,TEXT("bIsHotPath"),STRUCT_OFFSET(FEventGraphSample,_bIsHotPath),EEventPropertyFormatters::Bool),
FEventProperty(EEventPropertyIndex::bIsFiltered,TEXT("bIsFiltered"),STRUCT_OFFSET(FEventGraphSample,_bIsFiltered),EEventPropertyFormatters::Bool),
FEventProperty(EEventPropertyIndex::bIsCulled,TEXT("bIsCulled"),STRUCT_OFFSET(FEventGraphSample,_bIsCulled),EEventPropertyFormatters::Bool),
// Booleans internal
FEventProperty(EEventPropertyIndex::bNeedNotCulledChildrenUpdate,TEXT("bNeedNotCulledChildrenUpdate"),STRUCT_OFFSET(FEventGraphSample,bNeedNotCulledChildrenUpdate),EEventPropertyFormatters::Bool),
};
TMap<FName,const FEventProperty*> FEventGraphSample::NamedProperties;
void FEventGraphSample::InitializePropertyManagement()
{
static bool bInitialized = false;
if( !bInitialized )
{
NamedProperties = TMapBuilder<FName,const FEventProperty*>()
// Properties
.Add( TEXT( "StatName" ), &Properties[(uint32)EEventPropertyIndex::StatName] )
.Add( TEXT( "InclusiveTimeMS" ), &Properties[(uint32)EEventPropertyIndex::InclusiveTimeMS] )
.Add( TEXT( "InclusiveTimePct" ), &Properties[(uint32)EEventPropertyIndex::InclusiveTimePct] )
.Add( TEXT( "ExclusiveTimeMS" ), &Properties[(uint32)EEventPropertyIndex::ExclusiveTimeMS] )
.Add( TEXT( "ExclusiveTimePct" ), &Properties[(uint32)EEventPropertyIndex::ExclusiveTimePct] )
.Add( TEXT( "NumCallsPerFrame" ), &Properties[(uint32)EEventPropertyIndex::NumCallsPerFrame] )
// Special none property
.Add( NAME_None, &Properties[(uint32)EEventPropertyIndex::None] )
.Add( TEXT( "MinInclusiveTimeMS" ), &Properties[(uint32)EEventPropertyIndex::MinInclusiveTimeMS] )
.Add( TEXT( "MaxInclusiveTimeMS" ), &Properties[(uint32)EEventPropertyIndex::MaxInclusiveTimeMS] )
.Add( TEXT( "AvgInclusiveTimeMS" ), &Properties[(uint32)EEventPropertyIndex::AvgInclusiveTimeMS] )
.Add( TEXT( "MinNumCallsPerFrame" ), &Properties[(uint32)EEventPropertyIndex::MinNumCallsPerFrame] )
.Add( TEXT( "MaxNumCallsPerFrame" ), &Properties[(uint32)EEventPropertyIndex::MaxNumCallsPerFrame] )
.Add( TEXT( "AvgNumCallsPerFrame" ), &Properties[(uint32)EEventPropertyIndex::AvgNumCallsPerFrame] )
.Add( TEXT( "ThreadName" ), &Properties[(uint32)EEventPropertyIndex::ThreadName] )
.Add( TEXT( "ThreadDurationMS" ), &Properties[(uint32)EEventPropertyIndex::ThreadDurationMS] )
.Add( TEXT( "FrameDurationMS" ), &Properties[(uint32)EEventPropertyIndex::FrameDurationMS] )
.Add( TEXT( "ThreadPct" ), &Properties[(uint32)EEventPropertyIndex::ThreadPct] )
.Add( TEXT( "FramePct" ), &Properties[(uint32)EEventPropertyIndex::FramePct] )
.Add( TEXT( "ThreadToFramePct" ), &Properties[(uint32)EEventPropertyIndex::ThreadToFramePct] )
.Add( TEXT( "GroupName" ), &Properties[(uint32)EEventPropertyIndex::GroupName] )
// Booleans
.Add( TEXT( "bIsHotPath" ), &Properties[(uint32)EEventPropertyIndex::bIsHotPath] )
.Add( TEXT( "bIsFiltered" ), &Properties[(uint32)EEventPropertyIndex::bIsFiltered] )
.Add( TEXT( "bIsCulled" ), &Properties[(uint32)EEventPropertyIndex::bIsCulled] )
// Booleans internal
.Add( TEXT( "bNeedNotCulledChildrenUpdate" ), &Properties[(uint32)EEventPropertyIndex::bNeedNotCulledChildrenUpdate] )
;
// Make sure that the minimal property manager has been initialized.
bInitialized = true;
// Sanity checks.
check( NamedProperties.FindChecked( NAME_None )->Name == NAME_None );
check( NamedProperties.FindChecked( NAME_None )->Offset == INDEX_NONE );
check( FEventGraphSample::Properties[ (uint32)EEventPropertyIndex::None ].Name == NAME_None );
check( FEventGraphSample::Properties[ (uint32)EEventPropertyIndex::None ].Offset == INDEX_NONE );
}
}
void FEventGraphSample::SetMaximumTimesForAllChildren()
{
struct FCopyMaximum
{
void operator()( FEventGraphSample* EventPtr, FEventGraphSample* RootEvent, FEventGraphSample* ThreadEvent )
{
EventPtr->CopyMaximum( RootEvent, ThreadEvent );
}
};
FEventGraphSamplePtr RootEvent = AsShared();
const int32 NumChildren = _ChildrenPtr.Num();
for (int32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
{
const FEventGraphSamplePtr& ThreadEvent = _ChildrenPtr[ChildIndex];
ThreadEvent->ExecuteOperationForAllChildren( FCopyMaximum(), (FEventGraphSample*)RootEvent.Get(), (FEventGraphSample*)ThreadEvent.Get() );
}
}
void FEventGraphSample::SetRootAndThreadForAllChildren()
{
struct FSetRootAndThread
{
void operator()( FEventGraphSample* EventPtr, FEventGraphSample* RootEvent, FEventGraphSample* ThreadEvent )
{
EventPtr->_RootPtr = RootEvent;
EventPtr->_ThreadPtr = ThreadEvent;
}
};
FEventGraphSamplePtr RootEvent = AsShared();
const int32 NumChildren = _ChildrenPtr.Num();
for (int32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
{
const FEventGraphSamplePtr& ThreadEvent = _ChildrenPtr[ChildIndex];
ThreadEvent->ExecuteOperationForAllChildren( FSetRootAndThread(), (FEventGraphSample*)RootEvent.Get(), (FEventGraphSample*)ThreadEvent.Get() );
}
}
void FEventGraphSample::FixChildrenTimesAndCalcAveragesForAllChildren( const double InNumFrames )
{
struct FFixChildrenTimesAndCalcAverages
{
void operator()( FEventGraphSample* EventPtr, const double NumFrames )
{
EventPtr->FixChildrenTimesAndCalcAverages( NumFrames );
}
};
ExecuteOperationForAllChildren( FFixChildrenTimesAndCalcAverages(), InNumFrames );
}
FEventGraphSamplePtr FEventGraphSample::FindChildPtr( const FEventGraphSamplePtr& OtherChild )
{
FEventGraphSamplePtr FoundChildPtr;
for( int32 ChildIndex = 0; ChildIndex < _ChildrenPtr.Num(); ++ChildIndex )
{
const FEventGraphSamplePtr& ThisChild = _ChildrenPtr[ChildIndex];
const bool bTheSame = OtherChild->AreTheSamePtr( ThisChild );
if( bTheSame )
{
FoundChildPtr = ThisChild;
break;
}
}
return FoundChildPtr;
}
void FEventGraphSample::Combine_Recurrent( const FEventGraphSamplePtr& Other )
{
Combine( Other );
// Check other children.
for( int32 ChildIndex = 0; ChildIndex < Other->_ChildrenPtr.Num(); ++ChildIndex )
{
const FEventGraphSamplePtr& OtherChild = Other->_ChildrenPtr[ChildIndex];
FEventGraphSamplePtr ThisChild = FindChildPtr( OtherChild );
if( ThisChild.IsValid() )
{
ThisChild->Combine_Recurrent( OtherChild );
}
else
{
AddChildAndSetParentPtr( OtherChild->DuplicateWithHierarchyPtr() );
}
}
}
/*-----------------------------------------------------------------------------
FEventGraphData
-----------------------------------------------------------------------------*/
FEventGraphData::FEventGraphData()
: RootEvent( FEventGraphSample::CreateNamedEvent( FEventGraphConsts::RootEvent ) )
, FrameStartIndex( 0 )
, FrameEndIndex( 0 )
{}
FEventGraphData::FEventGraphData( const FProfilerSession * const InProfilerSession, const uint32 InFrameIndex )
: FrameStartIndex( InFrameIndex )
, FrameEndIndex( InFrameIndex+1 )
{
static FTotalTimeAndCount Current(0.0f, 0);
PROFILER_SCOPE_LOG_TIME( TEXT( "FEventGraphData::FEventGraphData" ), &Current );
Description = FString::Printf( TEXT("%s: %i"), *InProfilerSession->GetShortName(), InFrameIndex );
// @TODO: Duplicate is not needed, remove it later.
const TSharedRef<IDataProvider>& SessionDataProvider = InProfilerSession->GetDataProvider();
const TSharedRef<IDataProvider> DataProvider = SessionDataProvider->Duplicate<FArrayDataProvider>( FrameStartIndex );
const double FrameDurationMS = DataProvider->GetFrameTimeMS( 0 );
const FProfilerSample& RootProfilerSample = DataProvider->GetCollection()[0];
RootEvent = FEventGraphSample::CreateNamedEvent( FEventGraphConsts::RootEvent );
PopulateHierarchy_Recurrent( InProfilerSession, RootEvent, RootProfilerSample, DataProvider );
// Root sample contains FrameDurationMS
const TSharedRef<FProfilerStatMetaData>& MetaData = InProfilerSession->GetMetaData();
RootEvent->_InclusiveTimeMS = MetaData->ConvertCyclesToMS( RootProfilerSample.GetDurationCycles() );
RootEvent->_MaxInclusiveTimeMS = RootEvent->_MinInclusiveTimeMS = RootEvent->_AvgInclusiveTimeMS = RootEvent->_InclusiveTimeMS;
RootEvent->_InclusiveTimePct = 100.0f;
RootEvent->_MinNumCallsPerFrame = RootEvent->_MaxNumCallsPerFrame = RootEvent->_AvgNumCallsPerFrame = RootEvent->_NumCallsPerFrame;
// Set root and thread event.
RootEvent->SetRootAndThreadForAllChildren();
// Fix all children.
const double MyNumFrames = 1.0;
RootEvent->FixChildrenTimesAndCalcAveragesForAllChildren( MyNumFrames );
}
void FEventGraphData::PopulateHierarchy_Recurrent
(
const FProfilerSession * const ProfilerSession,
const FEventGraphSamplePtr ParentEvent,
const FProfilerSample& ParentSample,
const TSharedRef<IDataProvider> DataProvider
)
{
const TSharedRef<FProfilerStatMetaData>& MetaData = ProfilerSession->GetMetaData();
for( int32 ChildIndex = 0; ChildIndex < ParentSample.ChildrenIndices().Num(); ChildIndex++ )
{
const FProfilerSample& ChildSample = DataProvider->GetCollection()[ ParentSample.ChildrenIndices()[ChildIndex] ];
const FProfilerStat& ProfilerThread = MetaData->GetStatByID( ChildSample.ThreadID() );
const FName& ThreadName = ProfilerThread.Name();
const FProfilerStat& ProfilerStat = MetaData->GetStatByID( ChildSample.StatID() );
const FName& StatName = ProfilerStat.Name();
const FName& GroupName = ProfilerStat.OwningGroup().Name();
FEventGraphSample* ChildEvent = new FEventGraphSample
(
ThreadName, GroupName, ChildSample.StatID(), StatName,
MetaData->ConvertCyclesToMS( ChildSample.GetDurationCycles() ), (double)ChildSample.GetCallCount(),
ParentEvent
);
FEventGraphSamplePtr ChildEventPtr = MakeShareable( ChildEvent );
ParentEvent->AddChildPtr( ChildEventPtr );
PopulateHierarchy_Recurrent( ProfilerSession, ChildEventPtr, ChildSample, DataProvider );
}
}
FEventGraphData::FEventGraphData( const FEventGraphData& Source )
: FrameStartIndex( Source.FrameStartIndex )
, FrameEndIndex( Source.FrameEndIndex )
{
RootEvent = Source.GetRoot()->DuplicateWithHierarchyPtr();
RootEvent->SetRootAndThreadForAllChildren();
}
FEventGraphDataRef FEventGraphData::DuplicateAsRef()
{
FEventGraphDataRef EventGraphRef = MakeShareable( new FEventGraphData(*this) );
return EventGraphRef;
}
void FEventGraphData::Combine( const FEventGraphData& Other )
{
RootEvent->Combine_Recurrent( Other.GetRoot() );
Description = FString::Printf( TEXT("Combine: %i"), GetNumFrames() );
}
void FEventGraphData::SetAsAverage()
{
struct FCopyAverage
{
void operator()( FEventGraphSample* EventPtr, const double NumFrames )
{
EventPtr->CopyAverage( NumFrames );
}
};
const double NumFrames = (double)GetNumFrames();
RootEvent->ExecuteOperationForAllChildren( FCopyAverage(), NumFrames );
Description = FString::Printf( TEXT("Average: %i"), GetNumFrames() );
}
void FEventGraphData::SetAsMaximim()
{
RootEvent->SetMaximumTimesForAllChildren();
Description = FString::Printf( TEXT( "Maximum: %i" ), GetNumFrames() );
}
void FEventGraphData::Finalize( const uint32 InFrameStartIndex, const uint32 InFrameEndIndex )
{
FrameStartIndex = InFrameStartIndex;
FrameEndIndex = InFrameEndIndex;
const double NumFrames = (double)GetNumFrames();
// Set root and thread event.
RootEvent->SetRootAndThreadForAllChildren();
// Fix all children.
RootEvent->FixChildrenTimesAndCalcAveragesForAllChildren( NumFrames );
}
//}//namespace NEventGraphSample
FString EEventGraphTypes::ToName( const EEventGraphTypes::Type EventGraphType )
{
switch( EventGraphType )
{
case Average: return LOCTEXT("EventGraphType_Name_Average", "Average").ToString();
case Maximum: return LOCTEXT("EventGraphType_Name_Maximum", "Maximum").ToString();
case OneFrame: return LOCTEXT("EventGraphType_Name_OneFrame", "OneFrame").ToString();
case Total: return LOCTEXT( "EventGraphType_Name_Total", "Total" ).ToString();
default: return LOCTEXT("InvalidOrMax", "InvalidOrMax").ToString();
}
}
FString EEventGraphTypes::ToDescription( const EEventGraphTypes::Type EventGraphType )
{
switch( EventGraphType )
{
case Average: return LOCTEXT("EventGraphType_Desc_Average", "Per-frame average event graph").ToString();
case Maximum: return LOCTEXT("EventGraphType_Desc_Maximum", "Highest \"per-frame\" event graph").ToString();
case OneFrame: return LOCTEXT("EventGraphType_Desc_OneFrame", "Event graph for one frame").ToString();
case Total: return LOCTEXT( "EventGraphType_Desc_Total", "Event graph for selected frames" ).ToString();
default: return LOCTEXT("InvalidOrMax", "InvalidOrMax").ToString();
}
}
#undef LOCTEXT_NAMESPACE
#endif // STATS