/// <summary> Initializes common controls and setups all needed properties. </summary> private void CommonInit() { Options = UnrealControls.XmlHandler.ReadXml<SettableOptions>( Path.Combine( Application.StartupPath, "MemoryProfiler2.ClassGroups.xml" ) ); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler( CurrentDomain_AssemblyResolve ); ExclusiveListView.ListViewItemSorter = new FColumnSorter(); PopulateClassGroups(); InvertCallgraphViewMenuItem.Checked = Options.InvertCallStacksInCallGraphView; FilterObjectVMFunctionsMenuItem.Checked = Options.FilterOutObjectVMFunctions; SelectedMemoryPool = ( EMemoryPool )Options.MemoryPoolFilterState; UpdatePoolFilterFromSelectedPool(); FCallGraphTreeViewParser.SetProfilerWindow( this ); FCallStackHistoryView.SetProfilerWindow( this ); FExclusiveListViewParser.SetProfilerWindow( this ); FTimeLineChartView.SetProfilerWindow( this ); FHistogramParser.SetProfilerWindow( this ); FMemoryBitmapParser.SetProfilerWindow( this ); FShortLivedAllocationView.SetProfilerWindow( this ); SetupFilteringControls(); ResetFilteringState(); LastResizedSize = Size; ToolTip DetailsViewTips = new ToolTip(); DetailsViewTips.SetToolTip( DetailsViewStartLabel, "Shows start snapshot detailed information" ); DetailsViewTips.SetToolTip( DetailsViewDiffLabel, "Shows detailed information as a difference between end and start snapshot" ); DetailsViewTips.SetToolTip( DetailsViewEndLabel, "Shows end snapshot detailed information" ); }
/// <summary> Filter callstacks in based on the text filter AND the class filter. </summary> private bool FilterIn(string FilterInText, List <ClassGroup> ClassGroups, EMemoryPool MemoryPoolFilter) { // Check against memory pool filter if ((MemoryPoolFilter & MemoryPool) != EMemoryPool.MEMPOOL_None) { // Check against the simple text filter if ((FilterInText.Length == 0) || PassesTextFilterTest(FilterInText)) { // Check against any active classes if (ClassGroups.Contains(Group)) { return(true); } } } return(false); }
/// <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); }
public FMemoryPoolInfo this[EMemoryPool MemoryPool] { get { if (MemoryPool == EMemoryPool.MEMPOOL_None) { return(null); } // Work out index from flag (effectively log base 2). int Index = 0; int MemoryPoolIndex = ( int )MemoryPool; while (MemoryPoolIndex != 1) { MemoryPoolIndex = MemoryPoolIndex >> 1; Index++; } return(MemoryPoolInfos[Index]); } }
/// <summary> /// Each memory pool should only have memory allocated in one of the two /// histogram columns (Main memory or VRAM). This function returns which /// histogram column is valid for the given pool. /// </summary> public static int GetMemoryPoolHistogramColumn(EMemoryPool MemoryPool) { switch (MemoryPool) { case EMemoryPool.MEMPOOL_Main: return(0); case EMemoryPool.MEMPOOL_Local: return(1); case EMemoryPool.MEMPOOL_HostDefault: return(0); case EMemoryPool.MEMPOOL_HostMovies: return(0); default: // Some combination of the above flags. return(-1); } }
/// <summary> Filter callstacks out based on the text filter AND the class filter. </summary> private bool FilterOut(string FilterInText, List <ClassGroup> ClassGroups, EMemoryPool MemoryPoolFilter) { if ((MemoryPoolFilter & MemoryPool) != EMemoryPool.MEMPOOL_None) { // This callstack is in the selected pool, so filter it out return(false); } // Check against the simple text filter if ((FilterInText.Length > 0) && PassesTextFilterTest(FilterInText)) { // Found match, we do not want this callstack return(false); } // Check against any active classes if (ClassGroups.Contains(Group)) { return(false); } return(true); }
/// <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) { bool bReachedEndOfStream = false; // Initialize to defaults. SubType = EProfilingPayloadSubType.SUBTYPE_Unknown; TextIndex = -1; // 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(); Pool = EMemoryPool.MEMPOOL_Main; Type = (EProfilingPayloadType)(RawPointerData & TypeMask); Pointer = RawPointerData & PointerMask; Metrics.Clear(); LoadedLevels.Clear(); CallStackIndex = -1; TagsIndex = -1; ScriptCallstackIndex = -1; ScriptObjectTypeIndex = -1; NewPointer = 0; OldPointer = 0; Size = -1; Payload = 0; DeltaTime = -1.0f; // Serialize based on token type. switch (Type) { // Malloc case EProfilingPayloadType.TYPE_Malloc: { // Get the call stack index. CallStackIndex = BinaryStream.ReadInt32(); // Get the tags index. if (Version >= 7) { TagsIndex = 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; } // Free case EProfilingPayloadType.TYPE_Free: { break; } // Realloc case EProfilingPayloadType.TYPE_Realloc: { OldPointer = Pointer; NewPointer = BinaryStream.ReadUInt64(); CallStackIndex = BinaryStream.ReadInt32(); // Get the tags index. if (Version >= 7) { TagsIndex = BinaryStream.ReadInt32(); } UInt32 UnsignedSize = BinaryStream.ReadUInt32(); bool bHasGCMData = ReadGCMData(BinaryStream, ref UnsignedSize); if (bHasGCMData == false) { ReadScriptCallstack(BinaryStream); } Size = ( int )UnsignedSize; break; } // Other case EProfilingPayloadType.TYPE_Other: { SubType = ( EProfilingPayloadSubType )BinaryStream.ReadInt32(); Payload = BinaryStream.ReadUInt32(); // Read subtype. switch (SubType) { // End of stream! case EProfilingPayloadSubType.SUBTYPE_EndOfStreamMarker: { ReadMemoryAllocationsStats(BinaryStream); ReadLoadedLevels(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; ReadMemoryAllocationsStats(BinaryStream); ReadLoadedLevels(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; } } return(!bReachedEndOfStream); }
/// <summary> Runs all the current filters on this callstack. </summary> public bool RunFilters(string FilterInText, List <ClassGroup> ClassGroups, bool bFilterInClasses, EMemoryPool MemoryPoolFilter) { // Create a list of active groups List <ClassGroup> ActiveGroups = new List <ClassGroup>(); foreach (ClassGroup Group in ClassGroups) { if (Group.bFilter) { ActiveGroups.Add(Group); } } // Filter groups in or out if (bFilterInClasses) { return(FilterIn(FilterInText, ActiveGroups, MemoryPoolFilter)); } else { return(FilterOut(FilterInText, ActiveGroups, MemoryPoolFilter)); } }
/// <summary> Runs all the current filters on this callstack. </summary> public bool RunFilters(string FilterInText, List<ClassGroup> ClassGroups, bool bFilterInClasses, EMemoryPool MemoryPoolFilter) { // Create a list of active groups List<ClassGroup> ActiveGroups = new List<ClassGroup>(); foreach (ClassGroup Group in ClassGroups) { if (Group.bFilter) { ActiveGroups.Add(Group); } } // Filter groups in or out if (bFilterInClasses) { return FilterIn(FilterInText, ActiveGroups, MemoryPoolFilter); } else { return FilterOut(FilterInText, ActiveGroups, MemoryPoolFilter); } }
/// <summary> Filter callstacks out based on the text filter AND the class filter. </summary> private bool FilterOut(string FilterInText, List<ClassGroup> ClassGroups, EMemoryPool MemoryPoolFilter) { if ((MemoryPoolFilter & MemoryPool) != EMemoryPool.MEMPOOL_None) { // This callstack is in the selected pool, so filter it out return false; } // Check against the simple text filter if ((FilterInText.Length > 0) && PassesTextFilterTest(FilterInText)) { // Found match, we do not want this callstack return (false); } // Check against any active classes if (ClassGroups.Contains(Group)) { return (false); } return (true); }
/// <summary> Filter callstacks in based on the text filter AND the class filter. </summary> private bool FilterIn(string FilterInText, List<ClassGroup> ClassGroups, EMemoryPool MemoryPoolFilter) { // Check against memory pool filter if ((MemoryPoolFilter & MemoryPool) != EMemoryPool.MEMPOOL_None) { // Check against the simple text filter if ((FilterInText.Length == 0) || PassesTextFilterTest(FilterInText)) { // Check against any active classes if (ClassGroups.Contains(Group)) { return (true); } } } return (false); }
/// <summary> Updates the selected memory pool based on memory pool filter menu items. </summary> private void RefreshSelectedMemoryPool() { if (MemoryPoolFilterButton.Enabled) { SelectedMemoryPool = EMemoryPool.MEMPOOL_None; if (PoolMainItem.Checked) { SelectedMemoryPool |= EMemoryPool.MEMPOOL_Main; } if (PoolLocalItem.Checked) { SelectedMemoryPool |= EMemoryPool.MEMPOOL_Local; } if (PoolHostDefaultItem.Checked) { SelectedMemoryPool |= EMemoryPool.MEMPOOL_HostDefault; } if (PoolHostMoviesItem.Checked) { SelectedMemoryPool |= EMemoryPool.MEMPOOL_HostMovies; } } else { SelectedMemoryPool = EMemoryPool.MEMPOOL_All; } Options.MemoryPoolFilterState = ( uint )SelectedMemoryPool; UpdateFilteringState(); }
/// <summary> Parses the data stream into the current view. </summary> private void ParseCurrentView() { // Update the current snapshot based on combo box settings. UpdateCurrentSnapshot(); // If valid, parse it into the selected tab view. if( CurrentSnapshot != null ) { bool bShouldSortBySize = ( SortCriteriaSplitButton.Text == " Sort by Size" ); List<FCallStackAllocationInfo> CallStackList = null; if( AllocationsTypeSplitButton.Text == " Active Allocations" ) { CallStackList = CurrentSnapshot.ActiveCallStackList; } else { CallStackList = CurrentSnapshot.LifetimeCallStackList; } // make sure the SelectedMemoryPool isn't masking out anything for Non-PS3 profiles if (!MemoryPoolFilterButton.Enabled) { SelectedMemoryPool = IsFilteringIn() ? EMemoryPool.MEMPOOL_All : EMemoryPool.MEMPOOL_None; } // Parse snapshots into views. // updating the call graph view is WAY SLOW if( MainTabControl.SelectedTab == CallGraphTabPage ) { FCallGraphTreeViewParser.ParseSnapshot( CallGraphTreeView, CallStackList, bShouldSortBySize, FilterTextBox.Text.ToUpperInvariant(), Options.InvertCallStacksInCallGraphView ); } else if( MainTabControl.SelectedTab == ExclusiveTabPage ) { FExclusiveListViewParser.ParseSnapshot( ExclusiveListView, CallStackList, bShouldSortBySize, FilterTextBox.Text.ToUpperInvariant() ); } else if( MainTabControl.SelectedTab == TimeLineTabPage ) { FTimeLineChartView.ParseSnapshot( TimeLineChart, CurrentSnapshot ); } else if( MainTabControl.SelectedTab == HistogramTabPage ) { FHistogramParser.ParseSnapshot( CallStackList, FilterTextBox.Text.ToUpperInvariant() ); } else if( MainTabControl.SelectedTab == CallstackHistoryTabPage ) { // Refresh tab with existing history callstacks, in case any options have changed. FCallStackHistoryView.RefreshCallStackHistoryGraph(); } else if( MainTabControl.SelectedTab == MemoryBitmapTabPage ) { FMemoryBitmapParser.ResetZoom(); } else if( MainTabControl.SelectedTab == ShortLivedAllocationsTabPage ) { FShortLivedAllocationView.ParseSnapshot( FilterTextBox.Text.ToUpperInvariant() ); } ResetFilteringState(); } else { // Clear the views to signal error. ResetViews(); } UpdateStatus( "Displaying " + CurrentFilename ); }
/// <summary> Default constructor. </summary> public FFilteringState( bool bFake ) { StartSnapshot = -1; EndSnapshot = -1; SortType = ""; AllocationType = ""; ContainersVisibilityType = ""; FilterType = ""; GroupArray = new List<bool>( 40 ); TextFilter = ""; MemoryPool = EMemoryPool.MEMPOOL_None; }
/// <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 ) { bool bReachedEndOfStream = false; // Initialize to defaults. SubType = EProfilingPayloadSubType.SUBTYPE_Unknown; TextIndex = -1; // 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(); Pool = EMemoryPool.MEMPOOL_Main; Type = (EProfilingPayloadType)(RawPointerData & TypeMask); Pointer = RawPointerData & PointerMask; Metrics.Clear(); LoadedLevels.Clear(); MemoryAllocationStats.Zero(); CallStackIndex = -1; ScriptCallstackIndex = -1; ScriptObjectTypeIndex = -1; NewPointer = 0; OldPointer = 0; Size = -1; Payload = 0; DeltaTime = -1.0f; // Serialize based on token type. switch( Type ) { // Malloc case EProfilingPayloadType.TYPE_Malloc: { // 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; } // Free case EProfilingPayloadType.TYPE_Free: { 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; } // Other case EProfilingPayloadType.TYPE_Other: { SubType = ( EProfilingPayloadSubType )BinaryStream.ReadInt32(); Payload = BinaryStream.ReadUInt32(); // Read subtype. switch( SubType ) { // End of stream! case EProfilingPayloadSubType.SUBTYPE_EndOfStreamMarker: { if( Version > 2 ) { 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; if( Version > 2 ) { 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; } } return !bReachedEndOfStream; }
/// <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; }