2019-12-26 15:32:37 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-06-03 15:32:00 -04:00
2023-06-02 18:21:36 -04:00
# include "Analysis/Engine.h"
2023-01-25 04:26:15 -05:00
2020-06-23 18:40:00 -04:00
# include "Algo/BinarySearch.h"
# include "Algo/Sort.h"
2022-09-13 06:42:08 -04:00
# include "Algo/StableSort.h"
2019-06-03 15:32:00 -04:00
# include "Containers/ArrayView.h"
2023-01-25 04:26:15 -05:00
# include "CoreGlobals.h"
2019-06-03 15:32:00 -04:00
# include "HAL/UnrealMemory.h"
2023-01-19 05:33:25 -05:00
# include "Internationalization/Internationalization.h"
2021-09-03 08:32:31 -04:00
# include "Logging/LogMacros.h"
2023-10-31 04:07:11 -04:00
# include "Misc/StringBuilder.h"
2023-01-25 04:26:15 -05:00
# include "StreamReader.h"
2020-06-23 18:40:00 -04:00
# include "Templates/UnrealTemplate.h"
2023-10-31 04:07:11 -04:00
# include "TraceAnalysisDebug.h"
2023-06-19 07:17:37 -04:00
# include "Trace/Analysis.h"
2019-06-03 15:32:00 -04:00
# include "Trace/Analyzer.h"
2019-11-25 12:03:09 -05:00
# include "Trace/Detail/Protocol.h"
2021-04-06 09:35:47 -04:00
# include "Trace/Detail/Transport.h"
2019-11-25 12:03:09 -05:00
# include "Transport/PacketTransport.h"
# include "Transport/TidPacketTransport.h"
2023-01-19 05:33:25 -05:00
# include "Transport/Transport.h"
2019-06-03 15:32:00 -04:00
2023-01-25 04:26:15 -05:00
DEFINE_LOG_CATEGORY_STATIC ( LogTraceAnalysis , Log , All )
2023-01-19 05:33:25 -05:00
# define LOCTEXT_NAMESPACE "TraceAnalysis"
2023-01-25 04:26:15 -05:00
namespace UE {
namespace Trace {
2021-06-11 06:27:46 -04:00
// {{{1 misc -------------------------------------------------------------------
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
void SerializeToCborImpl ( TArray < uint8 > & , const IAnalyzer : : FEventData & , uint32 ) ;
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
class FFnv1aHash
{
public :
2019-11-25 12:03:09 -05:00
FFnv1aHash ( ) = default ;
FFnv1aHash ( uint32 PrevResult ) { Result = PrevResult ; }
void Add ( const ANSICHAR * String ) { for ( ; * String ; + + String ) { Add ( * String ) ; } }
void Add ( const uint8 * Data , uint32 Size ) { for ( uint32 i = 0 ; i < Size ; + + Data , + + i ) { Add ( * Data ) ; } }
void Add ( uint8 Value ) { Result ^ = Value ; Result * = 0x01000193 ; }
uint32 Get ( ) const { return Result ; }
2019-06-03 15:32:00 -04:00
private :
2019-11-25 12:03:09 -05:00
uint32 Result = 0x811c9dc5 ;
2019-06-03 15:32:00 -04:00
// uint32: bias=0x811c9dc5 prime=0x01000193
// uint64: bias=0xcbf29ce484222325 prime=0x00000100000001b3;
} ;
2021-06-11 06:27:46 -04:00
// {{{1 aux-data ---------------------------------------------------------------
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
struct FAuxData
{
const uint8 * Data ;
uint32 DataSize ;
uint16 FieldIndex ;
2022-05-20 03:37:02 -04:00
int8 FieldSizeAndType ;
2022-09-13 06:42:08 -04:00
uint8 bSigned : 1 ;
uint8 bFragmented : 1 ;
uint8 bOwnsData : 1 ;
uint8 _Unused : 5 ;
2019-12-13 11:07:03 -05:00
} ;
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
struct FAuxDataCollector
2022-09-13 06:42:08 -04:00
: public TArray < FAuxData , TInlineAllocator < 8 > >
2019-12-13 11:07:03 -05:00
{
2022-09-13 06:42:08 -04:00
using Super = TArray < FAuxData , TInlineAllocator < 8 > > ;
~ FAuxDataCollector ( ) { Reset ( ) ; }
void Add ( const FAuxData & Data ) ;
void Defragment ( FAuxData & Head ) ;
void Reset ( ) ;
2019-12-13 11:07:03 -05:00
} ;
2022-09-13 06:42:08 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAuxDataCollector : : Add ( const FAuxData & Data )
{
if ( Num ( ) = = 0 )
{
Super : : Add ( Data ) ;
return ;
}
FAuxData * Prev = & Last ( ) ;
if ( Prev - > FieldIndex ! = Data . FieldIndex )
{
Super : : Add ( Data ) ;
return ;
}
while ( Prev > GetData ( ) )
{
if ( Prev [ - 1 ] . FieldIndex ! = Data . FieldIndex )
{
break ;
}
- - Prev ;
}
Prev - > bFragmented = 1 ;
Super : : Add ( Data ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAuxDataCollector : : Defragment ( FAuxData & Data )
{
check ( Data . bFragmented ) ;
uint32 Size = Data . DataSize ;
for ( FAuxData * Read = & Data + 1 ; ; )
{
Size + = Read - > DataSize ;
+ + Read ;
if ( Read > & Last ( ) | | Read - > FieldIndex ! = Data . FieldIndex )
{
break ;
}
}
uint8 * Buffer = ( uint8 * ) ( FMemory : : Malloc ( Size ) ) ;
uint8 * Write = Buffer ;
uint8 * End = Buffer + Size ;
for ( FAuxData * Read = & Data ; ; + + Read )
{
FMemory : : Memcpy ( Write , Read - > Data , Read - > DataSize ) ;
Write + = Read - > DataSize ;
if ( Write > = End )
{
break ;
}
}
Data . Data = Buffer ;
Data . DataSize = Size ;
Data . bOwnsData = 1 ;
2023-10-31 04:07:11 -04:00
Data . bFragmented = 0 ;
2022-09-13 06:42:08 -04:00
}
////////////////////////////////////////////////////////////////////////////////
void FAuxDataCollector : : Reset ( )
{
for ( const FAuxData & AuxData : * this )
{
if ( ! AuxData . bOwnsData )
{
continue ;
}
FMemory : : Free ( ( void * ) ( AuxData . Data ) ) ;
}
Super : : Reset ( ) ;
}
2019-12-13 11:07:03 -05:00
2021-06-11 06:27:46 -04:00
// {{{1 threads ----------------------------------------------------------------
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
class FThreads
{
public :
struct FInfo
{
TArray < uint64 > ScopeRoutes ;
TArray < uint8 > Name ;
TArray < uint8 > GroupName ;
int64 PrevTimestamp = 0 ;
uint32 ThreadId = ~ 0u ;
uint32 SystemId = 0 ;
int32 SortHint = 0xff ;
} ;
FThreads ( ) ;
~ FThreads ( ) ;
FInfo * GetInfo ( ) ;
FInfo * GetInfo ( uint32 ThreadId ) ;
void SetGroupName ( const ANSICHAR * InGroupName , uint32 Length ) ;
const TArray < uint8 > * GetGroupName ( ) const ;
private :
uint32 LastGetInfoId = ~ 0u ;
TArray < FInfo * > Infos ;
TArray < uint8 > GroupName ;
} ;
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
FThreads : : FThreads ( )
{
Infos . Reserve ( 64 ) ;
}
2021-05-04 09:01:07 -04:00
////////////////////////////////////////////////////////////////////////////////
FThreads : : ~ FThreads ( )
{
for ( FInfo * Info : Infos )
{
delete Info ;
}
}
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
FThreads : : FInfo * FThreads : : GetInfo ( )
{
2021-01-05 05:37:24 -04:00
return GetInfo ( LastGetInfoId ) ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2020-12-30 05:35:41 -04:00
FThreads : : FInfo * FThreads : : GetInfo ( uint32 ThreadId )
2020-06-23 18:40:00 -04:00
{
LastGetInfoId = ThreadId ;
2021-01-05 05:37:24 -04:00
if ( ThreadId > = uint32 ( Infos . Num ( ) ) )
{
2021-05-04 09:01:07 -04:00
Infos . SetNumZeroed ( ThreadId + 1 ) ;
2021-01-05 05:37:24 -04:00
}
2021-05-04 09:01:07 -04:00
FInfo * Info = Infos [ ThreadId ] ;
if ( Info = = nullptr )
2020-06-23 18:40:00 -04:00
{
2021-05-04 09:01:07 -04:00
Info = new FInfo ( ) ;
Info - > ThreadId = ThreadId ;
Infos [ ThreadId ] = Info ;
2020-06-23 18:40:00 -04:00
}
2021-05-04 09:01:07 -04:00
return Info ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
void FThreads : : SetGroupName ( const ANSICHAR * InGroupName , uint32 Length )
{
if ( InGroupName = = nullptr | | * InGroupName = = ' \0 ' )
{
GroupName . SetNum ( 0 ) ;
return ;
}
GroupName . SetNumUninitialized ( Length + 1 ) ;
GroupName [ Length ] = ' \0 ' ;
FMemory : : Memcpy ( GroupName . GetData ( ) , InGroupName , Length ) ;
}
////////////////////////////////////////////////////////////////////////////////
const TArray < uint8 > * FThreads : : GetGroupName ( ) const
{
return ( GroupName . Num ( ) > 0 ) ? & GroupName : nullptr ;
}
2021-06-11 06:27:46 -04:00
// {{{1 thread-info ------------------------------------------------------------
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
uint32 IAnalyzer : : FThreadInfo : : GetId ( ) const
{
const auto * Info = ( const FThreads : : FInfo * ) this ;
return Info - > ThreadId ;
}
////////////////////////////////////////////////////////////////////////////////
uint32 IAnalyzer : : FThreadInfo : : GetSystemId ( ) const
{
const auto * Info = ( const FThreads : : FInfo * ) this ;
return Info - > SystemId ;
}
////////////////////////////////////////////////////////////////////////////////
int32 IAnalyzer : : FThreadInfo : : GetSortHint ( ) const
{
const auto * Info = ( const FThreads : : FInfo * ) this ;
return Info - > SortHint ;
}
////////////////////////////////////////////////////////////////////////////////
const ANSICHAR * IAnalyzer : : FThreadInfo : : GetName ( ) const
{
const auto * Info = ( const FThreads : : FInfo * ) this ;
if ( Info - > Name . Num ( ) < = 0 )
{
2020-09-24 00:43:27 -04:00
return nullptr ;
2020-06-23 18:40:00 -04:00
}
return ( const ANSICHAR * ) ( Info - > Name . GetData ( ) ) ;
}
////////////////////////////////////////////////////////////////////////////////
const ANSICHAR * IAnalyzer : : FThreadInfo : : GetGroupName ( ) const
{
const auto * Info = ( const FThreads : : FInfo * ) this ;
if ( Info - > GroupName . Num ( ) < = 0 )
{
return " " ;
}
return ( const ANSICHAR * ) ( Info - > GroupName . GetData ( ) ) ;
}
2021-07-28 02:24:21 -04:00
// {{{1 timing -----------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
struct FTiming
{
2021-09-09 05:01:09 -04:00
uint64 BaseTimestamp = 0 ;
uint64 TimestampHz = 0 ;
double InvTimestampHz = 0.0 ;
2021-07-28 02:24:21 -04:00
uint64 EventTimestamp = 0 ;
} ;
2021-06-11 06:27:46 -04:00
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
uint64 IAnalyzer : : FEventTime : : GetTimestamp ( ) const
{
const auto * Timing = ( const FTiming * ) this ;
return Timing - > EventTimestamp ;
}
////////////////////////////////////////////////////////////////////////////////
double IAnalyzer : : FEventTime : : AsSeconds ( ) const
{
const auto * Timing = ( const FTiming * ) this ;
return double ( Timing - > EventTimestamp ) * Timing - > InvTimestampHz ;
}
////////////////////////////////////////////////////////////////////////////////
uint64 IAnalyzer : : FEventTime : : AsCycle64 ( ) const
{
const auto * Timing = ( const FTiming * ) this ;
return Timing - > BaseTimestamp + Timing - > EventTimestamp ;
}
////////////////////////////////////////////////////////////////////////////////
double IAnalyzer : : FEventTime : : AsSeconds ( uint64 Cycles64 ) const
{
const auto * Timing = ( const FTiming * ) this ;
return double ( int64 ( Cycles64 ) - int64 ( Timing - > BaseTimestamp ) ) * Timing - > InvTimestampHz ;
}
////////////////////////////////////////////////////////////////////////////////
double IAnalyzer : : FEventTime : : AsSecondsAbsolute ( int64 DurationCycles64 ) const
{
const auto * Timing = ( const FTiming * ) this ;
return double ( DurationCycles64 ) * Timing - > InvTimestampHz ;
}
2021-06-11 06:27:46 -04:00
// {{{1 dispatch ---------------------------------------------------------------
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
struct FDispatch
2019-06-03 15:32:00 -04:00
{
2019-12-13 11:07:03 -05:00
enum
{
Flag_Important = 1 < < 0 ,
Flag_MaybeHasAux = 1 < < 1 ,
2020-02-05 14:26:36 -05:00
Flag_NoSync = 1 < < 2 ,
2022-05-05 05:30:07 -04:00
Flag_Definition = 1 < < 3 ,
2019-12-13 11:07:03 -05:00
} ;
2019-10-03 16:26:48 -04:00
struct FField
{
uint32 Hash ;
uint16 Offset ;
uint16 Size ;
uint16 NameOffset ; // From FField ptr
2020-06-23 18:40:00 -04:00
int8 SizeAndType ; // value == byte_size, sign == float < 0 < int
uint8 Class : 7 ;
uint8 bArray : 1 ;
2023-10-31 04:07:11 -04:00
uint32 RefUid ; // If reference field, uid of ref type
2019-10-03 16:26:48 -04:00
} ;
2019-06-03 15:32:00 -04:00
2020-06-23 18:40:00 -04:00
int32 GetFieldIndex ( const ANSICHAR * Name ) const ;
2019-11-25 12:03:09 -05:00
uint32 Hash = 0 ;
uint16 Uid = 0 ;
2019-12-13 11:07:03 -05:00
uint8 FieldCount = 0 ;
uint8 Flags = 0 ;
2019-11-25 12:03:09 -05:00
uint16 EventSize = 0 ;
uint16 LoggerNameOffset = 0 ; // From FDispatch ptr
uint16 EventNameOffset = 0 ; // From FDispatch ptr
2019-10-03 16:26:48 -04:00
FField Fields [ ] ;
} ;
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
int32 FDispatch : : GetFieldIndex ( const ANSICHAR * Name ) const
2019-12-13 11:07:03 -05:00
{
FFnv1aHash NameHash ;
NameHash . Add ( Name ) ;
2020-06-23 18:40:00 -04:00
for ( int32 i = 0 , n = FieldCount ; i < n ; + + i )
2019-12-13 11:07:03 -05:00
{
if ( Fields [ i ] . Hash = = NameHash . Get ( ) )
{
return i ;
}
}
2020-06-23 18:40:00 -04:00
return - 1 ;
2019-12-13 11:07:03 -05:00
}
2019-10-03 16:26:48 -04:00
2021-06-11 06:27:46 -04:00
// {{{1 dispatch-builder -------------------------------------------------------
2019-11-25 12:03:09 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
class FDispatchBuilder
2019-11-25 12:03:09 -05:00
{
public :
2019-12-13 11:07:03 -05:00
FDispatchBuilder ( ) ;
void SetUid ( uint16 Uid ) ;
void SetLoggerName ( const ANSICHAR * Name , int32 NameSize = - 1 ) ;
void SetEventName ( const ANSICHAR * Name , int32 NameSize = - 1 ) ;
void SetImportant ( ) ;
void SetMaybeHasAux ( ) ;
2020-02-05 14:26:36 -05:00
void SetNoSync ( ) ;
2022-05-05 05:30:07 -04:00
void SetDefinition ( ) ;
2019-12-13 11:07:03 -05:00
FDispatch : : FField & AddField ( const ANSICHAR * Name , int32 NameSize , uint16 Size ) ;
FDispatch * Finalize ( ) ;
2019-11-25 12:03:09 -05:00
private :
2019-12-13 11:07:03 -05:00
uint32 AppendName ( const ANSICHAR * Name , int32 NameSize ) ;
TArray < uint8 > Buffer ;
TArray < uint8 > NameBuffer ;
2019-11-25 12:03:09 -05:00
} ;
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
FDispatchBuilder : : FDispatchBuilder ( )
2019-11-25 12:03:09 -05:00
{
Buffer . SetNum ( sizeof ( FDispatch ) ) ;
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
new ( Dispatch ) FDispatch ( ) ;
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
FDispatch * FDispatchBuilder : : Finalize ( )
2019-11-25 12:03:09 -05:00
{
int32 Size = Buffer . Num ( ) + NameBuffer . Num ( ) ;
auto * Dispatch = ( FDispatch * ) FMemory : : Malloc ( Size ) ;
memcpy ( Dispatch , Buffer . GetData ( ) , Buffer . Num ( ) ) ;
memcpy ( Dispatch - > Fields + Dispatch - > FieldCount , NameBuffer . GetData ( ) , NameBuffer . Num ( ) ) ;
// Fix up name offsets
for ( int i = 0 , n = Dispatch - > FieldCount ; i < n ; + + i )
{
auto * Field = Dispatch - > Fields + i ;
2022-09-30 11:28:14 -04:00
Field - > NameOffset + = ( uint16 ) ( Buffer . Num ( ) - uint32 ( UPTRINT ( Field ) - UPTRINT ( Dispatch ) ) ) ;
2019-11-25 12:03:09 -05:00
}
// Calculate this dispatch's hash.
if ( Dispatch - > LoggerNameOffset | | Dispatch - > EventNameOffset )
{
2022-09-30 11:28:14 -04:00
Dispatch - > LoggerNameOffset + = ( uint16 ) Buffer . Num ( ) ;
Dispatch - > EventNameOffset + = ( uint16 ) Buffer . Num ( ) ;
2019-11-25 12:03:09 -05:00
FFnv1aHash Hash ;
Hash . Add ( ( const ANSICHAR * ) Dispatch + Dispatch - > LoggerNameOffset ) ;
Hash . Add ( ( const ANSICHAR * ) Dispatch + Dispatch - > EventNameOffset ) ;
Dispatch - > Hash = Hash . Get ( ) ;
}
return Dispatch ;
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
void FDispatchBuilder : : SetUid ( uint16 Uid )
2019-11-25 12:03:09 -05:00
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
Dispatch - > Uid = Uid ;
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
void FDispatchBuilder : : SetLoggerName ( const ANSICHAR * Name , int32 NameSize )
2019-11-25 12:03:09 -05:00
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
2022-09-30 11:28:14 -04:00
Dispatch - > LoggerNameOffset + = ( uint16 ) AppendName ( Name , NameSize ) ;
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
void FDispatchBuilder : : SetEventName ( const ANSICHAR * Name , int32 NameSize )
2019-11-25 12:03:09 -05:00
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
2022-09-30 11:28:14 -04:00
Dispatch - > EventNameOffset = ( uint16 ) AppendName ( Name , NameSize ) ;
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
void FDispatchBuilder : : SetImportant ( )
2019-12-13 11:07:03 -05:00
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
Dispatch - > Flags | = FDispatch : : Flag_Important ;
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
void FDispatchBuilder : : SetMaybeHasAux ( )
2019-12-13 11:07:03 -05:00
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
Dispatch - > Flags | = FDispatch : : Flag_MaybeHasAux ;
}
2020-02-05 14:26:36 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
void FDispatchBuilder : : SetNoSync ( )
2020-02-05 14:26:36 -05:00
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
Dispatch - > Flags | = FDispatch : : Flag_NoSync ;
}
2022-05-05 05:30:07 -04:00
////////////////////////////////////////////////////////////////////////////////
void FDispatchBuilder : : SetDefinition ( )
{
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
Dispatch - > Flags | = FDispatch : : Flag_Definition ;
}
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
FDispatch : : FField & FDispatchBuilder : : AddField ( const ANSICHAR * Name , int32 NameSize , uint16 Size )
2019-11-25 12:03:09 -05:00
{
int32 Bufoff = Buffer . AddUninitialized ( sizeof ( FDispatch : : FField ) ) ;
auto * Field = ( FDispatch : : FField * ) ( Buffer . GetData ( ) + Bufoff ) ;
2022-09-30 11:28:14 -04:00
Field - > NameOffset = ( uint16 ) AppendName ( Name , NameSize ) ;
2019-11-25 12:03:09 -05:00
Field - > Size = Size ;
2022-05-05 05:30:07 -04:00
Field - > RefUid = 0 ;
2019-11-25 12:03:09 -05:00
FFnv1aHash Hash ;
Hash . Add ( ( const uint8 * ) Name , NameSize ) ;
Field - > Hash = Hash . Get ( ) ;
2023-01-25 04:26:15 -05:00
2019-11-25 12:03:09 -05:00
auto * Dispatch = ( FDispatch * ) ( Buffer . GetData ( ) ) ;
Dispatch - > FieldCount + + ;
Dispatch - > EventSize + = Field - > Size ;
2019-12-13 11:07:03 -05:00
return * Field ;
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
uint32 FDispatchBuilder : : AppendName ( const ANSICHAR * Name , int32 NameSize )
2019-11-25 12:03:09 -05:00
{
if ( NameSize < 0 )
{
NameSize = int32 ( FCStringAnsi : : Strlen ( Name ) ) ;
}
int32 Ret = NameBuffer . AddUninitialized ( NameSize + 1 ) ;
uint8 * Out = NameBuffer . GetData ( ) + Ret ;
memcpy ( Out , Name , NameSize ) ;
Out [ NameSize ] = ' \0 ' ;
return Ret ;
}
2021-06-11 06:27:46 -04:00
// {{{1 event-type-info --------------------------------------------------------
2019-10-03 16:26:48 -04:00
////////////////////////////////////////////////////////////////////////////////
uint32 IAnalyzer : : FEventTypeInfo : : GetId ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2019-11-25 12:03:09 -05:00
return Inner - > Uid ;
2019-10-03 16:26:48 -04:00
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
uint8 IAnalyzer : : FEventTypeInfo : : GetFlags ( ) const
{
const auto * Inner = ( const FDispatch * ) this ;
return Inner - > Flags ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2019-10-03 16:26:48 -04:00
////////////////////////////////////////////////////////////////////////////////
const ANSICHAR * IAnalyzer : : FEventTypeInfo : : GetName ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2019-11-25 12:03:09 -05:00
return ( const ANSICHAR * ) Inner + Inner - > EventNameOffset ;
2019-10-03 16:26:48 -04:00
}
////////////////////////////////////////////////////////////////////////////////
const ANSICHAR * IAnalyzer : : FEventTypeInfo : : GetLoggerName ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2019-11-25 12:03:09 -05:00
return ( const ANSICHAR * ) Inner + Inner - > LoggerNameOffset ;
2019-10-03 16:26:48 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2021-04-26 03:33:22 -04:00
uint32 IAnalyzer : : FEventTypeInfo : : GetSize ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2021-04-26 03:33:22 -04:00
return Inner - > EventSize ;
}
////////////////////////////////////////////////////////////////////////////////
2019-10-03 16:26:48 -04:00
uint32 IAnalyzer : : FEventTypeInfo : : GetFieldCount ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2019-11-25 12:03:09 -05:00
return Inner - > FieldCount ;
2019-10-03 16:26:48 -04:00
}
////////////////////////////////////////////////////////////////////////////////
const IAnalyzer : : FEventFieldInfo * IAnalyzer : : FEventTypeInfo : : GetFieldInfo ( uint32 Index ) const
{
if ( Index > = GetFieldCount ( ) )
2019-10-15 03:35:31 -04:00
{
2019-10-03 16:26:48 -04:00
return nullptr ;
2019-10-15 03:35:31 -04:00
}
2019-10-03 16:26:48 -04:00
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2019-11-25 12:03:09 -05:00
return ( const IAnalyzer : : FEventFieldInfo * ) ( Inner - > Fields + Index ) ;
2019-10-15 03:35:31 -04:00
}
2019-10-03 16:26:48 -04:00
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
int32 IAnalyzer : : FEventTypeInfo : : GetFieldIndex ( const ANSICHAR * FieldName ) const
{
const auto * Inner = ( const FDispatch * ) this ;
return Inner - > GetFieldIndex ( FieldName ) ;
}
2022-05-27 09:29:46 -04:00
////////////////////////////////////////////////////////////////////////////////
IAnalyzer : : FEventFieldHandle IAnalyzer : : FEventTypeInfo : : GetFieldHandleUnchecked ( uint32 Index ) const
{
const auto * Inner = ( const FDispatch * ) this ;
if ( Index > = Inner - > FieldCount )
{
return FEventFieldHandle { - 1 } ;
}
2023-10-31 04:07:11 -04:00
return FEventFieldHandle { Inner - > Fields [ Index ] . Offset } ;
2022-05-27 09:29:46 -04:00
}
2021-01-10 16:26:31 -04:00
////////////////////////////////////////////////////////////////////////////////
IAnalyzer : : FEventFieldHandle IAnalyzer : : FEventTypeInfo : : GetFieldHandleImpl (
const ANSICHAR * FieldName ,
int16 & SizeAndType ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch * ) this ;
2021-01-10 16:26:31 -04:00
int32 Index = Inner - > GetFieldIndex ( FieldName ) ;
if ( Index < 0 )
{
return { - 1 } ;
}
2021-06-15 02:55:20 -04:00
const FDispatch : : FField & Field = Inner - > Fields [ Index ] ;
2021-01-10 16:26:31 -04:00
SizeAndType = Field . SizeAndType ;
return { Field . Offset } ;
}
2019-10-03 16:26:48 -04:00
2021-06-11 06:27:46 -04:00
// {{{1 field-info -------------------------------------------------------------
2019-10-03 16:26:48 -04:00
////////////////////////////////////////////////////////////////////////////////
const ANSICHAR * IAnalyzer : : FEventFieldInfo : : GetName ( ) const
2019-10-15 03:35:31 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch : : FField * ) this ;
2019-10-03 16:26:48 -04:00
return ( const ANSICHAR * ) ( UPTRINT ( Inner ) + Inner - > NameOffset ) ;
2019-10-15 03:35:31 -04:00
}
2019-10-03 16:26:48 -04:00
////////////////////////////////////////////////////////////////////////////////
IAnalyzer : : FEventFieldInfo : : EType IAnalyzer : : FEventFieldInfo : : GetType ( ) const
2019-10-15 03:35:31 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch : : FField * ) this ;
2020-06-23 18:40:00 -04:00
2022-05-05 05:30:07 -04:00
if ( Inner - > RefUid ! = 0 )
{
switch ( Inner - > Size )
{
case sizeof ( uint8 ) : return EType : : Reference8 ;
case sizeof ( uint16 ) : return EType : : Reference16 ;
case sizeof ( uint32 ) : return EType : : Reference32 ;
case sizeof ( uint64 ) : return EType : : Reference64 ;
default : check ( false ) ; // Unsupported width
}
}
2023-01-25 04:26:15 -05:00
2020-11-17 06:54:28 -04:00
if ( Inner - > Class = = UE : : Trace : : Protocol0 : : Field_String )
2020-06-23 18:40:00 -04:00
{
return ( Inner - > SizeAndType = = 1 ) ? EType : : AnsiString : EType : : WideString ;
}
2019-10-03 16:26:48 -04:00
if ( Inner - > SizeAndType > 0 )
2019-10-15 03:35:31 -04:00
{
2019-10-03 16:26:48 -04:00
return EType : : Integer ;
}
if ( Inner - > SizeAndType < 0 )
{
return EType : : Float ;
}
return EType : : None ;
2019-10-15 03:35:31 -04:00
}
2019-10-03 16:26:48 -04:00
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
bool IAnalyzer : : FEventFieldInfo : : IsArray ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Inner = ( const FDispatch : : FField * ) this ;
2020-06-23 18:40:00 -04:00
return Inner - > bArray ;
2019-12-13 11:07:03 -05:00
}
2022-05-20 03:37:02 -04:00
////////////////////////////////////////////////////////////////////////////////
bool IAnalyzer : : FEventFieldInfo : : IsSigned ( ) const
{
const auto * Inner = ( const FDispatch : : FField * ) this ;
return ( Inner - > Class & UE : : Trace : : Protocol0 : : Field_Signed ) ! = 0 ;
}
2019-12-13 11:07:03 -05:00
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
uint32 IAnalyzer : : FEventFieldInfo : : GetOffset ( ) const
{
const auto * Inner = ( const FDispatch : : FField * ) this ;
return Inner - > Offset ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2022-05-27 09:29:46 -04:00
////////////////////////////////////////////////////////////////////////////////
uint8 IAnalyzer : : FEventFieldInfo : : GetSize ( ) const
{
const auto * Inner = ( const FDispatch : : FField * ) this ;
2022-09-30 11:28:14 -04:00
return uint8 ( Inner - > Size ) ;
2022-05-27 09:29:46 -04:00
}
2019-12-13 11:07:03 -05:00
2023-10-31 04:07:11 -04:00
2021-06-11 06:27:46 -04:00
// {{{1 array-reader -----------------------------------------------------------
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
uint32 IAnalyzer : : FArrayReader : : Num ( ) const
{
const auto * Inner = ( const FAuxData * ) this ;
int32 SizeAndType = Inner - > FieldSizeAndType ;
SizeAndType = ( SizeAndType < 0 ) ? - SizeAndType : SizeAndType ;
2020-01-17 07:31:56 -05:00
return ( SizeAndType = = 0 ) ? SizeAndType : ( Inner - > DataSize / SizeAndType ) ;
2019-12-13 11:07:03 -05:00
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
const uint8 * IAnalyzer : : FArrayReader : : GetRawData ( ) const
{
const auto * Inner = ( const FAuxData * ) this ;
return Inner - > Data ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
uint32 IAnalyzer : : FArrayReader : : GetRawDataSize ( ) const
{
const auto * Inner = ( const FAuxData * ) this ;
return Inner - > DataSize ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
int8 IAnalyzer : : FArrayReader : : GetSizeAndType ( ) const
{
const auto * Inner = ( const FAuxData * ) this ;
return Inner - > FieldSizeAndType ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
2022-05-20 03:37:02 -04:00
const void * IAnalyzer : : FArrayReader : : GetImpl ( uint32 Index , int8 & SizeAndType ) const
2019-12-13 11:07:03 -05:00
{
const auto * Inner = ( const FAuxData * ) this ;
SizeAndType = Inner - > FieldSizeAndType ;
uint32 Count = Num ( ) ;
if ( Index > = Count )
{
return nullptr ;
}
SizeAndType = ( SizeAndType < 0 ) ? - SizeAndType : SizeAndType ;
return Inner - > Data + ( Index * SizeAndType ) ;
}
2019-10-03 16:26:48 -04:00
2021-06-11 06:27:46 -04:00
// {{{1 event-data -------------------------------------------------------------
2019-10-03 16:26:48 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
struct FEventDataInfo
2019-10-03 16:26:48 -04:00
{
2020-06-23 18:40:00 -04:00
const FAuxData * GetAuxData ( uint32 FieldIndex ) const ;
2021-01-10 16:18:43 -04:00
const uint8 * Ptr ;
2019-10-03 16:26:48 -04:00
const FDispatch & Dispatch ;
2019-12-13 11:07:03 -05:00
FAuxDataCollector * AuxCollector ;
2019-10-15 03:35:31 -04:00
uint16 Size ;
2019-06-03 15:32:00 -04:00
} ;
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-06-15 02:55:20 -04:00
const FAuxData * FEventDataInfo : : GetAuxData ( uint32 FieldIndex ) const
2020-06-23 18:40:00 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2020-06-23 18:40:00 -04:00
if ( Info - > AuxCollector = = nullptr )
{
return nullptr ;
}
for ( FAuxData & Data : * ( Info - > AuxCollector ) )
{
if ( Data . FieldIndex = = FieldIndex )
{
2022-09-13 06:42:08 -04:00
if ( Data . bFragmented )
{
Info - > AuxCollector - > Defragment ( Data ) ;
}
2022-05-20 03:37:02 -04:00
const FDispatch : : FField & Field = Info - > Dispatch . Fields [ FieldIndex ] ;
Data . FieldSizeAndType = Field . SizeAndType ;
Data . bSigned = ( Field . Class & UE : : Trace : : Protocol0 : : Field_Signed ) ! = 0 ;
2020-06-23 18:40:00 -04:00
return & Data ;
}
}
return nullptr ;
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2019-10-03 16:26:48 -04:00
const IAnalyzer : : FEventTypeInfo & IAnalyzer : : FEventData : : GetTypeInfo ( ) const
2019-06-03 15:32:00 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2019-11-25 12:03:09 -05:00
return ( const FEventTypeInfo & ) ( Info - > Dispatch ) ;
2019-06-03 15:32:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2019-12-13 11:07:03 -05:00
const IAnalyzer : : FArrayReader * IAnalyzer : : FEventData : : GetArrayImpl ( const ANSICHAR * FieldName ) const
2019-06-03 15:32:00 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2019-12-13 11:07:03 -05:00
2020-06-23 18:40:00 -04:00
int32 Index = Info - > Dispatch . GetFieldIndex ( FieldName ) ;
if ( Index > = 0 )
2019-12-13 11:07:03 -05:00
{
2020-06-23 18:40:00 -04:00
if ( const FAuxData * Data = Info - > GetAuxData ( Index ) )
2019-06-03 15:32:00 -04:00
{
2020-06-23 18:40:00 -04:00
return ( IAnalyzer : : FArrayReader * ) Data ;
2019-06-03 15:32:00 -04:00
}
}
2020-06-23 18:40:00 -04:00
static const FAuxData EmptyAuxData = { } ;
return ( const IAnalyzer : : FArrayReader * ) & EmptyAuxData ;
2019-12-13 11:07:03 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2022-05-20 03:37:02 -04:00
const void * IAnalyzer : : FEventData : : GetValueImpl ( const ANSICHAR * FieldName , int8 & SizeAndType ) const
2019-12-13 11:07:03 -05:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2019-12-13 11:07:03 -05:00
const auto & Dispatch = Info - > Dispatch ;
2020-06-23 18:40:00 -04:00
int32 Index = Dispatch . GetFieldIndex ( FieldName ) ;
if ( Index < 0 )
2019-12-13 11:07:03 -05:00
{
return nullptr ;
}
const auto & Field = Dispatch . Fields [ Index ] ;
SizeAndType = Field . SizeAndType ;
return ( Info - > Ptr + Field . Offset ) ;
2019-06-03 15:32:00 -04:00
}
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
bool IAnalyzer : : FEventData : : GetString ( const ANSICHAR * FieldName , FAnsiStringView & Out ) const
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2020-06-23 18:40:00 -04:00
const auto & Dispatch = Info - > Dispatch ;
int32 Index = Dispatch . GetFieldIndex ( FieldName ) ;
if ( Index < 0 )
{
return false ;
}
const auto & Field = Dispatch . Fields [ Index ] ;
2020-11-17 06:54:28 -04:00
if ( Field . Class ! = UE : : Trace : : Protocol0 : : Field_String | | Field . SizeAndType ! = sizeof ( ANSICHAR ) )
2020-06-23 18:40:00 -04:00
{
return false ;
}
if ( const FAuxData * Data = Info - > GetAuxData ( Index ) )
{
Out = FAnsiStringView ( ( const ANSICHAR * ) ( Data - > Data ) , Data - > DataSize ) ;
return true ;
}
2021-04-29 08:12:58 -04:00
Out = FAnsiStringView ( ) ;
return true ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2022-02-04 09:16:04 -05:00
bool IAnalyzer : : FEventData : : GetString ( const ANSICHAR * FieldName , FWideStringView & Out ) const
2020-06-23 18:40:00 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2020-06-23 18:40:00 -04:00
const auto & Dispatch = Info - > Dispatch ;
int32 Index = Dispatch . GetFieldIndex ( FieldName ) ;
if ( Index < 0 )
{
return false ;
}
const auto & Field = Dispatch . Fields [ Index ] ;
2022-02-04 09:16:04 -05:00
if ( Field . Class ! = UE : : Trace : : Protocol0 : : Field_String | | Field . SizeAndType ! = sizeof ( WIDECHAR ) )
2020-06-23 18:40:00 -04:00
{
return false ;
}
if ( const FAuxData * Data = Info - > GetAuxData ( Index ) )
{
2022-02-04 09:16:04 -05:00
Out = FWideStringView ( ( const WIDECHAR * ) ( Data - > Data ) , Data - > DataSize / sizeof ( WIDECHAR ) ) ;
2020-06-23 18:40:00 -04:00
return true ;
}
2022-02-04 09:16:04 -05:00
Out = FWideStringView ( ) ;
2021-04-29 08:12:58 -04:00
return true ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
bool IAnalyzer : : FEventData : : GetString ( const ANSICHAR * FieldName , FString & Out ) const
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2020-06-23 18:40:00 -04:00
const auto & Dispatch = Info - > Dispatch ;
int32 Index = Dispatch . GetFieldIndex ( FieldName ) ;
if ( Index < 0 )
{
return false ;
}
const auto & Field = Dispatch . Fields [ Index ] ;
2020-11-17 06:54:28 -04:00
if ( Field . Class = = UE : : Trace : : Protocol0 : : Field_String )
2020-06-23 18:40:00 -04:00
{
2021-04-29 08:12:58 -04:00
const FAuxData * Data = Info - > GetAuxData ( Index ) ;
if ( Data = = nullptr )
{
Out = FString ( ) ;
return true ;
}
2020-06-23 18:40:00 -04:00
if ( Field . SizeAndType = = sizeof ( ANSICHAR ) )
{
Out = FString ( Data - > DataSize , ( const ANSICHAR * ) ( Data - > Data ) ) ;
return true ;
}
2022-02-04 09:16:04 -05:00
if ( Field . SizeAndType = = sizeof ( WIDECHAR ) )
2020-06-23 18:40:00 -04:00
{
2022-02-04 09:16:04 -05:00
Out = FWideStringView ( ( const WIDECHAR * ) ( Data - > Data ) , Data - > DataSize / sizeof ( WIDECHAR ) ) ;
2020-06-23 18:40:00 -04:00
return true ;
}
}
return false ;
}
2021-04-26 03:35:01 -04:00
////////////////////////////////////////////////////////////////////////////////
uint32 IAnalyzer : : FEventData : : GetSize ( ) const
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2021-04-26 03:35:01 -04:00
uint32 Size = Info - > Size ;
2022-05-05 05:30:07 -04:00
if ( Info - > AuxCollector )
2021-04-26 03:35:01 -04:00
{
2022-05-05 05:30:07 -04:00
for ( const FAuxData & Data : * ( Info - > AuxCollector ) )
{
Size + = Data . DataSize ;
}
2021-04-26 03:35:01 -04:00
}
return Size ;
}
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
void IAnalyzer : : FEventData : : SerializeToCbor ( TArray < uint8 > & Out ) const
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2020-06-23 18:40:00 -04:00
uint32 Size = Info - > Size ;
2021-04-29 08:14:42 -04:00
if ( Info - > AuxCollector ! = nullptr )
2020-06-23 18:40:00 -04:00
{
2021-04-29 08:14:42 -04:00
for ( FAuxData & Data : * ( Info - > AuxCollector ) )
{
Size + = Data . DataSize ;
}
2020-06-23 18:40:00 -04:00
}
SerializeToCborImpl ( Out , * this , Size ) ;
}
2022-05-27 09:29:46 -04:00
////////////////////////////////////////////////////////////////////////////////
const void * IAnalyzer : : FEventData : : GetValueRaw ( FEventFieldHandle Handle ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
if ( ! Handle . IsValid ( ) )
{
return nullptr ;
}
return Info - > Ptr + Handle . Detail ;
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2019-10-03 16:26:48 -04:00
const uint8 * IAnalyzer : : FEventData : : GetAttachment ( ) const
2019-06-03 15:32:00 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2019-11-25 12:03:09 -05:00
return Info - > Ptr + Info - > Dispatch . EventSize ;
2019-06-03 15:32:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2019-10-03 16:26:48 -04:00
uint32 IAnalyzer : : FEventData : : GetAttachmentSize ( ) const
2019-06-03 15:32:00 -04:00
{
2021-06-15 02:55:20 -04:00
const auto * Info = ( const FEventDataInfo * ) this ;
2019-11-25 12:03:09 -05:00
return Info - > Size - Info - > Dispatch . EventSize ;
2019-06-03 15:32:00 -04:00
}
2022-05-05 05:30:07 -04:00
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
const uint8 * IAnalyzer : : FEventData : : GetRawPointer ( ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
return Info - > Ptr ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
uint32 IAnalyzer : : FEventData : : GetRawSize ( ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
return Info - > Size ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
uint32 IAnalyzer : : FEventData : : GetAuxSize ( ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
if ( ( Info - > Dispatch . Flags & UE : : Trace : : FDispatch : : Flag_MaybeHasAux ) = = 0 )
{
return 0 ;
}
else
{
uint32 Size = 0 ;
if ( Info - > AuxCollector )
{
for ( FAuxData & Data : * ( Info - > AuxCollector ) )
{
Size + = 4 ; // aux field header
Size + = Data . DataSize ;
}
}
+ + Size ; // aux terminator
return Size ;
}
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
uint32 IAnalyzer : : FEventData : : GetTotalSize ( IAnalyzer : : EStyle Style , const IAnalyzer : : FOnEventContext & Context , uint32 ProtocolVersion ) const
{
uint32 Size = 0 ;
if ( Style = = EStyle : : EnterScope )
{
// Include the size of the previous EnterScope event.
if ( Context . EventTime . GetTimestamp ( ) = = 0 )
{
Size = 1 ; // uid
}
else
{
Size = 8 ; // 1 uid + 7 timestamp
}
}
else if ( Style = = EStyle : : LeaveScope )
{
// Return only the size of the LeaveScope event.
if ( Context . EventTime . GetTimestamp ( ) = = 0 )
{
return 1 ; // uid
}
else
{
return 8 ; // 1 uid + 7 timestamp
}
}
const auto * Info = ( const FEventDataInfo * ) this ;
const uint16 KnownEventUids = ( ProtocolVersion > = 5 ) ? Protocol5 : : EKnownEventUids : : User :
( ProtocolVersion = = 4 ) ? Protocol4 : : EKnownEventUids : : User : 0 ;
static_assert ( Protocol6 : : EKnownEventUids : : User = = Protocol5 : : EKnownEventUids : : User , " Protocol6::EKnownEventUids::User " ) ;
static_assert ( Protocol7 : : EKnownEventUids : : User = = Protocol5 : : EKnownEventUids : : User , " Protocol7::EKnownEventUids::User " ) ;
// Add header size.
if ( Info - > Dispatch . Uid < KnownEventUids )
{
Size + = 1 ; // uid
}
else if ( ( Info - > Dispatch . Flags & UE : : Trace : : FDispatch : : Flag_Important ) ! = 0 )
{
Size + = 4 ; // sizeof(UE::Trace::Protocol5::FImportantEventHeader);
}
else if ( Info - > Dispatch . Flags & UE : : Trace : : FDispatch : : Flag_NoSync )
{
if ( ProtocolVersion < 5 )
{
Size + = 4 ; // sizeof(UE::Trace::Protocol2::FEventHeader);
}
else
{
Size + = 2 ; // uid == sizeof(UE::Trace::Protocol5::FEventHeader);
}
}
else // Sync
{
if ( ProtocolVersion < 5 )
{
Size + = 7 ; // sizeof(UE::Trace::Protocol2::FEventHeaderSync);
}
else
{
Size + = 2 + 3 ; // uid + serial == sizeof(UE::Trace::Protocol5::FEventHeaderSync);
}
}
// Add fixed size and attachment size.
Size + = Info - > Size ;
// Add aux data size (including headers).
Size + = GetAuxSize ( ) ;
return Size ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2022-05-05 05:30:07 -04:00
////////////////////////////////////////////////////////////////////////////////
bool IAnalyzer : : FEventData : : IsDefinitionImpl ( uint32 & OutTypeId ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
OutTypeId = Info - > Dispatch . Uid ;
return ( Info - > Dispatch . Flags & FDispatch : : Flag_Definition ) ! = 0 ;
}
////////////////////////////////////////////////////////////////////////////////
const void * IAnalyzer : : FEventData : : GetReferenceValueImpl ( const char * FieldName , uint16 & OutSizeType , uint32 & OutTypeUid ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
const auto & Dispatch = Info - > Dispatch ;
const int32 Index = Dispatch . GetFieldIndex ( FieldName ) ;
if ( Index < 0 )
{
return nullptr ;
}
const auto & Field = Dispatch . Fields [ Index ] ;
if ( Field . RefUid )
{
OutSizeType = Field . SizeAndType ;
OutTypeUid = Field . RefUid ;
return ( Info - > Ptr + Field . Offset ) ;
}
return nullptr ;
}
2022-06-21 08:20:57 -04:00
////////////////////////////////////////////////////////////////////////////////
const void * IAnalyzer : : FEventData : : GetReferenceValueImpl ( uint32 FieldIndex , uint32 & OutTypeUid ) const
{
const auto * Info = ( const FEventDataInfo * ) this ;
const auto & Dispatch = Info - > Dispatch ;
const auto & Field = Dispatch . Fields [ FieldIndex ] ;
if ( Field . RefUid )
{
OutTypeUid = Field . RefUid ;
return ( Info - > Ptr + Field . Offset ) ;
}
return nullptr ;
}
2021-07-28 02:24:21 -04:00
// }}}
2019-06-03 15:32:00 -04:00
2021-07-28 02:24:21 -04:00
// {{{1 type-registry ----------------------------------------------------------
class FTypeRegistry
2019-06-03 15:32:00 -04:00
{
2021-07-28 02:24:21 -04:00
public :
typedef FDispatch FTypeInfo ;
~ FTypeRegistry ( ) ;
2022-05-05 05:30:07 -04:00
const FTypeInfo * Add ( const void * TraceData , uint32 Version ) ;
const FTypeInfo * AddVersion4 ( const void * TraceData ) ;
const FTypeInfo * AddVersion6 ( const void * TraceData ) ;
2021-07-29 08:29:56 -04:00
void Add ( FTypeInfo * TypeInfo ) ;
2021-07-28 02:24:21 -04:00
const FTypeInfo * Get ( uint32 Uid ) const ;
2021-09-03 04:31:47 -04:00
bool IsUidValid ( uint32 Uid ) const ;
2021-07-28 02:24:21 -04:00
private :
TArray < FTypeInfo * > TypeInfos ;
2019-06-03 15:32:00 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FTypeRegistry : : ~ FTypeRegistry ( )
2019-06-03 15:32:00 -04:00
{
2021-07-28 02:24:21 -04:00
for ( FTypeInfo * TypeInfo : TypeInfos )
{
FMemory : : Free ( TypeInfo ) ;
}
2019-06-03 15:32:00 -04:00
}
2022-05-05 05:30:07 -04:00
////////////////////////////////////////////////////////////////////////////////
const FTypeRegistry : : FTypeInfo * FTypeRegistry : : Add ( const void * TraceData , uint32 Version )
{
switch ( Version )
{
case 0 : return AddVersion4 ( TraceData ) ;
case 4 : return AddVersion4 ( TraceData ) ;
case 6 : return AddVersion6 ( TraceData ) ;
2023-01-25 04:26:15 -05:00
case 7 : return AddVersion6 ( TraceData ) ;
2022-05-05 05:30:07 -04:00
default :
check ( false ) ; // Unknown version
}
return nullptr ;
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
const FTypeRegistry : : FTypeInfo * FTypeRegistry : : Get ( uint32 Uid ) const
2020-01-29 08:18:18 -05:00
{
2021-07-28 02:24:21 -04:00
if ( Uid > = uint32 ( TypeInfos . Num ( ) ) )
{
return nullptr ;
}
return TypeInfos [ Uid ] ;
2020-01-29 08:18:18 -05:00
}
2020-06-23 18:40:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2022-05-05 05:30:07 -04:00
const FTypeRegistry : : FTypeInfo * FTypeRegistry : : AddVersion4 ( const void * TraceData )
2021-07-28 02:24:21 -04:00
{
FDispatchBuilder Builder ;
const auto & NewEvent = * ( Protocol4 : : FNewEventEvent * ) ( TraceData ) ;
const auto * NameCursor = ( const ANSICHAR * ) ( NewEvent . Fields + NewEvent . FieldCount ) ;
Builder . SetLoggerName ( NameCursor , NewEvent . LoggerNameSize ) ;
NameCursor + = NewEvent . LoggerNameSize ;
Builder . SetEventName ( NameCursor , NewEvent . EventNameSize ) ;
NameCursor + = NewEvent . EventNameSize ;
Builder . SetUid ( NewEvent . EventUid ) ;
// Fill out the fields
for ( int32 i = 0 , n = NewEvent . FieldCount ; i < n ; + + i )
{
const auto & Field = NewEvent . Fields [ i ] ;
2023-09-29 07:22:52 -04:00
int8 TypeSize = ( int8 ) ( 1 < < ( Field . TypeInfo & Protocol0 : : Field_Pow2SizeMask ) ) ;
2021-07-28 02:24:21 -04:00
if ( Field . TypeInfo & Protocol0 : : Field_Float )
{
TypeSize = - TypeSize ;
}
auto & OutField = Builder . AddField ( NameCursor , Field . NameSize , Field . Size ) ;
OutField . Offset = Field . Offset ;
OutField . SizeAndType = TypeSize ;
OutField . Class = Field . TypeInfo & Protocol0 : : Field_SpecialMask ;
OutField . bArray = ! ! ( Field . TypeInfo & Protocol0 : : Field_Array ) ;
NameCursor + = Field . NameSize ;
}
if ( NewEvent . Flags & uint32 ( Protocol4 : : EEventFlags : : Important ) )
{
Builder . SetImportant ( ) ;
}
if ( NewEvent . Flags & uint32 ( Protocol4 : : EEventFlags : : MaybeHasAux ) )
{
Builder . SetMaybeHasAux ( ) ;
}
if ( NewEvent . Flags & uint32 ( Protocol4 : : EEventFlags : : NoSync ) )
{
Builder . SetNoSync ( ) ;
}
FTypeInfo * TypeInfo = Builder . Finalize ( ) ;
2021-07-29 08:29:56 -04:00
Add ( TypeInfo ) ;
2021-07-28 02:24:21 -04:00
2021-07-29 08:29:56 -04:00
return TypeInfo ;
}
2022-05-05 05:30:07 -04:00
////////////////////////////////////////////////////////////////////////////////
const FTypeRegistry : : FTypeInfo * FTypeRegistry : : AddVersion6 ( const void * TraceData )
{
using namespace Protocol6 ;
FDispatchBuilder Builder ;
const auto & NewEvent = * ( FNewEventEvent * ) ( TraceData ) ;
const auto * NameCursor = ( const ANSICHAR * ) ( NewEvent . Fields + NewEvent . FieldCount ) ;
Builder . SetLoggerName ( NameCursor , NewEvent . LoggerNameSize ) ;
NameCursor + = NewEvent . LoggerNameSize ;
Builder . SetEventName ( NameCursor , NewEvent . EventNameSize ) ;
NameCursor + = NewEvent . EventNameSize ;
Builder . SetUid ( NewEvent . EventUid ) ;
// Fill out the fields
for ( int32 i = 0 , n = NewEvent . FieldCount ; i < n ; + + i )
{
const auto & Field = NewEvent . Fields [ i ] ;
if ( Field . FieldType = = EFieldFamily : : Regular )
{
2023-09-29 07:22:52 -04:00
int8 TypeSize = ( int8 ) ( 1 < < ( Field . Regular . TypeInfo & Protocol0 : : Field_Pow2SizeMask ) ) ;
2022-05-05 05:30:07 -04:00
if ( Field . Regular . TypeInfo & Protocol0 : : Field_Float )
{
TypeSize = - TypeSize ;
}
auto & OutField = Builder . AddField ( NameCursor , Field . Regular . NameSize , Field . Regular . Size ) ;
OutField . Offset = Field . Regular . Offset ;
OutField . SizeAndType = TypeSize ;
OutField . Class = Field . Regular . TypeInfo & Protocol0 : : Field_SpecialMask ;
OutField . bArray = ! ! ( Field . Regular . TypeInfo & Protocol0 : : Field_Array ) ;
NameCursor + = Field . Regular . NameSize ;
}
else if ( Field . FieldType = = EFieldFamily : : Reference )
{
check ( ( Field . Reference . TypeInfo & Protocol0 : : Field_CategoryMask ) = = Protocol0 : : Field_Integer ) ;
2023-09-29 07:22:52 -04:00
const int8 TypeSize = ( int8 ) ( 1 < < ( Field . Reference . TypeInfo & Protocol0 : : Field_Pow2SizeMask ) ) ;
2022-05-05 05:30:07 -04:00
auto & OutField = Builder . AddField ( NameCursor , Field . Reference . NameSize , TypeSize ) ;
OutField . Offset = Field . Reference . Offset ;
OutField . SizeAndType = TypeSize ;
2022-05-27 09:29:46 -04:00
OutField . RefUid = uint32 ( Field . Reference . RefUid ) ;
2022-05-05 05:30:07 -04:00
OutField . Class = 0 ;
OutField . bArray = false ;
NameCursor + = Field . Reference . NameSize ;
}
else if ( Field . FieldType = = EFieldFamily : : DefinitionId )
{
check ( ( Field . DefinitionId . TypeInfo & Protocol0 : : Field_CategoryMask ) = = Protocol0 : : Field_Integer ) ;
2023-09-29 07:22:52 -04:00
const int8 TypeSize = ( int8 ) ( 1 < < ( Field . DefinitionId . TypeInfo & Protocol0 : : Field_Pow2SizeMask ) ) ;
2023-01-25 04:26:15 -05:00
2022-05-05 05:30:07 -04:00
auto DefinitionIdFieldName = ANSITEXTVIEW ( " DefinitionId " ) ;
auto & OutField = Builder . AddField ( DefinitionIdFieldName . GetData ( ) , DefinitionIdFieldName . Len ( ) , TypeSize ) ;
OutField . Offset = Field . DefinitionId . Offset ;
OutField . SizeAndType = TypeSize ;
OutField . RefUid = NewEvent . EventUid ;
OutField . Class = 0 ;
OutField . bArray = false ;
}
else
{
// Error!
continue ;
}
}
if ( NewEvent . Flags & uint32 ( EEventFlags : : Important ) )
{
Builder . SetImportant ( ) ;
}
if ( NewEvent . Flags & uint32 ( EEventFlags : : MaybeHasAux ) )
{
Builder . SetMaybeHasAux ( ) ;
}
if ( NewEvent . Flags & uint32 ( EEventFlags : : NoSync ) )
{
Builder . SetNoSync ( ) ;
}
if ( NewEvent . Flags & uint32 ( EEventFlags : : Definition ) )
{
Builder . SetDefinition ( ) ;
}
FTypeInfo * TypeInfo = Builder . Finalize ( ) ;
Add ( TypeInfo ) ;
return TypeInfo ;
}
2021-07-29 08:29:56 -04:00
////////////////////////////////////////////////////////////////////////////////
void FTypeRegistry : : Add ( FTypeInfo * TypeInfo )
{
2021-07-28 02:24:21 -04:00
// Add the type to the type-infos table. Usually duplicates are an error
// but due to backwards compatibility we'll override existing types.
uint16 Uid = TypeInfo - > Uid ;
2021-09-03 04:35:00 -04:00
if ( Uid < uint32 ( TypeInfos . Num ( ) ) )
2023-01-25 04:26:15 -05:00
{
2021-07-28 02:24:21 -04:00
if ( TypeInfos [ Uid ] ! = nullptr )
2023-01-25 04:26:15 -05:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Warning: Override type for Uid=%u " , uint32 ( Uid ) ) ;
2021-07-28 02:24:21 -04:00
FMemory : : Free ( TypeInfos [ Uid ] ) ;
TypeInfos [ Uid ] = nullptr ;
2023-01-25 04:26:15 -05:00
}
}
2021-07-28 02:24:21 -04:00
else
2023-01-25 04:26:15 -05:00
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
if ( Uid > TypeInfos . Num ( ) + 100 )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Warning: Unexpected large Uid=%u " , uint32 ( Uid ) ) ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-07-28 02:24:21 -04:00
TypeInfos . SetNum ( Uid + 1 ) ;
2023-01-25 04:26:15 -05:00
}
2021-07-28 02:24:21 -04:00
2021-07-29 08:29:56 -04:00
TypeInfos [ Uid ] = TypeInfo ;
2021-07-28 02:24:21 -04:00
}
2021-09-03 04:31:47 -04:00
////////////////////////////////////////////////////////////////////////////////
bool FTypeRegistry : : IsUidValid ( uint32 Uid ) const
{
return ( Uid < uint32 ( TypeInfos . Num ( ) ) ) & & ( TypeInfos [ Uid ] ! = nullptr ) ;
}
2021-07-28 02:24:21 -04:00
// {{{1 analyzer-hub -----------------------------------------------------------
class FAnalyzerHub
{
public :
void End ( ) ;
void SetAnalyzers ( TArray < IAnalyzer * > & & InAnalyzers ) ;
2022-02-11 04:03:07 -05:00
uint32 GetActiveAnalyzerNum ( ) const ;
2021-07-28 02:24:21 -04:00
void OnNewType ( const FTypeRegistry : : FTypeInfo * TypeInfo ) ;
void OnEvent ( const FTypeRegistry : : FTypeInfo & TypeInfo , IAnalyzer : : EStyle Style , const IAnalyzer : : FOnEventContext & Context ) ;
void OnThreadInfo ( const FThreads : : FInfo & ThreadInfo ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG_API
void OnVersion ( uint32 TransportVersion , uint32 ProtocolVersion ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2021-07-28 02:24:21 -04:00
private :
void BuildRoutes ( ) ;
void AddRoute ( uint16 AnalyzerIndex , uint16 Id , const ANSICHAR * Logger , const ANSICHAR * Event , bool bScoped ) ;
int32 GetRouteIndex ( const FTypeRegistry : : FTypeInfo & TypeInfo ) ;
void RetireAnalyzer ( IAnalyzer * Analyzer ) ;
template < typename ImplType >
void ForEachRoute ( uint32 RouteIndex , bool bScoped , ImplType & & Impl ) const ;
struct FRoute
{
uint32 Hash ;
uint16 AnalyzerIndex : 15 ;
uint16 bScoped : 1 ;
uint16 Id ;
union
{
uint32 ParentHash ;
struct
{
int16 Count ;
int16 Parent ;
} ;
} ;
} ;
typedef TArray < uint16 , TInlineAllocator < 96 > > TypeToRouteArray ;
TArray < IAnalyzer * > Analyzers ;
TArray < FRoute > Routes ;
TypeToRouteArray TypeToRoute ; // biases by one so zero represents no route
} ;
////////////////////////////////////////////////////////////////////////////////
void FAnalyzerHub : : End ( )
{
for ( IAnalyzer * Analyzer : Analyzers )
{
if ( Analyzer ! = nullptr )
{
Analyzer - > OnAnalysisEnd ( ) ;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void FAnalyzerHub : : SetAnalyzers ( TArray < IAnalyzer * > & & InAnalyzers )
{
Analyzers = MoveTemp ( InAnalyzers ) ;
BuildRoutes ( ) ;
}
2022-02-11 04:03:07 -05:00
////////////////////////////////////////////////////////////////////////////////
uint32 FAnalyzerHub : : GetActiveAnalyzerNum ( ) const
{
uint32 Count = 0 ;
for ( IAnalyzer * Analyzer : Analyzers )
{
Count + = ( Analyzer ! = nullptr ) ;
}
return Count ;
}
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
int32 FAnalyzerHub : : GetRouteIndex ( const FTypeRegistry : : FTypeInfo & TypeInfo )
{
if ( TypeInfo . Uid > = uint32 ( TypeToRoute . Num ( ) ) )
{
return - 1 ;
}
return int32 ( TypeToRoute [ TypeInfo . Uid ] ) - 1 ;
}
////////////////////////////////////////////////////////////////////////////////
template < typename ImplType >
void FAnalyzerHub : : ForEachRoute ( uint32 RouteIndex , bool bScoped , ImplType & & Impl ) const
{
uint32 RouteCount = Routes . Num ( ) ;
if ( RouteIndex > = RouteCount )
{
return ;
}
const FRoute * FirstRoute = Routes . GetData ( ) ;
const FRoute * Route = FirstRoute + RouteIndex ;
do
{
const FRoute * NextRoute = FirstRoute + Route - > Parent ;
for ( uint32 n = Route - > Count ; n - - ; + + Route )
{
if ( Route - > bScoped ! = ( bScoped = = true ) )
{
continue ;
}
IAnalyzer * Analyzer = Analyzers [ Route - > AnalyzerIndex ] ;
if ( Analyzer ! = nullptr )
{
Impl ( Analyzer , Route - > Id ) ;
}
}
Route = NextRoute ;
}
while ( Route > = FirstRoute ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalyzerHub : : OnNewType ( const FTypeRegistry : : FTypeInfo * TypeInfo )
{
// Find routes that have subscribed to this event.
auto FindRoute = [ this ] ( uint32 Hash )
{
int32 Index = Algo : : LowerBoundBy ( Routes , Hash , [ ] ( const FRoute & Route ) { return Route . Hash ; } ) ;
return ( Index < Routes . Num ( ) & & Routes [ Index ] . Hash = = Hash ) ? Index : - 1 ;
} ;
int32 FirstRoute = FindRoute ( TypeInfo - > Hash ) ;
if ( FirstRoute < 0 )
{
FFnv1aHash LoggerHash ;
LoggerHash . Add ( ( const ANSICHAR * ) TypeInfo + TypeInfo - > LoggerNameOffset ) ;
if ( ( FirstRoute = FindRoute ( LoggerHash . Get ( ) ) ) < 0 )
{
FirstRoute = FindRoute ( FFnv1aHash ( ) . Get ( ) ) ;
}
}
uint16 Uid = TypeInfo - > Uid ;
if ( Uid > = uint16 ( TypeToRoute . Num ( ) ) )
2023-01-25 04:26:15 -05:00
{
2021-07-28 02:24:21 -04:00
TypeToRoute . SetNumZeroed ( Uid + 32 ) ;
2023-01-25 04:26:15 -05:00
}
2021-07-28 02:24:21 -04:00
TypeToRoute [ Uid ] = uint16 ( FirstRoute + 1 ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
const IAnalyzer : : FEventTypeInfo & EventTypeInfo = * ( IAnalyzer : : FEventTypeInfo * ) TypeInfo ;
# if UE_TRACE_ANALYSIS_DEBUG_API
const uint8 EventTypeFlags = EventTypeInfo . GetFlags ( ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " NewEvent: Uid=%u (%s.%s) Flags=%s%s%s%s " ,
EventTypeInfo . GetId ( ) , EventTypeInfo . GetLoggerName ( ) , EventTypeInfo . GetName ( ) ,
( EventTypeFlags & FDispatch : : Flag_Definition ) ? " Definition| " : " " ,
( EventTypeFlags & FDispatch : : Flag_Important ) ? " Important| " : " " ,
( EventTypeFlags & FDispatch : : Flag_MaybeHasAux ) ? " MaybeHasAux| " : " " ,
( EventTypeFlags & FDispatch : : Flag_NoSync ) ? " NoSync " : " Sync " ) ;
# else // UE_TRACE_ANALYSIS_DEBUG_API
UE_TRACE_ANALYSIS_DEBUG_LOG ( " NewEvent: Uid=%u (%s.%s) " ,
EventTypeInfo . GetId ( ) , EventTypeInfo . GetLoggerName ( ) , EventTypeInfo . GetName ( ) ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_API
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-07-28 02:24:21 -04:00
// Inform routes that a new event has been declared.
if ( FirstRoute > = 0 )
{
ForEachRoute ( FirstRoute , false , [ & ] ( IAnalyzer * Analyzer , uint16 RouteId )
{
if ( ! Analyzer - > OnNewEvent ( RouteId , * ( IAnalyzer : : FEventTypeInfo * ) TypeInfo ) )
{
RetireAnalyzer ( Analyzer ) ;
}
} ) ;
}
}
////////////////////////////////////////////////////////////////////////////////
void FAnalyzerHub : : OnEvent (
const FTypeRegistry : : FTypeInfo & TypeInfo ,
const IAnalyzer : : EStyle Style ,
const IAnalyzer : : FOnEventContext & Context )
{
int32 RouteIndex = GetRouteIndex ( TypeInfo ) ;
if ( RouteIndex < 0 )
{
return ;
}
2021-08-05 05:27:03 -04:00
bool bScoped = ( Style ! = IAnalyzer : : EStyle : : Normal ) ;
ForEachRoute ( RouteIndex , bScoped , [ & ] ( IAnalyzer * Analyzer , uint16 RouteId )
2021-07-28 02:24:21 -04:00
{
if ( ! Analyzer - > OnEvent ( RouteId , Style , Context ) )
{
RetireAnalyzer ( Analyzer ) ;
}
} ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalyzerHub : : OnThreadInfo ( const FThreads : : FInfo & ThreadInfo )
{
const auto & OuterThreadInfo = ( IAnalyzer : : FThreadInfo & ) ThreadInfo ;
for ( IAnalyzer * Analyzer : Analyzers )
{
if ( Analyzer ! = nullptr )
{
Analyzer - > OnThreadInfo ( OuterThreadInfo ) ;
}
}
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG_API
void FAnalyzerHub : : OnVersion ( uint32 TransportVersion , uint32 ProtocolVersion )
{
for ( IAnalyzer * Analyzer : Analyzers )
{
if ( Analyzer ! = nullptr )
{
Analyzer - > OnVersion ( TransportVersion , ProtocolVersion ) ;
}
}
}
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalyzerHub : : BuildRoutes ( )
2020-06-23 18:40:00 -04:00
{
// Call out to all registered analyzers to have them register event interest
2021-07-28 02:24:21 -04:00
struct : public IAnalyzer : : FInterfaceBuilder
2020-06-23 18:40:00 -04:00
{
virtual void RouteEvent ( uint16 RouteId , const ANSICHAR * Logger , const ANSICHAR * Event , bool bScoped ) override
{
Self - > AddRoute ( AnalyzerIndex , RouteId , Logger , Event , bScoped ) ;
}
virtual void RouteLoggerEvents ( uint16 RouteId , const ANSICHAR * Logger , bool bScoped ) override
{
Self - > AddRoute ( AnalyzerIndex , RouteId , Logger , " " , bScoped ) ;
}
virtual void RouteAllEvents ( uint16 RouteId , bool bScoped ) override
{
Self - > AddRoute ( AnalyzerIndex , RouteId , " " , " " , bScoped ) ;
}
2021-07-28 02:24:21 -04:00
FAnalyzerHub * Self ;
2020-06-23 18:40:00 -04:00
uint16 AnalyzerIndex ;
} Builder ;
Builder . Self = this ;
2021-07-28 02:24:21 -04:00
IAnalyzer : : FOnAnalysisContext OnAnalysisContext = { Builder } ;
2022-09-30 11:28:14 -04:00
for ( uint16 i = 0 , n = uint16 ( Analyzers . Num ( ) ) ; i < n ; + + i )
2020-06-23 18:40:00 -04:00
{
uint32 RouteCount = Routes . Num ( ) ;
Builder . AnalyzerIndex = i ;
IAnalyzer * Analyzer = Analyzers [ i ] ;
Analyzer - > OnAnalysisBegin ( OnAnalysisContext ) ;
// If the analyzer didn't add any routes we'll retire it immediately
2021-07-28 02:24:21 -04:00
if ( RouteCount = = Routes . Num ( ) )
2020-06-23 18:40:00 -04:00
{
RetireAnalyzer ( Analyzer ) ;
}
}
2021-07-28 02:24:21 -04:00
// Sort routes by their hashes.
2020-06-23 18:40:00 -04:00
auto RouteProjection = [ ] ( const FRoute & Route ) { return Route . Hash ; } ;
Algo : : SortBy ( Routes , RouteProjection ) ;
auto FindRoute = [ this , & RouteProjection ] ( uint32 Hash )
{
int32 Index = Algo : : LowerBoundBy ( Routes , Hash , RouteProjection ) ;
return ( Index < Routes . Num ( ) & & Routes [ Index ] . Hash = = Hash ) ? Index : - 1 ;
} ;
int32 AllEventsIndex = FindRoute ( FFnv1aHash ( ) . Get ( ) ) ;
2023-01-25 04:26:15 -05:00
auto FixupRoute = [ this , & FindRoute , AllEventsIndex ] ( FRoute * Route )
2020-06-23 18:40:00 -04:00
{
if ( Route - > ParentHash )
{
int32 ParentIndex = FindRoute ( Route - > ParentHash ) ;
Route - > Parent = int16 ( ( ParentIndex < 0 ) ? AllEventsIndex : ParentIndex ) ;
}
else
{
Route - > Parent = - 1 ;
}
Route - > Count = 1 ;
return Route ;
} ;
FRoute * Cursor = FixupRoute ( Routes . GetData ( ) ) ;
2022-09-30 11:28:14 -04:00
for ( uint16 i = 1 , n = uint16 ( Routes . Num ( ) ) ; i < n ; + + i )
2020-06-23 18:40:00 -04:00
{
FRoute * Route = Routes . GetData ( ) + i ;
if ( Route - > Hash = = Cursor - > Hash )
{
Cursor - > Count + + ;
}
else
{
Cursor = FixupRoute ( Route ) ;
}
}
}
2021-07-27 04:32:25 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FAnalyzerHub : : RetireAnalyzer ( IAnalyzer * Analyzer )
2019-06-03 15:32:00 -04:00
{
2019-11-25 12:03:09 -05:00
for ( uint32 i = 0 , n = Analyzers . Num ( ) ; i < n ; + + i )
2019-10-03 16:26:48 -04:00
{
2019-11-25 12:03:09 -05:00
if ( Analyzers [ i ] ! = Analyzer )
{
continue ;
}
Analyzer - > OnAnalysisEnd ( ) ;
Analyzers [ i ] = nullptr ;
break ;
2019-10-15 03:35:31 -04:00
}
2019-06-03 15:32:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FAnalyzerHub : : AddRoute (
2019-06-03 15:32:00 -04:00
uint16 AnalyzerIndex ,
uint16 Id ,
const ANSICHAR * Logger ,
2020-06-23 18:40:00 -04:00
const ANSICHAR * Event ,
bool bScoped )
2019-06-03 15:32:00 -04:00
{
check ( AnalyzerIndex < Analyzers . Num ( ) ) ;
2020-06-23 18:40:00 -04:00
uint32 ParentHash = 0 ;
if ( Logger [ 0 ] & & Event [ 0 ] )
{
FFnv1aHash Hash ;
Hash . Add ( Logger ) ;
ParentHash = Hash . Get ( ) ;
}
FFnv1aHash Hash ;
Hash . Add ( Logger ) ;
Hash . Add ( Event ) ;
2019-06-03 15:32:00 -04:00
FRoute & Route = Routes . Emplace_GetRef ( ) ;
Route . Id = Id ;
2020-06-23 18:40:00 -04:00
Route . Hash = Hash . Get ( ) ;
Route . ParentHash = ParentHash ;
2019-06-03 15:32:00 -04:00
Route . AnalyzerIndex = AnalyzerIndex ;
2020-06-23 18:40:00 -04:00
Route . bScoped = ( bScoped = = true ) ;
2019-06-03 15:32:00 -04:00
}
2021-07-28 02:24:21 -04:00
// {{{1 state ------------------------------------------------------------------
2019-11-25 12:03:09 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
struct FAnalysisState
{
struct FSerial
{
uint32 Value = 0 ;
uint32 Mask = 0 ;
} ;
FThreads Threads ;
FTiming Timing ;
FSerial Serial ;
uint32 UserUidBias = Protocol4 : : EKnownEventUids : : User ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
uint32 TempUidBytes = 0 ; // for protocol 4
int32 MaxEventDescs = 0 ; // for protocol 5
int32 SerialWrappedCount = 0 ; // for protocol 5
int32 NumSkippedSerialGaps = 0 ; // for protocol 5
uint64 TotalEventCount = 0 ;
uint64 NewEventCount = 0 ;
uint64 SyncEventCount = 0 ;
uint64 ImportantNoSyncEventCount = 0 ;
uint64 OtherNoSyncEventCount = 0 ;
uint64 EnterScopeEventCount = 0 ;
uint64 LeaveScopeEventCount = 0 ;
uint64 EnterScopeTEventCount = 0 ;
uint64 LeaveScopeTEventCount = 0 ;
uint64 TotalEventSize = 0 ;
uint64 NewEventSize = 0 ;
uint64 SyncEventSize = 0 ;
uint64 ImportantNoSyncEventSize = 0 ;
uint64 OtherNoSyncEventSize = 0 ;
uint64 EnterScopeEventSize = 0 ;
uint64 LeaveScopeEventSize = 0 ;
uint64 EnterScopeTEventSize = 0 ;
uint64 LeaveScopeTEventSize = 0 ;
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-07-28 02:24:21 -04:00
} ;
// {{{1 thread-info-cb ---------------------------------------------------------
class FThreadInfoCallback
{
public :
virtual ~ FThreadInfoCallback ( ) { }
virtual void OnThreadInfo ( const FThreads : : FInfo & Info ) = 0 ;
} ;
// {{{1 analyzer ---------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
enum
{
RouteId_NewTrace ,
RouteId_SerialSync ,
RouteId_Timing ,
RouteId_ThreadTiming ,
RouteId_ThreadInfo ,
RouteId_ThreadGroupBegin ,
RouteId_ThreadGroupEnd ,
} ;
////////////////////////////////////////////////////////////////////////////////
class FTraceAnalyzer
: public IAnalyzer
{
public :
FTraceAnalyzer ( FAnalysisState & InState , FThreadInfoCallback & InCallback ) ;
virtual bool OnEvent ( uint16 RouteId , EStyle Style , const FOnEventContext & Context ) override ;
virtual void OnAnalysisBegin ( const FOnAnalysisContext & Context ) override ;
void OnNewTrace ( const FOnEventContext & Context ) ;
void OnSerialSync ( const FOnEventContext & Context ) ;
void OnThreadTiming ( const FOnEventContext & Context ) ;
void OnThreadInfoInternal ( const FOnEventContext & Context ) ;
void OnThreadGroupBegin ( const FOnEventContext & Context ) ;
void OnThreadGroupEnd ( ) ;
void OnTiming ( const FOnEventContext & Context ) ;
private :
FAnalysisState & State ;
FThreadInfoCallback & ThreadInfoCallback ;
} ;
////////////////////////////////////////////////////////////////////////////////
FTraceAnalyzer : : FTraceAnalyzer ( FAnalysisState & InState , FThreadInfoCallback & InCallback )
: State ( InState )
, ThreadInfoCallback ( InCallback )
{
}
////////////////////////////////////////////////////////////////////////////////
void FTraceAnalyzer : : OnAnalysisBegin ( const FOnAnalysisContext & Context )
2019-11-25 12:03:09 -05:00
{
2020-06-23 18:40:00 -04:00
auto & Builder = Context . InterfaceBuilder ;
Builder . RouteEvent ( RouteId_NewTrace , " $Trace " , " NewTrace " ) ;
2021-01-11 04:15:10 -04:00
Builder . RouteEvent ( RouteId_SerialSync , " $Trace " , " SerialSync " ) ;
2020-06-23 18:40:00 -04:00
Builder . RouteEvent ( RouteId_Timing , " $Trace " , " Timing " ) ;
Builder . RouteEvent ( RouteId_ThreadTiming , " $Trace " , " ThreadTiming " ) ;
Builder . RouteEvent ( RouteId_ThreadInfo , " $Trace " , " ThreadInfo " ) ;
Builder . RouteEvent ( RouteId_ThreadGroupBegin , " $Trace " , " ThreadGroupBegin " ) ;
Builder . RouteEvent ( RouteId_ThreadGroupEnd , " $Trace " , " ThreadGroupEnd " ) ;
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
bool FTraceAnalyzer : : OnEvent ( uint16 RouteId , EStyle Style , const FOnEventContext & Context )
2020-06-23 18:40:00 -04:00
{
2019-11-25 12:03:09 -05:00
switch ( RouteId )
{
2020-06-23 18:40:00 -04:00
case RouteId_NewTrace : OnNewTrace ( Context ) ; break ;
2021-01-11 04:15:10 -04:00
case RouteId_SerialSync : OnSerialSync ( Context ) ; break ;
2020-06-23 18:40:00 -04:00
case RouteId_Timing : OnTiming ( Context ) ; break ;
case RouteId_ThreadTiming : OnThreadTiming ( Context ) ; break ;
case RouteId_ThreadInfo : OnThreadInfoInternal ( Context ) ; break ;
case RouteId_ThreadGroupBegin : OnThreadGroupBegin ( Context ) ; break ;
case RouteId_ThreadGroupEnd : OnThreadGroupEnd ( ) ; break ;
2019-11-25 12:03:09 -05:00
}
return true ;
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnNewTrace ( const FOnEventContext & Context )
2019-06-03 15:32:00 -04:00
{
2019-11-25 12:03:09 -05:00
const FEventData & EventData = Context . EventData ;
2020-06-23 18:40:00 -04:00
// "Serial" will tell us approximately where we've started in the log serial
2021-04-29 08:16:23 -04:00
// range. We'll bias it by half so we won't accept any serialised events and
2020-06-23 18:40:00 -04:00
// mark the MSB to indicate that the current serial should be corrected.
2021-07-28 02:24:21 -04:00
auto & Serial = State . Serial ;
2020-06-23 18:40:00 -04:00
uint32 Hint = EventData . GetValue < uint32 > ( " Serial " ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Serial=%u (hint) " , Hint ) ;
2020-06-23 18:40:00 -04:00
Hint - = ( Serial . Mask + 1 ) > > 1 ;
Hint & = Serial . Mask ;
2021-01-11 04:15:10 -04:00
Serial . Value = Hint ;
Serial . Value | = 0xc0000000 ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Serial.Value=%u|0xC0000000 (Next=%u) " , Hint , Serial . Value & Serial . Mask ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Serial.Mask=0x%X " , Serial . Mask ) ;
2021-01-11 04:15:10 -04:00
// Later traces will have an explicit "SerialSync" trace event to indicate
// when there is enough data to establish the correct log serial
2023-01-25 04:26:15 -05:00
const uint8 FeatureSet = EventData . GetValue < uint8 > ( " FeatureSet " ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " FeatureSet=%d " , FeatureSet ) ;
2023-01-25 04:26:15 -05:00
if ( ( FeatureSet & 1 ) = = 0 )
2021-01-11 04:15:10 -04:00
{
OnSerialSync ( Context ) ;
}
2019-06-03 15:32:00 -04:00
2021-07-28 02:24:21 -04:00
State . UserUidBias = EventData . GetValue < uint32 > ( " UserUidBias " , uint32 ( UE : : Trace : : Protocol3 : : EKnownEventUids : : User ) ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " UserUidBias=%u " , State . UserUidBias ) ;
2020-10-26 03:29:23 -04:00
OnTiming ( Context ) ;
2019-06-03 15:32:00 -04:00
}
2021-01-11 04:15:10 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnSerialSync ( const FOnEventContext & Context )
2021-01-11 04:15:10 -04:00
{
2021-07-28 02:24:21 -04:00
State . Serial . Value & = ~ 0x40000000 ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " SerialSync: Next=%u " , State . Serial . Value & State . Serial . Mask ) ;
2021-01-11 04:15:10 -04:00
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnTiming ( const FOnEventContext & Context )
2019-06-03 15:32:00 -04:00
{
2020-06-23 18:40:00 -04:00
uint64 StartCycle = Context . EventData . GetValue < uint64 > ( " StartCycle " ) ;
uint64 CycleFrequency = Context . EventData . GetValue < uint64 > ( " CycleFrequency " ) ;
2021-07-28 02:24:21 -04:00
State . Timing . BaseTimestamp = StartCycle ;
State . Timing . TimestampHz = CycleFrequency ;
State . Timing . InvTimestampHz = 1.0 / double ( CycleFrequency ) ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnThreadTiming ( const FOnEventContext & Context )
2020-06-23 18:40:00 -04:00
{
uint64 BaseTimestamp = Context . EventData . GetValue < uint64 > ( " BaseTimestamp " ) ;
2021-07-28 02:24:21 -04:00
if ( FThreads : : FInfo * Info = State . Threads . GetInfo ( ) )
2020-06-23 18:40:00 -04:00
{
Info - > PrevTimestamp = BaseTimestamp ;
// We can springboard of this event as a way to know a thread has just
// started (or at least is about to send its first event). Notify analyzers
// so they're aware of threads that never get explicitly registered.
2021-07-28 02:24:21 -04:00
ThreadInfoCallback . OnThreadInfo ( * Info ) ;
2020-06-23 18:40:00 -04:00
}
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnThreadInfoInternal ( const FOnEventContext & Context )
2020-06-23 18:40:00 -04:00
{
const FEventData & EventData = Context . EventData ;
2020-12-30 06:06:38 -04:00
FThreads : : FInfo * ThreadInfo ;
uint32 ThreadId = EventData . GetValue < uint32 > ( " ThreadId " , ~ 0u ) ;
if ( ThreadId ! = ~ 0u )
{
// Post important-events; the thread-info event is not on the thread it
// represents anymore. Fortunately the thread-id is traced now.
2021-07-28 02:24:21 -04:00
ThreadInfo = State . Threads . GetInfo ( ThreadId ) ;
2020-12-30 06:06:38 -04:00
}
else
{
2021-07-28 02:24:21 -04:00
ThreadInfo = State . Threads . GetInfo ( ) ;
2020-12-30 06:06:38 -04:00
}
2020-06-23 18:40:00 -04:00
if ( ThreadInfo = = nullptr )
{
return ;
}
2020-12-30 06:06:38 -04:00
2020-06-23 18:40:00 -04:00
ThreadInfo - > SystemId = EventData . GetValue < uint32 > ( " SystemId " ) ;
ThreadInfo - > SortHint = EventData . GetValue < int32 > ( " SortHint " ) ;
2023-01-25 04:26:15 -05:00
2020-06-23 18:40:00 -04:00
FAnsiStringView Name ;
EventData . GetString ( " Name " , Name ) ;
ThreadInfo - > Name . SetNumUninitialized ( Name . Len ( ) + 1 ) ;
ThreadInfo - > Name [ Name . Len ( ) ] = ' \0 ' ;
FMemory : : Memcpy ( ThreadInfo - > Name . GetData ( ) , Name . GetData ( ) , Name . Len ( ) ) ;
if ( ThreadInfo - > GroupName . Num ( ) < = 0 )
{
2021-07-28 02:24:21 -04:00
if ( const TArray < uint8 > * GroupName = State . Threads . GetGroupName ( ) )
2020-06-23 18:40:00 -04:00
{
ThreadInfo - > GroupName = * GroupName ;
}
}
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Thread: Tid=%u SysId=0x%X Name= \" %s \" " , ThreadInfo - > ThreadId , ThreadInfo - > SystemId , ThreadInfo - > Name . GetData ( ) ) ;
2021-07-28 02:24:21 -04:00
ThreadInfoCallback . OnThreadInfo ( * ThreadInfo ) ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnThreadGroupBegin ( const FOnEventContext & Context )
2020-06-23 18:40:00 -04:00
{
const FEventData & EventData = Context . EventData ;
FAnsiStringView Name ;
EventData . GetString ( " Name " , Name ) ;
2021-07-28 02:24:21 -04:00
State . Threads . SetGroupName ( Name . GetData ( ) , Name . Len ( ) ) ;
2020-06-23 18:40:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FTraceAnalyzer : : OnThreadGroupEnd ( )
2020-06-23 18:40:00 -04:00
{
2021-07-28 02:24:21 -04:00
State . Threads . SetGroupName ( " " , 0 ) ;
}
2023-10-31 04:07:11 -04:00
2021-07-28 02:24:21 -04:00
// {{{1 bridge -----------------------------------------------------------------
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
class FAnalysisBridge
: public FThreadInfoCallback
{
public :
typedef FAnalysisState : : FSerial FSerial ;
FAnalysisBridge ( TArray < IAnalyzer * > & & Analyzers ) ;
2022-02-11 04:03:07 -05:00
bool IsStillAnalyzing ( ) const ;
2021-07-28 02:24:21 -04:00
void Reset ( ) ;
2023-10-31 04:07:11 -04:00
FAnalysisState & GetState ( ) ;
2021-07-28 02:24:21 -04:00
uint32 GetUserUidBias ( ) const ;
FSerial & GetSerial ( ) ;
2023-10-31 04:07:11 -04:00
uint32 GetActiveThreadId ( ) const ;
2021-07-28 02:24:21 -04:00
void SetActiveThread ( uint32 ThreadId ) ;
void OnNewType ( const FTypeRegistry : : FTypeInfo * TypeInfo ) ;
void OnEvent ( const FEventDataInfo & EventDataInfo ) ;
virtual void OnThreadInfo ( const FThreads : : FInfo & InThreadInfo ) override ;
2021-09-27 02:03:31 -04:00
void EnterScope ( ) ;
2023-01-25 04:26:15 -05:00
void EnterScope ( uint64 RelativeTimestamp ) ;
void EnterScopeA ( uint64 AbsoluteTimestamp ) ;
2023-01-31 13:23:28 -05:00
void EnterScopeB ( uint64 BaseRelativeTimestamp ) ;
2021-09-27 02:03:31 -04:00
void LeaveScope ( ) ;
2023-01-25 04:26:15 -05:00
void LeaveScope ( uint64 RelativeTimestamp ) ;
void LeaveScopeA ( uint64 AbsoluteTimestamp ) ;
2023-01-31 13:23:28 -05:00
void LeaveScopeB ( uint64 BaseRelativeTimestamp ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG_API
void OnVersion ( uint32 TransportVersion , uint32 ProtocolVersion ) { AnalyzerHub . OnVersion ( TransportVersion , ProtocolVersion ) ; }
# endif // UE_TRACE_ANALYSIS_DEBUG_API
# if UE_TRACE_ANALYSIS_DEBUG
void DebugLogEvent ( const FTypeRegistry : : FTypeInfo * TypeInfo , uint32 FixedSize , uint32 AuxSize , uint32 Serial ) ;
void DebugLogNewEvent ( uint32 Uid , const FTypeRegistry : : FTypeInfo * TypeInfo , uint32 EventSize ) ;
void DebugLogEnterScopeEvent ( uint32 Uid , uint32 EventSize ) ;
void DebugLogEnterScopeEvent ( uint32 Uid , uint64 RelativeTimestamp , uint32 EventSize ) ;
void DebugLogEnterScopeAEvent ( uint32 Uid , uint64 AbsoluteTimestamp , uint32 EventSize ) ;
void DebugLogEnterScopeBEvent ( uint32 Uid , uint64 BaseRelativeTimestamp , uint32 EventSize ) ;
void DebugLogLeaveScopeEvent ( uint32 Uid , uint32 EventSize ) ;
void DebugLogLeaveScopeEvent ( uint32 Uid , uint64 RelativeTimestamp , uint32 EventSize ) ;
void DebugLogLeaveScopeAEvent ( uint32 Uid , uint64 AbsoluteTimestamp , uint32 EventSize ) ;
void DebugLogLeaveScopeBEvent ( uint32 Uid , uint64 BaseRelativeTimestamp , uint32 EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2021-09-27 02:03:31 -04:00
private :
void DispatchLeaveScope ( ) ;
2021-07-28 02:24:21 -04:00
FAnalysisState State ;
FTraceAnalyzer TraceAnalyzer = { State , * this } ;
FAnalyzerHub AnalyzerHub ;
FThreads : : FInfo * ThreadInfo = nullptr ;
} ;
////////////////////////////////////////////////////////////////////////////////
FAnalysisBridge : : FAnalysisBridge ( TArray < IAnalyzer * > & & Analyzers )
{
TArray < IAnalyzer * > TempAnalyzers ( MoveTemp ( Analyzers ) ) ;
TempAnalyzers . Add ( & TraceAnalyzer ) ;
AnalyzerHub . SetAnalyzers ( MoveTemp ( TempAnalyzers ) ) ;
2019-06-03 15:32:00 -04:00
}
2022-02-11 04:03:07 -05:00
////////////////////////////////////////////////////////////////////////////////
bool FAnalysisBridge : : IsStillAnalyzing ( ) const
{
// "> 1" because TraceAnalyzer is always present but shouldn't be considered
return AnalyzerHub . GetActiveAnalyzerNum ( ) > 1 ;
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
void FAnalysisBridge : : Reset ( )
2019-06-03 15:32:00 -04:00
{
2021-07-28 02:24:21 -04:00
AnalyzerHub . End ( ) ;
2019-06-03 15:32:00 -04:00
2021-07-28 02:24:21 -04:00
State . ~ FAnalysisState ( ) ;
new ( & State ) FAnalysisState ( ) ;
2019-06-03 15:32:00 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2023-10-31 04:07:11 -04:00
FAnalysisState & FAnalysisBridge : : GetState ( )
2019-11-25 12:03:09 -05:00
{
2023-10-31 04:07:11 -04:00
return State ;
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
uint32 FAnalysisBridge : : GetUserUidBias ( ) const
2019-11-25 12:03:09 -05:00
{
2021-07-28 02:24:21 -04:00
return State . UserUidBias ;
}
////////////////////////////////////////////////////////////////////////////////
FAnalysisBridge : : FSerial & FAnalysisBridge : : GetSerial ( )
{
return State . Serial ;
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
uint32 FAnalysisBridge : : GetActiveThreadId ( ) const
{
return ThreadInfo ? ThreadInfo - > ThreadId : ~ 0u ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : SetActiveThread ( uint32 ThreadId )
{
ThreadInfo = State . Threads . GetInfo ( ThreadId ) ;
}
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : OnNewType ( const FTypeRegistry : : FTypeInfo * TypeInfo )
{
AnalyzerHub . OnNewType ( TypeInfo ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : OnEvent ( const FEventDataInfo & EventDataInfo )
{
2021-08-08 17:19:29 -04:00
// TODO "Dispatch" should be renamed "EventTypeInfo" or similar.
const FTypeRegistry : : FTypeInfo * TypeInfo = & ( EventDataInfo . Dispatch ) ;
2021-07-28 02:24:21 -04:00
IAnalyzer : : EStyle Style = IAnalyzer : : EStyle : : Normal ;
if ( ThreadInfo - > ScopeRoutes . Num ( ) > 0 & & int64 ( ThreadInfo - > ScopeRoutes . Last ( ) ) < 0 )
{
Style = IAnalyzer : : EStyle : : EnterScope ;
State . Timing . EventTimestamp = ~ ( ThreadInfo - > ScopeRoutes . Last ( ) ) ;
2021-08-08 17:19:29 -04:00
ThreadInfo - > ScopeRoutes . Last ( ) = PTRINT ( TypeInfo ) ;
2021-07-28 02:24:21 -04:00
}
2019-11-25 12:03:09 -05:00
else
{
2021-07-28 02:24:21 -04:00
State . Timing . EventTimestamp = 0 ;
}
IAnalyzer : : FOnEventContext Context = {
* ( const IAnalyzer : : FThreadInfo * ) ThreadInfo ,
( const IAnalyzer : : FEventTime & ) ( State . Timing ) ,
( const IAnalyzer : : FEventData & ) EventDataInfo ,
} ;
AnalyzerHub . OnEvent ( * TypeInfo , Style , Context ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : OnThreadInfo ( const FThreads : : FInfo & InThreadInfo )
{
// Note that InThreadInfo might not equal the bridge's ThreadInfo because
// information about threads comes from trace and could have been traced on
// a different thread to the one it is describing (or no thread at all in
// the case of important events).
AnalyzerHub . OnThreadInfo ( InThreadInfo ) ;
}
2021-09-27 02:03:31 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : EnterScope ( )
{
ThreadInfo - > ScopeRoutes . Push ( ~ 0 ) ;
}
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : EnterScope ( uint64 Timestamp )
{
2021-09-27 02:03:31 -04:00
Timestamp = ThreadInfo - > PrevTimestamp + = Timestamp ;
ThreadInfo - > ScopeRoutes . Push ( ~ Timestamp ) ;
}
2021-07-28 02:24:21 -04:00
2023-01-25 04:26:15 -05:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : EnterScopeA ( uint64 Timestamp )
{
2023-01-25 15:58:23 -05:00
Timestamp - = State . Timing . BaseTimestamp ;
2023-01-25 04:26:15 -05:00
ThreadInfo - > ScopeRoutes . Push ( ~ Timestamp ) ;
}
2023-01-31 13:23:28 -05:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : EnterScopeB ( uint64 Timestamp )
{
ThreadInfo - > ScopeRoutes . Push ( ~ Timestamp ) ;
}
2021-09-27 02:03:31 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : LeaveScope ( )
{
State . Timing . EventTimestamp = 0 ;
DispatchLeaveScope ( ) ;
2021-07-28 02:24:21 -04:00
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : LeaveScope ( uint64 Timestamp )
{
2021-09-27 02:03:31 -04:00
Timestamp = ThreadInfo - > PrevTimestamp + = Timestamp ;
2021-07-28 02:24:21 -04:00
State . Timing . EventTimestamp = Timestamp ;
2021-09-27 02:03:31 -04:00
DispatchLeaveScope ( ) ;
State . Timing . EventTimestamp = 0 ;
}
2021-07-28 02:24:21 -04:00
2023-01-25 04:26:15 -05:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : LeaveScopeA ( uint64 Timestamp )
{
2023-01-25 15:58:23 -05:00
Timestamp - = State . Timing . BaseTimestamp ;
2023-01-25 04:26:15 -05:00
State . Timing . EventTimestamp = Timestamp ;
DispatchLeaveScope ( ) ;
State . Timing . EventTimestamp = 0 ;
}
2023-01-31 13:23:28 -05:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : LeaveScopeB ( uint64 Timestamp )
{
State . Timing . EventTimestamp = Timestamp ;
DispatchLeaveScope ( ) ;
State . Timing . EventTimestamp = 0 ;
}
2021-09-27 02:03:31 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DispatchLeaveScope ( )
{
2021-10-04 07:50:57 -04:00
if ( ThreadInfo - > ScopeRoutes . Num ( ) < = 0 )
2021-07-28 02:24:21 -04:00
{
2021-10-04 07:50:57 -04:00
// Leave scope without a corresponding enter
return ;
2021-07-28 02:24:21 -04:00
}
2021-10-04 07:50:57 -04:00
2024-01-19 16:41:35 -05:00
int64 ScopeValue = int64 ( ThreadInfo - > ScopeRoutes . Pop ( EAllowShrinking : : No ) ) ;
2021-10-04 07:50:57 -04:00
if ( ScopeValue < 0 )
{
// enter/leave pair without an event inbetween.
return ;
}
const auto * TypeInfo = ( FTypeRegistry : : FTypeInfo * ) PTRINT ( ScopeValue ) ;
FEventDataInfo EmptyEventInfo = {
nullptr ,
* TypeInfo
} ;
IAnalyzer : : FOnEventContext Context = {
* ( const IAnalyzer : : FThreadInfo * ) ThreadInfo ,
( const IAnalyzer : : FEventTime & ) ( State . Timing ) ,
( const IAnalyzer : : FEventData & ) EmptyEventInfo ,
} ;
AnalyzerHub . OnEvent ( * TypeInfo , IAnalyzer : : EStyle : : LeaveScope , Context ) ;
2021-07-28 02:24:21 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogEvent ( const FTypeRegistry : : FTypeInfo * TypeInfo , uint32 FixedSize , uint32 AuxSize , uint32 Serial )
{
+ + State . TotalEventCount ;
uint32 EventSize = FixedSize + AuxSize ;
State . TotalEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_BeginStringBuilder ( ) ;
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " [EVENT %llu] " , State . TotalEventCount ) ;
if ( GetActiveThreadId ( ) ! = ~ 0u )
{
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Tid=%u " , GetActiveThreadId ( ) ) ;
}
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Uid=%u " , uint32 ( TypeInfo - > Uid ) ) ;
const IAnalyzer : : FEventTypeInfo & EventTypeInfo = * ( IAnalyzer : : FEventTypeInfo * ) TypeInfo ;
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " (%s.%s) " , EventTypeInfo . GetLoggerName ( ) , EventTypeInfo . GetName ( ) ) ;
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Size=%u " , EventSize ) ;
if ( AuxSize ! = 0 )
{
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " (%u + %u) " , FixedSize , AuxSize ) ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
if ( ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_NoSync ) = = 0 )
{
+ + State . SyncEventCount ;
State . SyncEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Sync=%u " , Serial ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
else if ( ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_Important ) ! = 0 )
{
+ + State . ImportantNoSyncEventCount ;
State . ImportantNoSyncEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_Append ( " Important " ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
else
{
+ + State . OtherNoSyncEventCount ;
State . OtherNoSyncEventSize + = EventSize ;
}
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_EndStringBuilder ( ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogNewEvent ( uint32 Uid , const FTypeRegistry : : FTypeInfo * TypeInfo , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . NewEventCount ;
State . TotalEventSize + = EventSize ;
State . NewEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
const uint32 Tid = ETransportTid : : Importants ; // GetActiveThreadId()
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (NewEvent) Size=%u " , State . TotalEventCount , Tid , Uid , EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogEnterScopeEvent ( uint32 Uid , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . EnterScopeEventCount ;
State . TotalEventSize + = EventSize ;
State . EnterScopeEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (EnterScope) Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid , EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogEnterScopeEvent ( uint32 Uid , uint64 RelativeTimestamp , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . EnterScopeTEventCount ;
State . TotalEventSize + = EventSize ;
State . EnterScopeTEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
check ( ThreadInfo ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (EnterScope_T) Timestamp=(+%llu)=%llu Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid ,
RelativeTimestamp , State . Timing . BaseTimestamp + ThreadInfo - > PrevTimestamp + RelativeTimestamp ,
EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogEnterScopeAEvent ( uint32 Uid , uint64 AbsoluteTimestamp , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . EnterScopeTEventCount ;
State . TotalEventSize + = EventSize ;
State . EnterScopeTEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (EnterScope_TA) Timestamp=%llu Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid ,
AbsoluteTimestamp ,
EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogEnterScopeBEvent ( uint32 Uid , uint64 BaseAbsoluteTimestamp , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . EnterScopeTEventCount ;
State . TotalEventSize + = EventSize ;
State . EnterScopeTEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (EnterScope_TB) Timestamp=(+%llu)=%llu Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid ,
BaseAbsoluteTimestamp , State . Timing . BaseTimestamp + BaseAbsoluteTimestamp ,
EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogLeaveScopeEvent ( uint32 Uid , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . LeaveScopeEventCount ;
State . TotalEventSize + = EventSize ;
State . LeaveScopeEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (LeaveScope) Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid , EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogLeaveScopeEvent ( uint32 Uid , uint64 RelativeTimestamp , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . LeaveScopeTEventCount ;
State . TotalEventSize + = EventSize ;
State . LeaveScopeTEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
check ( ThreadInfo ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (LeaveScope_T) Timestamp=(+%llu)=%llu Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid ,
RelativeTimestamp , State . Timing . BaseTimestamp + ThreadInfo - > PrevTimestamp + RelativeTimestamp ,
EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogLeaveScopeAEvent ( uint32 Uid , uint64 AbsoluteTimestamp , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . LeaveScopeTEventCount ;
State . TotalEventSize + = EventSize ;
State . LeaveScopeTEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (LeaveScope_TA) Timestamp=%llu Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid ,
AbsoluteTimestamp ,
EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisBridge : : DebugLogLeaveScopeBEvent ( uint32 Uid , uint64 BaseAbsoluteTimestamp , uint32 EventSize )
{
+ + State . TotalEventCount ;
+ + State . LeaveScopeTEventCount ;
State . TotalEventSize + = EventSize ;
State . LeaveScopeTEventSize + = EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " [EVENT %llu] Tid=%u Uid=%u (LeaveScope_TB) Timestamp=(+%llu)=%llu Size=%u " ,
State . TotalEventCount , GetActiveThreadId ( ) , Uid ,
BaseAbsoluteTimestamp , State . Timing . BaseTimestamp + BaseAbsoluteTimestamp ,
EventSize ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
}
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-07-28 02:24:21 -04:00
// {{{1 machine ----------------------------------------------------------------
2023-10-31 04:07:11 -04:00
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
class FAnalysisMachine
{
public :
enum class EStatus
{
Error ,
Abort ,
NotEnoughData ,
2021-10-13 09:10:55 -04:00
EndOfStream ,
2021-07-28 02:24:21 -04:00
Continue ,
2022-07-18 05:15:45 -04:00
Sync ,
2020-06-23 18:40:00 -04:00
} ;
2021-07-28 02:24:21 -04:00
struct FMachineContext
2020-06-23 18:40:00 -04:00
{
2021-07-28 02:24:21 -04:00
FAnalysisMachine & Machine ;
FAnalysisBridge & Bridge ;
2023-06-19 07:17:37 -04:00
FMessageDelegate & OnMessage ;
inline void EmitMessage ( EAnalysisMessageSeverity Severity , FStringView Message ) const
{
const bool _ = OnMessage . ExecuteIfBound ( Severity , Message ) ;
}
template < typename FormatType , typename . . . Types >
inline void EmitMessagef ( EAnalysisMessageSeverity Severity , const FormatType & Format , Types . . . Args ) const
{
2023-10-31 04:07:11 -04:00
TStringBuilder < 128 > FormattedMessage ;
2023-06-19 07:17:37 -04:00
FormattedMessage . Appendf ( Format , Forward < Types > ( Args ) . . . ) ;
EmitMessage ( Severity , FormattedMessage . ToView ( ) ) ;
}
2021-07-28 02:24:21 -04:00
} ;
2019-11-25 12:03:09 -05:00
2021-07-28 02:24:21 -04:00
class FStage
{
public :
typedef FAnalysisMachine : : FMachineContext FMachineContext ;
typedef FAnalysisMachine : : EStatus EStatus ;
virtual ~ FStage ( ) { }
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) = 0 ;
virtual void EnterStage ( const FMachineContext & Context ) { } ;
virtual void ExitStage ( const FMachineContext & Context ) { } ;
} ;
2023-06-19 07:17:37 -04:00
FAnalysisMachine ( FAnalysisBridge & InBridge , FMessageDelegate & & InMessage ) ;
2021-07-28 02:24:21 -04:00
~ FAnalysisMachine ( ) ;
EStatus OnData ( FStreamReader & Reader ) ;
void Transition ( ) ;
template < class StageType , typename . . . ArgsType >
StageType * QueueStage ( ArgsType . . . Args ) ;
private :
void CleanUp ( ) ;
FAnalysisBridge & Bridge ;
FStage * ActiveStage = nullptr ;
TArray < FStage * > StageQueue ;
TArray < FStage * > DeadStages ;
2023-06-19 07:17:37 -04:00
FMessageDelegate OnMessage ;
2021-07-28 02:24:21 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
2023-06-19 07:17:37 -04:00
FAnalysisMachine : : FAnalysisMachine ( FAnalysisBridge & InBridge , FMessageDelegate & & InMessage )
2021-07-28 02:24:21 -04:00
: Bridge ( InBridge )
2023-06-19 07:17:37 -04:00
, OnMessage ( InMessage )
2021-07-28 02:24:21 -04:00
{
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FAnalysisMachine : : ~ FAnalysisMachine ( )
2019-11-25 12:03:09 -05:00
{
2021-07-28 02:24:21 -04:00
CleanUp ( ) ;
}
2019-11-25 12:03:09 -05:00
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisMachine : : CleanUp ( )
{
for ( FStage * Stage : DeadStages )
2019-11-25 12:03:09 -05:00
{
2021-07-28 02:24:21 -04:00
delete Stage ;
}
DeadStages . Reset ( ) ;
}
2019-11-25 12:03:09 -05:00
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
template < class StageType , typename . . . ArgsType >
StageType * FAnalysisMachine : : QueueStage ( ArgsType . . . Args )
{
StageType * Stage = new StageType ( Args . . . ) ;
StageQueue . Insert ( Stage , 0 ) ;
return Stage ;
}
2019-11-25 12:03:09 -05:00
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
void FAnalysisMachine : : Transition ( )
{
if ( ActiveStage ! = nullptr )
{
2023-06-19 07:17:37 -04:00
const FMachineContext Context = { * this , Bridge , OnMessage } ;
2021-07-28 02:24:21 -04:00
ActiveStage - > ExitStage ( Context ) ;
2020-06-23 18:40:00 -04:00
2021-07-28 02:24:21 -04:00
DeadStages . Add ( ActiveStage ) ;
}
2019-11-25 12:03:09 -05:00
2021-07-28 02:24:21 -04:00
ActiveStage = ( StageQueue . Num ( ) > 0 ) ? StageQueue . Pop ( ) : nullptr ;
if ( ActiveStage ! = nullptr )
{
2023-06-19 07:17:37 -04:00
const FMachineContext Context = { * this , Bridge , OnMessage } ;
2021-07-28 02:24:21 -04:00
ActiveStage - > EnterStage ( Context ) ;
2019-11-25 12:03:09 -05:00
}
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FAnalysisMachine : : EStatus FAnalysisMachine : : OnData ( FStreamReader & Reader )
2019-11-25 12:03:09 -05:00
{
2023-06-19 07:17:37 -04:00
const FMachineContext Context = { * this , Bridge , OnMessage } ;
2021-07-28 02:24:21 -04:00
EStatus Ret ;
do
2019-12-13 11:07:03 -05:00
{
2021-07-28 02:24:21 -04:00
CleanUp ( ) ;
check ( ActiveStage ! = nullptr ) ;
Ret = ActiveStage - > OnData ( Reader , Context ) ;
2019-12-13 11:07:03 -05:00
}
2021-07-28 02:24:21 -04:00
while ( Ret = = EStatus : : Continue ) ;
return Ret ;
}
2019-12-13 11:07:03 -05:00
2020-02-05 14:26:36 -05:00
2021-07-28 02:24:21 -04:00
// {{{1 protocol-0 -------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FProtocol0Stage
: public FAnalysisMachine : : FStage
{
public :
FProtocol0Stage ( FTransport * InTransport ) ;
~ FProtocol0Stage ( ) ;
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) override ;
2021-07-29 08:31:27 -04:00
virtual void EnterStage ( const FMachineContext & Context ) override ;
2023-10-31 04:07:11 -04:00
virtual void ExitStage ( const FMachineContext & Context ) override ;
2021-07-28 02:24:21 -04:00
private :
FTypeRegistry TypeRegistry ;
FTransport * Transport ;
} ;
////////////////////////////////////////////////////////////////////////////////
FProtocol0Stage : : FProtocol0Stage ( FTransport * InTransport )
: Transport ( InTransport )
{
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FProtocol0Stage : : ~ FProtocol0Stage ( )
2019-06-03 15:32:00 -04:00
{
2021-07-28 02:24:21 -04:00
delete Transport ;
2019-06-03 15:32:00 -04:00
}
2021-07-29 08:31:27 -04:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol0Stage : : EnterStage ( const FMachineContext & Context )
{
Context . Bridge . SetActiveThread ( 0 ) ;
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol0Stage : : ExitStage ( const FMachineContext & Context )
{
// Ensure the transport does not have pending buffers (i.e. event data not yet processed).
if ( ! Transport - > IsEmpty ( ) )
{
Context . EmitMessage ( EAnalysisMessageSeverity : : Warning , TEXT ( " Transport buffers are not empty at end of analysis (protocol 0)! " ) ) ;
}
# if UE_TRACE_ANALYSIS_DEBUG
Transport - > DebugEnd ( ) ;
# endif
}
2019-06-03 15:32:00 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FProtocol0Stage : : EStatus FProtocol0Stage : : OnData (
FStreamReader & Reader ,
const FMachineContext & Context )
2019-06-03 15:32:00 -04:00
{
2019-11-25 12:03:09 -05:00
Transport - > SetReader ( Reader ) ;
2020-06-23 18:40:00 -04:00
2019-11-25 12:03:09 -05:00
while ( true )
{
const auto * Header = Transport - > GetPointer < Protocol0 : : FEventHeader > ( ) ;
if ( Header = = nullptr )
{
break ;
}
uint32 BlockSize = Header - > Size + sizeof ( Protocol0 : : FEventHeader ) ;
Header = Transport - > GetPointer < Protocol0 : : FEventHeader > ( BlockSize ) ;
if ( Header = = nullptr )
{
break ;
}
2021-04-29 08:15:47 -04:00
uint32 Uid = uint32 ( Header - > Uid ) & uint32 ( Protocol0 : : EKnownEventUids : : UidMask ) ;
2021-07-28 02:24:21 -04:00
if ( Uid = = uint32 ( Protocol0 : : EKnownEventUids : : NewEvent ) )
2019-11-25 12:03:09 -05:00
{
2021-07-28 02:24:21 -04:00
// There is no need to check size here as the runtime never builds
// packets that fragment new-event events.
2022-05-05 05:30:07 -04:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Add ( Header - > EventData , 0 ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogNewEvent ( Uid , TypeInfo , BlockSize ) ;
# endif
2021-07-28 02:24:21 -04:00
Context . Bridge . OnNewType ( TypeInfo ) ;
Transport - > Advance ( BlockSize ) ;
continue ;
2019-11-25 12:03:09 -05:00
}
2021-07-28 02:24:21 -04:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Get ( Uid ) ;
if ( TypeInfo = = nullptr )
2019-11-25 12:03:09 -05:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid TypeInfo for Uid %u (Tid=%u) " , Uid , Context . Bridge . GetActiveThreadId ( ) ) ;
2021-07-28 02:24:21 -04:00
return EStatus : : Error ;
2019-11-25 12:03:09 -05:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEvent ( TypeInfo , BlockSize , 0 , Context . Bridge . GetSerial ( ) . Value ) ; //???
# endif
2019-12-13 11:07:03 -05:00
FEventDataInfo EventDataInfo = {
2021-01-10 16:18:43 -04:00
Header - > EventData ,
2021-07-28 02:24:21 -04:00
* TypeInfo ,
2019-12-13 11:07:03 -05:00
nullptr ,
Header - > Size
} ;
2019-11-25 12:03:09 -05:00
2021-07-28 02:24:21 -04:00
Context . Bridge . OnEvent ( EventDataInfo ) ;
2019-11-25 12:03:09 -05:00
Transport - > Advance ( BlockSize ) ;
}
2021-10-13 09:10:55 -04:00
return Reader . IsEmpty ( ) ? EStatus : : EndOfStream : EStatus : : NotEnoughData ;
2021-07-28 02:24:21 -04:00
}
// {{{1 protocol-2 -------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FProtocol2Stage
: public FAnalysisMachine : : FStage
{
public :
2023-10-31 04:07:11 -04:00
FProtocol2Stage ( uint32 Version , FTransport * InTransport ) ;
~ FProtocol2Stage ( ) ;
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) override ;
virtual void EnterStage ( const FMachineContext & Context ) override ;
virtual void ExitStage ( const FMachineContext & Context ) override ;
2021-07-28 02:24:21 -04:00
protected :
2023-10-31 04:07:11 -04:00
virtual int32 OnData ( FStreamReader & Reader , FAnalysisBridge & Bridge ) ;
int32 OnDataAux ( FStreamReader & Reader , FAuxDataCollector & Collector ) ;
FTypeRegistry TypeRegistry ;
FTransport * Transport ;
uint32 ProtocolVersion ;
uint32 SerialInertia = ~ 0u ;
2021-07-28 02:24:21 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
FProtocol2Stage : : FProtocol2Stage ( uint32 Version , FTransport * InTransport )
: Transport ( InTransport )
, ProtocolVersion ( Version )
{
2021-07-29 08:58:34 -04:00
switch ( ProtocolVersion )
{
case Protocol0 : : EProtocol : : Id :
case Protocol1 : : EProtocol : : Id :
case Protocol2 : : EProtocol : : Id :
{
FDispatchBuilder Dispatch ;
Dispatch . SetUid ( uint16 ( Protocol2 : : EKnownEventUids : : NewEvent ) ) ;
Dispatch . SetLoggerName ( " $Trace " ) ;
Dispatch . SetEventName ( " NewEvent " ) ;
TypeRegistry . Add ( Dispatch . Finalize ( ) ) ;
}
break ;
case Protocol3 : : EProtocol : : Id :
{
FDispatchBuilder Dispatch ;
Dispatch . SetUid ( uint16 ( Protocol3 : : EKnownEventUids : : NewEvent ) ) ;
Dispatch . SetLoggerName ( " $Trace " ) ;
Dispatch . SetEventName ( " NewEvent " ) ;
Dispatch . SetNoSync ( ) ;
TypeRegistry . Add ( Dispatch . Finalize ( ) ) ;
}
break ;
}
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FProtocol2Stage : : ~ FProtocol2Stage ( )
{
delete Transport ;
}
////////////////////////////////////////////////////////////////////////////////
void FProtocol2Stage : : EnterStage ( const FMachineContext & Context )
{
auto & Serial = Context . Bridge . GetSerial ( ) ;
if ( ProtocolVersion = = Protocol1 : : EProtocol : : Id )
{
Serial . Mask = 0x0000ffff ;
}
else
{
Serial . Mask = 0x00ffffff ;
}
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Serial.Mask = 0x%X " , Serial . Mask ) ;
2021-07-28 02:24:21 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2023-10-31 04:07:11 -04:00
void FProtocol2Stage : : ExitStage ( const FMachineContext & Context )
{
// Ensure the transport does not have pending buffers (i.e. event data not yet processed).
if ( ! Transport - > IsEmpty ( ) )
{
Context . EmitMessagef ( EAnalysisMessageSeverity : : Warning , TEXT ( " Transport buffers are not empty at end of analysis (protocol %u)! " ) , ProtocolVersion ) ;
}
# if UE_TRACE_ANALYSIS_DEBUG
Transport - > DebugEnd ( ) ;
# endif
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
FProtocol2Stage : : EStatus FProtocol2Stage : : OnData (
FStreamReader & Reader ,
const FMachineContext & Context )
2019-11-25 12:03:09 -05:00
{
auto * InnerTransport = ( FTidPacketTransport * ) Transport ;
2021-07-28 02:24:21 -04:00
InnerTransport - > SetReader ( Reader ) ;
2023-02-09 05:19:47 -05:00
const FTidPacketTransport : : ETransportResult Result = InnerTransport - > Update ( ) ;
if ( Result = = FTidPacketTransport : : ETransportResult : : Error )
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: An error was detected in the transport layer, most likely due to a corrupt trace file. " ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessage (
EAnalysisMessageSeverity : : Error ,
TEXT ( " An error was detected in the transport layer, most likely due to a corrupt trace file. See log for details. " )
) ;
2023-02-09 05:19:47 -05:00
return EStatus : : Error ;
}
2019-11-25 12:03:09 -05:00
2020-06-23 18:40:00 -04:00
struct FRotaItem
2019-11-25 12:03:09 -05:00
{
2020-06-23 18:40:00 -04:00
uint32 Serial ;
uint32 ThreadId ;
FStreamReader * Reader ;
2021-09-02 00:19:42 -04:00
2022-01-28 03:41:42 -05:00
bool operator < ( const FRotaItem & Rhs ) const
2021-09-02 00:19:42 -04:00
{
int32 Delta = Rhs . Serial - Serial ;
int32 Wrapped = uint32 ( Delta + 0x007f'fffe ) > = uint32 ( 0x00ff'fffd ) ;
return ( Wrapped ^ ( Delta > 0 ) ) ! = 0 ;
}
2020-06-23 18:40:00 -04:00
} ;
TArray < FRotaItem > Rota ;
for ( uint32 i = 0 , n = InnerTransport - > GetThreadCount ( ) ; i < n ; + + i )
{
2021-07-28 02:24:21 -04:00
FStreamReader * ThreadReader = InnerTransport - > GetThreadStream ( i ) ;
2020-06-23 18:40:00 -04:00
uint32 ThreadId = InnerTransport - > GetThreadId ( i ) ;
2021-07-28 02:24:21 -04:00
Rota . Add ( { ~ 0u , ThreadId , ThreadReader } ) ;
2020-06-23 18:40:00 -04:00
}
2021-07-28 02:24:21 -04:00
auto & Serial = Context . Bridge . GetSerial ( ) ;
2023-10-31 04:07:11 -04:00
2020-06-23 18:40:00 -04:00
while ( true )
{
2022-02-16 10:14:39 -05:00
uint32 ActiveCount = uint32 ( Rota . Num ( ) ) ;
2020-06-23 18:40:00 -04:00
for ( uint32 i = 0 ; i < ActiveCount ; )
2019-11-25 12:03:09 -05:00
{
2020-06-23 18:40:00 -04:00
FRotaItem & RotaItem = Rota [ i ] ;
if ( int32 ( RotaItem . Serial ) > int32 ( Serial . Value & Serial . Mask ) )
2019-11-25 12:03:09 -05:00
{
2020-06-23 18:40:00 -04:00
+ + i ;
continue ;
2019-11-25 12:03:09 -05:00
}
2021-07-28 02:24:21 -04:00
Context . Bridge . SetActiveThread ( RotaItem . ThreadId ) ;
2020-06-23 18:40:00 -04:00
2021-07-28 02:24:21 -04:00
uint32 AvailableSerial = OnData ( * ( RotaItem . Reader ) , Context . Bridge ) ;
2020-06-23 18:40:00 -04:00
if ( int32 ( AvailableSerial ) > = 0 )
{
RotaItem . Serial = AvailableSerial ;
if ( Rota [ 0 ] . Serial > AvailableSerial )
{
Swap ( Rota [ 0 ] , RotaItem ) ;
}
+ + i ;
}
else
{
FRotaItem TempItem = RotaItem ;
TempItem . Serial = ~ 0u ;
for ( uint32 j = i , m = ActiveCount - 1 ; j < m ; + + j )
{
Rota [ j ] = Rota [ j + 1 ] ;
}
Rota [ ActiveCount - 1 ] = TempItem ;
- - ActiveCount ;
}
if ( ( ( Rota [ 0 ] . Serial - Serial . Value ) & Serial . Mask ) = = 0 )
{
i = 0 ;
}
}
if ( ActiveCount < 1 )
{
break ;
}
2020-09-24 00:43:27 -04:00
TArrayView < FRotaItem > ActiveRota ( Rota . GetData ( ) , ActiveCount ) ;
Algo : : Sort ( ActiveRota ) ;
2020-06-23 18:40:00 -04:00
int32 MinLogSerial = Rota [ 0 ] . Serial ;
if ( ActiveCount > 1 )
{
int32 MaxLogSerial = Rota [ ActiveCount - 1 ] . Serial ;
if ( ( uint32 ( MinLogSerial - Serial . Value ) & Serial . Mask ) = = 0 )
{
continue ;
}
// If min/max are more than half the serial range apart consider them
// as having wrapped.
int32 HalfRange = int32 ( Serial . Mask > > 1 ) ;
if ( ( MaxLogSerial - MinLogSerial ) > = HalfRange )
{
for ( uint32 i = 0 ; i < ActiveCount ; + + i )
{
FRotaItem & RotaItem = Rota [ i ] ;
if ( int32 ( RotaItem . Serial ) > = HalfRange )
{
MinLogSerial = RotaItem . Serial ;
break ;
}
}
}
}
// If the current serial has its MSB set we're currently in a mode trying
// to derive the best starting serial.
2021-01-12 04:25:33 -04:00
if ( int32 ( Serial . Value ) < int32 ( 0xc0000000 ) )
2020-06-23 18:40:00 -04:00
{
Serial . Value = ( MinLogSerial & Serial . Mask ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " New Serial.Value: %u " , Serial . Value ) ;
2020-06-23 18:40:00 -04:00
continue ;
}
// If we didn't stumble across the next serialised event we have done all
// we can for now.
if ( ( uint32 ( MinLogSerial - Serial . Value ) & Serial . Mask ) ! = 0 )
{
break ;
2019-11-25 12:03:09 -05:00
}
}
2021-08-19 08:08:40 -04:00
// Patch the serial value to try and recover from gaps. Note that the bits
// used to wait for the serial-sync event are ignored as that event may never
2023-10-31 04:07:11 -04:00
// be reached if leading events are synchronized. Some inertia is added as
2021-09-02 00:19:42 -04:00
// the missing range of events can be in subsequent packets. (Maximum inertia
// need only be the size of the tail / io-read-size).
2021-08-19 08:08:40 -04:00
if ( Rota . Num ( ) > 0 )
{
int32 LowestSerial = int32 ( Rota [ 0 ] . Serial ) ;
if ( LowestSerial > = 0 )
{
2021-09-02 00:19:42 -04:00
enum {
InertiaLen = 0x20 ,
InertiaStart = 0x7f - InertiaLen ,
InertiaBase = InertiaStart < < 25 , // leaves bit 24 unset so
InertiaInc = 1 < < 25 , // ~0u can never happen
} ;
if ( SerialInertia = = ~ 0u )
2021-08-19 08:08:40 -04:00
{
2021-09-02 00:19:42 -04:00
SerialInertia = LowestSerial + InertiaBase ;
2021-08-19 08:08:40 -04:00
}
else
{
2021-09-02 00:19:42 -04:00
SerialInertia + = InertiaInc ;
if ( int32 ( SerialInertia ) > = 0 )
{
if ( SerialInertia = = LowestSerial )
{
SerialInertia = ~ 0u ;
Serial . Value = LowestSerial ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " New Serial.Value: %u (LowestSerial) " , Serial . Value ) ;
2021-09-02 00:19:42 -04:00
return OnData ( Reader , Context ) ;
}
SerialInertia = ~ 0u ;
}
2021-08-19 08:08:40 -04:00
}
}
}
2021-10-13 09:10:55 -04:00
return Reader . IsEmpty ( ) ? EStatus : : EndOfStream : EStatus : : NotEnoughData ;
2019-11-25 12:03:09 -05:00
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
int32 FProtocol2Stage : : OnData ( FStreamReader & Reader , FAnalysisBridge & Bridge )
2019-11-25 12:03:09 -05:00
{
2021-07-28 02:24:21 -04:00
auto & Serial = Bridge . GetSerial ( ) ;
2020-06-23 18:40:00 -04:00
while ( true )
2019-11-25 12:03:09 -05:00
{
2019-12-13 11:07:03 -05:00
auto Mark = Reader . SaveMark ( ) ;
const auto * Header = Reader . GetPointer < Protocol2 : : FEventHeader > ( ) ;
2019-11-25 12:03:09 -05:00
if ( Header = = nullptr )
{
break ;
}
2021-04-29 08:15:47 -04:00
uint32 Uid = uint32 ( Header - > Uid ) & uint32 ( Protocol2 : : EKnownEventUids : : UidMask ) ;
2021-07-28 02:24:21 -04:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Get ( Uid ) ;
if ( TypeInfo = = nullptr )
2019-11-25 12:03:09 -05:00
{
2020-06-23 18:40:00 -04:00
// Event-types may not to be discovered in Uid order.
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid TypeInfo for Uid %u (Tid=%u) " , Uid , Bridge . GetActiveThreadId ( ) ) ;
2020-06-23 18:40:00 -04:00
break ;
2019-11-25 12:03:09 -05:00
}
2019-12-13 11:07:03 -05:00
uint32 BlockSize = Header - > Size ;
2020-02-05 14:26:36 -05:00
// Make sure we consume events in the correct order
2021-07-28 02:24:21 -04:00
if ( ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_NoSync ) = = 0 )
2019-12-13 11:07:03 -05:00
{
2020-02-05 14:26:36 -05:00
switch ( ProtocolVersion )
{
2019-12-13 11:07:03 -05:00
case Protocol1 : : EProtocol : : Id :
{
const auto * HeaderV1 = ( Protocol1 : : FEventHeader * ) Header ;
2020-06-23 18:40:00 -04:00
if ( HeaderV1 - > Serial ! = ( Serial . Value & Serial . Mask ) )
2019-12-13 11:07:03 -05:00
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Tid=%u --> EventSerial=%u " , Bridge . GetActiveThreadId ( ) , HeaderV1 - > Serial ) ;
# endif
2020-06-23 18:40:00 -04:00
return HeaderV1 - > Serial ;
2019-12-13 11:07:03 -05:00
}
BlockSize + = sizeof ( * HeaderV1 ) ;
}
break ;
case Protocol2 : : EProtocol : : Id :
2020-06-23 18:40:00 -04:00
case Protocol3 : : EProtocol : : Id :
2019-12-13 11:07:03 -05:00
{
2020-02-05 14:26:36 -05:00
const auto * HeaderSync = ( Protocol2 : : FEventHeaderSync * ) Header ;
uint32 EventSerial = HeaderSync - > SerialLow | ( uint32 ( HeaderSync - > SerialHigh ) < < 16 ) ;
2020-06-23 18:40:00 -04:00
if ( EventSerial ! = ( Serial . Value & Serial . Mask ) )
2019-12-13 11:07:03 -05:00
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Tid=%u --> EventSerial=%u " , Bridge . GetActiveThreadId ( ) , EventSerial ) ;
# endif
2020-06-23 18:40:00 -04:00
return EventSerial ;
2019-12-13 11:07:03 -05:00
}
2020-02-05 14:26:36 -05:00
BlockSize + = sizeof ( * HeaderSync ) ;
2019-12-13 11:07:03 -05:00
}
break ;
2020-02-05 14:26:36 -05:00
}
}
else
{
BlockSize + = sizeof ( * Header ) ;
2019-12-13 11:07:03 -05:00
}
if ( Reader . GetPointer ( BlockSize ) = = nullptr )
{
break ;
}
Reader . Advance ( BlockSize ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
uint32 AuxSize = 0 ;
# endif
2019-12-13 11:07:03 -05:00
FAuxDataCollector AuxCollector ;
2021-07-28 02:24:21 -04:00
if ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_MaybeHasAux )
2019-12-13 11:07:03 -05:00
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
auto AuxMark = Reader . SaveMark ( ) ;
# endif
2021-07-28 02:24:21 -04:00
int AuxStatus = OnDataAux ( Reader , AuxCollector ) ;
2019-12-13 11:07:03 -05:00
if ( AuxStatus = = 0 )
{
Reader . RestoreMark ( Mark ) ;
break ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
AuxSize = uint32 ( UPTRINT ( Reader . SaveMark ( ) ) - UPTRINT ( AuxMark ) ) ;
# endif
2019-12-13 11:07:03 -05:00
}
2021-07-28 02:24:21 -04:00
if ( ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_NoSync ) = = 0 )
2020-02-05 14:26:36 -05:00
{
2020-06-23 18:40:00 -04:00
Serial . Value + = 1 ;
2021-08-19 08:08:40 -04:00
Serial . Value & = 0x3fffffff ; // Don't set MSBs. They have other uses
2020-02-05 14:26:36 -05:00
}
2019-11-25 12:03:09 -05:00
2021-07-29 08:58:34 -04:00
auto * EventData = ( const uint8 * ) Header + BlockSize - Header - > Size ;
if ( Uid = = uint32 ( Protocol2 : : EKnownEventUids : : NewEvent ) )
{
// There is no need to check size here as the runtime never builds
// packets that fragment new-event events.
2022-05-05 05:30:07 -04:00
TypeInfo = TypeRegistry . Add ( EventData , 0 ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Bridge . DebugLogNewEvent ( Uid , TypeInfo , uint32 ( UPTRINT ( Reader . SaveMark ( ) ) - UPTRINT ( Mark ) ) ) ;
# endif
2021-07-29 08:58:34 -04:00
Bridge . OnNewType ( TypeInfo ) ;
}
else
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
const uint32 EventSize = uint32 ( UPTRINT ( Reader . SaveMark ( ) ) - UPTRINT ( Mark ) ) ;
Bridge . DebugLogEvent ( TypeInfo , EventSize - AuxSize , AuxSize , Serial . Value - 1 ) ;
# endif
2021-07-29 08:58:34 -04:00
FEventDataInfo EventDataInfo = {
EventData ,
* TypeInfo ,
& AuxCollector ,
Header - > Size ,
} ;
Bridge . OnEvent ( EventDataInfo ) ;
}
2019-11-25 12:03:09 -05:00
}
2020-06-23 18:40:00 -04:00
return - 1 ;
2019-06-03 15:32:00 -04:00
}
2019-12-13 11:07:03 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
int32 FProtocol2Stage : : OnDataAux ( FStreamReader & Reader , FAuxDataCollector & Collector )
2019-12-13 11:07:03 -05:00
{
while ( true )
{
const uint8 * NextByte = Reader . GetPointer < uint8 > ( ) ;
if ( NextByte = = nullptr )
{
return 0 ;
}
// Is the following sequence a blob of auxilary data or the null
// terminator byte?
if ( NextByte [ 0 ] = = 0 )
{
Reader . Advance ( 1 ) ;
return 1 ;
}
// Get header and the auxilary blob's size
const auto * Header = Reader . GetPointer < Protocol1 : : FAuxHeader > ( ) ;
if ( Header = = nullptr )
{
return 0 ;
}
// Check it exists
uint32 BlockSize = ( Header - > Size > > 8 ) + sizeof ( * Header ) ;
if ( Reader . GetPointer ( BlockSize ) = = nullptr )
{
return 0 ;
}
// Attach to event
2022-09-13 06:42:08 -04:00
FAuxData AuxData = { } ;
2019-12-13 11:07:03 -05:00
AuxData . Data = Header - > Data ;
AuxData . DataSize = uint32 ( BlockSize - sizeof ( * Header ) ) ;
AuxData . FieldIndex = uint16 ( Header - > FieldIndex & Protocol1 : : FAuxHeader : : FieldMask ) ;
Collector . Push ( AuxData ) ;
Reader . Advance ( BlockSize ) ;
}
}
2021-07-28 02:24:21 -04:00
// {{{1 protocol-4 -------------------------------------------------------------
2020-01-13 07:16:09 -05:00
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
class FProtocol4Stage
: public FProtocol2Stage
{
public :
2023-10-31 04:07:11 -04:00
FProtocol4Stage ( uint32 Version , FTransport * InTransport ) ;
2021-07-28 02:24:21 -04:00
private :
2023-10-31 04:07:11 -04:00
virtual int32 OnData ( FStreamReader & Reader , FAnalysisBridge & Bridge ) override ;
int32 OnDataImpl ( FStreamReader & Reader , FAnalysisBridge & Bridge ) ;
int32 OnDataKnown ( uint32 Uid , FStreamReader & Reader , FAnalysisBridge & Bridge ) ;
2021-07-28 02:24:21 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
FProtocol4Stage : : FProtocol4Stage ( uint32 Version , FTransport * InTransport )
: FProtocol2Stage ( Version , InTransport )
{
}
////////////////////////////////////////////////////////////////////////////////
int32 FProtocol4Stage : : OnData ( FStreamReader & Reader , FAnalysisBridge & Bridge )
2020-01-13 07:16:09 -05:00
{
2020-06-23 18:40:00 -04:00
while ( true )
2020-01-13 07:16:09 -05:00
{
2021-07-28 02:24:21 -04:00
if ( int32 TriResult = OnDataImpl ( Reader , Bridge ) )
2020-06-23 18:40:00 -04:00
{
return ( TriResult < 0 ) ? ~ TriResult : - 1 ;
}
2020-01-13 07:16:09 -05:00
}
}
////////////////////////////////////////////////////////////////////////////////
2021-07-28 02:24:21 -04:00
int32 FProtocol4Stage : : OnDataImpl ( FStreamReader & Reader , FAnalysisBridge & Bridge )
2020-01-13 07:16:09 -05:00
{
2021-07-28 02:24:21 -04:00
auto & Serial = Bridge . GetSerial ( ) ;
2020-01-13 07:16:09 -05:00
2020-06-23 18:40:00 -04:00
/* Returns 0 if an event was successfully processed, 1 if there's not enough
* data available , or ~ AvailableLogSerial if the pending event is in the future */
auto Mark = Reader . SaveMark ( ) ;
const auto * UidCursor = Reader . GetPointer < uint8 > ( ) ;
if ( UidCursor = = nullptr )
{
return 1 ;
2020-01-13 07:16:09 -05:00
}
2020-06-23 18:40:00 -04:00
2021-08-06 04:14:50 -04:00
uint32 UidBytes = 1 + ! ! ( * UidCursor & Protocol4 : : EKnownEventUids : : Flag_TwoByteUid ) ;
2020-06-23 18:40:00 -04:00
if ( UidBytes > 1 & & Reader . GetPointer ( UidBytes ) = = nullptr )
{
return 1 ;
}
uint32 Uid = ~ 0u ;
switch ( UidBytes )
{
case 1 : Uid = * UidCursor ; break ;
case 2 : Uid = * ( uint16 * ) UidCursor ; break ;
}
2021-08-06 04:14:50 -04:00
Uid > > = Protocol4 : : EKnownEventUids : : _UidShift ;
2020-06-23 18:40:00 -04:00
2021-07-28 02:24:21 -04:00
if ( Uid < Bridge . GetUserUidBias ( ) )
2020-06-23 18:40:00 -04:00
{
Reader . Advance ( UidBytes ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
FAnalysisState & State = Bridge . GetState ( ) ;
State . TempUidBytes = UidBytes ;
# endif
2021-07-28 02:24:21 -04:00
if ( ! OnDataKnown ( Uid , Reader , Bridge ) )
2020-06-23 18:40:00 -04:00
{
Reader . RestoreMark ( Mark ) ;
return 1 ;
}
return 0 ;
}
// Do we know about this event type yet?
2021-07-28 02:24:21 -04:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Get ( Uid ) ;
if ( TypeInfo = = nullptr )
2020-06-23 18:40:00 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid TypeInfo for Uid %u (Tid=%u) " , Uid , Bridge . GetActiveThreadId ( ) ) ;
return 1 ;
}
if ( ! ensure ( UidBytes = = 2 ) ) // see Protocol4::FEventHeader
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid trace stream: Tid=%u Uid=%u encoded on 1 byte (instead of 2 bytes). " , Bridge . GetActiveThreadId ( ) , Uid ) ;
2020-06-23 18:40:00 -04:00
return 1 ;
}
// Parse the header
2021-08-06 04:14:50 -04:00
const auto * Header = Reader . GetPointer < Protocol4 : : FEventHeader > ( ) ;
2020-06-23 18:40:00 -04:00
if ( Header = = nullptr )
{
return 1 ;
}
uint32 BlockSize = Header - > Size ;
// Make sure we consume events in the correct order
2021-07-28 02:24:21 -04:00
if ( ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_NoSync ) = = 0 )
2020-06-23 18:40:00 -04:00
{
2021-08-06 04:14:50 -04:00
if ( Reader . GetPointer < Protocol4 : : FEventHeaderSync > ( ) = = nullptr )
2021-04-29 08:18:34 -04:00
{
return 1 ;
}
2023-01-25 04:26:15 -05:00
2021-08-06 04:14:50 -04:00
const auto * HeaderSync = ( Protocol4 : : FEventHeaderSync * ) Header ;
2020-06-23 18:40:00 -04:00
uint32 EventSerial = HeaderSync - > SerialLow | ( uint32 ( HeaderSync - > SerialHigh ) < < 16 ) ;
if ( EventSerial ! = ( Serial . Value & Serial . Mask ) )
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Tid=%u --> EventSerial=%u " , Bridge . GetActiveThreadId ( ) , EventSerial ) ;
# endif
2020-06-23 18:40:00 -04:00
return ~ EventSerial ;
}
BlockSize + = sizeof ( * HeaderSync ) ;
}
else
{
BlockSize + = sizeof ( * Header ) ;
}
// Is all the event's data available?
if ( Reader . GetPointer ( BlockSize ) = = nullptr )
{
return 1 ;
}
Reader . Advance ( BlockSize ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
uint32 AuxSize = 0 ;
# endif
2020-06-23 18:40:00 -04:00
// Collect auxiliary data
FAuxDataCollector AuxCollector ;
2021-07-28 02:24:21 -04:00
if ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_MaybeHasAux )
2020-06-23 18:40:00 -04:00
{
2020-10-26 03:29:23 -04:00
// Important events' size may include their array data so we need to backtrack
auto NextMark = Reader . SaveMark ( ) ;
2021-07-28 02:24:21 -04:00
if ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_Important )
2020-10-26 03:29:23 -04:00
{
Reader . RestoreMark ( Mark ) ;
2021-08-06 04:14:50 -04:00
Reader . Advance ( sizeof ( Protocol4 : : FEventHeader ) + TypeInfo - > EventSize ) ;
2020-10-26 03:29:23 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
auto AuxMark = Reader . SaveMark ( ) ;
# endif
2021-07-28 02:24:21 -04:00
int AuxStatus = OnDataAux ( Reader , AuxCollector ) ;
2020-06-23 18:40:00 -04:00
if ( AuxStatus = = 0 )
{
Reader . RestoreMark ( Mark ) ;
return 1 ;
}
2020-10-26 03:29:23 -04:00
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
AuxSize = uint32 ( UPTRINT ( Reader . SaveMark ( ) ) - UPTRINT ( AuxMark ) ) ;
# endif
2020-10-26 03:29:23 -04:00
// User error could have resulted in less space being used that was
// allocated for important events. So we can't assume that aux data
// reading has read all the way up to the next event. So we use marks
2021-07-28 02:24:21 -04:00
if ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_Important )
2020-10-26 03:29:23 -04:00
{
Reader . RestoreMark ( NextMark ) ;
}
2020-06-23 18:40:00 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
const uint32 EventSize = uint32 ( UPTRINT ( Reader . SaveMark ( ) ) - UPTRINT ( Mark ) ) ;
Bridge . DebugLogEvent ( TypeInfo , EventSize - AuxSize , AuxSize , Serial . Value ) ;
# endif
2020-06-23 18:40:00 -04:00
// Maintain sync
2021-07-28 02:24:21 -04:00
if ( ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_NoSync ) = = 0 )
2020-06-23 18:40:00 -04:00
{
Serial . Value + = 1 ;
Serial . Value & = 0x7fffffff ; // don't set msb. that has other uses
}
// Sent the event to subscribed analyzers
FEventDataInfo EventDataInfo = {
2021-01-10 16:18:43 -04:00
( const uint8 * ) Header + BlockSize - Header - > Size ,
2021-07-28 02:24:21 -04:00
* TypeInfo ,
2020-06-23 18:40:00 -04:00
& AuxCollector ,
Header - > Size ,
} ;
2021-07-28 02:24:21 -04:00
Bridge . OnEvent ( EventDataInfo ) ;
2020-06-23 18:40:00 -04:00
return 0 ;
2020-01-13 07:16:09 -05:00
}
2021-07-28 02:24:21 -04:00
////////////////////////////////////////////////////////////////////////////////
int32 FProtocol4Stage : : OnDataKnown (
uint32 Uid ,
FStreamReader & Reader ,
FAnalysisBridge & Bridge )
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
FAnalysisState & State = Bridge . GetState ( ) ;
# endif
2021-07-28 02:24:21 -04:00
switch ( Uid )
{
2021-08-06 04:14:50 -04:00
case Protocol4 : : EKnownEventUids : : NewEvent :
2021-07-28 02:24:21 -04:00
{
const auto * Size = Reader . GetPointer < uint16 > ( ) ;
2023-10-31 04:07:11 -04:00
check ( Size ! = nullptr ) ;
const void * EventTypeAndData = Reader . GetPointer ( sizeof ( * Size ) + * Size ) ;
check ( EventTypeAndData ! = nullptr ) ;
2022-05-05 05:30:07 -04:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Add ( Size + 1 , 4 ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Bridge . DebugLogNewEvent ( Uid , TypeInfo , uint32 ( State . TempUidBytes + sizeof ( * Size ) + * Size ) ) ;
# endif
2021-07-28 02:24:21 -04:00
Bridge . OnNewType ( TypeInfo ) ;
Reader . Advance ( sizeof ( * Size ) + * Size ) ;
}
2023-01-25 04:26:15 -05:00
return 1 ;
2021-07-28 02:24:21 -04:00
2021-08-06 04:14:50 -04:00
case Protocol4 : : EKnownEventUids : : EnterScope :
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Bridge . DebugLogEnterScopeEvent ( Uid , State . TempUidBytes ) ;
# endif
2023-01-25 04:26:15 -05:00
Bridge . EnterScope ( ) ;
2021-07-28 02:24:21 -04:00
return 1 ;
2021-08-06 04:14:50 -04:00
case Protocol4 : : EKnownEventUids : : LeaveScope :
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Bridge . DebugLogLeaveScopeEvent ( Uid , State . TempUidBytes ) ;
# endif
2023-01-25 04:26:15 -05:00
Bridge . LeaveScope ( ) ;
return 1 ;
case Protocol4 : : EKnownEventUids : : EnterScope_T :
2021-07-28 02:24:21 -04:00
{
const uint8 * Stamp = Reader . GetPointer ( sizeof ( uint64 ) - 1 ) ;
if ( Stamp = = nullptr )
{
2023-01-25 04:26:15 -05:00
return 0 ;
2021-07-28 02:24:21 -04:00
}
2023-01-25 04:26:15 -05:00
const uint64 RelativeTimestamp = * ( uint64 * ) ( Stamp - 1 ) > > 8 ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Bridge . DebugLogEnterScopeEvent ( Uid , RelativeTimestamp , uint32 ( State . TempUidBytes + sizeof ( uint64 ) - 1 ) ) ;
# endif
2023-01-25 04:26:15 -05:00
Bridge . EnterScope ( RelativeTimestamp ) ;
2021-07-28 02:24:21 -04:00
Reader . Advance ( sizeof ( uint64 ) - 1 ) ;
}
2023-01-25 04:26:15 -05:00
return 1 ;
case Protocol4 : : EKnownEventUids : : LeaveScope_T :
2021-07-28 02:24:21 -04:00
{
2023-01-25 04:26:15 -05:00
const uint8 * Stamp = Reader . GetPointer ( sizeof ( uint64 ) - 1 ) ;
if ( Stamp = = nullptr )
{
return 0 ;
}
const uint64 RelativeTimestamp = * ( uint64 * ) ( Stamp - 1 ) > > 8 ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Bridge . DebugLogLeaveScopeEvent ( Uid , RelativeTimestamp , uint32 ( State . TempUidBytes + sizeof ( uint64 ) - 1 ) ) ;
# endif
2023-01-25 04:26:15 -05:00
Bridge . LeaveScope ( RelativeTimestamp ) ;
Reader . Advance ( sizeof ( uint64 ) - 1 ) ;
2021-07-28 02:24:21 -04:00
}
return 1 ;
2023-01-25 04:26:15 -05:00
default :
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Cannot process known event %llu with Uid %u " , State . TotalEventCount , Uid ) ;
2023-01-25 04:26:15 -05:00
return 0 ;
} ;
2021-07-28 02:24:21 -04:00
}
2021-09-03 08:32:31 -04:00
// {{{1 protocol-5 -------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FProtocol5Stage
: public FAnalysisMachine : : FStage
{
public :
2023-10-31 04:07:11 -04:00
FProtocol5Stage ( FTransport * InTransport ) ;
virtual void ExitStage ( const FMachineContext & Context ) override ;
2021-09-03 08:32:31 -04:00
2022-05-05 05:30:07 -04:00
protected :
2021-09-03 08:32:31 -04:00
struct alignas ( 16 ) FEventDesc
{
2021-09-09 05:01:09 -04:00
union
{
struct
{
int32 Serial ;
2021-10-04 07:52:24 -04:00
uint16 Uid : 14 ;
uint16 bTwoByteUid : 1 ;
2021-09-09 05:01:09 -04:00
uint16 bHasAux : 1 ;
uint16 AuxKey ;
} ;
uint64 Meta = 0 ;
} ;
2021-10-06 02:20:31 -04:00
union
{
uint32 GapLength ;
2023-10-31 04:07:11 -04:00
const uint8 * Data = nullptr ;
2021-10-06 02:20:31 -04:00
} ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
uint32 EventSize = 0 ;
uint32 AuxSize = 0 ;
uint64 Reserved = 0 ;
# endif
2021-09-03 08:32:31 -04:00
} ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
static_assert ( sizeof ( FEventDesc ) = = 32 , " " ) ;
# else
2021-09-03 08:32:31 -04:00
static_assert ( sizeof ( FEventDesc ) = = 16 , " " ) ;
2023-10-31 04:07:11 -04:00
# endif
2021-09-03 08:32:31 -04:00
2021-10-04 08:37:25 -04:00
struct alignas ( 16 ) FEventDescStream
{
uint32 ThreadId ;
uint32 TransportIndex ;
union
{
uint32 ContainerIndex ;
const FEventDesc * EventDescs ;
} ;
2021-10-04 08:39:31 -04:00
2021-10-06 02:20:31 -04:00
enum { GapThreadId = ~ 0u } ;
2021-10-04 08:37:25 -04:00
} ;
static_assert ( sizeof ( FEventDescStream ) = = 16 , " " ) ;
2023-01-20 09:17:33 -05:00
struct FSerialDistancePredicate
{
bool operator ( ) ( const FEventDescStream & Lhs , const FEventDescStream & Rhs ) const
{
2023-07-31 04:33:40 -04:00
// Provided that less than approximately "SerialRange * BytesPerSerial"
// is buffered there should never be more that "SerialRange / 2" serial
// numbers. Thus if the distance between any two serial numbers is larger
// than half the serial space, they have wrapped.
2023-01-20 09:17:33 -05:00
uint32 Ld = Lhs . EventDescs - > Serial - Origin ;
uint32 Rd = Rhs . EventDescs - > Serial - Origin ;
return Ld < Rd ;
} ;
uint32 Origin ;
} ;
2023-01-25 04:26:15 -05:00
enum ESerial : int32
2021-09-03 08:32:31 -04:00
{
Bits = 24 ,
Mask = ( 1 < < Bits ) - 1 ,
Range = 1 < < Bits ,
Ignored = Range < < 2 , // far away so proper serials always compare less-than
Terminal ,
} ;
using EventDescArray = TArray < FEventDesc > ;
using EKnownUids = Protocol5 : : EKnownEventUids ;
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) override ;
2021-10-13 08:33:31 -04:00
EStatus OnDataNewEvents ( const FMachineContext & Context ) ;
2021-09-03 08:32:31 -04:00
EStatus OnDataImportant ( const FMachineContext & Context ) ;
EStatus OnDataNormal ( const FMachineContext & Context ) ;
2023-01-19 05:33:25 -05:00
int32 ParseImportantEvents ( FStreamReader & Reader , EventDescArray & OutEventDescs , const FMachineContext & Context ) ;
int32 ParseEvents ( FStreamReader & Reader , EventDescArray & OutEventDescs , const FMachineContext & Context ) ;
int32 ParseEventsWithAux ( FStreamReader & Reader , EventDescArray & OutEventDescs , const FMachineContext & Context ) ;
int32 ParseEvent ( FStreamReader & Reader , FEventDesc & OutEventDesc , const FMachineContext & Context ) ;
2023-01-25 04:26:15 -05:00
virtual void SetSizeIfKnownEvent ( uint32 Uid , uint32 & InOutEventSize ) ;
virtual bool DispatchKnownEvent ( const FMachineContext & Context , uint32 Uid , const FEventDesc * Cursor ) ;
2023-07-31 04:33:40 -04:00
int32 DispatchNormalEvents ( const FMachineContext & Context , TArray < FEventDescStream > & EventDescHeap ) ;
2023-01-19 05:33:25 -05:00
int32 DispatchEvents ( const FMachineContext & Context , TArray < FEventDescStream > & EventDescHeap ) ;
2023-07-31 04:33:40 -04:00
int32 DispatchEvents ( const FMachineContext & Context , const FEventDesc * EventDesc , uint32 Count ) ;
2021-10-06 02:20:31 -04:00
void DetectSerialGaps ( TArray < FEventDescStream > & EventDescHeap ) ;
2022-01-27 05:21:14 -05:00
template < typename Callback >
void ForEachSerialGap ( const TArray < FEventDescStream > & EventDescHeap , Callback & & InCallback ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
void PrintParsedEvent ( int EventIndex , const FEventDesc & EventDesc , int32 Size ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG
2023-01-25 04:26:15 -05:00
2021-09-03 08:32:31 -04:00
FTypeRegistry TypeRegistry ;
FTidPacketTransport & Transport ;
EventDescArray EventDescs ;
2021-10-06 02:20:31 -04:00
EventDescArray SerialGaps ;
2021-10-04 08:25:02 -04:00
uint32 NextSerial = ~ 0u ;
2023-10-31 04:07:11 -04:00
uint32 OldNextSerial = ~ 0u ;
uint32 NextSerialWaitCount = 0 ;
2021-10-06 02:20:31 -04:00
uint32 SyncCount ;
2022-05-05 05:30:07 -04:00
uint32 EventVersion = 4 ; //Protocol version 5 uses the event version from protocol 4
2023-07-31 04:33:40 -04:00
bool bSkipSerialError = false ;
2023-10-31 04:07:11 -04:00
bool bSkipSerial = false ;
2021-09-03 08:32:31 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
FProtocol5Stage : : FProtocol5Stage ( FTransport * InTransport )
: Transport ( * ( FTidPacketTransport * ) InTransport )
2021-10-06 02:20:31 -04:00
, SyncCount ( Transport . GetSyncCount ( ) )
2021-09-03 08:32:31 -04:00
{
EventDescs . Reserve ( 8 < < 10 ) ;
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol5Stage : : ExitStage ( const FMachineContext & Context )
{
// Ensure the transport does not have pending buffers (i.e. event data not yet processed).
if ( ! Transport . IsEmpty ( ) )
{
Context . EmitMessage ( EAnalysisMessageSeverity : : Warning , TEXT ( " Transport buffers are not empty at end of analysis (protocol 5)! " ) ) ;
}
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . GetSerial ( ) . Value = NextSerial ;
Transport . DebugEnd ( ) ;
# endif
}
2021-09-03 08:32:31 -04:00
////////////////////////////////////////////////////////////////////////////////
FProtocol5Stage : : EStatus FProtocol5Stage : : OnData (
FStreamReader & Reader ,
const FMachineContext & Context )
{
Transport . SetReader ( Reader ) ;
2023-02-09 05:19:47 -05:00
const FTidPacketTransport : : ETransportResult Result = Transport . Update ( ) ;
if ( Result = = FTidPacketTransport : : ETransportResult : : Error )
{
2023-06-19 07:17:37 -04:00
Context . EmitMessage (
EAnalysisMessageSeverity : : Error ,
TEXT ( " An error was detected in the transport layer, most likely due to a corrupt trace file. See log for details. " )
) ;
2023-02-09 05:19:47 -05:00
return EStatus : : Error ;
}
2021-09-03 08:32:31 -04:00
2023-10-31 04:07:11 -04:00
do
2021-10-13 08:33:31 -04:00
{
2023-10-31 04:07:11 -04:00
// New-events. They must be processed before anything else otherwise events
// can not be interpreted.
EStatus Ret = OnDataNewEvents ( Context ) ;
if ( Ret = = EStatus : : Error )
{
return Ret ;
}
2021-10-13 08:33:31 -04:00
2023-10-31 04:07:11 -04:00
// Important events
Ret = OnDataImportant ( Context ) ;
if ( Ret = = EStatus : : Error )
{
return Ret ;
}
bool bNotEnoughData = ( Ret = = EStatus : : NotEnoughData ) ;
2021-09-03 08:32:31 -04:00
2023-10-31 04:07:11 -04:00
// Normal events
Ret = OnDataNormal ( Context ) ;
if ( Ret = = EStatus : : Error )
{
return Ret ;
}
if ( Ret = = EStatus : : Sync )
{
// After processing a SYNC packet, we need to read data once more.
return OnData ( Reader , Context ) ;
}
bNotEnoughData | = ( Ret = = EStatus : : NotEnoughData ) ;
2021-10-04 08:49:19 -04:00
2023-10-31 04:07:11 -04:00
if ( bNotEnoughData & & ! bSkipSerial )
{
return EStatus : : NotEnoughData ;
}
2021-11-09 03:51:41 -05:00
}
2023-10-31 04:07:11 -04:00
while ( bSkipSerial ) ;
2021-11-09 03:51:41 -05:00
2021-11-23 09:34:58 -05:00
return Reader . CanMeetDemand ( ) ? EStatus : : Continue : EStatus : : EndOfStream ;
2021-09-03 08:32:31 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2021-10-13 08:33:31 -04:00
FProtocol5Stage : : EStatus FProtocol5Stage : : OnDataNewEvents ( const FMachineContext & Context )
2021-09-03 08:32:31 -04:00
{
EventDescs . Reset ( ) ;
2021-10-13 08:33:31 -04:00
FStreamReader * ThreadReader = Transport . GetThreadStream ( ETransportTid : : Events ) ;
if ( ThreadReader - > IsEmpty ( ) )
2021-09-03 08:32:31 -04:00
{
2021-10-13 09:10:55 -04:00
return EStatus : : EndOfStream ;
2021-09-03 08:32:31 -04:00
}
2023-01-19 05:33:25 -05:00
if ( ParseImportantEvents ( * ThreadReader , EventDescs , Context ) < 0 )
2021-09-03 08:32:31 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to parse important events " ) ;
2021-10-13 08:33:31 -04:00
return EStatus : : Error ;
}
2021-09-03 08:32:31 -04:00
2021-10-13 08:33:31 -04:00
for ( const FEventDesc & EventDesc : EventDescs )
{
2022-05-05 05:30:07 -04:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Add ( EventDesc . Data , EventVersion ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogNewEvent ( uint32 ( EventDesc . Uid ) , TypeInfo , EventDesc . EventSize + EventDesc . AuxSize ) ;
# endif
2021-09-03 08:32:31 -04:00
Context . Bridge . OnNewType ( TypeInfo ) ;
}
2021-10-13 09:10:55 -04:00
return EStatus : : EndOfStream ;
2021-10-13 08:33:31 -04:00
}
////////////////////////////////////////////////////////////////////////////////
FProtocol5Stage : : EStatus FProtocol5Stage : : OnDataImportant ( const FMachineContext & Context )
{
static_assert ( ETransportTid : : Importants = = ETransportTid : : Internal , " It is assumed there is only one 'important' thread stream " ) ;
EventDescs . Reset ( ) ;
FStreamReader * ThreadReader = Transport . GetThreadStream ( ETransportTid : : Importants ) ;
if ( ThreadReader - > IsEmpty ( ) )
{
2021-10-13 09:10:55 -04:00
return EStatus : : EndOfStream ;
2021-10-13 08:33:31 -04:00
}
2023-01-19 05:33:25 -05:00
if ( ParseImportantEvents ( * ThreadReader , EventDescs , Context ) < 0 )
2021-10-13 08:33:31 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to parse important events " ) ;
2021-10-13 08:33:31 -04:00
return EStatus : : Error ;
}
bool bNotEnoughData = ! ThreadReader - > IsEmpty ( ) ;
2021-09-03 08:32:31 -04:00
if ( EventDescs . Num ( ) < = 0 )
{
2021-10-13 09:10:55 -04:00
return bNotEnoughData ? EStatus : : NotEnoughData : EStatus : : EndOfStream ;
2021-09-03 08:32:31 -04:00
}
// Dispatch looks ahead to the next desc looking for runs of aux blobs. As
// such we should add a terminal desc for it to read. Note the "- 1" too.
FEventDesc & EventDesc = EventDescs . Emplace_GetRef ( ) ;
EventDesc . Serial = ESerial : : Terminal ;
Context . Bridge . SetActiveThread ( ETransportTid : : Importants ) ;
2023-01-19 05:33:25 -05:00
if ( DispatchEvents ( Context , EventDescs . GetData ( ) , EventDescs . Num ( ) - 1 ) < 0 )
2021-09-03 08:32:31 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to dispatch important events " ) ;
2021-09-03 08:32:31 -04:00
return EStatus : : Error ;
}
2021-10-13 09:10:55 -04:00
return bNotEnoughData ? EStatus : : NotEnoughData : EStatus : : EndOfStream ;
2021-09-03 08:32:31 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2023-01-19 05:33:25 -05:00
int32 FProtocol5Stage : : ParseImportantEvents ( FStreamReader & Reader , EventDescArray & OutEventDescs , const FMachineContext & Context )
2021-09-03 08:32:31 -04:00
{
using namespace Protocol5 ;
while ( true )
{
2023-10-31 04:07:11 -04:00
uint32 Remaining = Reader . GetRemaining ( ) ;
2021-09-03 08:32:31 -04:00
if ( Remaining < sizeof ( FImportantEventHeader ) )
{
return 1 ;
}
const auto * Header = Reader . GetPointerUnchecked < FImportantEventHeader > ( ) ;
2023-10-31 04:07:11 -04:00
if ( Remaining < uint32 ( Header - > Size ) + sizeof ( FImportantEventHeader ) )
2021-09-03 08:32:31 -04:00
{
return 1 ;
}
uint32 Uid = Header - > Uid ;
FEventDesc EventDesc ;
2021-09-09 05:01:09 -04:00
EventDesc . Serial = ESerial : : Ignored ;
2023-09-29 07:22:52 -04:00
EventDesc . Uid = ( uint16 ) Uid ;
2021-09-03 08:32:31 -04:00
EventDesc . Data = Header - > Data ;
// Special case for new events. It would work to add a 0 type to the
// registry but this way avoid raveling things together.
if ( Uid = = EKnownUids : : NewEvent )
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
EventDesc . EventSize = sizeof ( * Header ) + Header - > Size ;
# endif
2021-09-03 08:32:31 -04:00
OutEventDescs . Add ( EventDesc ) ;
Reader . Advance ( sizeof ( * Header ) + Header - > Size ) ;
continue ;
}
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Get ( Uid ) ;
if ( TypeInfo = = nullptr )
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " UID %u (0x%X) was not declared yet. " , Uid , Uid ) ;
2021-09-03 08:32:31 -04:00
return 1 ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
EventDesc . EventSize = sizeof ( * Header ) + TypeInfo - > EventSize ;
# endif
2021-09-09 05:01:09 -04:00
if ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_MaybeHasAux )
{
EventDesc . bHasAux = 1 ;
}
2021-09-03 08:32:31 -04:00
OutEventDescs . Add ( EventDesc ) ;
if ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_MaybeHasAux )
{
const uint8 * Cursor = Header - > Data + TypeInfo - > EventSize ;
const uint8 * End = Header - > Data + Header - > Size ;
while ( Cursor < = End )
{
if ( Cursor [ 0 ] = = uint8 ( EKnownUids : : AuxDataTerminal ) )
{
break ;
}
const auto * AuxHeader = ( FAuxHeader * ) Cursor ;
FEventDesc & AuxDesc = OutEventDescs . Emplace_GetRef ( ) ;
AuxDesc . Uid = uint8 ( EKnownUids : : AuxData ) ;
AuxDesc . Data = AuxHeader - > Data ;
2021-09-27 08:02:04 -04:00
AuxDesc . Serial = ESerial : : Ignored ;
2021-09-03 08:32:31 -04:00
Cursor = AuxHeader - > Data + ( AuxHeader - > Pack > > FAuxHeader : : SizeShift ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
AuxDesc . EventSize = sizeof ( FAuxHeader ) ;
AuxDesc . AuxSize = ( AuxHeader - > Pack > > FAuxHeader : : SizeShift ) ;
# endif
2021-09-03 08:32:31 -04:00
}
if ( Cursor [ 0 ] ! = uint8 ( EKnownUids : : AuxDataTerminal ) )
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Expecting AuxDataTerminal event " ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessage ( EAnalysisMessageSeverity : : Warning , TEXT ( " Expected an aux data terminal in the stream. " ) ) ;
2021-09-03 08:32:31 -04:00
return - 1 ;
}
}
Reader . Advance ( sizeof ( * Header ) + Header - > Size ) ;
}
return 0 ;
}
////////////////////////////////////////////////////////////////////////////////
FProtocol5Stage : : EStatus FProtocol5Stage : : OnDataNormal ( const FMachineContext & Context )
{
// Ordinary events
EventDescs . Reset ( ) ;
bool bNotEnoughData = false ;
TArray < FEventDescStream > EventDescHeap ;
EventDescHeap . Reserve ( Transport . GetThreadCount ( ) ) ;
2023-10-31 04:07:11 -04:00
bSkipSerial = false ;
2023-07-31 04:33:40 -04:00
2021-09-03 08:32:31 -04:00
for ( uint32 i = ETransportTid : : Bias , n = Transport . GetThreadCount ( ) ; i < n ; + + i )
{
uint32 NumEventDescs = EventDescs . Num ( ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 3
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Thread:%u Id:%u " , i , Transport . GetThreadId ( i ) ) ;
# endif
2023-01-25 04:26:15 -05:00
2021-09-03 08:32:31 -04:00
// Extract all the events in the stream for this thread
FStreamReader * ThreadReader = Transport . GetThreadStream ( i ) ;
2022-12-14 06:13:07 -05:00
2023-10-31 04:07:11 -04:00
// Test if analysis has accumulated too much data for this thread.
2022-12-14 06:13:07 -05:00
// This can happen on corrupted traces (ex. with serial sync events missing or out of order).
2023-10-31 04:07:11 -04:00
constexpr uint32 MaxAccumulatedBytes = 2'000'000'000u ;
2023-06-19 07:17:37 -04:00
if ( ThreadReader - > GetRemaining ( ) > MaxAccumulatedBytes )
2022-12-14 06:13:07 -05:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Trace analysis accumulated too much data (%.2f MiB on thread %u) and will start to skip the missing serial sync events! " ,
( double ) ThreadReader - > GetRemaining ( ) / ( 1024.0 * 1024.0 ) ,
Transport . GetThreadId ( i ) ) ;
2023-07-31 04:33:40 -04:00
if ( ! bSkipSerialError )
{
bSkipSerialError = true ;
Context . EmitMessagef (
EAnalysisMessageSeverity : : Error ,
2023-10-31 04:07:11 -04:00
TEXT ( " Trace analysis accumulated too much data (%.2f MiB on thread %u) and will start to skip the missing serial sync events! " ) ,
( double ) ThreadReader - > GetRemaining ( ) / ( 1024.0 * 1024.0 ) ,
2023-07-31 04:33:40 -04:00
Transport . GetThreadId ( i )
) ;
}
bSkipSerial = true ;
2022-12-14 06:13:07 -05:00
}
2023-01-19 05:33:25 -05:00
if ( ParseEvents ( * ThreadReader , EventDescs , Context ) < 0 )
2021-09-03 08:32:31 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to parse events " ) ;
2021-09-03 08:32:31 -04:00
return EStatus : : Error ;
}
bNotEnoughData | = ! ThreadReader - > IsEmpty ( ) ;
if ( uint32 ( EventDescs . Num ( ) ) ! = NumEventDescs )
{
// Add a dummy event to delineate the end of this thread's events
FEventDesc & EventDesc = EventDescs . Emplace_GetRef ( ) ;
EventDesc . Serial = ESerial : : Terminal ;
2021-09-27 08:45:43 -04:00
FEventDescStream Out ;
Out . ThreadId = Transport . GetThreadId ( i ) ;
Out . TransportIndex = i ;
2021-10-04 08:34:45 -04:00
Out . ContainerIndex = NumEventDescs ;
2021-09-27 08:45:43 -04:00
EventDescHeap . Add ( Out ) ;
2021-09-03 08:32:31 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 3
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Thread:%u bNotEnoughData:%d " , i , bNotEnoughData ) ;
# endif
2021-09-03 08:32:31 -04:00
}
// Now EventDescs is stable we can convert the indices into pointers
for ( FEventDescStream & Stream : EventDescHeap )
{
2021-10-04 08:34:45 -04:00
Stream . EventDescs = EventDescs . GetData ( ) + Stream . ContainerIndex ;
2021-09-03 08:32:31 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
FAnalysisState & State = Context . Bridge . GetState ( ) ;
if ( EventDescs . Num ( ) > State . MaxEventDescs )
{
State . MaxEventDescs = EventDescs . Num ( ) ;
}
# endif
2023-07-31 04:33:40 -04:00
const bool bSync = ( SyncCount ! = Transport . GetSyncCount ( ) ) ;
2023-10-31 04:07:11 -04:00
int32 NumAvailableEvents = EventDescs . Num ( ) ;
// Try to dispatch the parsed events.
2023-07-31 04:33:40 -04:00
{
int32 NumDispatchedEvents = DispatchNormalEvents ( Context , EventDescHeap ) ;
if ( NumDispatchedEvents < 0 )
{
return EStatus : : Error ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Dispatched %d normal events (%d --> %d) " , NumDispatchedEvents , NumAvailableEvents , NumAvailableEvents - NumDispatchedEvents ) ;
# endif
NumAvailableEvents - = NumDispatchedEvents ;
check ( NumAvailableEvents > = 0 ) ;
// Count how many times we dispatched events, but without dispatching any "sync" event.
if ( OldNextSerial = = NextSerial )
2023-07-31 04:33:40 -04:00
{
2023-10-31 04:07:11 -04:00
+ + NextSerialWaitCount ;
2023-07-31 04:33:40 -04:00
}
2023-10-31 04:07:11 -04:00
else
{
OldNextSerial = NextSerial ;
NextSerialWaitCount = 0 ;
}
}
// Test if analysis has accumulated too much data (parsed events not dispatched yet).
// But, only enforce the limit after we have received at least one SYNC package
// (e.g. server traces can accumulate large amounts of data before first SYNC event).
2024-01-22 09:24:24 -05:00
constexpr int32 MaxAvailableEventsHighLimit = 90'000'000 ;
constexpr int32 MaxAvailableEventsLowLimit = 50'000'000 ;
2023-10-31 04:07:11 -04:00
constexpr uint32 MaxNextSerialWaitCount = 20 ;
2024-01-22 09:24:24 -05:00
bool bSkipSerialNow = false ;
2023-10-31 04:07:11 -04:00
if ( SyncCount > 0 & &
2024-01-22 09:24:24 -05:00
! bSkipSerialError & &
NumAvailableEvents > MaxAvailableEventsHighLimit & &
2023-10-31 04:07:11 -04:00
NextSerialWaitCount > MaxNextSerialWaitCount )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Trace analysis accumulated too much data (%d parsed events) and will start to skip the missing serial sync events! " , NumAvailableEvents ) ;
if ( ! bSkipSerialError )
{
bSkipSerialError = true ;
Context . EmitMessagef (
EAnalysisMessageSeverity : : Error ,
TEXT ( " Trace analysis accumulated too much data (%d parsed events) and will start to skip the missing serial sync events! " ) , NumAvailableEvents ) ;
}
2024-01-22 09:24:24 -05:00
bSkipSerialNow = true ;
}
if ( bSkipSerialNow | |
( bSkipSerialError & & NumAvailableEvents > MaxAvailableEventsLowLimit ) )
{
do
2023-10-31 04:07:11 -04:00
{
2024-01-22 09:24:24 -05:00
// Skip serials and continue to dispatch parsed events.
bSkipSerial = true ;
NextSerialWaitCount = 0 ;
int32 NumDispatchedEvents = DispatchNormalEvents ( Context , EventDescHeap ) ;
if ( NumDispatchedEvents < 0 )
{
return EStatus : : Error ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
2024-01-22 09:24:24 -05:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Skipped serials and dispatched %d normal events (%d --> %d) " , NumDispatchedEvents , NumAvailableEvents , NumAvailableEvents - NumDispatchedEvents ) ;
2023-10-31 04:07:11 -04:00
# endif
2024-01-22 09:24:24 -05:00
NumAvailableEvents - = NumDispatchedEvents ;
check ( NumAvailableEvents > = 0 ) ;
}
while ( NumAvailableEvents > MaxAvailableEventsLowLimit ) ;
2023-07-31 04:33:40 -04:00
}
// If there are any streams left in the heap then we are unable to proceed
// until more data is received. We'll rewind the streams until more data is
// available. It is not an efficient way to do things, but it is simple way.
for ( FEventDescStream & Stream : EventDescHeap )
{
const FEventDesc & EventDesc = Stream . EventDescs [ 0 ] ;
uint32 HeaderSize = 1 + EventDesc . bTwoByteUid + ( ESerial : : Bits / 8 ) ;
FStreamReader * Reader = Transport . GetThreadStream ( Stream . TransportIndex ) ;
Reader - > Backtrack ( EventDesc . Data - HeaderSize ) ;
}
if ( bSync & & SyncCount = = Transport . GetSyncCount ( ) )
{
return EStatus : : Sync ;
}
if ( bNotEnoughData )
{
return EStatus : : NotEnoughData ;
}
return EStatus : : EndOfStream ;
}
////////////////////////////////////////////////////////////////////////////////
int32 FProtocol5Stage : : DispatchNormalEvents ( const FMachineContext & Context , TArray < FEventDescStream > & EventDescHeap )
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Queued event descs: %d " , EventDescs . Num ( ) ) ;
# endif
2023-07-31 04:33:40 -04:00
int32 NumDispatchedUnsyncEvents = 0 ;
2023-10-31 04:07:11 -04:00
// Process leading unsynchronized events so that each stream starts with a synchronized event.
2021-09-27 07:58:46 -04:00
for ( FEventDescStream & Stream : EventDescHeap )
{
2023-10-31 04:07:11 -04:00
// Extract a run of consecutive unsynchronized events
2021-09-27 07:58:46 -04:00
const FEventDesc * EndDesc = Stream . EventDescs ;
for ( ; EndDesc - > Serial = = ESerial : : Ignored ; + + EndDesc ) ;
// Dispatch.
const FEventDesc * StartDesc = Stream . EventDescs ;
int32 DescNum = int32 ( UPTRINT ( EndDesc - StartDesc ) ) ;
if ( DescNum > 0 )
{
2023-07-31 04:33:40 -04:00
NumDispatchedUnsyncEvents + = DescNum ;
2021-09-27 07:58:46 -04:00
Context . Bridge . SetActiveThread ( Stream . ThreadId ) ;
2023-01-19 05:33:25 -05:00
if ( DispatchEvents ( Context , StartDesc , DescNum ) < 0 )
2021-09-27 07:58:46 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to dispatch events " ) ;
2023-07-31 04:33:40 -04:00
return - 1 ;
2021-09-27 07:58:46 -04:00
}
Stream . EventDescs = EndDesc ;
}
}
// Trim off empty streams
EventDescHeap . RemoveAllSwap ( [ ] ( const FEventDescStream & Stream )
{
return ( Stream . EventDescs - > Serial = = ESerial : : Terminal ) ;
} ) ;
// Early out if there isn't any events available.
if ( UNLIKELY ( EventDescHeap . IsEmpty ( ) ) )
{
2023-07-31 04:33:40 -04:00
return NumDispatchedUnsyncEvents ;
2021-09-27 07:58:46 -04:00
}
2021-09-03 08:32:31 -04:00
// A min-heap is used to peel off groups of events by lowest serial
2023-01-20 09:17:33 -05:00
EventDescHeap . Heapify ( FSerialDistancePredicate { NextSerial } ) ;
2021-09-03 08:32:31 -04:00
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
2021-10-04 08:25:02 -04:00
{
2023-10-31 04:07:11 -04:00
const FEventDescStream & TopStream = EventDescHeap . HeapTop ( ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " NextSerial=%u LowestSerial=%d (Tid=%u) " , NextSerial , TopStream . EventDescs [ 0 ] . Serial , TopStream . ThreadId ) ;
}
# endif
// Events must be consumed contiguously.
if ( bSkipSerial )
{
uint32 LowestSerial = EventDescHeap . HeapTop ( ) . EventDescs [ 0 ] . Serial ;
if ( LowestSerial ! = NextSerial )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Warning: NextSerial skips %lld events (from %u to %u) " , ( int64 ) LowestSerial - ( int64 ) NextSerial , NextSerial , LowestSerial ) ;
NextSerial = LowestSerial ;
}
}
else
if ( NextSerial = = ~ 0u )
{
uint32 LowestSerial = EventDescHeap . HeapTop ( ) . EventDescs [ 0 ] . Serial ;
if ( Transport . GetSyncCount ( ) | | LowestSerial = = 0 )
{
NextSerial = LowestSerial ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " NextSerial=%u " , NextSerial ) ;
}
2021-10-04 08:25:02 -04:00
}
2021-10-06 02:20:31 -04:00
DetectSerialGaps ( EventDescHeap ) ;
2023-07-31 04:33:40 -04:00
int32 NumDispatchedEvents = DispatchEvents ( Context , EventDescHeap ) ;
if ( NumDispatchedEvents < 0 )
2021-10-04 08:46:40 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to dispatch events " ) ;
2023-07-31 04:33:40 -04:00
return - 1 ;
2021-10-04 08:46:40 -04:00
}
2023-07-31 04:33:40 -04:00
return NumDispatchedUnsyncEvents + NumDispatchedEvents ;
2021-10-04 08:46:40 -04:00
}
////////////////////////////////////////////////////////////////////////////////
int32 FProtocol5Stage : : DispatchEvents (
2023-01-19 05:33:25 -05:00
const FMachineContext & Context ,
2021-10-04 08:46:40 -04:00
TArray < FEventDescStream > & EventDescHeap )
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
FAnalysisState & State = Context . Bridge . GetState ( ) ;
# endif
2021-10-04 08:59:13 -04:00
auto UpdateHeap = [ & ] ( const FEventDescStream & Stream , const FEventDesc * EventDesc )
{
if ( EventDesc - > Serial ! = ESerial : : Terminal )
{
FEventDescStream Next = Stream ;
Next . EventDescs = EventDesc ;
EventDescHeap . Add ( Next ) ;
}
2024-01-19 16:41:35 -05:00
EventDescHeap . HeapPopDiscard ( FSerialDistancePredicate { NextSerial } , EAllowShrinking : : No ) ;
2021-10-04 08:59:13 -04:00
} ;
2023-07-31 04:33:40 -04:00
int32 NumDispatchedEvents = 0 ;
2021-09-03 08:32:31 -04:00
do
{
const FEventDescStream & Stream = EventDescHeap . HeapTop ( ) ;
const FEventDesc * StartDesc = Stream . EventDescs ;
const FEventDesc * EndDesc = StartDesc ;
2021-10-06 02:20:31 -04:00
// DetectSerialGaps() will add a special stream that communicates gaps
2023-01-25 04:26:15 -05:00
// in serial numbers, gaps that will never be resolved. Thread IDs
2021-10-06 02:20:31 -04:00
// are uint16 everywhere else so they will never collide with GapThreadId.
if ( Stream . ThreadId = = FEventDescStream : : GapThreadId )
{
NextSerial = EndDesc - > Serial + EndDesc - > GapLength ;
NextSerial & = ESerial : : Mask ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
if ( NextSerial ! = EndDesc - > Serial + EndDesc - > GapLength )
{
State . SerialWrappedCount + + ;
}
State . NumSkippedSerialGaps + + ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Skip serial gap (%u +%u) --> NextSerial=%u " , EndDesc - > Serial , EndDesc - > GapLength , NextSerial ) ;
# endif
2021-10-06 02:20:31 -04:00
UpdateHeap ( Stream , EndDesc + 1 ) ;
continue ;
}
2021-09-03 08:32:31 -04:00
2023-10-31 04:07:11 -04:00
// Extract a run of consecutive events (plus runs of unsynchronized ones).
2021-10-04 08:25:02 -04:00
if ( EndDesc - > Serial = = NextSerial )
2021-09-03 08:32:31 -04:00
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
const uint32 CurrentSerial = NextSerial ;
# endif
2021-09-03 08:32:31 -04:00
do
{
2021-10-04 09:04:24 -04:00
NextSerial = ( NextSerial + 1 ) & ESerial : : Mask ;
2021-10-04 08:25:02 -04:00
2021-09-03 08:32:31 -04:00
do
{
+ + EndDesc ;
}
while ( EndDesc - > Serial = = ESerial : : Ignored ) ;
}
while ( EndDesc - > Serial = = NextSerial ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
if ( NextSerial < CurrentSerial )
{
+ + State . SerialWrappedCount ;
}
# endif
2021-09-03 08:32:31 -04:00
}
2021-10-04 08:25:02 -04:00
else
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
if ( uint32 ( EndDesc - > Serial ) < NextSerial & &
NextSerial ! = ~ 0u & &
NextSerial - uint32 ( EndDesc - > Serial ) < ESerial : : Range / 2 )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Lowest serial %d (Tid=%u Uid=%u) is too low (NextSerial=%u; %d event descs) !!! " , EndDesc - > Serial , Stream . ThreadId , uint32 ( EndDesc - > Uid ) , NextSerial , EventDescs . Num ( ) ) ;
}
else
{
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Lowest serial %d (Tid=%u Uid=%u) is not low enough (NextSerial=%u; %d event descs) " , EndDesc - > Serial , Stream . ThreadId , uint32 ( EndDesc - > Uid ) , NextSerial , EventDescs . Num ( ) ) ;
# endif
}
# if UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Available streams (SerialWrappedCount=%u): " , State . SerialWrappedCount ) ;
for ( const FEventDescStream & EventDescStream : EventDescHeap )
{
uint32 BufferSize = 0 ;
uint32 DataSize = 0 ;
FTidPacketTransport * InnerTransport = ( FTidPacketTransport * ) ( & Transport ) ;
for ( uint32 i = 0 , n = InnerTransport - > GetThreadCount ( ) ; i < n ; + + i )
{
FStreamBuffer * ThreadReader = ( FStreamBuffer * ) InnerTransport - > GetThreadStream ( i ) ;
uint32 ThreadId = InnerTransport - > GetThreadId ( i ) ;
if ( ThreadId = = EventDescStream . ThreadId )
{
BufferSize = ThreadReader - > GetBufferSize ( ) ;
DataSize = ThreadReader - > GetRemaining ( ) ;
}
}
if ( EventDescStream . EventDescs - > Serial = = NextSerial )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Tid=%u : Serial=%u BufferSize=%u DataSize=%u (next) " , EventDescStream . ThreadId , EventDescStream . EventDescs - > Serial , BufferSize , DataSize ) ;
}
else
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Tid=%u : Serial=%u BufferSize=%u DataSize=%u " , EventDescStream . ThreadId , EventDescStream . EventDescs - > Serial , BufferSize , DataSize ) ;
}
}
# endif // UE_TRACE_ANALYSIS_DEBUG_LEVEL
# endif // UE_TRACE_ANALYSIS_DEBUG
#if 0
int32 MinSerial = EndDesc - > Serial ;
EventDescHeap . Heapify ( ) ;
const FEventDescStream & MinStream = EventDescHeap . HeapTop ( ) ;
const FEventDesc * MinDesc = MinStream . EventDescs ;
if ( MinDesc - > Serial < MinSerial )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Try one more time with lowest serial %d (Tid=%u Uid=%u) " , MinDesc - > Serial , MinStream . ThreadId , uint32 ( MinDesc - > Uid ) ) ;
continue ;
}
# endif
// The lowest known serial number is not low enough so we are unable to proceed any further.
2021-10-04 08:25:02 -04:00
break ;
}
2021-09-03 08:32:31 -04:00
// Dispatch.
2023-01-19 05:33:25 -05:00
Context . Bridge . SetActiveThread ( Stream . ThreadId ) ;
2021-09-03 08:32:31 -04:00
int32 DescNum = int32 ( UPTRINT ( EndDesc - StartDesc ) ) ;
check ( DescNum > 0 ) ;
2023-07-31 04:33:40 -04:00
NumDispatchedEvents + = DescNum ;
2023-01-19 05:33:25 -05:00
if ( DispatchEvents ( Context , StartDesc , DescNum ) < 0 )
2021-09-03 08:32:31 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Failed to dispatch events " ) ;
2021-10-04 08:46:40 -04:00
return - 1 ;
2021-09-03 08:32:31 -04:00
}
2021-10-04 08:59:13 -04:00
UpdateHeap ( Stream , EndDesc ) ;
2021-09-03 08:32:31 -04:00
}
while ( ! EventDescHeap . IsEmpty ( ) ) ;
2023-07-31 04:33:40 -04:00
return NumDispatchedEvents ;
2021-09-03 08:32:31 -04:00
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
# if UE_TRACE_ANALYSIS_DEBUG
void FProtocol5Stage : : PrintParsedEvent ( int EventIndex , const FEventDesc & EventDesc , int32 Size )
{
UE_TRACE_ANALYSIS_DEBUG_BeginStringBuilder ( ) ;
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Event=%-6d Uid=%-4u " , EventIndex , uint32 ( EventDesc . Uid ) ) ;
if ( EventDesc . Serial > = ESerial : : Range )
{
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Serial=0x%07X " , EventDesc . Serial ) ;
}
else
{
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Serial=%-9d " , EventDesc . Serial ) ;
}
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Size=%d " , Size ) ;
if ( EventDesc . bHasAux )
{
UE_TRACE_ANALYSIS_DEBUG_Append ( " aux " ) ;
}
if ( EventDesc . Uid = = EKnownUids : : AuxData )
{
UE_TRACE_ANALYSIS_DEBUG_Append ( " data " ) ;
}
else if ( EventDesc . Uid = = EKnownUids : : AuxDataTerminal )
{
UE_TRACE_ANALYSIS_DEBUG_Append ( " end " ) ;
}
UE_TRACE_ANALYSIS_DEBUG_EndStringBuilder ( ) ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-09-03 08:32:31 -04:00
////////////////////////////////////////////////////////////////////////////////
2023-01-19 05:33:25 -05:00
int32 FProtocol5Stage : : ParseEvents ( FStreamReader & Reader , EventDescArray & OutEventDescs , const FMachineContext & Context )
2021-09-03 08:32:31 -04:00
{
while ( ! Reader . IsEmpty ( ) )
{
FEventDesc EventDesc ;
2023-10-31 04:07:11 -04:00
2023-01-19 05:33:25 -05:00
int32 Size = ParseEvent ( Reader , EventDesc , Context ) ;
2021-09-03 08:32:31 -04:00
if ( Size < = 0 )
{
return Size ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 3
PrintParsedEvent ( OutEventDescs . Num ( ) , EventDesc , Size ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-09-03 08:32:31 -04:00
OutEventDescs . Add ( EventDesc ) ;
if ( EventDesc . bHasAux )
{
uint32 RewindDescsNum = OutEventDescs . Num ( ) - 1 ;
auto RewindMark = Reader . SaveMark ( ) ;
Reader . Advance ( Size ) ;
2023-01-19 05:33:25 -05:00
int Ok = ParseEventsWithAux ( Reader , OutEventDescs , Context ) ;
2021-09-03 08:32:31 -04:00
if ( Ok < 0 )
{
return Ok ;
}
if ( Ok = = 0 )
{
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Warning: Incomplete aux stack! Rewind %d parsed events. " , OutEventDescs . Num ( ) - RewindDescsNum ) ;
# endif
2021-09-03 08:32:31 -04:00
OutEventDescs . SetNum ( RewindDescsNum ) ;
Reader . RestoreMark ( RewindMark ) ;
break ;
}
continue ;
}
Reader . Advance ( Size ) ;
}
return 0 ;
}
////////////////////////////////////////////////////////////////////////////////
2023-01-19 05:33:25 -05:00
int32 FProtocol5Stage : : ParseEventsWithAux ( FStreamReader & Reader , EventDescArray & OutEventDescs , const FMachineContext & Context )
2021-09-03 08:32:31 -04:00
{
// We are now "in" the scope of an event with zero or more aux-data blocks.
// We will consume events until we leave this scope (a aux-data-terminal).
// A running key is assigned to each event with a gap left following events
// that may have aux-data blocks. Aux-data blocks are assigned a key that
// fits in these gaps. Once sorted by this key, events maintain their order
// while aux-data blocks are moved to directly follow their owners.
TArray < uint16 , TInlineAllocator < 8 > > AuxKeyStack = { 0 } ;
uint32 AuxKey = 2 ;
uint32 FirstDescIndex = OutEventDescs . Num ( ) ;
bool bUnsorted = false ;
while ( ! Reader . IsEmpty ( ) )
{
FEventDesc EventDesc ;
2021-09-27 08:02:04 -04:00
EventDesc . Serial = ESerial : : Ignored ;
2021-09-03 08:32:31 -04:00
2023-01-19 05:33:25 -05:00
int32 Size = ParseEvent ( Reader , EventDesc , Context ) ;
2021-09-03 08:32:31 -04:00
if ( Size < = 0 )
{
return Size ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 3
PrintParsedEvent ( OutEventDescs . Num ( ) , EventDesc , Size ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-09-03 08:32:31 -04:00
Reader . Advance ( Size ) ;
if ( EventDesc . Uid = = EKnownUids : : AuxDataTerminal )
{
// Leave the scope of an aux-owning event.
if ( AuxKeyStack . Pop ( ) = = 0 )
{
break ;
}
continue ;
}
else if ( EventDesc . Uid = = EKnownUids : : AuxData )
{
// Move an aux-data block to follow its owning event
EventDesc . AuxKey = AuxKeyStack . Last ( ) + 1 ;
}
else
{
EventDesc . AuxKey = uint16 ( AuxKey ) ;
// Maybe it is time to create a new aux-data owner scope
if ( EventDesc . bHasAux )
{
AuxKeyStack . Add ( uint16 ( AuxKey ) ) ;
}
2022-09-13 06:42:08 -04:00
2023-10-31 04:07:11 -04:00
// This event may be in the middle of an earlier event's aux data blocks.
2022-09-13 06:42:08 -04:00
bUnsorted = true ;
2021-09-03 08:32:31 -04:00
}
OutEventDescs . Add ( EventDesc ) ;
+ + AuxKey ;
2023-10-31 04:07:11 -04:00
constexpr uint32 MaxAuxKey = 0x7fff ;
if ( AuxKeyStack . Num ( ) = = 1 & & AuxKey > MaxAuxKey )
{
// If an "aux terminal" for the initial event was not detected after
// many intermediate events, we can assume it is lost.
check ( FirstDescIndex > 0 ) ;
uint32 NumParsedEvents = uint32 ( OutEventDescs . Num ( ) ) - FirstDescIndex ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Ignoring lost aux terminal for event with uid %u (desc %d), after parsing %u events " ,
OutEventDescs [ FirstDescIndex - 1 ] . Uid ,
FirstDescIndex - 1 ,
NumParsedEvents ) ;
Context . EmitMessagef (
EAnalysisMessageSeverity : : Error ,
TEXT ( " Ignoring lost aux terminal for event with uid %u, after parsing %u events. " ) ,
OutEventDescs [ FirstDescIndex - 1 ] . Uid ,
NumParsedEvents ) ;
AuxKeyStack . Pop ( ) ;
break ;
}
2021-09-03 08:32:31 -04:00
}
if ( AuxKeyStack . Num ( ) > 0 )
{
// There was not enough data available to complete the outer most scope
return 0 ;
}
2023-10-31 04:07:11 -04:00
checkf ( ( AuxKey & 0xffff0000 ) = = 0 , TEXT ( " AuxKey overflow (0x%X) " ) , AuxKey ) ;
2021-09-03 08:32:31 -04:00
// Sort to get all aux-blocks contiguous with their owning event
if ( bUnsorted )
{
uint32 NumDescs = OutEventDescs . Num ( ) - FirstDescIndex ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Sorting %u event descs " , NumDescs ) ;
# endif
2021-09-03 08:32:31 -04:00
TArrayView < FEventDesc > DescsView ( OutEventDescs . GetData ( ) + FirstDescIndex , NumDescs ) ;
2022-09-13 06:42:08 -04:00
Algo : : StableSort (
2021-09-03 08:32:31 -04:00
DescsView ,
[ ] ( const FEventDesc & Lhs , const FEventDesc & Rhs )
{
return Lhs . AuxKey < Rhs . AuxKey ;
}
) ;
}
return 1 ;
}
////////////////////////////////////////////////////////////////////////////////
2023-01-19 05:33:25 -05:00
int32 FProtocol5Stage : : ParseEvent ( FStreamReader & Reader , FEventDesc & EventDesc , const FMachineContext & Context )
2021-09-03 08:32:31 -04:00
{
using namespace Protocol5 ;
// No need to aggressively bounds check here. Events are never fragmented
// due to the way that data is transported (aux payloads can be though).
const uint8 * Cursor = Reader . GetPointerUnchecked < uint8 > ( ) ;
// Parse the event's ID
uint32 Uid = * Cursor ;
if ( Uid & EKnownUids : : Flag_TwoByteUid )
{
2021-10-04 07:52:24 -04:00
EventDesc . bTwoByteUid = 1 ;
2021-09-03 08:32:31 -04:00
Uid = * ( uint16 * ) Cursor ;
+ + Cursor ;
}
Uid > > = EKnownUids : : _UidShift ;
+ + Cursor ;
// Calculate the size of the event
uint32 Serial = uint32 ( ESerial : : Ignored ) ;
uint32 EventSize = 0 ;
if ( Uid < EKnownUids : : User )
{
/* Well-known event */
if ( Uid = = Protocol5 : : EKnownEventUids : : AuxData )
{
- - Cursor ; // FAuxHeader includes the one-byte Uid
const auto * AuxHeader = ( FAuxHeader * ) Cursor ;
uint32 Remaining = Reader . GetRemaining ( ) ;
uint32 Size = AuxHeader - > Pack > > FAuxHeader : : SizeShift ;
if ( Remaining < Size + sizeof ( FAuxHeader ) )
{
return 0 ;
}
EventSize = Size ;
Cursor + = sizeof ( FAuxHeader ) ;
}
else
{
2023-01-25 04:26:15 -05:00
SetSizeIfKnownEvent ( Uid , EventSize ) ;
2021-09-03 08:32:31 -04:00
}
EventDesc . bHasAux = 0 ;
}
else
{
/* Ordinary events */
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Get ( Uid ) ;
if ( TypeInfo = = nullptr )
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Warning: UID %u (0x%X) was not declared yet! " , Uid , Uid ) ;
2021-09-03 08:32:31 -04:00
return 0 ;
}
EventSize = TypeInfo - > EventSize ;
EventDesc . bHasAux = ! ! ( TypeInfo - > Flags & FTypeRegistry : : FTypeInfo : : Flag_MaybeHasAux ) ;
if ( ( TypeInfo - > Flags & FDispatch : : Flag_NoSync ) = = 0 )
{
memcpy ( & Serial , Cursor , sizeof ( int32 ) ) ;
Serial & = ESerial : : Mask ;
Cursor + = 3 ;
}
}
EventDesc . Serial = Serial ;
2023-09-29 07:22:52 -04:00
EventDesc . Uid = ( uint16 ) Uid ;
2021-09-03 08:32:31 -04:00
EventDesc . Data = Cursor ;
uint32 HeaderSize = uint32 ( UPTRINT ( Cursor - Reader . GetPointer < uint8 > ( ) ) ) ;
2023-10-31 04:07:11 -04:00
uint32 TotalEventSize = HeaderSize + EventSize ;
# if UE_TRACE_ANALYSIS_DEBUG
EventDesc . EventSize = TotalEventSize ;
# endif
return TotalEventSize ;
2021-09-03 08:32:31 -04:00
}
2021-10-06 02:20:31 -04:00
////////////////////////////////////////////////////////////////////////////////
2022-01-27 05:21:14 -05:00
template < typename Callback >
2021-10-06 02:20:31 -04:00
void FProtocol5Stage : : ForEachSerialGap (
const TArray < FEventDescStream > & EventDescHeap ,
2022-01-27 05:21:14 -05:00
Callback & & InCallback )
2021-10-06 02:20:31 -04:00
{
TArray < FEventDescStream > HeapCopy ( EventDescHeap ) ;
int Serial = HeapCopy . HeapTop ( ) . EventDescs [ 0 ] . Serial ;
// There might be a gap at the beginning of the heap if some events have
// already been consumed.
if ( NextSerial ! = Serial )
{
2022-01-27 05:21:14 -05:00
if ( ! InCallback ( NextSerial , Serial ) )
2021-10-06 02:20:31 -04:00
{
return ;
}
}
// A min-heap is used to peel off each stream (thread) with the lowest serial
// numbered event.
do
{
const FEventDescStream & Stream = HeapCopy . HeapTop ( ) ;
const FEventDesc * EventDesc = Stream . EventDescs ;
// If the next lowest serial number doesn't match where we got up to in
// the previous stream we have found a gap. Celebration ensues.
if ( Serial ! = EventDesc - > Serial )
{
2022-01-27 05:21:14 -05:00
if ( ! InCallback ( Serial , EventDesc - > Serial ) )
2021-10-06 02:20:31 -04:00
{
return ;
}
}
2023-10-31 04:07:11 -04:00
// Consume consecutive events (including unsynchronized ones).
2021-10-06 02:20:31 -04:00
Serial = EventDesc - > Serial ;
do
{
do
{
+ + EventDesc ;
}
while ( EventDesc - > Serial = = ESerial : : Ignored ) ;
Serial = ( Serial + 1 ) & ESerial : : Mask ;
}
while ( EventDesc - > Serial = = Serial ) ;
// Update the heap
if ( EventDesc - > Serial ! = ESerial : : Terminal )
{
auto & Out = HeapCopy . Add_GetRef ( { Stream . ThreadId , Stream . TransportIndex } ) ;
Out . EventDescs = EventDesc ;
}
2024-01-19 16:41:35 -05:00
HeapCopy . HeapPopDiscard ( FSerialDistancePredicate { NextSerial } , EAllowShrinking : : No ) ;
2021-10-06 02:20:31 -04:00
}
while ( ! HeapCopy . IsEmpty ( ) ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FProtocol5Stage : : DetectSerialGaps ( TArray < FEventDescStream > & EventDescHeap )
{
2023-10-31 04:07:11 -04:00
// Events that should be synchronized across threads are assigned serial
// numbers so they can be analyzed in the correct order. Gaps in the
2021-10-06 02:20:31 -04:00
// serials can occur under two scenarios; 1) when packets are dropped from
// the trace tail to make space for new trace events, and 2) when Trace's
// worker thread ticks, samples all the trace buffers and sends their data.
// In late-connect scenarios these gaps need to be skipped over in order to
2023-10-31 04:07:11 -04:00
// successfully reserialize events in the data stream. To further complicate
2021-10-06 02:20:31 -04:00
// matters, most of the gaps from (2) will get filled by the following update,
// leading to initial false positive gaps. By embedding sync points in the
// stream we can reliably differentiate genuine gaps from temporary ones.
//
// Note that this could be done without sync points but it is an altogether
// more complex solution. So unsightly embedded syncs it is...
if ( SyncCount = = Transport . GetSyncCount ( ) )
{
return ;
}
SyncCount = Transport . GetSyncCount ( ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " SyncCount: %d (%d previous serial gaps) " , SyncCount , SerialGaps . Num ( ) ) ;
2021-10-06 02:20:31 -04:00
if ( SyncCount = = 1 )
{
// On the first update we will just collect gaps.
auto GatherGap = [ this ] ( int32 Lhs , int32 Rhs )
{
FEventDesc & Gap = SerialGaps . Emplace_GetRef ( ) ;
Gap . Serial = Lhs ;
Gap . GapLength = ( Rhs - Lhs ) & ESerial : : Mask ;
return true ;
} ;
ForEachSerialGap ( EventDescHeap , GatherGap ) ;
}
else
{
// On the second update we detect where gaps from the previous update
// start getting filled in. Any gaps preceding that point are genuine.
uint32 GapCount = 0 ;
auto RecordGap = [ this , & GapCount ] ( int32 Lhs , int32 Rhs )
{
2022-07-08 08:49:13 -04:00
if ( SerialGaps . IsEmpty ( ) | | GapCount > = ( uint32 ) SerialGaps . Num ( ) )
2021-10-06 02:20:31 -04:00
{
return false ;
}
2023-01-25 04:26:15 -05:00
2022-05-05 05:30:07 -04:00
const FEventDesc & SerialGap = SerialGaps [ GapCount ] ;
if ( SerialGap . Serial = = Lhs )
{
/* This is the expected case */
+ + GapCount ;
return true ;
}
if ( SerialGap . Serial > Lhs )
{
/* We've started receiving new gaps that are exist because not all
* data has been received yet . They ' re false positives . No need to process
* any further */
return false ;
}
// If we're here something's probably gone wrong
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Serial gaps detection failed (SerialGap.Serial=%d, Lhs=%d)! " , SerialGap . Serial , Lhs ) ;
2022-05-05 05:30:07 -04:00
return false ;
2021-10-06 02:20:31 -04:00
} ;
ForEachSerialGap ( EventDescHeap , RecordGap ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Serial gaps: %d " , GapCount ) ;
2021-12-16 19:09:46 -05:00
if ( GapCount = = 0 ) //-V547
2021-10-06 02:20:31 -04:00
{
SerialGaps . Empty ( ) ;
return ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
for ( uint32 GapIndex = 0 ; GapIndex < GapCount ; + + GapIndex )
{
const FEventDesc & SerialGap = SerialGaps [ GapIndex ] ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " gap %u +%u " , SerialGap . Serial , SerialGap . GapLength ) ;
}
# endif
2021-10-06 02:20:31 -04:00
// Turn the genuine gaps into a stream that DispatchEvents() can handle
// and use to skip over them.
if ( GapCount = = uint32 ( SerialGaps . Num ( ) ) )
{
SerialGaps . Emplace ( ) ;
}
FEventDesc & Terminator = SerialGaps [ GapCount ] ;
Terminator . Serial = ESerial : : Terminal ;
FEventDescStream Out = EventDescHeap [ 0 ] ;
Out . ThreadId = FEventDescStream : : GapThreadId ;
Out . EventDescs = SerialGaps . GetData ( ) ;
2023-01-20 09:17:33 -05:00
EventDescHeap . HeapPush ( Out , FSerialDistancePredicate { NextSerial } ) ;
2021-10-06 02:20:31 -04:00
}
}
2023-01-25 04:26:15 -05:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol5Stage : : SetSizeIfKnownEvent ( uint32 Uid , uint32 & InOutEventSize )
{
switch ( Uid )
{
case EKnownUids : : EnterScope_T :
case EKnownUids : : LeaveScope_T :
InOutEventSize = 7 ;
2023-01-31 13:23:28 -05:00
break ;
2023-01-25 04:26:15 -05:00
} ;
}
////////////////////////////////////////////////////////////////////////////////
bool FProtocol5Stage : : DispatchKnownEvent ( const FMachineContext & Context , uint32 Uid , const FEventDesc * Cursor )
{
// Maybe this is a "well-known" event that is handled a little different?
switch ( Uid )
{
case EKnownUids : : EnterScope :
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEnterScopeEvent ( Uid , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . EnterScope ( ) ;
return true ;
case EKnownUids : : LeaveScope :
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogLeaveScopeEvent ( Uid , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . LeaveScope ( ) ;
return true ;
case EKnownUids : : EnterScope_T :
{
uint64 RelativeTimestamp = * ( uint64 * ) ( Cursor - > Data - 1 ) > > 8 ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEnterScopeEvent ( Uid , RelativeTimestamp , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . EnterScope ( RelativeTimestamp ) ;
return true ;
}
case EKnownUids : : LeaveScope_T :
{
uint64 RelativeTimestamp = * ( uint64 * ) ( Cursor - > Data - 1 ) > > 8 ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogLeaveScopeEvent ( Uid , RelativeTimestamp , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . LeaveScope ( RelativeTimestamp ) ;
return true ;
}
case EKnownUids : : AuxData :
case EKnownUids : : AuxDataTerminal :
return true ;
default :
return false ;
}
}
2021-09-03 08:32:31 -04:00
////////////////////////////////////////////////////////////////////////////////
2021-10-04 08:36:03 -04:00
int32 FProtocol5Stage : : DispatchEvents (
2023-01-19 05:33:25 -05:00
const FMachineContext & Context ,
2021-09-03 08:32:31 -04:00
const FEventDesc * EventDesc , uint32 Count )
{
using namespace Protocol5 ;
FAuxDataCollector AuxCollector ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 2
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Dispatch run of %u consecutive events (Tid=%u) " , Count , Context . Bridge . GetActiveThreadId ( ) ) ;
# endif
2023-01-25 04:26:15 -05:00
for ( const FEventDesc * Cursor = EventDesc , * End = EventDesc + Count ; Cursor < End ; + + Cursor )
2021-09-03 08:32:31 -04:00
{
2023-01-25 04:26:15 -05:00
uint32 Uid = uint32 ( Cursor - > Uid ) ;
if ( DispatchKnownEvent ( Context , Uid , Cursor ) )
2021-09-03 08:32:31 -04:00
{
continue ;
}
2023-01-25 04:26:15 -05:00
if ( ! TypeRegistry . IsUidValid ( Uid ) )
2021-09-03 08:32:31 -04:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Warning: Unexpected event with UID %u (0x%X) " , Uid , Uid ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessagef ( EAnalysisMessageSeverity : : Warning , TEXT ( " An unknown event UID (%u) was encountered. " ) , Uid ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG && UE_TRACE_ANALYSIS_DEBUG_LEVEL >= 3
UE_TRACE_ANALYSIS_DEBUG_BeginStringBuilder ( ) ;
const uint8 * StartCursor = Cursor - > Data ;
for ( uint32 i = 0 ; i < 32 & & i < Cursor - > EventSize ; + + i )
{
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " %02X " , StartCursor [ i ] ) ;
}
UE_TRACE_ANALYSIS_DEBUG_EndStringBuilder ( ) ;
UE_TRACE_ANALYSIS_DEBUG_ResetStringBuilder ( ) ;
UE_TRACE_ANALYSIS_DEBUG_Append ( " [[[ " ) ;
for ( uint32 i = 0 ; i < 128 & & i < Cursor - > EventSize ; + + i )
{
UE_TRACE_ANALYSIS_DEBUG_AppendChar ( ( char ) StartCursor [ i ] ) ;
}
UE_TRACE_ANALYSIS_DEBUG_Append ( " ]]] " ) ;
UE_TRACE_ANALYSIS_DEBUG_EndStringBuilder ( ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG
2023-01-25 04:26:15 -05:00
return - 1 ;
2021-09-03 08:32:31 -04:00
}
// It is a normal event.
2023-01-25 04:26:15 -05:00
const FTypeRegistry : : FTypeInfo * TypeInfo = TypeRegistry . Get ( Uid ) ;
2021-09-03 08:32:31 -04:00
FEventDataInfo EventDataInfo = {
Cursor - > Data ,
* TypeInfo ,
& AuxCollector ,
TypeInfo - > EventSize ,
} ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
uint32 FixedSize = Cursor - > EventSize ;
uint32 AuxSize = Cursor - > AuxSize ;
const FEventDesc * EventCursor = Cursor ;
# endif
2021-09-03 08:32:31 -04:00
// Gather its auxiliary data blocks into a collector.
if ( Cursor - > bHasAux )
{
while ( true )
{
+ + Cursor ;
if ( Cursor - > Uid ! = EKnownUids : : AuxData )
{
- - Cursor ; // Read off too much. Put it back.
break ;
}
const auto * AuxHeader = ( ( FAuxHeader * ) ( Cursor - > Data ) ) - 1 ;
2022-09-13 06:42:08 -04:00
FAuxData AuxData = { } ;
2021-09-03 08:32:31 -04:00
AuxData . Data = AuxHeader - > Data ;
AuxData . DataSize = ( AuxHeader - > Pack > > FAuxHeader : : SizeShift ) ;
AuxData . FieldIndex = AuxHeader - > FieldIndex_Size & FAuxHeader : : FieldMask ;
// AuxData.FieldSizeAndType = ... - this is assigned on demand in GetData()
AuxCollector . Add ( AuxData ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
AuxSize + = Cursor - > EventSize + Cursor - > AuxSize ;
# endif
2021-09-03 08:32:31 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
AuxSize + = 1 ; // for AuxDataTerminal
# endif
2021-09-03 08:32:31 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEvent ( TypeInfo , FixedSize , AuxSize , EventCursor - > Serial ) ;
# endif
2023-01-19 05:33:25 -05:00
Context . Bridge . OnEvent ( EventDataInfo ) ;
2021-09-03 08:32:31 -04:00
AuxCollector . Reset ( ) ;
}
return 0 ;
}
2023-01-25 04:26:15 -05:00
2022-05-05 05:30:07 -04:00
// {{{1 protocol-6 -------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
2023-10-31 04:07:11 -04:00
class FProtocol6Stage
: public FProtocol5Stage
2022-05-05 05:30:07 -04:00
{
public :
2023-10-31 04:07:11 -04:00
FProtocol6Stage ( FTransport * InTransport ) ;
virtual void ExitStage ( const FMachineContext & Context ) override ;
2022-05-05 05:30:07 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
FProtocol6Stage : : FProtocol6Stage ( FTransport * InTransport )
: FProtocol5Stage ( InTransport )
{
EventVersion = 6 ;
}
2021-09-03 08:32:31 -04:00
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol6Stage : : ExitStage ( const FMachineContext & Context )
{
// Ensure the transport does not have pending buffers (i.e. event data not yet processed).
if ( ! Transport . IsEmpty ( ) )
{
Context . EmitMessage ( EAnalysisMessageSeverity : : Warning , TEXT ( " Transport buffers are not empty at end of analysis (protocol 6)! " ) ) ;
}
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . GetSerial ( ) . Value = NextSerial ;
Transport . DebugEnd ( ) ;
# endif
}
2023-01-25 04:26:15 -05:00
// {{{1 protocol-7 -------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
2023-10-31 04:07:11 -04:00
class FProtocol7Stage
: public FProtocol6Stage
2023-01-25 04:26:15 -05:00
{
public :
2023-10-31 04:07:11 -04:00
FProtocol7Stage ( FTransport * InTransport ) ;
virtual void ExitStage ( const FMachineContext & Context ) override ;
virtual void SetSizeIfKnownEvent ( uint32 Uid , uint32 & InOutEventSize ) override ;
virtual bool DispatchKnownEvent ( const FMachineContext & Context , uint32 Uid , const FEventDesc * Cursor ) override ;
2023-01-25 04:26:15 -05:00
protected :
2023-10-31 04:07:11 -04:00
using EKnownUids = Protocol7 : : EKnownEventUids ;
2023-01-25 04:26:15 -05:00
} ;
////////////////////////////////////////////////////////////////////////////////
FProtocol7Stage : : FProtocol7Stage ( FTransport * InTransport )
: FProtocol6Stage ( InTransport )
{
EventVersion = 7 ;
}
2023-10-31 04:07:11 -04:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol7Stage : : ExitStage ( const FMachineContext & Context )
{
// Ensure the transport does not have pending buffers (i.e. event data not yet processed).
if ( ! Transport . IsEmpty ( ) )
{
Context . EmitMessage ( EAnalysisMessageSeverity : : Warning , TEXT ( " Transport buffers are not empty at end of analysis (protocol 7)! " ) ) ;
}
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . GetSerial ( ) . Value = NextSerial ;
Transport . DebugEnd ( ) ;
# endif
}
2023-01-25 04:26:15 -05:00
////////////////////////////////////////////////////////////////////////////////
void FProtocol7Stage : : SetSizeIfKnownEvent ( uint32 Uid , uint32 & InOutEventSize )
{
switch ( Uid )
{
case EKnownUids : : EnterScope_TA :
case EKnownUids : : LeaveScope_TA :
InOutEventSize = 8 ;
2023-01-31 13:23:28 -05:00
break ;
case EKnownUids : : EnterScope_TB :
case EKnownUids : : LeaveScope_TB :
InOutEventSize = 7 ;
break ;
2023-01-25 04:26:15 -05:00
} ;
}
////////////////////////////////////////////////////////////////////////////////
bool FProtocol7Stage : : DispatchKnownEvent ( const FMachineContext & Context , uint32 Uid , const FEventDesc * Cursor )
{
// Maybe this is a "well-known" event that is handled a little different?
switch ( Uid )
{
case EKnownUids : : EnterScope :
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEnterScopeEvent ( Uid , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . EnterScope ( ) ;
return true ;
case EKnownUids : : LeaveScope :
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogLeaveScopeEvent ( Uid , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . LeaveScope ( ) ;
return true ;
case EKnownUids : : EnterScope_TA :
{
uint64 AbsoluteTimestamp = * ( uint64 * ) Cursor - > Data ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEnterScopeAEvent ( Uid , AbsoluteTimestamp , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . EnterScopeA ( AbsoluteTimestamp ) ;
return true ;
}
case EKnownUids : : LeaveScope_TA :
{
uint64 AbsoluteTimestamp = * ( uint64 * ) Cursor - > Data ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogLeaveScopeAEvent ( Uid , AbsoluteTimestamp , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-25 04:26:15 -05:00
Context . Bridge . LeaveScopeA ( AbsoluteTimestamp ) ;
return true ;
}
2023-01-31 13:23:28 -05:00
case EKnownUids : : EnterScope_TB :
{
uint64 BaseRelativeTimestamp = * ( uint64 * ) ( Cursor - > Data - 1 ) > > 8 ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogEnterScopeBEvent ( Uid , BaseRelativeTimestamp , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-31 13:23:28 -05:00
Context . Bridge . EnterScopeB ( BaseRelativeTimestamp ) ;
return true ;
}
case EKnownUids : : LeaveScope_TB :
{
uint64 BaseRelativeTimestamp = * ( uint64 * ) ( Cursor - > Data - 1 ) > > 8 ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Context . Bridge . DebugLogLeaveScopeBEvent ( Uid , BaseRelativeTimestamp , Cursor - > EventSize + Cursor - > AuxSize ) ;
# endif
2023-01-31 13:23:28 -05:00
Context . Bridge . LeaveScopeB ( BaseRelativeTimestamp ) ;
return true ;
}
2023-01-25 04:26:15 -05:00
case EKnownUids : : AuxData :
case EKnownUids : : AuxDataTerminal :
return true ;
default :
return false ;
}
}
2021-07-28 02:24:21 -04:00
// {{{1 est.-transport ---------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FEstablishTransportStage
: public FAnalysisMachine : : FStage
{
public :
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) override ;
} ;
////////////////////////////////////////////////////////////////////////////////
FEstablishTransportStage : : EStatus FEstablishTransportStage : : OnData (
FStreamReader & Reader ,
const FMachineContext & Context )
{
using namespace UE : : Trace ;
const struct {
uint8 TransportVersion ;
uint8 ProtocolVersion ;
} * Header = decltype ( Header ) ( Reader . GetPointer ( sizeof ( * Header ) ) ) ;
if ( Header = = nullptr )
{
return EStatus : : NotEnoughData ;
}
2023-01-25 04:26:15 -05:00
uint32 TransportVersion = Header - > TransportVersion ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " TransportVersion: %u " , TransportVersion ) ;
2023-01-25 04:26:15 -05:00
uint32 ProtocolVersion = Header - > ProtocolVersion ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " ProtocolVersion: %u " , ProtocolVersion ) ;
2023-01-25 04:26:15 -05:00
2021-07-28 02:24:21 -04:00
FTransport * Transport = nullptr ;
2023-01-25 04:26:15 -05:00
switch ( TransportVersion )
2021-07-28 02:24:21 -04:00
{
2021-10-05 09:30:32 -04:00
case ETransport : : Raw : Transport = new FTransport ( ) ; break ;
case ETransport : : Packet : Transport = new FPacketTransport ( ) ; break ;
case ETransport : : TidPacket : Transport = new FTidPacketTransport ( ) ; break ;
case ETransport : : TidPacketSync : Transport = new FTidPacketTransportSync ( ) ; break ;
2023-01-19 05:33:25 -05:00
default :
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid transport version %u " , TransportVersion ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessagef (
EAnalysisMessageSeverity : : Error ,
TEXT ( " Unknown transport version: %u. You may need to recompile this application " ) ,
TransportVersion
) ;
2023-01-19 05:33:25 -05:00
return EStatus : : Error ;
}
2021-07-28 02:24:21 -04:00
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
Transport - > DebugBegin ( ) ;
# endif
2021-07-28 02:24:21 -04:00
switch ( ProtocolVersion )
{
case Protocol0 : : EProtocol : : Id :
Context . Machine . QueueStage < FProtocol0Stage > ( Transport ) ;
Context . Machine . Transition ( ) ;
break ;
case Protocol1 : : EProtocol : : Id :
2021-07-29 08:35:36 -04:00
case Protocol2 : : EProtocol : : Id :
case Protocol3 : : EProtocol : : Id :
2021-07-28 02:24:21 -04:00
Context . Machine . QueueStage < FProtocol2Stage > ( ProtocolVersion , Transport ) ;
Context . Machine . Transition ( ) ;
break ;
case Protocol4 : : EProtocol : : Id :
Context . Machine . QueueStage < FProtocol4Stage > ( ProtocolVersion , Transport ) ;
Context . Machine . Transition ( ) ;
break ;
2021-09-03 08:32:31 -04:00
case Protocol5 : : EProtocol : : Id :
Context . Machine . QueueStage < FProtocol5Stage > ( Transport ) ;
Context . Machine . Transition ( ) ;
break ;
2022-05-05 05:30:07 -04:00
case Protocol6 : : EProtocol : : Id :
Context . Machine . QueueStage < FProtocol6Stage > ( Transport ) ;
Context . Machine . Transition ( ) ;
break ;
2023-01-25 04:26:15 -05:00
case Protocol7 : : EProtocol : : Id :
Context . Machine . QueueStage < FProtocol7Stage > ( Transport ) ;
Context . Machine . Transition ( ) ;
break ;
2021-07-28 02:24:21 -04:00
default :
2023-01-19 05:33:25 -05:00
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid protocol version %u " , ProtocolVersion ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessagef (
EAnalysisMessageSeverity : : Error ,
TEXT ( " Unknown protocol version: %u. You may need to recompile this application " ) ,
ProtocolVersion
) ;
2023-01-19 05:33:25 -05:00
return EStatus : : Error ;
}
2021-07-28 02:24:21 -04:00
}
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " " ) ;
2021-07-28 02:24:21 -04:00
Reader . Advance ( sizeof ( * Header ) ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG_API
Context . Bridge . OnVersion ( TransportVersion , ProtocolVersion ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG_API
2021-07-28 02:24:21 -04:00
return EStatus : : Continue ;
}
// {{{1 metadata ---------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FMetadataStage
: public FAnalysisMachine : : FStage
{
public :
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) override ;
} ;
////////////////////////////////////////////////////////////////////////////////
FMetadataStage : : EStatus FMetadataStage : : OnData (
FStreamReader & Reader ,
const FMachineContext & Context )
{
const auto * MetadataSize = Reader . GetPointer < uint16 > ( ) ;
if ( MetadataSize = = nullptr )
{
return EStatus : : NotEnoughData ;
}
2021-09-09 05:01:09 -04:00
const uint8 * Metadata = Reader . GetPointer ( sizeof ( * MetadataSize ) + * MetadataSize ) ;
if ( Metadata = = nullptr )
{
return EStatus : : NotEnoughData ;
}
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
UE_TRACE_ANALYSIS_DEBUG_BeginStringBuilder ( ) ;
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " Metadata: %u + %u bytes ( " , uint32 ( sizeof ( * MetadataSize ) ) , uint32 ( * MetadataSize ) ) ;
const uint32 PrintByteCount = FMath : : Min ( 32u , uint32 ( * MetadataSize ) ) ;
Metadata + = sizeof ( * MetadataSize ) ;
for ( uint32 Index = 0 ; Index < PrintByteCount ; + + Index , + + Metadata )
{
if ( Index ! = 0 )
{
UE_TRACE_ANALYSIS_DEBUG_AppendChar ( ' ' ) ;
}
UE_TRACE_ANALYSIS_DEBUG_Appendf ( " %02X " , uint32 ( * Metadata ) ) ;
}
if ( PrintByteCount ! = uint32 ( * MetadataSize ) )
{
UE_TRACE_ANALYSIS_DEBUG_Append ( " ... " ) ;
}
UE_TRACE_ANALYSIS_DEBUG_AppendChar ( ' ) ' ) ;
UE_TRACE_ANALYSIS_DEBUG_EndStringBuilder ( ) ;
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-07-28 02:24:21 -04:00
Reader . Advance ( sizeof ( * MetadataSize ) + * MetadataSize ) ;
Context . Machine . QueueStage < FEstablishTransportStage > ( ) ;
Context . Machine . Transition ( ) ;
return EStatus : : Continue ;
}
// {{{1 magic ------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FMagicStage
: public FAnalysisMachine : : FStage
{
public :
virtual EStatus OnData ( FStreamReader & Reader , const FMachineContext & Context ) override ;
} ;
////////////////////////////////////////////////////////////////////////////////
FMagicStage : : EStatus FMagicStage : : OnData (
FStreamReader & Reader ,
const FMachineContext & Context )
{
const auto * MagicPtr = Reader . GetPointer < uint32 > ( ) ;
if ( MagicPtr = = nullptr )
{
return EStatus : : NotEnoughData ;
}
uint32 Magic = * MagicPtr ;
if ( Magic = = ' ECRT ' | | Magic = = ' 2 CRT ' )
{
// Source is big-endian which we don't currently support
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid magic header (big-endian not supported) " ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessage ( EAnalysisMessageSeverity : : Error , TEXT ( " Big endian traces are currently not supported. " ) ) ;
2021-07-28 02:24:21 -04:00
return EStatus : : Error ;
}
if ( Magic = = ' TRCE ' )
{
2021-07-29 08:51:16 -04:00
Reader . Advance ( sizeof ( * MagicPtr ) ) ;
2021-07-28 02:24:21 -04:00
Context . Machine . QueueStage < FEstablishTransportStage > ( ) ;
Context . Machine . Transition ( ) ;
return EStatus : : Continue ;
}
if ( Magic = = ' TRC2 ' )
{
2021-07-29 08:51:16 -04:00
Reader . Advance ( sizeof ( * MagicPtr ) ) ;
2021-07-28 02:24:21 -04:00
Context . Machine . QueueStage < FMetadataStage > ( ) ;
Context . Machine . Transition ( ) ;
return EStatus : : Continue ;
2021-07-29 08:51:16 -04:00
}
// There was no header on early traces so they went straight into declaring
// protocol and transport versions.
if ( Magic = = 0x00'00'00'01 ) // protocol 0, transport 1
{
Context . Machine . QueueStage < FEstablishTransportStage > ( ) ;
Context . Machine . Transition ( ) ;
return EStatus : : Continue ;
2021-07-28 02:24:21 -04:00
}
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Error: Invalid magic header " ) ;
2023-06-19 07:17:37 -04:00
Context . EmitMessage ( EAnalysisMessageSeverity : : Error , TEXT ( " The file or stream was not recognized as trace stream. " ) ) ;
2021-07-28 02:24:21 -04:00
return EStatus : : Error ;
}
// {{{1 engine -----------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
class FAnalysisEngine : : FImpl
{
public :
2023-06-19 07:17:37 -04:00
FImpl ( TArray < IAnalyzer * > & & Analyzers , FMessageDelegate & & InMessage ) ;
2021-07-28 02:24:21 -04:00
void Begin ( ) ;
void End ( ) ;
bool OnData ( FStreamReader & Reader ) ;
FAnalysisBridge Bridge ;
2023-01-19 05:33:25 -05:00
FAnalysisMachine Machine ;
2021-07-28 02:24:21 -04:00
} ;
////////////////////////////////////////////////////////////////////////////////
2023-06-19 07:17:37 -04:00
FAnalysisEngine : : FImpl : : FImpl ( TArray < IAnalyzer * > & & Analyzers , FMessageDelegate & & InMessage )
2021-07-28 02:24:21 -04:00
: Bridge ( Forward < TArray < IAnalyzer * > > ( Analyzers ) )
2023-06-19 07:17:37 -04:00
, Machine ( Bridge , Forward < FMessageDelegate > ( InMessage ) )
2021-07-28 02:24:21 -04:00
{
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisEngine : : FImpl : : Begin ( )
{
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " FAnalysisEngine::Begin() " ) ;
2021-07-28 02:24:21 -04:00
Machine . QueueStage < FMagicStage > ( ) ;
Machine . Transition ( ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisEngine : : FImpl : : End ( )
{
Machine . Transition ( ) ;
2023-10-31 04:07:11 -04:00
# if UE_TRACE_ANALYSIS_DEBUG
FAnalysisState & State = Bridge . GetState ( ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " " ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " SerialWrappedCount: %d " , State . SerialWrappedCount ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Serial.Value: %u (0x%X) " , State . Serial . Value , State . Serial . Value ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " MaxEventDescs: %d " , State . MaxEventDescs ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " SkippedSerialGaps: %d " , State . NumSkippedSerialGaps ) ;
uint32 Digits = 0 ;
uint64 Value = State . TotalEventSize ;
do
{
Value / = 10 ;
+ + Digits ;
} while ( Value ! = 0 ) ;
uint64 ScopeEventCount = State . EnterScopeEventCount + State . LeaveScopeEventCount ;
uint64 ScopeTEventCount = State . EnterScopeTEventCount + State . LeaveScopeTEventCount ;
const int32 NC = Digits ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " " ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " TotalEventCount:%*llu events " , NC , State . TotalEventCount ) ;
if ( State . TotalEventCount > 0 )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " NewEvent:%*llu events (%.1f%%) " , NC , State . NewEventCount , ( double ) State . NewEventCount / ( double ) State . TotalEventCount * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Sync:%*llu events (%.1f%%) " , NC , State . SyncEventCount , ( double ) State . SyncEventCount / ( double ) State . TotalEventCount * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " ImportantNoSync:%*llu events (%.1f%%) " , NC , State . ImportantNoSyncEventCount , ( double ) State . ImportantNoSyncEventCount / ( double ) State . TotalEventCount * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " OtherNoSync:%*llu events (%.1f%%) " , NC , State . OtherNoSyncEventCount , ( double ) State . OtherNoSyncEventCount / ( double ) State . TotalEventCount * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Scope:%*llu events (%.1f%%) = %llu enter + %llu leave " ,
NC , ScopeEventCount ,
( double ) ScopeEventCount / ( double ) State . TotalEventCount * 100.0 ,
State . EnterScopeEventCount ,
State . LeaveScopeEventCount ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Scope_T:%*llu events (%.1f%%) = %llu enter + %llu leave " ,
NC , ScopeTEventCount ,
( double ) ScopeTEventCount / ( double ) State . TotalEventCount * 100.0 ,
State . EnterScopeTEventCount ,
State . LeaveScopeTEventCount ) ;
const int64 CountError =
State . TotalEventCount
- State . NewEventCount
- State . SyncEventCount
- State . ImportantNoSyncEventCount
- State . OtherNoSyncEventCount
- ScopeEventCount
- ScopeTEventCount ;
if ( CountError ! = 0 )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " error: %lld !!! " , CountError ) ;
}
uint64 DispatchedEventCount = State . TotalEventCount - State . NewEventCount - State . EnterScopeEventCount - State . EnterScopeTEventCount ;
uint64 NormalEventCount = State . SyncEventCount + State . ImportantNoSyncEventCount + State . OtherNoSyncEventCount - State . EnterScopeEventCount - State . EnterScopeTEventCount ;
check ( DispatchedEventCount = = NormalEventCount + ScopeEventCount + ScopeTEventCount ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Dispatched:%*llu events = %llu normal + %llu scoped " , NC , DispatchedEventCount , NormalEventCount , ScopeEventCount + ScopeTEventCount ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " (normal dispatched events = sync events + no sync events - scope enter events) " ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " " ) ;
}
uint64 ScopeEventSize = State . EnterScopeEventSize + State . LeaveScopeEventSize ;
uint64 ScopeTEventSize = State . EnterScopeTEventSize + State . LeaveScopeTEventSize ;
const int32 NS = Digits + 1 ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " TotalEventSize:%*llu bytes (%.1f MiB) " , NS , State . TotalEventSize , ( double ) State . TotalEventSize / ( 1024.0 * 1024.0 ) ) ;
if ( State . TotalEventSize > 0 )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " NewEvent:%*llu bytes (%.1f%%) " , NS , State . NewEventSize , ( double ) State . NewEventSize / ( double ) State . TotalEventSize * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Sync:%*llu bytes (%.1f%%) " , NS , State . SyncEventSize , ( double ) State . SyncEventSize / ( double ) State . TotalEventSize * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " ImportantNoSync:%*llu bytes (%.1f%%) " , NS , State . ImportantNoSyncEventSize , ( double ) State . ImportantNoSyncEventSize / ( double ) State . TotalEventSize * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " OtherNoSync:%*llu bytes (%.1f%%) " , NS , State . OtherNoSyncEventSize , ( double ) State . OtherNoSyncEventSize / ( double ) State . TotalEventSize * 100.0 ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Scope:%*llu bytes (%.1f%%) = %llu enter + %llu leave " ,
NS , ScopeEventSize ,
( double ) ScopeEventSize / ( double ) State . TotalEventSize * 100.0 ,
State . EnterScopeEventSize ,
State . LeaveScopeEventSize ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Scope_T:%*llu bytes (%.1f%%) = %llu enter + %llu leave " ,
NS , ScopeTEventSize ,
( double ) ScopeTEventSize / ( double ) State . TotalEventSize * 100.0 ,
State . EnterScopeTEventSize ,
State . LeaveScopeTEventSize ) ;
const int64 SizeError =
State . TotalEventSize
- State . NewEventSize
- State . SyncEventSize
- State . ImportantNoSyncEventSize
- State . OtherNoSyncEventSize
- ScopeEventSize
- ScopeTEventSize ;
if ( SizeError ! = 0 )
{
UE_TRACE_ANALYSIS_DEBUG_LOG ( " error: %lld !!! " , SizeError ) ;
}
UE_TRACE_ANALYSIS_DEBUG_LOG ( " Dispatched:%*llu bytes (Total - NewEvent) " , NS , State . TotalEventSize - State . NewEventSize ) ;
}
# endif // UE_TRACE_ANALYSIS_DEBUG
2021-07-28 02:24:21 -04:00
Bridge . Reset ( ) ;
2023-10-31 04:07:11 -04:00
UE_TRACE_ANALYSIS_DEBUG_LOG ( " " ) ;
UE_TRACE_ANALYSIS_DEBUG_LOG ( " FAnalysisEngine::End() " ) ;
2021-07-28 02:24:21 -04:00
}
////////////////////////////////////////////////////////////////////////////////
bool FAnalysisEngine : : FImpl : : OnData ( FStreamReader & Reader )
{
2022-02-11 04:03:07 -05:00
bool bRet = ( Machine . OnData ( Reader ) ! = FAnalysisMachine : : EStatus : : Error ) ;
bRet & = Bridge . IsStillAnalyzing ( ) ;
return bRet ;
2021-07-28 02:24:21 -04:00
}
////////////////////////////////////////////////////////////////////////////////
2023-06-19 07:17:37 -04:00
FAnalysisEngine : : FAnalysisEngine ( TArray < IAnalyzer * > & & Analyzers , FMessageDelegate & & InMessage )
: Impl ( new FImpl ( Forward < TArray < IAnalyzer * > > ( Analyzers ) , Forward < FMessageDelegate > ( InMessage ) ) )
2021-07-28 02:24:21 -04:00
{
}
////////////////////////////////////////////////////////////////////////////////
FAnalysisEngine : : ~ FAnalysisEngine ( )
{
delete Impl ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisEngine : : Begin ( )
{
Impl - > Begin ( ) ;
}
////////////////////////////////////////////////////////////////////////////////
void FAnalysisEngine : : End ( )
{
Impl - > End ( ) ;
}
////////////////////////////////////////////////////////////////////////////////
bool FAnalysisEngine : : OnData ( FStreamReader & Reader )
{
return Impl - > OnData ( Reader ) ;
}
2021-06-11 06:27:46 -04:00
// }}}
2019-06-03 15:32:00 -04:00
} // namespace Trace
2020-11-17 06:54:28 -04:00
} // namespace UE
2021-06-11 06:27:46 -04:00
2023-01-19 05:33:25 -05:00
# undef LOCTEXT_NAMESPACE
2021-06-11 06:27:46 -04:00
/* vim: set foldlevel=1 : */