2019-01-17 18:54:05 -05:00
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
2016-10-28 15:04:38 -04:00
# include "ProfilerClientManager.h"
2016-11-23 15:48:37 -05:00
# include "HAL/FileManager.h"
2017-08-30 09:37:09 -04:00
# include "MessageEndpointBuilder.h"
2016-11-23 15:48:37 -05:00
# include "Misc/Paths.h"
# include "Misc/SecureHash.h"
2017-08-30 09:37:09 -04:00
# include "Serialization/MemoryReader.h"
# include "ProfilerServiceMessages.h"
2014-03-14 14:13:41 -04:00
2016-10-28 15:04:38 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogProfilerClient , Log , All ) ;
DECLARE_CYCLE_STAT ( TEXT ( " HandleDataReceived " ) , STAT_PC_HandleDataReceived , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " ReadStatMessages " ) , STAT_PC_ReadStatMessages , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " AddStatMessages " ) , STAT_PC_AddStatMessages , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " GenerateDataFrame " ) , STAT_PC_GenerateDataFrame , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " AddStatFName " ) , STAT_PC_AddStatFName , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " AddGroupFName " ) , STAT_PC_AddGroupFName , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " GenerateCycleGraph " ) , STAT_PC_GenerateCycleGraph , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " GenerateAccumulator " ) , STAT_PC_GenerateAccumulator , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " FindOrAddStat " ) , STAT_PC_FindOrAddStat , STATGROUP_Profiler ) ;
DECLARE_CYCLE_STAT ( TEXT ( " FindOrAddThread " ) , STAT_PC_FindOrAddThread , STATGROUP_Profiler ) ;
2014-03-14 14:13:41 -04:00
/* FProfilerClientManager structors
*****************************************************************************/
2016-10-28 15:04:38 -04:00
FProfilerClientManager : : FProfilerClientManager ( const TSharedRef < IMessageBus , ESPMode : : ThreadSafe > & InMessageBus )
2014-03-14 14:13:41 -04:00
{
# if STATS
MessageBus = InMessageBus ;
MessageEndpoint = FMessageEndpoint : : Builder ( " FProfilerClientModule " , InMessageBus )
2015-05-14 08:13:44 -04:00
. Handling < FProfilerServiceAuthorize > ( this , & FProfilerClientManager : : HandleServiceAuthorizeMessage )
. Handling < FProfilerServiceData2 > ( this , & FProfilerClientManager : : HandleProfilerServiceData2Message )
2014-03-14 14:13:41 -04:00
. Handling < FProfilerServicePreviewAck > ( this , & FProfilerClientManager : : HandleServicePreviewAckMessage )
. Handling < FProfilerServiceFileChunk > ( this , & FProfilerClientManager : : HandleServiceFileChunk )
. Handling < FProfilerServicePing > ( this , & FProfilerClientManager : : HandleServicePingMessage ) ;
if ( MessageEndpoint . IsValid ( ) )
{
2016-10-28 15:04:38 -04:00
OnShutdownMessageBusDelegateHandle = InMessageBus - > OnShutdown ( ) . AddRaw ( this , & FProfilerClientManager : : HandleMessageBusShutdown ) ;
2014-03-14 14:13:41 -04:00
MessageEndpoint - > Subscribe < FProfilerServicePing > ( ) ;
}
TickDelegate = FTickerDelegate : : CreateRaw ( this , & FProfilerClientManager : : HandleTicker ) ;
MessageDelegate = FTickerDelegate : : CreateRaw ( this , & FProfilerClientManager : : HandleMessagesTicker ) ;
LastPingTime = FDateTime : : Now ( ) ;
RetryTime = 5.f ;
LoadConnection = nullptr ;
2015-05-14 08:13:44 -04:00
MessageDelegateHandle = FTicker : : GetCoreTicker ( ) . AddTicker ( MessageDelegate , 0.1f ) ;
2014-03-14 14:13:41 -04:00
# endif
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
FProfilerClientManager : : ~ FProfilerClientManager ( )
{
# if STATS
2015-12-03 14:21:29 -05:00
Shutdown ( ) ;
2014-03-14 14:13:41 -04:00
Unsubscribe ( ) ;
if ( MessageBus . IsValid ( ) )
{
2016-10-28 15:04:38 -04:00
MessageBus - > OnShutdown ( ) . Remove ( OnShutdownMessageBusDelegateHandle ) ;
2014-03-14 14:13:41 -04:00
}
LoadConnection = nullptr ;
# endif
}
/* IProfilerClient interface
*****************************************************************************/
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : Subscribe ( const FGuid & Session )
2014-03-14 14:13:41 -04:00
{
# if STATS
FGuid OldSessionId = ActiveSessionId ;
PendingSessionId = Session ;
if ( MessageEndpoint . IsValid ( ) )
{
if ( OldSessionId . IsValid ( ) )
{
TArray < FGuid > Instances ;
Connections . GenerateKeyArray ( Instances ) ;
for ( int32 i = 0 ; i < Instances . Num ( ) ; + + i )
{
MessageEndpoint - > Publish ( new FProfilerServiceUnsubscribe ( OldSessionId , Instances [ i ] ) , EMessageScope : : Network ) ;
// fire the disconnection delegate
ProfilerClientDisconnectedDelegate . Broadcast ( ActiveSessionId , Instances [ i ] ) ;
}
ActiveSessionId . Invalidate ( ) ;
}
ActiveSessionId = PendingSessionId ;
}
Connections . Reset ( ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Log , TEXT ( " Subscribe Session: %s " ) , * Session . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : Track ( const FGuid & Instance )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( MessageEndpoint . IsValid ( ) & & ActiveSessionId . IsValid ( ) & & ! PendingInstances . Contains ( Instance ) )
{
PendingInstances . Add ( Instance ) ;
MessageEndpoint - > Publish ( new FProfilerServiceSubscribe ( ActiveSessionId , Instance ) , EMessageScope : : Network ) ;
RetryTime = 5.f ;
2015-01-08 09:29:27 -05:00
TickDelegateHandle = FTicker : : GetCoreTicker ( ) . AddTicker ( TickDelegate , RetryTime ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " Track Session: %s, Instance: %s " ) , * ActiveSessionId . ToString ( ) , * Instance . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : Untrack ( const FGuid & Instance )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( MessageEndpoint . IsValid ( ) & & ActiveSessionId . IsValid ( ) )
{
MessageEndpoint - > Publish ( new FProfilerServiceUnsubscribe ( ActiveSessionId , Instance ) , EMessageScope : : Network ) ;
Connections . Remove ( Instance ) ;
// fire the disconnection delegate
ProfilerClientDisconnectedDelegate . Broadcast ( ActiveSessionId , Instance ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " Untrack Session: %s, Instance: %s " ) , * ActiveSessionId . ToString ( ) , * Instance . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
# endif
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
void FProfilerClientManager : : Unsubscribe ( )
{
# if STATS
PendingSessionId . Invalidate ( ) ;
Subscribe ( PendingSessionId ) ;
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : SetCaptureState ( const bool bRequestedCaptureState , const FGuid & InstanceId /*= FGuid()*/ )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( MessageEndpoint . IsValid ( ) & & ActiveSessionId . IsValid ( ) )
{
2016-10-28 15:04:38 -04:00
if ( ! InstanceId . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
TArray < FMessageAddress > Instances ;
for ( auto It = Connections . CreateConstIterator ( ) ; It ; + + It )
{
2016-10-28 15:04:38 -04:00
Instances . Add ( It . Value ( ) . ProfilerServiceAddress ) ;
2014-03-14 14:13:41 -04:00
}
MessageEndpoint - > Send ( new FProfilerServiceCapture ( bRequestedCaptureState ) , Instances ) ;
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " SetCaptureState Session: %s, Instance: %s, State: %i " ) , * ActiveSessionId . ToString ( ) , * InstanceId . ToString ( ) , ( int32 ) bRequestedCaptureState ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2017-05-03 14:18:32 -04:00
const FMessageAddress & MessageAddress = Connections . Find ( InstanceId ) - > ProfilerServiceAddress ;
MessageEndpoint - > Send ( new FProfilerServiceCapture ( bRequestedCaptureState ) , MessageAddress ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " SetCaptureState Session: %s, Instance: %s, State: %i " ) , * ActiveSessionId . ToString ( ) , * InstanceId . ToString ( ) , ( int32 ) bRequestedCaptureState ) ;
2014-03-14 14:13:41 -04:00
}
}
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : SetPreviewState ( const bool bRequestedPreviewState , const FGuid & InstanceId /*= FGuid()*/ )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( MessageEndpoint . IsValid ( ) & & ActiveSessionId . IsValid ( ) )
{
2016-10-28 15:04:38 -04:00
if ( ! InstanceId . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
TArray < FMessageAddress > Instances ;
for ( auto It = Connections . CreateConstIterator ( ) ; It ; + + It )
{
2016-10-28 15:04:38 -04:00
Instances . Add ( It . Value ( ) . ProfilerServiceAddress ) ;
2014-03-14 14:13:41 -04:00
}
MessageEndpoint - > Send ( new FProfilerServicePreview ( bRequestedPreviewState ) , Instances ) ;
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " SetPreviewState Session: %s, Instance: %s, State: %i " ) , * ActiveSessionId . ToString ( ) , * InstanceId . ToString ( ) , ( int32 ) bRequestedPreviewState ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2017-05-03 14:18:32 -04:00
const FMessageAddress & MessageAddress = Connections . Find ( InstanceId ) - > ProfilerServiceAddress ;
MessageEndpoint - > Send ( new FProfilerServicePreview ( bRequestedPreviewState ) , MessageAddress ) ;
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " SetPreviewState Session: %s, Instance: %s, State: %i " ) , * ActiveSessionId . ToString ( ) , * InstanceId . ToString ( ) , ( int32 ) bRequestedPreviewState ) ;
2014-03-14 14:13:41 -04:00
}
}
# endif
}
2016-10-28 15:04:38 -04:00
2015-12-03 14:21:29 -05:00
/*-----------------------------------------------------------------------------
New read test, still temporary, but around 4x faster
-----------------------------------------------------------------------------*/
class FNewStatsReader : public FStatsReadFile
{
friend struct FStatsReader < FNewStatsReader > ;
typedef FStatsReadFile Super ;
public :
2016-10-28 15:04:38 -04:00
2015-12-03 14:21:29 -05:00
/** Initialize. */
2016-10-28 15:04:38 -04:00
void Initialize ( FProfilerClientManager * InProfilerClientManager , FServiceConnection * InLoadConnection )
2015-12-03 14:21:29 -05:00
{
ProfilerClientManager = InProfilerClientManager ;
LoadConnection = InLoadConnection ;
}
protected :
/** Initialization constructor. */
2016-10-28 15:04:38 -04:00
FNewStatsReader ( const TCHAR * InFilename )
: FStatsReadFile ( InFilename , false )
, ProfilerClientManager ( nullptr )
, LoadConnection ( nullptr )
2015-12-03 14:21:29 -05:00
{
// Keep only the last frame.
2016-10-28 15:04:38 -04:00
SetHistoryFrames ( 1 ) ;
2015-12-03 14:21:29 -05:00
}
/** Called every each frame has been read from the file. */
2016-10-28 15:04:38 -04:00
virtual void ReadStatsFrame ( const TArray < FStatMessage > & CondensedMessages , const int64 Frame ) override
2015-12-03 14:21:29 -05:00
{
2016-10-28 15:04:38 -04:00
SCOPE_CYCLE_COUNTER ( STAT_PC_GenerateDataFrame ) ;
2015-12-03 14:21:29 -05:00
FProfilerDataFrame & DataFrame = LoadConnection - > CurrentData ;
DataFrame . Frame = Frame ;
DataFrame . FrameStart = 0.0 ;
DataFrame . CountAccumulators . Reset ( ) ;
DataFrame . CycleGraphs . Reset ( ) ;
DataFrame . FloatAccumulators . Reset ( ) ;
DataFrame . MetaDataUpdated = false ;
// Get the stat stack root and the non frame stats.
FRawStatStackNode Stack ;
TArray < FStatMessage > NonFrameStats ;
2016-10-28 15:04:38 -04:00
State . UncondenseStackStats ( CondensedMessages , Stack , nullptr , & NonFrameStats ) ;
2015-12-03 14:21:29 -05:00
2016-10-28 15:04:38 -04:00
LoadConnection - > GenerateCycleGraphs ( Stack , DataFrame . CycleGraphs ) ;
LoadConnection - > GenerateAccumulators ( NonFrameStats , DataFrame . CountAccumulators , DataFrame . FloatAccumulators ) ;
2015-12-03 14:21:29 -05:00
// Create a copy of the stats metadata.
FStatMetaData * MetaDataPtr = nullptr ;
if ( DataFrame . MetaDataUpdated )
{
MetaDataPtr = new FStatMetaData ( ) ;
* MetaDataPtr = LoadConnection - > StatMetaData ;
}
// Create a copy of the stats data.
FProfilerDataFrame * DataFramePtr = new FProfilerDataFrame ( ) ;
* DataFramePtr = DataFrame ;
// Send to game thread.
FSimpleDelegateGraphTask : : CreateAndDispatchWhenReady
(
2016-10-28 15:04:38 -04:00
FSimpleDelegateGraphTask : : FDelegate : : CreateRaw ( ProfilerClientManager , & FProfilerClientManager : : SendProfilerDataFrameToGame , DataFramePtr , MetaDataPtr , LoadConnection - > InstanceId ) ,
2015-12-03 14:21:29 -05:00
TStatId ( ) , nullptr , ENamedThreads : : GameThread
) ;
}
/** Called after reading all data from the file. */
virtual void PreProcessStats ( ) override
{
2016-06-01 12:08:56 -04:00
FSimpleDelegateGraphTask : : CreateAndDispatchWhenReady
(
2016-10-28 15:04:38 -04:00
FSimpleDelegateGraphTask : : FDelegate : : CreateRaw ( ProfilerClientManager , & FProfilerClientManager : : FinalizeLoading , LoadConnection - > InstanceId ) ,
2016-06-01 12:08:56 -04:00
TStatId ( ) , NULL , ENamedThreads : : GameThread
) ;
2015-12-03 14:21:29 -05:00
}
FProfilerClientManager * ProfilerClientManager ;
FServiceConnection * LoadConnection ;
} ;
2016-10-28 15:04:38 -04:00
void FServiceConnection : : LoadCapture ( const FString & DataFilepath , FProfilerClientManager * ProfilerClientManager )
2015-12-03 14:21:29 -05:00
{
2016-10-28 15:04:38 -04:00
StatsReader = FStatsReader < FNewStatsReader > : : Create ( * DataFilepath ) ;
2015-12-03 14:21:29 -05:00
if ( StatsReader )
{
2016-10-28 15:04:38 -04:00
StatsReader - > Initialize ( ProfilerClientManager , this ) ;
2015-12-03 14:21:29 -05:00
StatsReader - > ReadAndProcessAsynchronously ( ) ;
}
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : LoadCapture ( const FString & DataFilepath , const FGuid & ProfileId )
2014-03-14 14:13:41 -04:00
{
# if STATS
2015-12-03 14:21:29 -05:00
// Start an async load.
2014-03-14 14:13:41 -04:00
LoadConnection = & Connections . FindOrAdd ( ProfileId ) ;
LoadConnection - > InstanceId = ProfileId ;
2015-12-03 14:21:29 -05:00
LoadConnection - > StatMetaData . SecondsPerCycle = FPlatformTime : : GetSecondsPerCycle ( ) ; // fix this by adding a message which specifies this
2014-03-14 14:13:41 -04:00
2016-10-28 15:04:38 -04:00
ProfilerLoadStartedDelegate . Broadcast ( ProfileId ) ;
LoadConnection - > LoadCapture ( DataFilepath , this ) ;
2014-03-14 14:13:41 -04:00
RetryTime = 0.05f ;
2015-12-03 14:21:29 -05:00
TickDelegateHandle = FTicker : : GetCoreTicker ( ) . AddTicker ( TickDelegate , RetryTime ) ;
2014-03-14 14:13:41 -04:00
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : RequestLastCapturedFile ( const FGuid & InstanceId /*= FGuid()*/ )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( MessageEndpoint . IsValid ( ) & & ActiveSessionId . IsValid ( ) )
{
2016-10-28 15:04:38 -04:00
if ( ! InstanceId . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
TArray < FMessageAddress > Instances ;
for ( auto It = Connections . CreateConstIterator ( ) ; It ; + + It )
{
2016-10-28 15:04:38 -04:00
Instances . Add ( It . Value ( ) . ProfilerServiceAddress ) ;
2014-03-14 14:13:41 -04:00
}
MessageEndpoint - > Send ( new FProfilerServiceRequest ( EProfilerRequestType : : PRT_SendLastCapturedFile ) , Instances ) ;
}
else
{
2017-05-03 14:18:32 -04:00
const FMessageAddress & MessageAddress = Connections . Find ( InstanceId ) - > ProfilerServiceAddress ;
MessageEndpoint - > Send ( new FProfilerServiceRequest ( EProfilerRequestType : : PRT_SendLastCapturedFile ) , MessageAddress ) ;
2014-03-14 14:13:41 -04:00
}
}
# endif
}
2016-10-28 15:04:38 -04:00
const FStatMetaData & FProfilerClientManager : : GetStatMetaData ( const FGuid & InstanceId ) const
{
return Connections . Find ( InstanceId ) - > StatMetaData ;
}
FProfilerClientDataDelegate & FProfilerClientManager : : OnProfilerData ( )
{
return ProfilerDataDelegate ;
}
FProfilerFileTransferDelegate & FProfilerClientManager : : OnProfilerFileTransfer ( )
{
return ProfilerFileTransferDelegate ;
}
FProfilerClientConnectedDelegate & FProfilerClientManager : : OnProfilerClientConnected ( )
{
return ProfilerClientConnectedDelegate ;
}
FProfilerClientDisconnectedDelegate & FProfilerClientManager : : OnProfilerClientDisconnected ( )
{
return ProfilerClientDisconnectedDelegate ;
}
FProfilerMetaDataUpdateDelegate & FProfilerClientManager : : OnMetaDataUpdated ( )
{
return ProfilerMetaDataUpdatedDelegate ;
}
FProfilerLoadStartedDelegate & FProfilerClientManager : : OnLoadStarted ( )
{
return ProfilerLoadStartedDelegate ;
}
FProfilerLoadCompletedDelegate & FProfilerClientManager : : OnLoadCompleted ( )
{
return ProfilerLoadCompletedDelegate ;
}
FProfilerLoadCancelledDelegate & FProfilerClientManager : : OnLoadCancelled ( )
{
return ProfilerLoadCancelledDelegate ;
}
2014-03-14 14:13:41 -04:00
/* FProfilerClientManager event handlers
*****************************************************************************/
void FProfilerClientManager : : HandleMessageBusShutdown ( )
{
# if STATS
2015-12-03 14:21:29 -05:00
Shutdown ( ) ;
2014-03-14 14:13:41 -04:00
MessageEndpoint . Reset ( ) ;
MessageBus . Reset ( ) ;
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : HandleServiceAuthorizeMessage ( const FProfilerServiceAuthorize & Message , const TSharedRef < IMessageContext , ESPMode : : ThreadSafe > & Context )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( ActiveSessionId = = Message . SessionId & & PendingInstances . Contains ( Message . InstanceId ) )
{
PendingInstances . Remove ( Message . InstanceId ) ;
FServiceConnection & Connection = Connections . FindOrAdd ( Message . InstanceId ) ;
Connection . Initialize ( Message , Context ) ;
// Fire a meta data update message
2015-12-03 14:21:29 -05:00
//ProfilerMetaDataUpdatedDelegate.Broadcast(Message.InstanceId);
2014-03-14 14:13:41 -04:00
// Fire the client connection event
ProfilerClientConnectedDelegate . Broadcast ( ActiveSessionId , Message . InstanceId ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " Authorize SessionId: %s, InstanceId: %s " ) , * Message . SessionId . ToString ( ) , * Message . InstanceId . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
# endif
}
2016-10-28 15:04:38 -04:00
/* FServiceConnection
*****************************************************************************/
2015-12-03 14:21:29 -05:00
FServiceConnection : : FServiceConnection ( )
2016-10-28 15:04:38 -04:00
: StatsReader ( nullptr )
{ }
2015-12-03 14:21:29 -05:00
FServiceConnection : : ~ FServiceConnection ( )
{
if ( StatsReader )
{
StatsReader - > RequestStop ( ) ;
while ( StatsReader - > IsBusy ( ) )
{
2016-10-28 15:04:38 -04:00
FPlatformProcess : : Sleep ( 2.0f ) ;
UE_LOG ( LogStats , Log , TEXT ( " RequestStop: Stage: %s / %3i%% " ) , * StatsReader - > GetProcessingStageAsString ( ) , StatsReader - > GetStageProgress ( ) ) ;
2015-12-03 14:21:29 -05:00
}
delete StatsReader ;
StatsReader = nullptr ;
}
2015-12-16 11:52:36 -05:00
for ( const auto & It : ReceivedData )
{
delete It . Value ;
}
2015-12-03 14:21:29 -05:00
}
2016-10-28 15:04:38 -04:00
void FServiceConnection : : Initialize ( const FProfilerServiceAuthorize & Message , const TSharedRef < IMessageContext , ESPMode : : ThreadSafe > & Context )
2014-03-14 14:13:41 -04:00
{
# if STATS
2015-05-14 08:13:44 -04:00
ProfilerServiceAddress = Context - > GetSender ( ) ;
2014-03-14 14:13:41 -04:00
InstanceId = Message . InstanceId ;
CurrentData . Frame = 0 ;
# endif
}
2016-10-28 15:04:38 -04:00
bool FProfilerClientManager : : CheckHashAndWrite ( const FProfilerServiceFileChunk & FileChunk , const FProfilerFileChunkHeader & FileChunkHeader , FArchive * Writer )
2014-03-14 14:13:41 -04:00
{
# if STATS
const int32 HashSize = 20 ;
uint8 LocalHash [ HashSize ] = { 0 } ;
2015-07-15 09:52:41 -04:00
// De-hex string into TArray<uint8>
TArray < uint8 > FileChunkData ;
const int32 DataLength = FileChunk . HexData . Len ( ) / 2 ;
2016-10-28 15:04:38 -04:00
FileChunkData . Reset ( DataLength ) ;
FileChunkData . AddUninitialized ( DataLength ) ;
FString : : ToHexBlob ( FileChunk . HexData , FileChunkData . GetData ( ) , DataLength ) ;
2015-07-15 09:52:41 -04:00
2014-03-14 14:13:41 -04:00
// Hash file chunk data.
FSHA1 Sha ;
2016-10-28 15:04:38 -04:00
Sha . Update ( FileChunkData . GetData ( ) , FileChunkHeader . ChunkSize ) ;
2014-03-14 14:13:41 -04:00
// Hash file chunk header.
2016-10-28 15:04:38 -04:00
Sha . Update ( FileChunk . Header . GetData ( ) , FileChunk . Header . Num ( ) ) ;
2014-03-14 14:13:41 -04:00
Sha . Final ( ) ;
2016-10-28 15:04:38 -04:00
Sha . GetHash ( LocalHash ) ;
2014-03-14 14:13:41 -04:00
2016-10-28 15:04:38 -04:00
const int32 MemDiff = FMemory : : Memcmp ( FileChunk . ChunkHash . GetData ( ) , LocalHash , HashSize ) ;
2014-03-14 14:13:41 -04:00
bool bResult = false ;
2016-10-28 15:04:38 -04:00
if ( MemDiff = = 0 )
2014-03-14 14:13:41 -04:00
{
// Write the data to the archive.
2016-10-28 15:04:38 -04:00
Writer - > Seek ( FileChunkHeader . ChunkOffset ) ;
Writer - > Serialize ( ( void * ) FileChunkData . GetData ( ) , FileChunkHeader . ChunkSize ) ;
2014-03-14 14:13:41 -04:00
bResult = true ;
}
return bResult ;
# else
return false ;
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : HandleServiceFileChunk ( const FProfilerServiceFileChunk & FileChunk , const TSharedRef < IMessageContext , ESPMode : : ThreadSafe > & Context )
2014-03-14 14:13:41 -04:00
{
# if STATS
const TCHAR * StrTmp = TEXT ( " .tmp " ) ;
// Read file chunk header.
2016-10-28 15:04:38 -04:00
FMemoryReader Reader ( FileChunk . Header ) ;
2014-03-14 14:13:41 -04:00
FProfilerFileChunkHeader FileChunkHeader ;
Reader < < FileChunkHeader ;
FileChunkHeader . Validate ( ) ;
2016-10-28 15:04:38 -04:00
const bool bValidFileChunk = ! FailedTransfer . Contains ( FileChunk . Filename ) ;
2014-03-14 14:13:41 -04:00
if ( ActiveSessionId . IsValid ( ) & & Connections . Find ( FileChunk . InstanceId ) ! = nullptr & & bValidFileChunk )
{
2016-10-28 15:04:38 -04:00
FReceivedFileInfo * ReceivedFileInfo = ActiveTransfers . Find ( FileChunk . Filename ) ;
if ( ! ReceivedFileInfo )
2014-03-14 14:13:41 -04:00
{
const FString PathName = FPaths : : ProfilingDir ( ) + TEXT ( " UnrealStats/Received/ " ) ;
const FString StatFilepath = PathName + FileChunk . Filename + StrTmp ;
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Log , TEXT ( " Opening stats file for service-client sending: %s " ) , * StatFilepath ) ;
2014-03-14 14:13:41 -04:00
FArchive * FileWriter = IFileManager : : Get ( ) . CreateFileWriter ( * StatFilepath ) ;
2016-10-28 15:04:38 -04:00
if ( ! FileWriter )
2014-03-14 14:13:41 -04:00
{
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Error , TEXT ( " Could not open: %s " ) , * StatFilepath ) ;
2014-03-14 14:13:41 -04:00
return ;
}
2016-10-28 15:04:38 -04:00
ReceivedFileInfo = & ActiveTransfers . Add ( FileChunk . Filename , FReceivedFileInfo ( FileWriter , 0 , StatFilepath ) ) ;
ProfilerFileTransferDelegate . Broadcast ( FileChunk . Filename , ReceivedFileInfo - > Progress , FileChunkHeader . FileSize ) ;
2014-03-14 14:13:41 -04:00
}
const bool bSimulateBadFileChunk = true ; //FMath::Rand() % 10 != 0;
2016-10-28 15:04:38 -04:00
const bool bSuccess = CheckHashAndWrite ( FileChunk , FileChunkHeader , ReceivedFileInfo - > FileWriter ) & & bSimulateBadFileChunk ;
if ( bSuccess )
2014-03-14 14:13:41 -04:00
{
ReceivedFileInfo - > Progress + = FileChunkHeader . ChunkSize ;
ReceivedFileInfo - > Update ( ) ;
2016-10-28 15:04:38 -04:00
if ( ReceivedFileInfo - > Progress = = FileChunkHeader . FileSize )
2014-03-14 14:13:41 -04:00
{
// File has been successfully sent, so send this information to the profiler service.
2016-10-28 15:04:38 -04:00
if ( MessageEndpoint . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2016-10-28 15:04:38 -04:00
MessageEndpoint - > Send ( new FProfilerServiceFileChunk ( FGuid ( ) , FileChunk . Filename , FProfilerFileChunkHeader ( 0 , 0 , 0 , EProfilerFileChunkType : : FinalizeFile ) . AsArray ( ) ) , Context - > GetSender ( ) ) ;
ProfilerFileTransferDelegate . Broadcast ( FileChunk . Filename , ReceivedFileInfo - > Progress , FileChunkHeader . FileSize ) ;
2014-03-14 14:13:41 -04:00
}
// Delete the file writer.
delete ReceivedFileInfo - > FileWriter ;
ReceivedFileInfo - > FileWriter = nullptr ;
// Rename the stats file.
2016-10-28 15:04:38 -04:00
IFileManager : : Get ( ) . Move ( * ReceivedFileInfo - > DestFilepath . Replace ( StrTmp , TEXT ( " " ) ) , * ReceivedFileInfo - > DestFilepath ) ;
2014-03-14 14:13:41 -04:00
2016-10-28 15:04:38 -04:00
ActiveTransfers . Remove ( FileChunk . Filename ) ;
2014-03-14 14:13:41 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Log , TEXT ( " File service-client received successfully: %s " ) , * FileChunk . Filename ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2016-10-28 15:04:38 -04:00
ProfilerFileTransferDelegate . Broadcast ( FileChunk . Filename , ReceivedFileInfo - > Progress , FileChunkHeader . FileSize ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
// This chunk is a bad chunk, so ask for resending it.
2016-10-28 15:04:38 -04:00
if ( MessageEndpoint . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2016-10-28 15:04:38 -04:00
MessageEndpoint - > Send ( new FProfilerServiceFileChunk ( FileChunk , FProfilerServiceFileChunk : : FNullTag ( ) ) , Context - > GetSender ( ) ) ;
UE_LOG ( LogProfilerClient , Log , TEXT ( " Received a bad chunk of file, resending: %5i, %6u, %10u, %s " ) , FileChunk . HexData . Len ( ) , ReceivedFileInfo - > Progress , FileChunkHeader . FileSize , * FileChunk . Filename ) ;
2014-03-14 14:13:41 -04:00
}
}
}
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : HandleServicePingMessage ( const FProfilerServicePing & Message , const TSharedRef < IMessageContext , ESPMode : : ThreadSafe > & Context )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( MessageEndpoint . IsValid ( ) )
{
TArray < FMessageAddress > Instances ;
for ( auto It = Connections . CreateConstIterator ( ) ; It ; + + It )
{
2015-05-14 08:13:44 -04:00
Instances . Add ( It . Value ( ) . ProfilerServiceAddress ) ;
2014-03-14 14:13:41 -04:00
}
MessageEndpoint - > Send ( new FProfilerServicePong ( ) , Instances ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " Ping GetSender: %s " ) , * Context - > GetSender ( ) . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
# endif
}
2016-10-28 15:04:38 -04:00
bool FProfilerClientManager : : HandleTicker ( float DeltaTime )
2014-03-14 14:13:41 -04:00
{
# if STATS
if ( PendingInstances . Num ( ) > 0 & & FDateTime : : Now ( ) > LastPingTime + DeltaTime )
{
TArray < FGuid > Instances ;
Instances . Append ( PendingInstances ) ;
PendingInstances . Reset ( ) ;
for ( int32 i = 0 ; i < Instances . Num ( ) ; + + i )
{
Track ( Instances [ i ] ) ;
}
LastPingTime = FDateTime : : Now ( ) ;
}
# endif
return false ;
}
2016-10-28 15:04:38 -04:00
bool FProfilerClientManager : : HandleMessagesTicker ( float DeltaTime )
2014-03-14 14:13:41 -04:00
{
2018-05-23 21:04:31 -04:00
QUICK_SCOPE_CYCLE_COUNTER ( STAT_FProfilerClientManager_HandleMessagesTicker ) ;
2014-03-14 14:13:41 -04:00
# if STATS
for ( auto It = Connections . CreateIterator ( ) ; It ; + + It )
{
FServiceConnection & Connection = It . Value ( ) ;
2015-02-26 04:39:06 -05:00
TArray < int64 > Frames ;
2016-10-28 15:04:38 -04:00
Connection . ReceivedData . GenerateKeyArray ( Frames ) ;
2015-02-26 04:39:06 -05:00
Frames . Sort ( ) ;
2015-05-14 08:13:44 -04:00
// MessageBus sends all data in out of order fashion.
// We buffer frame to make sure that all frames are received in the proper order.
const int32 NUM_BUFFERED_FRAMES = 15 ;
2016-10-28 15:04:38 -04:00
for ( int32 Index = 0 ; Index < Frames . Num ( ) ; Index + + )
2014-03-14 14:13:41 -04:00
{
2015-12-16 11:52:36 -05:00
if ( Connection . ReceivedData . Num ( ) < NUM_BUFFERED_FRAMES )
2015-05-14 08:13:44 -04:00
{
break ;
}
2016-10-28 15:04:38 -04:00
//FScopeLogTime SLT("HandleMessagesTicker");
2015-12-03 14:21:29 -05:00
2015-12-16 11:52:36 -05:00
const int64 FrameNum = Frames [ Index ] ;
2016-10-28 15:04:38 -04:00
const TArray < uint8 > * const Data = Connection . ReceivedData . FindChecked ( FrameNum ) ;
2014-03-14 14:13:41 -04:00
FStatsReadStream & Stream = Connection . Stream ;
2015-05-14 08:13:44 -04:00
2015-12-16 11:52:36 -05:00
// Read all messages from the uncompressed buffer.
2016-10-28 15:04:38 -04:00
FMemoryReader MemoryReader ( * Data , true ) ;
2015-12-16 11:52:36 -05:00
while ( MemoryReader . Tell ( ) < MemoryReader . TotalSize ( ) )
2014-03-14 14:13:41 -04:00
{
2015-12-16 11:52:36 -05:00
// Read the message.
2016-10-28 15:04:38 -04:00
FStatMessage Message ( Stream . ReadMessage ( MemoryReader ) ) ;
new ( Connection . PendingStatMessagesMessages ) FStatMessage ( Message ) ;
2014-03-14 14:13:41 -04:00
}
2015-12-16 11:52:36 -05:00
// Adds a new from from the pending messages, the pending messages will be removed after the call.
2016-10-28 15:04:38 -04:00
Connection . CurrentThreadState . ProcessMetaDataAndLeaveDataOnly ( Connection . PendingStatMessagesMessages ) ;
Connection . CurrentThreadState . AddFrameFromCondensedMessages ( Connection . PendingStatMessagesMessages ) ;
2015-12-16 11:52:36 -05:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , VeryVerbose , TEXT ( " Frame=%i/%i, FNamesIndexMap=%i, CurrentMetadataSize=%i " ) , FrameNum , Frames . Num ( ) , Connection . Stream . FNamesIndexMap . Num ( ) , Connection . CurrentThreadState . ShortNameToLongName . Num ( ) ) ;
2015-12-16 11:52:36 -05:00
2014-03-14 14:13:41 -04:00
// create an old format data frame from the data
2014-04-02 18:09:23 -04:00
Connection . GenerateProfilerDataFrame ( ) ;
2014-03-14 14:13:41 -04:00
// Fire a meta data update message
if ( Connection . CurrentData . MetaDataUpdated )
{
2016-10-28 15:04:38 -04:00
ProfilerMetaDataUpdatedDelegate . Broadcast ( Connection . InstanceId , Connection . StatMetaData ) ;
2014-03-14 14:13:41 -04:00
}
// send the data out
2016-10-28 15:04:38 -04:00
ProfilerDataDelegate . Broadcast ( Connection . InstanceId , Connection . CurrentData ) ;
2014-03-14 14:13:41 -04:00
2015-12-16 11:52:36 -05:00
delete Data ;
2016-10-28 15:04:38 -04:00
Connection . ReceivedData . Remove ( FrameNum ) ;
2014-03-14 14:13:41 -04:00
}
}
// Remove any active transfer that timed out.
2016-10-28 15:04:38 -04:00
for ( auto It = ActiveTransfers . CreateIterator ( ) ; It ; + + It )
2014-03-14 14:13:41 -04:00
{
FReceivedFileInfo & ReceivedFileInfo = It . Value ( ) ;
const FString & Filename = It . Key ( ) ;
2016-10-28 15:04:38 -04:00
if ( ReceivedFileInfo . IsTimedOut ( ) )
2014-03-14 14:13:41 -04:00
{
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Log , TEXT ( " File service-client timed out, aborted: %s " ) , * Filename ) ;
FailedTransfer . Add ( Filename ) ;
2014-03-14 14:13:41 -04:00
delete ReceivedFileInfo . FileWriter ;
ReceivedFileInfo . FileWriter = nullptr ;
2016-10-28 15:04:38 -04:00
IFileManager : : Get ( ) . Delete ( * ReceivedFileInfo . DestFilepath ) ;
ProfilerFileTransferDelegate . Broadcast ( Filename , - 1 , - 1 ) ;
2014-03-14 14:13:41 -04:00
It . RemoveCurrent ( ) ;
}
}
# endif
return true ;
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : HandleServicePreviewAckMessage ( const FProfilerServicePreviewAck & Message , const TSharedRef < IMessageContext , ESPMode : : ThreadSafe > & Context )
2014-03-14 14:13:41 -04:00
{
# if STATS
2015-12-03 14:21:29 -05:00
if ( ActiveSessionId . IsValid ( ) & & Connections . Find ( Message . InstanceId ) ! = nullptr )
2014-03-14 14:13:41 -04:00
{
FServiceConnection & Connection = * Connections . Find ( Message . InstanceId ) ;
2015-05-14 08:13:44 -04:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Verbose , TEXT ( " PreviewAck InstanceId: %s, GetSender: %s " ) , * Message . InstanceId . ToString ( ) , * Context - > GetSender ( ) . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : HandleProfilerServiceData2Message ( const FProfilerServiceData2 & Message , const TSharedRef < IMessageContext , ESPMode : : ThreadSafe > & Context )
2014-03-14 14:13:41 -04:00
{
# if STATS
SCOPE_CYCLE_COUNTER ( STAT_PC_HandleDataReceived ) ;
if ( ActiveSessionId . IsValid ( ) & & Connections . Find ( Message . InstanceId ) ! = nullptr )
{
2015-05-15 10:26:05 -04:00
// Create a temporary profiler data and prepare all data.
2016-10-28 15:04:38 -04:00
FProfilerServiceData2 * ToProcess = new FProfilerServiceData2 ( Message . InstanceId , Message . Frame , Message . HexData , Message . CompressedSize , Message . UncompressedSize ) ;
2014-03-14 14:13:41 -04:00
2015-05-15 10:26:05 -04:00
// Decompression and decoding is done on the task graph.
FSimpleDelegateGraphTask : : CreateAndDispatchWhenReady
(
2016-10-28 15:04:38 -04:00
FSimpleDelegateGraphTask : : FDelegate : : CreateRaw ( this , & FProfilerClientManager : : DecompressDataAndSendToGame , ToProcess ) ,
2015-05-15 10:26:05 -04:00
TStatId ( )
) ;
2014-03-14 14:13:41 -04:00
}
# endif
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : DecompressDataAndSendToGame ( FProfilerServiceData2 * ToProcess )
2015-05-15 10:26:05 -04:00
{
2016-10-28 15:04:38 -04:00
DECLARE_SCOPE_CYCLE_COUNTER ( TEXT ( " FProfilerClientManager::DecompressDataAndSendToGame " ) , STAT_FProfilerClientManager_DecompressDataAndSendToGame , STATGROUP_Profiler ) ;
2015-05-15 10:26:05 -04:00
// De-hex string into TArray<uint8>
TArray < uint8 > CompressedData ;
2016-10-28 15:04:38 -04:00
CompressedData . Reset ( ToProcess - > CompressedSize ) ;
CompressedData . AddUninitialized ( ToProcess - > CompressedSize ) ;
FString : : ToHexBlob ( ToProcess - > HexData , CompressedData . GetData ( ) , ToProcess - > CompressedSize ) ;
2015-05-15 10:26:05 -04:00
// Decompress data.
TArray < uint8 > UncompressedData ;
2016-10-28 15:04:38 -04:00
UncompressedData . Reset ( ToProcess - > UncompressedSize ) ;
UncompressedData . AddUninitialized ( ToProcess - > UncompressedSize ) ;
2015-05-15 10:26:05 -04:00
2019-01-23 19:56:41 -05:00
bool bResult = FCompression : : UncompressMemory ( NAME_Zlib , UncompressedData . GetData ( ) , ToProcess - > UncompressedSize , CompressedData . GetData ( ) , ToProcess - > CompressedSize ) ;
2016-10-28 15:04:38 -04:00
check ( bResult ) ;
2015-05-15 10:26:05 -04:00
// Send to the game thread. Connections is not thread-safe, so we cannot add the data here.
2016-10-28 15:04:38 -04:00
TArray < uint8 > * DateToGame = new TArray < uint8 > ( MoveTemp ( UncompressedData ) ) ;
2015-05-15 10:26:05 -04:00
FSimpleDelegateGraphTask : : CreateAndDispatchWhenReady
(
2016-10-28 15:04:38 -04:00
FSimpleDelegateGraphTask : : FDelegate : : CreateRaw ( this , & FProfilerClientManager : : SendDataToGame , DateToGame , ToProcess - > Frame , ToProcess - > InstanceId ) ,
2015-05-15 10:26:05 -04:00
TStatId ( ) , nullptr , ENamedThreads : : GameThread
) ;
delete ToProcess ;
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : SendDataToGame ( TArray < uint8 > * DataToGame , int64 Frame , const FGuid InstanceId )
2015-05-15 10:26:05 -04:00
{
2016-10-28 15:04:38 -04:00
if ( ActiveSessionId . IsValid ( ) & & Connections . Find ( InstanceId ) ! = nullptr )
2015-05-15 10:26:05 -04:00
{
2016-10-28 15:04:38 -04:00
FServiceConnection & Connection = * Connections . Find ( InstanceId ) ;
2015-05-15 10:26:05 -04:00
// Add the message to the connections queue.
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , VeryVerbose , TEXT ( " Frame: %i, UncompressedSize: %i, InstanceId: %s " ) , Frame , DataToGame - > Num ( ) , * InstanceId . ToString ( ) ) ;
Connection . ReceivedData . Add ( Frame , DataToGame ) ;
2015-05-15 10:26:05 -04:00
}
}
2016-10-28 15:04:38 -04:00
void FProfilerClientManager : : SendProfilerDataFrameToGame ( FProfilerDataFrame * NewData , FStatMetaData * MetaDataPtr , const FGuid InstanceId )
2014-04-02 18:09:23 -04:00
{
2016-06-01 12:08:56 -04:00
if ( Connections . Find ( InstanceId ) ! = nullptr )
2014-04-02 18:09:23 -04:00
{
2016-06-01 12:08:56 -04:00
if ( MetaDataPtr )
{
2016-10-28 15:04:38 -04:00
ProfilerMetaDataUpdatedDelegate . Broadcast ( InstanceId , * MetaDataPtr ) ;
2016-06-01 12:08:56 -04:00
delete MetaDataPtr ;
MetaDataPtr = nullptr ;
}
2015-12-03 14:21:29 -05:00
2016-06-01 12:08:56 -04:00
if ( NewData )
{
2016-10-28 15:04:38 -04:00
ProfilerDataDelegate . Broadcast ( InstanceId , * NewData ) ;
2016-06-01 12:08:56 -04:00
delete NewData ;
NewData = nullptr ;
}
2015-12-03 14:21:29 -05:00
}
}
2016-10-28 15:04:38 -04:00
2015-12-03 14:21:29 -05:00
void FProfilerClientManager : : Shutdown ( )
{
// Delete all active file writers and remove temporary files.
for ( auto It = ActiveTransfers . CreateIterator ( ) ; It ; + + It )
{
FReceivedFileInfo & ReceivedFileInfo = It . Value ( ) ;
delete ReceivedFileInfo . FileWriter ;
ReceivedFileInfo . FileWriter = nullptr ;
2016-10-28 15:04:38 -04:00
IFileManager : : Get ( ) . Delete ( * ReceivedFileInfo . DestFilepath ) ;
2015-12-03 14:21:29 -05:00
2016-10-28 15:04:38 -04:00
UE_LOG ( LogProfilerClient , Log , TEXT ( " File service-client transfer aborted: %s " ) , * It . Key ( ) ) ;
2015-12-03 14:21:29 -05:00
}
2016-10-28 15:04:38 -04:00
FTicker : : GetCoreTicker ( ) . RemoveTicker ( MessageDelegateHandle ) ;
FTicker : : GetCoreTicker ( ) . RemoveTicker ( TickDelegateHandle ) ;
2014-04-02 18:09:23 -04:00
}
2016-10-28 15:04:38 -04:00
2016-06-01 12:08:56 -04:00
void FProfilerClientManager : : FinalizeLoading ( const FGuid InstanceId )
2014-04-02 18:09:23 -04:00
{
2016-06-01 12:08:56 -04:00
if ( Connections . Find ( InstanceId ) ! = nullptr )
{
ProfilerLoadCompletedDelegate . Broadcast ( InstanceId ) ;
LoadConnection = & Connections . FindChecked ( InstanceId ) ;
delete LoadConnection - > StatsReader ;
LoadConnection - > StatsReader = nullptr ;
LoadConnection = nullptr ;
Connections . Remove ( InstanceId ) ;
2015-12-03 14:21:29 -05:00
2016-06-01 12:08:56 -04:00
RetryTime = 5.f ;
}
}
2016-10-28 15:04:38 -04:00
2016-06-01 12:08:56 -04:00
void FProfilerClientManager : : CancelLoading ( const FGuid InstanceId )
{
if ( Connections . Find ( InstanceId ) ! = nullptr )
{
ProfilerLoadCancelledDelegate . Broadcast ( InstanceId ) ;
LoadConnection = & Connections . FindChecked ( InstanceId ) ;
delete LoadConnection - > StatsReader ;
LoadConnection - > StatsReader = nullptr ;
LoadConnection = nullptr ;
Connections . Remove ( InstanceId ) ;
}
2014-04-02 18:09:23 -04:00
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
# if STATS
2016-10-28 15:04:38 -04:00
int32 FServiceConnection : : FindOrAddStat ( const FStatNameAndInfo & StatNameAndInfo , uint32 StatType )
2014-03-14 14:13:41 -04:00
{
SCOPE_CYCLE_COUNTER ( STAT_PC_FindOrAddStat ) ;
const FName LongName = StatNameAndInfo . GetRawName ( ) ;
2016-10-28 15:04:38 -04:00
int32 * const StatIDPtr = LongNameToStatID . Find ( LongName ) ;
2014-03-14 14:13:41 -04:00
int32 StatID = StatIDPtr ! = nullptr ? * StatIDPtr : - 1 ;
if ( ! StatIDPtr )
{
// meta data has been updated
CurrentData . MetaDataUpdated = true ;
const FName StatName = StatNameAndInfo . GetShortName ( ) ;
FName GroupName = StatNameAndInfo . GetGroupName ( ) ;
2014-04-29 04:04:27 -04:00
const FString Description = StatNameAndInfo . GetDescription ( ) ;
2014-03-14 14:13:41 -04:00
// do some special stats first
if ( StatName = = TEXT ( " STAT_FrameTime " ) )
{
StatID = LongNameToStatID . Add ( LongName , 2 ) ;
}
else if ( StatName = = FStatConstants : : NAME_ThreadRoot )
{
StatID = LongNameToStatID . Add ( LongName , 1 ) ;
2016-10-28 15:04:38 -04:00
GroupName = TEXT ( " NoGroup " ) ;
2014-03-14 14:13:41 -04:00
}
else
{
StatID = LongNameToStatID . Add ( LongName , LongNameToStatID . Num ( ) + 10 ) ;
}
check ( StatID ! = - 1 ) ;
// add a new stat description to the meta data
FStatDescription StatDescription ;
StatDescription . ID = StatID ;
2014-04-29 04:04:27 -04:00
StatDescription . Name = ! Description . IsEmpty ( ) ? Description : StatName . ToString ( ) ;
2016-10-28 15:04:38 -04:00
if ( StatDescription . Name . Contains ( TEXT ( " STAT_ " ) ) )
2014-03-14 14:13:41 -04:00
{
StatDescription . Name = StatDescription . Name . RightChop ( FString ( TEXT ( " STAT_ " ) ) . Len ( ) ) ;
}
StatDescription . StatType = StatType ;
2016-10-28 15:04:38 -04:00
if ( GroupName = = NAME_None & & Stream . Header . Version = = EStatMagicNoHeader : : NO_VERSION )
2014-03-14 14:13:41 -04:00
{
// @todo Add more ways to group the stats.
2016-10-28 15:04:38 -04:00
const int32 Thread_Pos = StatDescription . Name . Find ( TEXT ( " Thread_ " ) ) ;
const int32 _0Pos = StatDescription . Name . Find ( TEXT ( " _0 " ) ) ;
2014-03-14 14:13:41 -04:00
const bool bIsThread = Thread_Pos ! = INDEX_NONE & & _0Pos > Thread_Pos ;
// Add a special group for all threads.
2016-10-28 15:04:38 -04:00
if ( bIsThread )
2014-03-14 14:13:41 -04:00
{
GroupName = TEXT ( " Threads " ) ;
}
// Add a special group for all objects.
else
{
GroupName = TEXT ( " Objects " ) ;
}
}
2016-10-28 15:04:38 -04:00
int32 * const GroupIDPtr = GroupNameArray . Find ( GroupName ) ;
2014-03-14 14:13:41 -04:00
int32 GroupID = GroupIDPtr ! = nullptr ? * GroupIDPtr : - 1 ;
2016-10-28 15:04:38 -04:00
if ( ! GroupIDPtr )
2014-03-14 14:13:41 -04:00
{
// add a new group description to the meta data
GroupID = GroupNameArray . Add ( GroupName , GroupNameArray . Num ( ) + 10 ) ;
2016-10-28 15:04:38 -04:00
check ( GroupID ! = - 1 ) ;
2014-03-14 14:13:41 -04:00
FStatGroupDescription GroupDescription ;
GroupDescription . ID = GroupID ;
GroupDescription . Name = GroupName . ToString ( ) ;
2014-04-29 04:04:27 -04:00
GroupDescription . Name . RemoveFromStart ( TEXT ( " STATGROUP_ " ) ) ;
2014-03-14 14:13:41 -04:00
// add to the meta data
2015-12-03 14:21:29 -05:00
StatMetaData . GroupDescriptions . Add ( GroupDescription . ID , GroupDescription ) ;
2014-03-14 14:13:41 -04:00
}
2015-12-03 14:21:29 -05:00
StatDescription . GroupID = GroupID ;
StatMetaData . StatDescriptions . Add ( StatDescription . ID , StatDescription ) ;
2014-03-14 14:13:41 -04:00
}
// return the stat id
return StatID ;
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
int32 FServiceConnection : : FindOrAddThread ( const FStatNameAndInfo & Thread )
{
SCOPE_CYCLE_COUNTER ( STAT_PC_FindOrAddThread ) ;
2014-04-29 04:04:27 -04:00
// The description of a thread group contains the thread id
const FString Desc = Thread . GetDescription ( ) ;
2016-10-28 15:04:38 -04:00
const uint32 ThreadID = FStatsUtils : : ParseThreadID ( Desc ) ;
2014-04-23 18:59:44 -04:00
2014-05-05 11:15:08 -04:00
const FName ShortName = Thread . GetShortName ( ) ;
2014-04-29 04:04:27 -04:00
2014-05-05 11:15:08 -04:00
// add to the meta data
2015-12-03 14:21:29 -05:00
const int32 OldNum = StatMetaData . ThreadDescriptions . Num ( ) ;
2016-10-28 15:04:38 -04:00
StatMetaData . ThreadDescriptions . Add ( ThreadID , ShortName . ToString ( ) ) ;
2015-12-03 14:21:29 -05:00
const int32 NewNum = StatMetaData . ThreadDescriptions . Num ( ) ;
2014-04-23 18:59:44 -04:00
2014-05-05 11:15:08 -04:00
// meta data has been updated
CurrentData . MetaDataUpdated = CurrentData . MetaDataUpdated | | OldNum ! = NewNum ;
2014-03-14 14:13:41 -04:00
return ThreadID ;
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
void FServiceConnection : : GenerateAccumulators ( TArray < FStatMessage > & Stats , TArray < FProfilerCountAccumulator > & CountAccumulators , TArray < FProfilerFloatAccumulator > & FloatAccumulators )
{
SCOPE_CYCLE_COUNTER ( STAT_PC_GenerateAccumulator )
for ( int32 Index = 0 ; Index < Stats . Num ( ) ; + + Index )
{
2015-11-18 16:20:49 -05:00
const FStatMessage & StatMessage = Stats [ Index ] ;
2014-03-14 14:13:41 -04:00
2015-11-18 16:20:49 -05:00
uint32 StatType = STATTYPE_Error ;
if ( StatMessage . NameAndInfo . GetField < EStatDataType > ( ) = = EStatDataType : : ST_int64 )
{
2016-10-28 15:04:38 -04:00
if ( StatMessage . NameAndInfo . GetFlag ( EStatMetaFlags : : IsCycle ) )
2014-03-14 14:13:41 -04:00
{
2015-11-18 16:20:49 -05:00
StatType = STATTYPE_CycleCounter ;
}
2016-10-28 15:04:38 -04:00
else if ( StatMessage . NameAndInfo . GetFlag ( EStatMetaFlags : : IsMemory ) )
2015-11-18 16:20:49 -05:00
{
StatType = STATTYPE_MemoryCounter ;
}
else
{
StatType = STATTYPE_AccumulatorDWORD ;
}
}
else if ( StatMessage . NameAndInfo . GetField < EStatDataType > ( ) = = EStatDataType : : ST_double )
{
StatType = STATTYPE_AccumulatorFLOAT ;
}
if ( StatType ! = STATTYPE_Error )
{
2016-10-28 15:04:38 -04:00
const int32 StatId = FindOrAddStat ( StatMessage . NameAndInfo , StatType ) ;
2015-11-18 16:20:49 -05:00
if ( StatMessage . NameAndInfo . GetField < EStatDataType > ( ) = = EStatDataType : : ST_int64 )
{
// add a count accumulator
FProfilerCountAccumulator Data ;
Data . StatId = StatId ;
Data . Value = StatMessage . GetValue_int64 ( ) ;
2016-10-28 15:04:38 -04:00
CountAccumulators . Add ( Data ) ;
2015-11-18 16:20:49 -05:00
}
else if ( StatMessage . NameAndInfo . GetField < EStatDataType > ( ) = = EStatDataType : : ST_double )
{
// add a float accumulator
FProfilerFloatAccumulator Data ;
Data . StatId = StatId ;
Data . Value = StatMessage . GetValue_double ( ) ;
2016-10-28 15:04:38 -04:00
FloatAccumulators . Add ( Data ) ;
2015-11-18 16:20:49 -05:00
2015-12-03 14:21:29 -05:00
const FName StatName = StatMessage . NameAndInfo . GetRawName ( ) ;
if ( StatName = = FStatConstants : : RAW_SecondsPerCycle )
2015-11-18 16:20:49 -05:00
{
2015-12-03 14:21:29 -05:00
StatMetaData . SecondsPerCycle = StatMessage . GetValue_double ( ) ;
2015-11-18 16:20:49 -05:00
}
2014-03-14 14:13:41 -04:00
}
}
}
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
void FServiceConnection : : CreateGraphRecursively ( const FRawStatStackNode * Root , FProfilerCycleGraph & Graph , uint32 InStartCycles )
{
Graph . FrameStart = InStartCycles ;
Graph . StatId = FindOrAddStat ( Root - > Meta . NameAndInfo , STATTYPE_CycleCounter ) ;
// add the data
if ( Root - > Meta . NameAndInfo . GetField < EStatDataType > ( ) = = EStatDataType : : ST_int64 )
{
if ( Root - > Meta . NameAndInfo . GetFlag ( EStatMetaFlags : : IsPackedCCAndDuration ) )
{
Graph . CallsPerFrame = FromPackedCallCountDuration_CallCount ( Root - > Meta . GetValue_int64 ( ) ) ;
Graph . Value = FromPackedCallCountDuration_Duration ( Root - > Meta . GetValue_int64 ( ) ) ;
}
else
{
Graph . CallsPerFrame = 1 ;
Graph . Value = Root - > Meta . GetValue_int64 ( ) ;
}
}
uint32 ChildStartCycles = InStartCycles ;
TArray < FRawStatStackNode * > ChildArray ;
Root - > Children . GenerateValueArray ( ChildArray ) ;
2016-10-28 15:04:38 -04:00
ChildArray . Sort ( FStatDurationComparer < FRawStatStackNode > ( ) ) ;
for ( int32 Index = 0 ; Index < ChildArray . Num ( ) ; + + Index )
2014-03-14 14:13:41 -04:00
{
const FRawStatStackNode * ChildStat = ChildArray [ Index ] ;
// create the child graph
FProfilerCycleGraph ChildGraph ;
ChildGraph . ThreadId = Graph . ThreadId ;
CreateGraphRecursively ( ChildStat , ChildGraph , ChildStartCycles ) ;
// add to the graph
Graph . Children . Add ( ChildGraph ) ;
// update the start cycles
ChildStartCycles + = ChildGraph . Value ;
}
}
2016-10-28 15:04:38 -04:00
2014-03-14 14:13:41 -04:00
void FServiceConnection : : GenerateCycleGraphs ( const FRawStatStackNode & Root , TMap < uint32 , FProfilerCycleGraph > & CycleGraphs )
{
SCOPE_CYCLE_COUNTER ( STAT_PC_GenerateCycleGraph ) ;
// Initialize the root stat.
FindOrAddStat ( Root . Meta . NameAndInfo , STATTYPE_CycleCounter ) ;
// get the cycle graph from each child of the stack root
TArray < FRawStatStackNode * > ChildArray ;
Root . Children . GenerateValueArray ( ChildArray ) ;
for ( int32 Index = 0 ; Index < ChildArray . Num ( ) ; + + Index )
{
FRawStatStackNode * ThreadNode = ChildArray [ Index ] ;
FProfilerCycleGraph Graph ;
// determine the thread id
Graph . ThreadId = FindOrAddThread ( ThreadNode - > Meta . NameAndInfo ) ;
// create the thread graph
CreateGraphRecursively ( ThreadNode , Graph , 0 ) ;
// add to the map
CycleGraphs . Add ( Graph . ThreadId , Graph ) ;
}
}
2014-04-02 18:09:23 -04:00
2016-10-28 15:04:38 -04:00
2014-04-02 18:09:23 -04:00
void FServiceConnection : : GenerateProfilerDataFrame ( )
{
2016-10-28 15:04:38 -04:00
SCOPE_CYCLE_COUNTER ( STAT_PC_GenerateDataFrame ) ;
2014-04-02 18:09:23 -04:00
FProfilerDataFrame & DataFrame = CurrentData ;
DataFrame . Frame = CurrentThreadState . CurrentGameFrame ;
DataFrame . FrameStart = 0.0 ;
DataFrame . CountAccumulators . Reset ( ) ;
DataFrame . CycleGraphs . Reset ( ) ;
DataFrame . FloatAccumulators . Reset ( ) ;
2014-04-23 19:20:24 -04:00
DataFrame . MetaDataUpdated = false ;
2014-04-02 18:09:23 -04:00
// get the stat stack root and the non frame stats
FRawStatStackNode Stack ;
TArray < FStatMessage > NonFrameStats ;
2016-10-28 15:04:38 -04:00
CurrentThreadState . UncondenseStackStats ( CurrentThreadState . CurrentGameFrame , Stack , nullptr , & NonFrameStats ) ;
2014-04-02 18:09:23 -04:00
// cycle graphs
2016-10-28 15:04:38 -04:00
GenerateCycleGraphs ( Stack , DataFrame . CycleGraphs ) ;
2014-04-02 18:09:23 -04:00
// accumulators
2016-10-28 15:04:38 -04:00
GenerateAccumulators ( NonFrameStats , DataFrame . CountAccumulators , DataFrame . FloatAccumulators ) ;
2014-04-02 18:09:23 -04:00
}
2016-10-28 15:04:38 -04:00
2014-06-05 17:11:45 -04:00
# endif