示例#1
0
void FProfilerManager::LoadProfilerCapture( const FString& ProfilerCaptureFilepath, const bool bAdd /*= false*/ )
{
	// deselect the active session
	if (ActiveSession.IsValid())
	{
		SessionManager->SelectSession(NULL);
	}

	if( bAdd == false )
	{
		ClearStatsAndInstances();
	}

	FProfilerSessionRef ProfilerSession = MakeShareable( new FProfilerSession( ProfilerCaptureFilepath ) );
	auto Var = ProfilerSession->AsShared();
	const FGuid ProfilerInstanceID = ProfilerSession->GetInstanceID();

	ProfilerSession->
		SetOnCaptureFileProcessed( FProfilerSession::FCaptureFileProcessedDelegate::CreateSP( this, &FProfilerManager::ProfilerSession_OnCaptureFileProcessed ) )
		.SetOnAddThreadTime( FProfilerSession::FAddThreadTimeDelegate::CreateSP( this, &FProfilerManager::ProfilerSession_OnAddThreadTime ) );

	ProfilerSessionInstances.Add( ProfilerInstanceID, ProfilerSession );
	{
		PROFILER_SCOPE_LOG_TIME( TEXT( "ProfilerClient->LoadCapture" ), nullptr );
		ProfilerClient->LoadCapture( ProfilerCaptureFilepath, ProfilerInstanceID );
	}

	SessionInstancesUpdatedEvent.Broadcast();
	ProfilerType = EProfilerSessionTypes::StatsFile;
	
	GetProfilerWindow()->ManageEventGraphTab( ProfilerInstanceID, true, ProfilerSession->GetName() );
	SetViewMode( EProfilerViewMode::LineIndexBased );
}
void FProfilerSession::UpdateAggregatedStats( const uint32 FrameIndex )
{
	static FTotalTimeAndCount TimeAndCount( 0.0f, 0 );
	PROFILER_SCOPE_LOG_TIME( TEXT( "2 FProfilerSession::UpdateAggregatedStats" ), &TimeAndCount );

	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 uint32 StatID = ProfilerSample.StatID();
		FProfilerAggregatedStat* AggregatedStat = AggregatedStats.Find( StatID );
		if( !AggregatedStat )
		{
			const FProfilerStat& ProfilerStat = GetMetaData()->GetStatByID( StatID );
			AggregatedStat = &AggregatedStats.Add( ProfilerSample.StatID(), FProfilerAggregatedStat( ProfilerStat.Name(), ProfilerStat.OwningGroup().Name(), ProfilerSample.Type() ) );
		}
		(*AggregatedStat) += ProfilerSample;
	}

	for( auto It = AggregatedStats.CreateIterator(); It; ++It )
	{
		FProfilerAggregatedStat& AggregatedStat = It.Value();
		AggregatedStat.Advance();
	}

	// @TODO: Create map for stats TMap<uint32, TArray<uint32> >; StatID -> Sample indices for faster lookup in data providers
}
void FProfilerStatMetaData::Update( const FStatMetaData& ClientStatMetaData )
{
	PROFILER_SCOPE_LOG_TIME( TEXT( "FProfilerStatMetaData.Update" ), nullptr );

	// Iterate through all thread descriptions.
	ThreadDescriptions.Append( ClientStatMetaData.ThreadDescriptions );

	// Initialize fake stat for Self.
	const uint32 NoGroupID = 0;

	InitializeGroup( NoGroupID, "NoGroup" );
	InitializeStat( 0, NoGroupID, TEXT( "Self" ), STATTYPE_CycleCounter );
	InitializeStat( 1, NoGroupID, FStatConstants::NAME_ThreadRoot.GetPlainNameString(), STATTYPE_CycleCounter, FStatConstants::NAME_ThreadRoot );

	// Iterate through all stat group descriptions.
	for( auto It = ClientStatMetaData.GroupDescriptions.CreateConstIterator(); It; ++It )
	{
		const FStatGroupDescription& GroupDesc = It.Value();
		InitializeGroup( GroupDesc.ID, GroupDesc.Name );
	}

	// Iterate through all stat descriptions.
	for( auto It = ClientStatMetaData.StatDescriptions.CreateConstIterator(); It; ++It )
	{
		const FStatDescription& StatDesc = It.Value();
		InitializeStat( StatDesc.ID, StatDesc.GroupID, StatDesc.Name, (EStatType)StatDesc.StatType );
	}

	SecondsPerCycle = ClientStatMetaData.SecondsPerCycle;
}
FEventGraphDataRef FProfilerSession::CreateEventGraphData( const uint32 FrameStartIndex, const uint32 FrameEndIndex, const EEventGraphTypes::Type EventGraphType )
{
	static FTotalTimeAndCount Current(0.0f, 0);
	PROFILER_SCOPE_LOG_TIME( TEXT( "FProfilerSession::CreateEventGraphData" ), &Current );

	FEventGraphData* EventGraphData = new FEventGraphData();

	if( EventGraphType == EEventGraphTypes::Average )
	{
		for( uint32 FrameIndex = FrameStartIndex; FrameIndex < FrameEndIndex+1; ++FrameIndex )
		{
			// Create a temporary event graph data for the specified frame.
			const FEventGraphData CurrentEventGraphData( AsShared(), FrameIndex );
			EventGraphData->CombineAndAdd( CurrentEventGraphData );
		}
	
		EventGraphData->Advance( FrameStartIndex, FrameEndIndex+1 );
		EventGraphData->Divide( (double)EventGraphData->GetNumFrames() );
	}
	else if( EventGraphType == EEventGraphTypes::Maximum )
	{
		for( uint32 FrameIndex = FrameStartIndex; FrameIndex < FrameEndIndex+1; ++FrameIndex )
		{
			// Create a temporary event graph data for the specified frame.
			const FEventGraphData CurrentEventGraphData( AsShared(), FrameIndex );
			EventGraphData->CombineAndFindMax( CurrentEventGraphData );
		}
		EventGraphData->Advance( FrameStartIndex, FrameEndIndex+1 );
	}

	return MakeShareable( EventGraphData );
}
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 IDataProviderRef& SessionDataProvider = InProfilerSession->GetDataProvider(); 
	const IDataProviderRef 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 FProfilerStatMetaDataRef& 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 FProfilerSession::CompletionSyncAggregatedEventGraphData()
{
	if (CompletionSync.GetReference() && !CompletionSync->IsComplete())
	{
		static FTotalTimeAndCount JoinTasksTimeAndCont( 0.0f, 0 );
		PROFILER_SCOPE_LOG_TIME( TEXT( "4   FProfilerSession::CombineJoinAndContinue" ), &JoinTasksTimeAndCont );

		FTaskGraphInterface::Get().WaitUntilTaskCompletes( CompletionSync, ENamedThreads::GameThread );
	}
}
void FProfilerSession::UpdateAggregatedEventGraphData( const uint32 FrameIndex )
{
	static FTotalTimeAndCount TimeAndCount( 0.0f, 0 );
	PROFILER_SCOPE_LOG_TIME( TEXT( "3  FProfilerSession::UpdateAggregatedEventGraphData" ), &TimeAndCount );

	CompletionSyncAggregatedEventGraphData();

	// Create a temporary event graph data for the specified frame.
	delete EventGraphDataCurrent;
	EventGraphDataCurrent = new FEventGraphData( AsShared(), FrameIndex );
	const uint32 NumFramesLocal = SessionType == EProfilerSessionTypes::Live ? DataProvider->GetNumFrames() : 0;

	static const bool bUseTaskGraph = true;

	if( bUseTaskGraph )
	{
		FGraphEventArray EventGraphCombineTasks;

		DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.EventGraphData.CombineAndFindMax"),
			STAT_FSimpleDelegateGraphTask_EventGraphData_CombineAndFindMax,
			STATGROUP_TaskGraphTasks);
		DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.EventGraphData.CombineAndAdd"),
			STAT_FSimpleDelegateGraphTask_EventGraphData_EventGraphCombineAndAdd,
			STATGROUP_TaskGraphTasks);

		new (EventGraphCombineTasks) FGraphEventRef(FSimpleDelegateGraphTask::CreateAndDispatchWhenReady
		(
			FSimpleDelegateGraphTask::FDelegate::CreateRaw( this, &FProfilerSession::EventGraphCombineAndMax, EventGraphDataCurrent, NumFramesLocal ), 
			GET_STATID(STAT_FSimpleDelegateGraphTask_EventGraphData_CombineAndFindMax), nullptr
		));

		new (EventGraphCombineTasks) FGraphEventRef(FSimpleDelegateGraphTask::CreateAndDispatchWhenReady
		(
			FSimpleDelegateGraphTask::FDelegate::CreateRaw( this, &FProfilerSession::EventGraphCombineAndAdd, EventGraphDataCurrent, NumFramesLocal ), 
			GET_STATID(STAT_FSimpleDelegateGraphTask_EventGraphData_EventGraphCombineAndAdd), nullptr
		));

		DECLARE_CYCLE_STAT(TEXT("FNullGraphTask.EventGraphData.CombineJoinAndContinue"),
			STAT_FNullGraphTask_EventGraphData_CombineJoinAndContinue,
			STATGROUP_TaskGraphTasks);

		// JoinThreads
		CompletionSync = TGraphTask<FNullGraphTask>::CreateTask( &EventGraphCombineTasks, ENamedThreads::GameThread )
			.ConstructAndDispatchWhenReady(GET_STATID(STAT_FNullGraphTask_EventGraphData_CombineJoinAndContinue), ENamedThreads::AnyThread);
	}
	else
	{
		EventGraphCombineAndMax( EventGraphDataCurrent, NumFramesLocal );
		EventGraphCombineAndAdd( EventGraphDataCurrent, NumFramesLocal );
	}
}
示例#8
0
void FProfilerManager::DataGraph_OnSelectionChangedForIndex( uint32 FrameStartIndex, uint32 FrameEndIndex )
{
	PROFILER_SCOPE_LOG_TIME( TEXT( "FProfilerManager::DataGraph_OnSelectionChangedForIndex" ), nullptr );

	for( auto It = GetProfilerInstancesIterator(); It; ++It )
	{
		FProfilerSessionRef ProfilerSession = It.Value();
	
		FEventGraphDataRef EventGraphDataAverage = ProfilerSession->CreateEventGraphData( FrameStartIndex, FrameEndIndex, EEventGraphTypes::Average );
		FEventGraphDataRef EventGraphDataMaximum = ProfilerSession->CreateEventGraphData( FrameStartIndex, FrameEndIndex, EEventGraphTypes::Maximum );

		GetProfilerWindow()->UpdateEventGraph( ProfilerSession->GetInstanceID(), EventGraphDataAverage, EventGraphDataMaximum, false );
	}
}
bool FProfilerSession::HandleTicker( float DeltaTime )
{
	// Update metadata if needed
	if( bRequestStatMetadataUpdate )
	{
		StatMetaData->Update( ClientStatMetadata );
		bRequestStatMetadataUpdate = false;
	}

	static double ProcessingTime = 1.0;
	ProcessingTime -= DeltaTime;

	static int32 NumFramesProcessedLastTime = 0;

	if (ProcessingTime < 0.0)
	{
		UE_LOG( LogStats, Verbose, TEXT( "NumFramesProcessedLastTime: %4i / %4i" ), NumFramesProcessedLastTime, FrameToProcess.Num() );
		ProcessingTime = 1.0;
		NumFramesProcessedLastTime = 0;
	}

	// Limit processing to 50ms per frame.
	const double TimeLimit = 50 / 1000.0;
	double Seconds = 0;
	
	for( int32 FrameNumber = 0; FrameNumber < FrameToProcess.Num(); FrameNumber++ )
	{	
		if( Seconds > TimeLimit )
		{
			break;
		}

		static FTotalTimeAndCount Current( 0.0f, 0 );
		PROFILER_SCOPE_LOG_TIME( TEXT( "1 FProfilerSession::HandleTicker" ), &Current );

		NumFramesProcessedLastTime++;
		NumFramesProcessed++;

		FSimpleScopeSecondsCounter SecondsCounter(Seconds);

		const uint32 FrameIndex = FrameToProcess[0];
		FrameToProcess.RemoveAt( 0 );

		FProfilerDataFrame& CurrentProfilerData = FrameToProfilerDataMapping.FindChecked( FrameIndex );

		TMap<uint32, float> ThreadMS;

		// Preprocess the hierarchical samples for the specified frame.
		const TMap<uint32, FProfilerCycleGraph>& CycleGraphs = CurrentProfilerData.CycleGraphs;

		// Add a root sample for this frame.
		// HACK 2013-07-19, 13:44 STAT_Root == ThreadRoot in stats2
		const uint32 FrameRootSampleIndex = DataProvider->AddHierarchicalSample( 0, StatMetaData->GetStatByID(1).OwningGroup().ID(), 1, 0.0f, 0.0f, 1 );
		
		double GameThreadTimeMS = 0.0f;
		double MaxThreadTimeMS = 0.0f;

		double ThreadStartTimeMS = 0.0;
		for( auto ThreadIt = CycleGraphs.CreateConstIterator(); ThreadIt; ++ThreadIt )
		{
			const uint32 ThreadID = ThreadIt.Key();
			const FProfilerCycleGraph& ThreadGraph = ThreadIt.Value();

			// Calculate total time for this thread.
			double ThreadDurationTimeMS = 0.0;
			ThreadStartTimeMS = CurrentProfilerData.FrameStart;
			for( int32 Index = 0; Index < ThreadGraph.Children.Num(); Index++ )
			{
				ThreadDurationTimeMS += StatMetaData->ConvertCyclesToMS( ThreadGraph.Children[Index].Value );
			}

			if (ThreadDurationTimeMS > 0.0)
			{
				// Check for game thread.
				const FString GameThreadName = FName( NAME_GameThread ).GetPlainNameString();
				const bool bGameThreadFound = StatMetaData->GetThreadDescriptions().FindChecked( ThreadID ).Contains( GameThreadName );
				if( bGameThreadFound )
				{
					GameThreadTimeMS = ThreadDurationTimeMS;
				}

				// Add a root sample for each thread.
				const uint32& NewThreadID = StatMetaData->ThreadIDtoStatID.FindChecked( ThreadID );
				const uint32 ThreadRootSampleIndex = DataProvider->AddHierarchicalSample
				( 
					NewThreadID/*ThreadID*/, 
					StatMetaData->GetStatByID(NewThreadID).OwningGroup().ID(), 
					NewThreadID, 
					ThreadStartTimeMS, 
					ThreadDurationTimeMS, 
					1, 
					FrameRootSampleIndex 
				);
				ThreadMS.FindOrAdd( ThreadID ) = (float)ThreadDurationTimeMS;

				// Recursively add children and parent to the root samples.
				for( int32 Index = 0; Index < ThreadGraph.Children.Num(); Index++ )
				{
					const FProfilerCycleGraph& CycleGraph = ThreadGraph.Children[Index];
					const double CycleDurationMS = StatMetaData->ConvertCyclesToMS( CycleGraph.Value );
					const double CycleStartTimeMS = ThreadStartTimeMS;

					if (CycleDurationMS > 0.0)
					{
						PopulateHierarchy_Recurrent( CycleGraph, CycleStartTimeMS, CycleDurationMS, ThreadRootSampleIndex );
					}
					ThreadStartTimeMS += CycleDurationMS;
				}

				MaxThreadTimeMS = FMath::Max( MaxThreadTimeMS, ThreadDurationTimeMS );
			}
		}

		// Fix the root stat time.
		FProfilerSampleArray& MutableCollection = const_cast<FProfilerSampleArray&>(DataProvider->GetCollection());
		MutableCollection[FrameRootSampleIndex].SetDurationMS( GameThreadTimeMS != 0.0f ? GameThreadTimeMS : MaxThreadTimeMS );

		FPSAnalyzer->AddSample( GameThreadTimeMS > 0.0f ? 1000.0f/GameThreadTimeMS : 0.0f );

		// Process the non-hierarchical samples for the specified frame.
		{
			// Process integer counters.
			for( int32 Index = 0; Index < CurrentProfilerData.CountAccumulators.Num(); Index++ )
			{
				const FProfilerCountAccumulator& IntCounter = CurrentProfilerData.CountAccumulators[Index];
				const EProfilerSampleTypes::Type ProfilerSampleType = StatMetaData->GetSampleTypeForStatID( IntCounter.StatId );
				DataProvider->AddCounterSample( StatMetaData->GetStatByID(IntCounter.StatId).OwningGroup().ID(), IntCounter.StatId, (double)IntCounter.Value, ProfilerSampleType );
			}

			// Process floating point counters.
			for( int32 Index = 0; Index < CurrentProfilerData.FloatAccumulators.Num(); Index++ )
			{
				const FProfilerFloatAccumulator& FloatCounter = CurrentProfilerData.FloatAccumulators[Index];
				DataProvider->AddCounterSample( StatMetaData->GetStatByID(FloatCounter.StatId).OwningGroup().ID(), FloatCounter.StatId, (double)FloatCounter.Value, EProfilerSampleTypes::NumberFloat );
			}
		}

		// Advance frame
		const uint32 LastFrameIndex = DataProvider->GetNumFrames();
		DataProvider->AdvanceFrame( MaxThreadTimeMS );

		// Update aggregated stats
		UpdateAggregatedStats( LastFrameIndex );

		// Update aggregated events.
		UpdateAggregatedEventGraphData( LastFrameIndex );

		{
			static FTotalTimeAndCount TotalOnAddThreadTime( 0.0f, 0 );
			PROFILER_SCOPE_LOG_TIME( TEXT( "5     FProfilerSession::HandleTicker.OnAddThreadTime" ), &Current );

			// Update mini-view.
			OnAddThreadTime.ExecuteIfBound( LastFrameIndex, ThreadMS, StatMetaData );
		}

		FrameToProfilerDataMapping.Remove( FrameIndex );
	}	

	if( SessionType == EProfilerSessionTypes::StatsFile )
	{
		if( FrameToProcess.Num() == 0 && bHasAllProfilerData )
		{
			CompletionSyncAggregatedEventGraphData();

			// Advance event graphs.
			EventGraphDataMaximum->Advance( 0, DataProvider->GetNumFrames() );
			EventGraphDataTotal->Advance( 0, DataProvider->GetNumFrames() );

			// Broadcast that a capture file has been fully processed.
			OnCaptureFileProcessed.ExecuteIfBound( GetInstanceID() );

			// Disable tick method as we no longer need to tick.
			return false;
		}
	}

	return true;
}