2014-03-14 14:13:41 -04:00
/ * *
2014-12-07 19:09:38 -05:00
* Copyright 1998 - 2015 Epic Games , Inc . All Rights Reserved .
2014-03-14 14:13:41 -04:00
* /
using System ;
using System.IO ;
using System.Collections.Generic ;
using System.Text ;
using System.Reflection ;
using System.Diagnostics ;
namespace MemoryProfiler2
{
/// <summary> The lower 2 bits of a pointer are piggy-bagged to store what kind of data follows it. This enum lists the possible types. </summary>
2014-04-23 16:37:47 -04:00
public enum EProfilingPayloadType
{
TYPE_Malloc = 0 ,
TYPE_Free = 1 ,
TYPE_Realloc = 2 ,
TYPE_Other = 3 ,
// Don't add more than 4 values - we only have 2 bits to store this.
}
2014-03-14 14:13:41 -04:00
/// <summary>
/// The the case of TYPE_Other, this enum determines the subtype of the token.
/// Mirrored in FMallocProfiler.h
/// </summary>
public enum EProfilingPayloadSubType
{
// Core marker types
/// <summary> Marker used to determine when malloc profiler stream has ended. </summary>
SUBTYPE_EndOfStreamMarker = 0 ,
/// <summary> Marker used to determine when we need to read data from the next file. </summary>
SUBTYPE_EndOfFileMarker = 1 ,
/// <summary> Marker used to determine when a snapshot has been added. </summary>
SUBTYPE_SnapshotMarker = 2 ,
/// <summary> Marker used to determine when a new frame has started. </summary>
SUBTYPE_FrameTimeMarker = 3 ,
/// <summary> Not used. Only for backward compatibility. Use a new snapshot marker instead. </summary>
SUBTYPE_TextMarker = 4 ,
// Marker types for periodic non-GMalloc memory status updates. Only for backward compatibility, replaced with SUBTYPE_MemoryAllocationStats
/// <summary> Marker used to store the total amount of memory used by the game. </summary>
SUBTYPE_TotalUsed = 5 ,
/// </summary> Marker used to store the total amount of memory allocated from the OS. </summary>
SUBTYPE_TotalAllocated = 6 ,
/// <summary> Marker used to store the allocated in use by the application virtual memory. </summary>
SUBTYPE_CPUUsed = 7 ,
/// <summary> Marker used to store the allocated from the OS/allocator, but not used by the application. </summary>
SUBTYPE_CPUSlack = 8 ,
/// <summary> Marker used to store the alignment waste from a pooled allocator plus book keeping overhead. </summary>
SUBTYPE_CPUWaste = 9 ,
/// <summary> Marker used to store the allocated in use by the application physical memory. </summary>
SUBTYPE_GPUUsed = 10 ,
/// <summary> Marker used to store the allocated from the OS, but not used by the application. </summary>
SUBTYPE_GPUSlack = 11 ,
/// <summary> Marker used to store the alignment waste from a pooled allocator plus book keeping overhead. </summary>
SUBTYPE_GPUWaste = 12 ,
/// <summary> Marker used to store the overhead of the operating system. </summary>
SUBTYPE_OSOverhead = 13 ,
/// <summary> Marker used to store the size of loaded executable, stack, static, and global object size. </summary>
SUBTYPE_ImageSize = 14 ,
/// Version 3
// Marker types for automatic snapshots.
/// <summary> Marker used to determine when engine has started the cleaning process before loading a new level. </summary>
SUBTYPE_SnapshotMarker_LoadMap_Start = 21 ,
/// <summary> Marker used to determine when a new level has started loading. </summary>
SUBTYPE_SnapshotMarker_LoadMap_Mid = 22 ,
/// <summary> Marker used to determine when a new level has been loaded. </summary>
SUBTYPE_SnapshotMarker_LoadMap_End = 23 ,
/// <summary> Marker used to determine when garbage collection has started. </summary>
SUBTYPE_SnapshotMarker_GC_Start = 24 ,
/// <summary> Marker used to determine when garbage collection has finished. </summary>
SUBTYPE_SnapshotMarker_GC_End = 25 ,
/// <summary> Marker used to determine when a new streaming level has been requested to load. </summary>
SUBTYPE_SnapshotMarker_LevelStream_Start = 26 ,
/// <summary> Marker used to determine when a previously streamed level has been made visible. </summary>
SUBTYPE_SnapshotMarker_LevelStream_End = 27 ,
2014-04-23 16:37:47 -04:00
/// <summary> Marker used to store a generic malloc statistics. @see FMallocProfiler::WriteMemoryAllocationStats </summary>
2014-03-14 14:13:41 -04:00
SUBTYPE_MemoryAllocationStats = 31 ,
/// <summary> Start licensee-specific subtypes from here. </summary>
SUBTYPE_LicenseeBase = 50 ,
/// <summary> Unknown the subtype of the token. </summary>
SUBTYPE_Unknown ,
} ;
2014-04-23 16:37:47 -04:00
public interface IMemoryStats
2014-03-14 14:13:41 -04:00
{
}
/// <summary> Struct used to hold memory allocation statistics. Mirrored in MemoryBase.h. This need to be a class because of how ReadMemoryAllocationsStats method works. </summary>
2014-04-23 16:37:47 -04:00
public class FMemoryAllocationStatsV3
2014-03-14 14:13:41 -04:00
{
/// <summary> The total amount of memory used by the game. </summary>
public Int64 TotalUsed ;
/// <summary> The total amount of memory allocated from the OS. </summary>
public Int64 TotalAllocated ;
// Virtual memory for Xbox and PC / Main memory for PS3 (tracked in the allocators) Host is not included ??
/// <summary> The allocated in use by the application virtual memory. </summary>
public Int64 CPUUsed ;
/// <summary> The allocated from the OS/allocator, but not used by the application. </summary>
public Int64 CPUSlack ;
/// <summary> Alignment waste from a pooled allocator plus book keeping overhead. </summary>
public Int64 CPUWaste ;
/// <summary> The amount of free memory before the first malloc has been done. (PS3 only). </summary>
public Int64 CPUAvailable ;
// Physical memory for Xbox and PC / Local memory for PS3 (tracked in the allocators)
/// <summary> The allocated in use by the application physical memory. </summary>
public Int64 GPUUsed ;
/// <summary> The allocated from the OS, but not used by the application. </summary>
public Int64 GPUSlack ;
/// <summary> Alignment waste from a pooled allocator plus book keeping overhead. </summary>
public Int64 GPUWaste ;
/// <summary> The total amount of memory available for the allocator. (PS3 only) </summary>
public Int64 GPUAvailable ;
/// <summary> Used memory as reported by the operating system. (Xbox360, PS3 only) </summary>
public Int64 OSReportedUsed ;
/// <summary> Free memory as reported by the operating system. (Xbox360, PS3 only) </summary>
public Int64 OSReportedFree ;
/// <summary> The overhead of the operating system. (Xbox360 only) </summary>
public Int64 OSOverhead ;
/// <summary> Size of loaded executable, stack, static, and global object size. (Xbox360, PS3 only) </summary>
public Int64 ImageSize ;
/// <summary> Host memory in use by the application. (PS3 only) </summary>
public Int64 HostUsed ;
/// <summary> Host memory allocated, but not used by the application. (PS3 only) </summary>
public Int64 HostSlack ;
/// <summary> Host memory wasted due to allocations' alignment. (PS3 only) </summary>
public Int64 HostWaste ;
/// <summary> The total amount of host memory that has been allocated. (PS3 only) </summary>
public Int64 HostAvailable ;
/// <summary> Size of allocated memory in the texture pool. </summary>
public Int64 AllocatedTextureMemorySize ;
/// <summary> Size of available memory in the texture pool. </summary>
public Int64 AvailableTextureMemorySize ;
public void Zero ( )
{
TotalUsed = 0 ;
TotalAllocated = 0 ;
CPUUsed = 0 ;
CPUSlack = 0 ;
CPUWaste = 0 ;
CPUAvailable = 0 ;
GPUUsed = 0 ;
GPUSlack = 0 ;
GPUWaste = 0 ;
GPUAvailable = 0 ;
HostUsed = 0 ;
HostSlack = 0 ;
HostWaste = 0 ;
HostAvailable = 0 ;
OSReportedUsed = 0 ;
OSReportedFree = 0 ;
OSOverhead = 0 ;
ImageSize = 0 ;
AllocatedTextureMemorySize = 0 ;
AvailableTextureMemorySize = 0 ;
}
/// <summary> Returns a difference between old and new memory allocation stats. </summary>
2014-04-23 16:37:47 -04:00
public static FMemoryAllocationStatsV3 Diff ( FMemoryAllocationStatsV3 Old , FMemoryAllocationStatsV3 New )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:37:47 -04:00
FMemoryAllocationStatsV3 Diff = new FMemoryAllocationStatsV3 ( ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 16:37:47 -04:00
FieldInfo [ ] FieldInfos = typeof ( FMemoryAllocationStatsV3 ) . GetFields ( ) ;
2014-03-14 14:13:41 -04:00
int PropertiesNum = FieldInfos . Length ;
for ( int FieldIndex = 0 ; FieldIndex < PropertiesNum ; FieldIndex + + )
{
Int64 OldValue = ( Int64 ) FieldInfos [ FieldIndex ] . GetValue ( Old ) ;
Int64 NewValue = ( Int64 ) FieldInfos [ FieldIndex ] . GetValue ( New ) ;
FieldInfos [ FieldIndex ] . SetValue ( Diff , NewValue - OldValue ) ;
}
return Diff ;
}
/// <summary> Creates a new copy of this class. </summary>
2014-04-23 16:37:47 -04:00
public FMemoryAllocationStatsV3 DeepCopy ( )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:37:47 -04:00
FMemoryAllocationStatsV3 Copy = ( FMemoryAllocationStatsV3 ) MemberwiseClone ( ) ;
2014-03-14 14:13:41 -04:00
return Copy ;
}
/// <summary> Converts this memory allocation statistics to its equivalent string representation. </summary>
public override string ToString ( )
{
StringBuilder StrBuilder = new StringBuilder ( 1024 ) ;
/// <summary> The total amount of memory used by the game. </summary>
StrBuilder . AppendLine ( " TotalUsed: " + MainWindow . FormatSizeString2 ( TotalUsed ) ) ;
/// <summary> The total amount of memory allocated from the OS. </summary>
StrBuilder . AppendLine ( " TotalAllocated: " + MainWindow . FormatSizeString2 ( TotalAllocated ) ) ;
// Virtual memory for Xbox and PC / Main memory for PS3 (tracked in the allocators) Host is not included ??
/// <summary> The allocated in use by the application virtual memory. </summary>
StrBuilder . AppendLine ( " CPUUsed: " + MainWindow . FormatSizeString2 ( CPUUsed ) ) ;
/// <summary> The allocated from the OS/allocator, but not used by the application. </summary>
StrBuilder . AppendLine ( " CPUSlack: " + MainWindow . FormatSizeString2 ( CPUSlack ) ) ;
/// <summary> Alignment waste from a pooled allocator plus book keeping overhead. </summary>
StrBuilder . AppendLine ( " CPUWaste: " + MainWindow . FormatSizeString2 ( CPUWaste ) ) ;
/// <summary> The amount of free memory before the first malloc has been done. (PS3 only). </summary>
if ( FStreamInfo . GlobalInstance . Platform = = EPlatformType . PS3 )
{
StrBuilder . AppendLine ( " CPUAvailable: " + MainWindow . FormatSizeString2 ( CPUAvailable ) ) ;
}
// Physical memory for Xbox and PC / Local memory for PS3 (tracked in the allocators)
/// <summary> The allocated in use by the application physical memory. </summary>
StrBuilder . AppendLine ( " GPUUsed: " + MainWindow . FormatSizeString2 ( GPUUsed ) ) ;
/// <summary> The allocated from the OS, but not used by the application. </summary>
StrBuilder . AppendLine ( " GPUSlack: " + MainWindow . FormatSizeString2 ( GPUSlack ) ) ;
/// <summary> Alignment waste from a pooled allocator plus book keeping overhead. </summary>
StrBuilder . AppendLine ( " GPUWaste: " + MainWindow . FormatSizeString2 ( GPUWaste ) ) ;
/// <summary> The total amount of memory available for the allocator. (PS3 only) </summary>
StrBuilder . AppendLine ( " GPUAvailable: " + MainWindow . FormatSizeString2 ( GPUAvailable ) ) ;
/// <summary> Used memory as reported by the operating system. (Xbox360, PS3 only) </summary>
if ( FStreamInfo . GlobalInstance . Platform = = EPlatformType . PS3 | | FStreamInfo . GlobalInstance . Platform = = EPlatformType . Xbox360 )
{
StrBuilder . AppendLine ( " OSReportedUsed: " + MainWindow . FormatSizeString2 ( OSReportedUsed ) ) ;
}
/// <summary> Free memory as reported by the operating system. (Xbox360, PS3 only) </summary>
if ( FStreamInfo . GlobalInstance . Platform = = EPlatformType . PS3 | | FStreamInfo . GlobalInstance . Platform = = EPlatformType . Xbox360 )
{
StrBuilder . AppendLine ( " OSReportedFree: " + MainWindow . FormatSizeString2 ( OSReportedFree ) ) ;
}
/// <summary> The overhead of the operating system. (Xbox360 only) </summary>
if ( FStreamInfo . GlobalInstance . Platform = = EPlatformType . Xbox360 )
{
StrBuilder . AppendLine ( " OSOverhead: " + MainWindow . FormatSizeString2 ( OSOverhead ) ) ;
}
/// <summary> Size of loaded executable, stack, static, and global object size. (Xbox360, PS3 only) </summary>
if ( FStreamInfo . GlobalInstance . Platform = = EPlatformType . PS3 | | FStreamInfo . GlobalInstance . Platform = = EPlatformType . Xbox360 )
{
StrBuilder . AppendLine ( " ImageSize: " + MainWindow . FormatSizeString2 ( ImageSize ) ) ;
}
if ( FStreamInfo . GlobalInstance . Platform = = EPlatformType . PS3 )
{
/// <summary> Host memory in use by the application. (PS3 only) </summary>
StrBuilder . AppendLine ( " HostUsed: " + MainWindow . FormatSizeString2 ( HostUsed ) ) ;
/// <summary> Host memory allocated, but not used by the application. (PS3 only) </summary>
StrBuilder . AppendLine ( " HostSlack: " + MainWindow . FormatSizeString2 ( HostSlack ) ) ;
/// <summary> Host memory wasted due to allocations' alignment. (PS3 only) </summary>
StrBuilder . AppendLine ( " HostWaste: " + MainWindow . FormatSizeString2 ( HostWaste ) ) ;
/// <summary> The total amount of host memory that has been allocated. (PS3 only) </summary>
StrBuilder . AppendLine ( " HostAvailable: " + MainWindow . FormatSizeString2 ( HostAvailable ) ) ;
}
/// <summary> Size of allocated memory in the texture pool. </summary>
StrBuilder . AppendLine ( " AllocatedTextureMemorySize: " + MainWindow . FormatSizeString2 ( AllocatedTextureMemorySize ) ) ;
/// <summary> Size of available memory in the texture pool. </summary>
StrBuilder . AppendLine ( " AvailableTextureMemorySize: " + MainWindow . FormatSizeString2 ( AvailableTextureMemorySize ) ) ;
return StrBuilder . ToString ( ) ;
}
} ;
2014-04-23 16:37:47 -04:00
/// <summary>
/// Struct used to hold platform memory stats and allocator stats. Valid only for MemoryProfiler2.FProfileDataHeader.Version >= 4.
/// @see FGenericPlatformMemory::GetStatsForMallocProfiler
/// @see FMalloc::GetAllocatorStats
/// @todo add support for non-generic platform memory stats.
/// </summary>
public class FMemoryAllocationStatsV4
{
2014-05-21 12:36:39 -04:00
// Names of generic platform memory stats. @see FGenericPlatformMemory::GetStatsForMallocProfiler / GenericPlatformMemory.cpp
2014-04-23 16:37:47 -04:00
/// <summary> The amount of actual physical memory, in bytes. </summary>
static public string PlatformTotalPhysical = "Total Physical" ;
/// <summary> The amount of virtual memory, in bytes. </summary>
static public string PlatformTotalVirtual = "Total Virtual" ;
/// <summary> The size of a page, in bytes. </summary>
static public string PlatformPageSize = "Page Size" ;
/// <summary> Approximate physical RAM in GB"; 1 on everything except PC. Used for "course tuning", like FPlatformMisc::NumberOfCores(). </summary>
static public string PlatformTotalPhysicalGB = "Total Physical GB" ;
/// <summary> The amount of physical memory currently available, in bytes. </summary>
static public string PlatformAvailablePhysical = "Available Physical" ;
/// <summary> The amount of virtual memory currently available, in bytes. </summary>
static public string PlatformAvailableVirtual = "Available Virtual" ;
/// <summary> The amount of physical memory used by the process, in bytes. </summary>
static public string PlatformUsedPhysical = "Used Physical" ;
/// <summary> The peak amount of physical memory used by the process, in bytes. </summary>
static public string PlatformPeakUsedPhysical = "Peak Used Physical" ;
/// <summary> Total amount of virtual memory used by the process. </summary>
static public string PlatformUsedVirtual = "Used Virtual" ;
/// <summary> The peak amount of virtual memory used by the process. </summary>
static public string PlatformPeakUsedVirtual = "Peak Used Virtual" ;
static public string MemoryProfilingOverhead = "Memory Profiling Overhead" ;
2014-05-21 12:36:39 -04:00
// Names of malloc binned memory stats. @see FMallocBinned.GetAllocatorStats / MallocBinned.h
2014-04-23 16:37:47 -04:00
static public string BinnedWasteCurrent = "Binned Waste Current" ;
static public string BinnedUsedCurrent = "Binned Used Current" ;
static public string BinnedSlackCurrent = "Binned Slack Current" ;
private Dictionary < string , Int64 > _Stats ;
public FMemoryAllocationStatsV4 ( )
{
_Stats = new Dictionary < string , Int64 > ( ) ;
}
public FMemoryAllocationStatsV4 ( FMemoryAllocationStatsV4 Other )
{
this . _Stats = new Dictionary < string , Int64 > ( Other . _Stats ) ;
}
public Int64 this [ string StatName ]
{
get
{
2014-05-21 13:26:53 -04:00
Int64 Value = 0 ;
_Stats . TryGetValue ( StatName , out Value ) ;
return Value ;
2014-04-23 16:37:47 -04:00
}
set
{
_Stats [ StatName ] = value ;
}
}
public Int64 NumStats ( )
{
return _Stats . Count ;
}
/// <summary> Returns a difference between old and new platform memory stats. </summary>
public static FMemoryAllocationStatsV4 Diff ( FMemoryAllocationStatsV4 Old , FMemoryAllocationStatsV4 New )
{
FMemoryAllocationStatsV4 Diff = new FMemoryAllocationStatsV4 ( ) ;
var Keys = Old . _Stats . Keys ;
foreach ( string KeyValue in Keys )
{
Int64 OldValue = Old [ KeyValue ] ;
Int64 NewValue = New [ KeyValue ] ;
Diff [ KeyValue ] = NewValue - OldValue ;
}
return Diff ;
}
/// <summary> Creates a new copy of this class. </summary>
public FMemoryAllocationStatsV4 DeepCopy ( )
{
FMemoryAllocationStatsV4 Copy = new FMemoryAllocationStatsV4 ( this ) ;
return Copy ;
}
/// <summary> Converts this memory allocation statistics to its equivalent string representation. </summary>
public override string ToString ( )
{
StringBuilder StrBuilder = new StringBuilder ( 1024 ) ;
foreach ( KeyValuePair < string , Int64 > KeyPairValue in _Stats )
{
StrBuilder . AppendLine ( string . Format ( " {0}: {1}" , KeyPairValue . Key , MainWindow . FormatSizeString2 ( KeyPairValue . Value ) ) ) ;
}
return StrBuilder . ToString ( ) ;
}
} ;
2014-03-14 14:13:41 -04:00
/// <summary>
2014-04-23 16:37:47 -04:00
/// Variable sized token emitted by capture code. The parsing code ReadNextToken deals with this and updates
/// internal data. The calling code is responsible for only accessing member variables associated with the type.
/// </summary>
public class FStreamToken //@TODO: Can I turn this back into a struct?
{
// Parsing configuration
2014-03-14 14:13:41 -04:00
/// <summary> Mask of pointer field to get a real pointer (the two LSB are type fields, and the top bits may be a pool index. </summary>
2014-04-23 16:37:47 -04:00
public static UInt64 PointerMask = 0xFFFFFFFFFFFFFFFC UL ;
2014-03-14 14:13:41 -04:00
2014-04-23 16:37:47 -04:00
public const UInt64 TypeMask = 0x3 UL ;
public static int PoolShift = 64 ;
2014-03-14 14:13:41 -04:00
2014-04-23 16:37:47 -04:00
/// <summary> Whether to decode the script callstacks. </summary>
public static bool bDecodeScriptCallstacks ;
2014-03-14 14:13:41 -04:00
2014-04-23 16:37:47 -04:00
/// <summary> Version of the stream, same as FProfileDataHeader.Version </summary>
public static uint Version ;
2014-03-14 14:13:41 -04:00
/// <summary> Position in the stream. </summary>
public ulong StreamIndex = 0 ;
/// <summary> Type of token. </summary>
2014-04-23 16:37:47 -04:00
public EProfilingPayloadType Type ;
2014-03-14 14:13:41 -04:00
/// <summary> Subtype of token if it's of TYPE_Other. </summary>
2014-04-23 16:37:47 -04:00
public EProfilingPayloadSubType SubType ;
2014-03-14 14:13:41 -04:00
/// <summary> Pointer in the case of alloc / free. </summary>
2014-04-23 16:37:47 -04:00
public UInt64 Pointer ;
2014-03-14 14:13:41 -04:00
/// <summary> Old pointer in the case of realloc. </summary>
2014-04-23 16:37:47 -04:00
public UInt64 OldPointer ;
2014-03-14 14:13:41 -04:00
/// <summary> New pointer in the case of realloc. </summary>
2014-04-23 16:37:47 -04:00
public UInt64 NewPointer ;
2014-03-14 14:13:41 -04:00
/// <summary> Index into callstack array. </summary>
2014-04-23 16:37:47 -04:00
public Int32 CallStackIndex ;
2014-03-14 14:13:41 -04:00
/// <summary> Size of allocation in alloc / realloc case. </summary>
2014-04-23 16:37:47 -04:00
public Int32 Size ;
2014-03-14 14:13:41 -04:00
/// <summary> Payload if type is TYPE_Other. </summary>
2014-04-23 16:37:47 -04:00
public UInt32 Payload ;
2014-03-14 14:13:41 -04:00
/// <summary> Payload data if type is TYPE_Other and subtype is SUBTYPE_SnapshotMarker or SUBTYPE_TextMarker. Index into array of unique names. </summary>
2014-04-23 16:37:47 -04:00
public int TextIndex ;
2014-03-14 14:13:41 -04:00
/// <summary> Payload data if type is TYPE_Other and subtype is SUBTYPE_FrameTimeMarker. Current delta time in seconds. </summary>
2014-04-23 16:37:47 -04:00
public float DeltaTime ;
2014-03-14 14:13:41 -04:00
/// <summary> Total time, increased every time DeltaTime has been read. </summary>
public float TotalTime = 0.0f ;
/// <summary> Time between two consecutive snapshot markers. </summary>
public float ElapsedTime = 0.0f ;
/// <summary> Memory pool. </summary>
2014-04-23 16:37:47 -04:00
public EMemoryPool Pool ;
2014-03-14 14:13:41 -04:00
/// <summary> Platform dependent memory metrics. </summary>
2014-04-23 16:37:47 -04:00
public List < long > Metrics = new List < long > ( ) ;
2014-03-14 14:13:41 -04:00
/// <summary> A list of indices into the name table, one for each loaded level including persistent level. </summary>
2014-04-23 16:37:47 -04:00
public List < int > LoadedLevels = new List < int > ( ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 16:37:47 -04:00
/// <summary> Generic memory allocation stats for V3. </summary>
public FMemoryAllocationStatsV3 MemoryAllocationStats3 = new FMemoryAllocationStatsV3 ( ) ;
/// <summary> Generic memory allocation stats for V4. </summary>
public FMemoryAllocationStatsV4 MemoryAllocationStats4 = new FMemoryAllocationStatsV4 ( ) ;
2014-03-14 14:13:41 -04:00
/// <summary> Index into script callstack array. </summary>
2014-04-23 16:37:47 -04:00
public int ScriptCallstackIndex ;
2014-03-14 14:13:41 -04:00
/// <summary> Index into script-object type array. </summary>
2014-04-23 16:37:47 -04:00
public int ScriptObjectTypeIndex ;
2014-03-14 14:13:41 -04:00
/// <summary> Reads a script callstack. </summary>
/// <param name="BinaryStream"> Stream to serialize data from </param>
void ReadScriptCallstack ( BinaryReader BinaryStream )
{
if ( bDecodeScriptCallstacks )
{
ScriptCallstackIndex = BinaryStream . ReadUInt16 ( ) ;
bool bAllocatingScriptObject = ( ScriptCallstackIndex & 0x8000 ) ! = 0 ;
ScriptCallstackIndex = ScriptCallstackIndex & 0x7FFF ;
if ( ScriptCallstackIndex = = 0x7FFF )
{
ScriptCallstackIndex = - 1 ;
}
if ( bAllocatingScriptObject )
{
int ScriptObjectTypeCompactedName = BinaryStream . ReadInt32 ( ) ;
ScriptObjectTypeIndex = ScriptObjectTypeCompactedName & 0x00FFFFFF ;
// Number is always 0.
int ScriptObjectTypeNumber = ( ScriptObjectTypeCompactedName & 0x7FFFFFFF ) > > 24 ;
}
}
}
/// <summary> Reads additional data required for GCM callstacks. </summary>
/// <param name="BinaryStream"> Stream to serialize data from </param>
bool ReadGCMData ( BinaryReader BinaryStream , ref UInt32 UnsignedSize )
{
// @see FMallocGcmProfiler.h
const UInt32 GCM_MEMORY_PROFILER_ID_BIT = 0x80000000 ;
bool bHasGCMData = false ;
if ( ( UnsignedSize & GCM_MEMORY_PROFILER_ID_BIT ) = = GCM_MEMORY_PROFILER_ID_BIT )
{
// Lower five bits are EAllocationType, upper three bits are EMemoryPool
byte AllocationType = BinaryStream . ReadByte ( ) ;
Pool = FMemoryPoolInfo . ConvertToMemoryPoolFlag ( ( EMemoryPoolSerialized ) ( AllocationType & 0xe0 ) ) ;
UnsignedSize & = ~ GCM_MEMORY_PROFILER_ID_BIT ;
bHasGCMData = true ;
}
return bHasGCMData ;
}
/// <summary> Reads platform dependent memory metrics. </summary>
/// <param name="BinaryStream"> Stream to serialize data from </param>
2014-04-23 16:37:47 -04:00
void ReadMetrics ( BinaryReader BinaryStream )
{
// Read the metrics
int NumMetrics = BinaryStream . ReadByte ( ) ;
for ( int i = 0 ; i < NumMetrics ; i + + )
{
Metrics . Add ( BinaryStream . ReadInt64 ( ) ) ;
}
}
2014-03-14 14:13:41 -04:00
/// <summary> Reads names of all loaded levels. </summary>
/// <param name="BinaryStream"> Stream to serialize data from </param>
void ReadLoadedLevels ( BinaryReader BinaryStream )
{
// Read the currently loaded levels
int NumLevels = BinaryStream . ReadInt16 ( ) ;
for ( int LevelIndex = 0 ; LevelIndex < NumLevels ; LevelIndex + + )
{
int LevelNameIndex = BinaryStream . ReadInt32 ( ) ;
LoadedLevels . Add ( LevelNameIndex ) ;
}
}
/// <summary> Reads generic memory allocations stats. </summary>
/// <param name="BinaryStream"> Stream to serialize data from </param>
private void ReadMemoryAllocationsStats ( BinaryReader BinaryStream )
{
2014-04-23 16:37:47 -04:00
if ( Version > = 4 )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:37:47 -04:00
// Read Platform Memory and Allocator Stats
// @see FMallocProfiler::WriteMemoryAllocationStats
int StatsNum = BinaryStream . ReadByte ( ) ;
for ( int StatIndex = 0 ; StatIndex < StatsNum ; StatIndex + + )
{
int NameIndex = BinaryStream . ReadInt32 ( ) ;
Int64 StatValue = BinaryStream . ReadInt64 ( ) ;
string StatName = FStreamInfo . GlobalInstance . NameArray [ NameIndex ] ;
MemoryAllocationStats4 [ StatName ] = StatValue ;
}
2014-03-14 14:13:41 -04:00
}
2014-04-23 16:37:47 -04:00
else
{
int StatsNum = BinaryStream . ReadByte ( ) ;
FieldInfo [ ] FieldInfos = MemoryAllocationStats3 . GetType ( ) . GetFields ( ) ;
int PropertiesNum = FieldInfos . Length ;
Debug . Assert ( StatsNum = = PropertiesNum ) ;
for ( int StatIndex = 0 ; StatIndex < StatsNum ; StatIndex + + )
{
Int64 Value = BinaryStream . ReadInt64 ( ) ;
FieldInfos [ StatIndex ] . SetValue ( MemoryAllocationStats3 , Value ) ;
}
}
2014-03-14 14:13:41 -04:00
}
/// <summary> Updates the token with data read from passed in stream and returns whether we've reached the end. </summary>
/// <param name="BinaryStream"> Stream to serialize data from </param>
public bool ReadNextToken ( BinaryReader BinaryStream )
2014-04-23 16:37:47 -04:00
{
bool bReachedEndOfStream = false ;
2014-03-14 14:13:41 -04:00
// Initialize to defaults.
SubType = EProfilingPayloadSubType . SUBTYPE_Unknown ;
TextIndex = - 1 ;
2014-04-23 16:37:47 -04:00
// Read the pointer and convert to token type by looking at lowest 2 bits. Pointers are always
// 4 byte aligned so need to clear them again after the conversion.
UInt64 RawPointerData = BinaryStream . ReadUInt64 ( ) ;
2014-03-14 14:13:41 -04:00
Pool = EMemoryPool . MEMPOOL_Main ;
2014-04-23 16:37:47 -04:00
Type = ( EProfilingPayloadType ) ( RawPointerData & TypeMask ) ;
Pointer = RawPointerData & PointerMask ;
2014-03-14 14:13:41 -04:00
2014-04-23 16:37:47 -04:00
Metrics . Clear ( ) ;
LoadedLevels . Clear ( ) ;
MemoryAllocationStats3 . Zero ( ) ;
2014-03-14 14:13:41 -04:00
CallStackIndex = - 1 ;
2014-04-23 16:37:47 -04:00
ScriptCallstackIndex = - 1 ;
ScriptObjectTypeIndex = - 1 ;
2014-03-14 14:13:41 -04:00
NewPointer = 0 ;
OldPointer = 0 ;
Size = - 1 ;
Payload = 0 ;
DeltaTime = - 1.0f ;
2014-04-23 16:37:47 -04:00
// Serialize based on token type.
2014-03-14 14:13:41 -04:00
switch ( Type )
2014-04-23 16:37:47 -04:00
{
// Malloc
case EProfilingPayloadType . TYPE_Malloc :
2014-03-14 14:13:41 -04:00
{
// Get the call stack index.
CallStackIndex = BinaryStream . ReadInt32 ( ) ;
// Get the size of an allocation.
UInt32 UnsignedSize = BinaryStream . ReadUInt32 ( ) ;
// Read GCM data if any.
bool bHasGCMData = ReadGCMData ( BinaryStream , ref UnsignedSize ) ;
// If GCM doesn't exist read script callstack.
if ( bHasGCMData = = false )
{
ReadScriptCallstack ( BinaryStream ) ;
}
Size = ( int ) UnsignedSize ;
break ;
}
2014-04-23 16:37:47 -04:00
// Free
case EProfilingPayloadType . TYPE_Free :
{
2014-03-14 14:13:41 -04:00
break ;
}
// Realloc
case EProfilingPayloadType . TYPE_Realloc :
{
OldPointer = Pointer ;
NewPointer = BinaryStream . ReadUInt64 ( ) ;
CallStackIndex = BinaryStream . ReadInt32 ( ) ;
UInt32 UnsignedSize = BinaryStream . ReadUInt32 ( ) ;
bool bHasGCMData = ReadGCMData ( BinaryStream , ref UnsignedSize ) ;
if ( bHasGCMData = = false )
{
ReadScriptCallstack ( BinaryStream ) ;
}
Size = ( int ) UnsignedSize ;
break ;
}
2014-04-23 16:37:47 -04:00
// Other
2014-03-14 14:13:41 -04:00
case EProfilingPayloadType . TYPE_Other :
{
SubType = ( EProfilingPayloadSubType ) BinaryStream . ReadInt32 ( ) ;
Payload = BinaryStream . ReadUInt32 ( ) ;
// Read subtype.
switch ( SubType )
{
// End of stream!
case EProfilingPayloadSubType . SUBTYPE_EndOfStreamMarker :
{
2014-04-23 16:37:47 -04:00
if ( Version > = 4 )
{
ReadMemoryAllocationsStats ( BinaryStream ) ;
ReadLoadedLevels ( BinaryStream ) ;
}
else
2014-03-14 14:13:41 -04:00
{
ReadMemoryAllocationsStats ( BinaryStream ) ;
ReadLoadedLevels ( BinaryStream ) ;
ReadMetrics ( BinaryStream ) ;
}
bReachedEndOfStream = true ;
break ;
}
case EProfilingPayloadSubType . SUBTYPE_EndOfFileMarker :
{
break ;
}
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_LoadMap_Start :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_LoadMap_Mid :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_LoadMap_End :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_GC_Start :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_GC_End :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_LevelStream_Start :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker_LevelStream_End :
case EProfilingPayloadSubType . SUBTYPE_SnapshotMarker :
{
TextIndex = ( int ) Payload ;
2014-04-23 16:37:47 -04:00
if ( Version > = 4 )
{
ReadMemoryAllocationsStats ( BinaryStream ) ;
ReadLoadedLevels ( BinaryStream ) ;
}
else
2014-03-14 14:13:41 -04:00
{
ReadMemoryAllocationsStats ( BinaryStream ) ;
ReadLoadedLevels ( BinaryStream ) ;
ReadMetrics ( BinaryStream ) ;
}
break ;
}
case EProfilingPayloadSubType . SUBTYPE_FrameTimeMarker :
{
DeltaTime = BitConverter . ToSingle ( System . BitConverter . GetBytes ( Payload ) , 0 ) ;
TotalTime + = DeltaTime ;
ElapsedTime + = DeltaTime ;
break ;
}
case EProfilingPayloadSubType . SUBTYPE_TextMarker :
{
TextIndex = ( int ) Payload ;
break ;
}
case EProfilingPayloadSubType . SUBTYPE_MemoryAllocationStats :
{
ReadMemoryAllocationsStats ( BinaryStream ) ;
break ;
}
case EProfilingPayloadSubType . SUBTYPE_TotalUsed :
case EProfilingPayloadSubType . SUBTYPE_TotalAllocated :
case EProfilingPayloadSubType . SUBTYPE_CPUUsed :
case EProfilingPayloadSubType . SUBTYPE_CPUSlack :
case EProfilingPayloadSubType . SUBTYPE_CPUWaste :
case EProfilingPayloadSubType . SUBTYPE_GPUUsed :
case EProfilingPayloadSubType . SUBTYPE_GPUSlack :
case EProfilingPayloadSubType . SUBTYPE_GPUWaste :
case EProfilingPayloadSubType . SUBTYPE_ImageSize :
case EProfilingPayloadSubType . SUBTYPE_OSOverhead :
{
break ;
}
default :
{
throw new InvalidDataException ( ) ;
}
}
break ;
}
}
2014-04-23 16:37:47 -04:00
return ! bReachedEndOfStream ;
}
}
2014-03-14 14:13:41 -04:00
}