/// <summary> Constructor. </summary> public FCallStackTag( FCallStack InCallStack, int InStartFrame, ulong InStreamIndex, ulong InPointer, ulong InSize ) { CallStack = InCallStack; StreamIndex = InStreamIndex; Pointer = InPointer; Size = InSize; }
/// <summary> Constructor. </summary> public FAllocationEvent(FStreamToken StreamToken, FCallStack InPreviousCallStack, FAllocationLifecycle InPreviousLifecycle) { StreamIndex = StreamToken.StreamIndex; Pointer = StreamToken.Type == EProfilingPayloadType.TYPE_Realloc ? StreamToken.NewPointer : StreamToken.Pointer; Size = StreamToken.Size; PreviousCallStack = InPreviousCallStack; PreviousLifecycle = InPreviousLifecycle; }
private static void InsertItemIntoMemoryBitmapListView( FCallStack CallStack, ulong StreamIndex, int StartFrame, int EndFrame, ulong AllocatedPointer, int AllocatedSize ) { ListViewItem LVItem = new ListViewItem(); LVItem.Text = StartFrame.ToString(); LVItem.SubItems.Add( EndFrame == 0 ? "" : EndFrame.ToString() ); LVItem.SubItems.Add( MainWindow.FormatSizeString( AllocatedSize ) ); LVItem.Tag = new FCallStackTag( CallStack, StartFrame, StreamIndex, AllocatedPointer, ( ulong )AllocatedSize ); bool bInserted = false; for( int ItemIndex = OwnerWindow.MemoryBitmapAllocationHistoryListView.Items.Count - 1; ItemIndex >= 0; ItemIndex-- ) { if( ( ( FCallStackTag )OwnerWindow.MemoryBitmapAllocationHistoryListView.Items[ ItemIndex ].Tag ).StreamIndex <= StreamIndex ) { OwnerWindow.MemoryBitmapAllocationHistoryListView.Items.Insert( ItemIndex + 1, LVItem ); bInserted = true; break; } } if( !bInserted ) { OwnerWindow.MemoryBitmapAllocationHistoryListView.Items.Insert( 0, LVItem ); } }
private static void ProcessLifecycleForPixel( ulong PointerFromPixel, FCallStack CallStack, FAllocationLifecycle AllocLifecycle, bool bUpdateEndFrame ) { int StartFrame = 1; int EndFrame = 1; bool bAllocated = false; ulong AllocatedPointer = 0; int AllocatedSize = 0; ulong AllocatedStreamIndex = FStreamInfo.INVALID_STREAM_INDEX; if( AllocLifecycle.AllocEvent.Pointer <= PointerFromPixel && AllocLifecycle.AllocEvent.Pointer + ( uint )AllocLifecycle.AllocEvent.Size > PointerFromPixel ) { bAllocated = true; AllocatedPointer = AllocLifecycle.AllocEvent.Pointer; AllocatedSize = AllocLifecycle.AllocEvent.Size; AllocatedStreamIndex = AllocLifecycle.AllocEvent.StreamIndex; StartFrame = FStreamInfo.GlobalInstance.GetFrameNumberFromStreamIndex( EndFrame, AllocLifecycle.AllocEvent.StreamIndex ); } if( AllocLifecycle.ReallocsEvents != null ) { for( int EventIndex = 0; EventIndex < AllocLifecycle.ReallocsEvents.Count; EventIndex++ ) { if( bAllocated ) { if( AllocLifecycle.ReallocsEvents[ EventIndex ].NewPointer > PointerFromPixel || AllocLifecycle.ReallocsEvents[ EventIndex ].NewPointer + ( uint )AllocLifecycle.ReallocsEvents[ EventIndex ].NewSize < PointerFromPixel ) { bAllocated = false; EndFrame = FStreamInfo.GlobalInstance.GetFrameNumberFromStreamIndex( StartFrame, AllocLifecycle.ReallocsEvents[ EventIndex ].StreamIndex ); InsertItemIntoMemoryBitmapListView( CallStack, AllocatedStreamIndex, StartFrame, EndFrame, AllocatedPointer, AllocatedSize ); } } else if( AllocLifecycle.ReallocsEvents[ EventIndex ].NewPointer <= PointerFromPixel && AllocLifecycle.ReallocsEvents[ EventIndex ].NewPointer + ( uint )AllocLifecycle.ReallocsEvents[ EventIndex ].NewSize > PointerFromPixel ) { bAllocated = true; AllocatedPointer = AllocLifecycle.ReallocsEvents[ EventIndex ].NewPointer; AllocatedSize = AllocLifecycle.ReallocsEvents[ EventIndex ].NewSize; AllocatedStreamIndex = AllocLifecycle.ReallocsEvents[ EventIndex ].StreamIndex; StartFrame = FStreamInfo.GlobalInstance.GetFrameNumberFromStreamIndex( EndFrame, AllocLifecycle.ReallocsEvents[ EventIndex ].StreamIndex ); } } } if( bAllocated ) { if( bUpdateEndFrame ) { EndFrame = AllocLifecycle.FreeStreamIndex == FStreamInfo.INVALID_STREAM_INDEX ? -1 : FStreamInfo.GlobalInstance.GetFrameNumberFromStreamIndex( StartFrame, AllocLifecycle.FreeStreamIndex ); } else { EndFrame = 0; } InsertItemIntoMemoryBitmapListView( CallStack, AllocatedStreamIndex, StartFrame, EndFrame, AllocatedPointer, AllocatedSize ); } }
public FShortLivedCallStackTag( FCallStack InCallStack, uint[] InColumnValues ) { CallStack = InCallStack; ColumnValues = InColumnValues; }
private static int GetVirtualCallStackIndex( FStreamToken StreamToken, StreamObserver Observer ) { if( StreamToken.ScriptCallstackIndex == -1 && StreamToken.ScriptObjectTypeIndex == -1 ) { return StreamToken.CallStackIndex; } FCallStack OriginalCallStack = FStreamInfo.GlobalInstance.CallStackArray[ StreamToken.CallStackIndex ]; FScriptCallStack ScriptCallStack = StreamToken.ScriptCallstackIndex == -1 ? null : FStreamInfo.GlobalInstance.ScriptCallstackArray[ StreamToken.ScriptCallstackIndex ]; // Get the script-object type for this index (if it's not cached, create a ScriptObjectType instance and cache it). FScriptObjectType ScriptObjectType = null; if( StreamToken.ScriptObjectTypeIndex != -1 ) { if( !FStreamInfo.GlobalInstance.ScriptObjectTypeMapping.TryGetValue( StreamToken.ScriptObjectTypeIndex, out ScriptObjectType ) ) { ScriptObjectType = new FScriptObjectType( FStreamInfo.GlobalInstance.ScriptNameArray[ StreamToken.ScriptObjectTypeIndex ] ); FStreamInfo.GlobalInstance.ScriptObjectTypeMapping.Add( StreamToken.ScriptObjectTypeIndex, ScriptObjectType ); } } for( int ChildIndex = 0; ChildIndex < OriginalCallStack.Children.Count; ChildIndex++ ) { if( ( OriginalCallStack.Children[ ChildIndex ].ScriptCallStack == ScriptCallStack ) && ( OriginalCallStack.Children[ ChildIndex ].ScriptObjectType == ScriptObjectType ) ) { return OriginalCallStack.ChildIndices[ ChildIndex ]; } } FCallStack NewCallStack = new FCallStack( OriginalCallStack, ScriptCallStack, ScriptObjectType, FStreamInfo.GlobalInstance.CallStackArray.Count ); FStreamInfo.GlobalInstance.CallStackArray.Add( NewCallStack ); return FStreamInfo.GlobalInstance.CallStackArray.Count - 1; }
public bool ContainsCallStack(FCallStack OtherCallStack) { return CallStacksSet.Contains(OtherCallStack); }
/// <summary> Processes realloc operation for this allocation lifecycle. </summary> public void Realloc(FStreamToken StreamToken, FCallStack InitialCallStack, out int SizeChange) { // reallocs that are really frees should be handled by free() Debug.Assert(StreamToken.Size > 0); int InitialSize = CurrentSize; LatestPointer = StreamToken.NewPointer; FCallStack ReallocCallStack = FStreamInfo.GlobalInstance.CallStackArray[StreamToken.CallStackIndex]; if (ReallocsEvents == null) { ReallocsEvents = new List<FReallocationEvent>(); } ReallocsEvents.Add(new FReallocationEvent(StreamToken, ReallocCallStack)); ReallocsEvents.TrimExcess(); if (ReallocCallStack != InitialCallStack) { // pointer has been realloced by a different callstack // it hasn't been freed, but it won't be tracked by this lifecycle object anymore, // so mark this object complete SizeChange = -InitialSize; bIsComplete = true; } else { SizeChange = StreamToken.Size - InitialSize; } if (AllocEvent.PreviousCallStack != null) { AllocEvent.PreviousCallStack.PropagateSizeGraphPoint(AllocEvent.PreviousLifecycle, StreamToken.StreamIndex, SizeChange); } }
/// <summary> Processes realloc operation for this callstack and updates lifecycles if needed. </summary> public FAllocationLifecycle ProcessRealloc(FStreamToken StreamToken, ref FAllocationLifecycle NewLifecycle, FCallStack PreviousCallStack, FAllocationLifecycle PreviousLifecycle) { FAllocationLifecycle Result = null; int SizeChange = 0; bool bFreshRealloc = true; FAllocationLifecycle Lifecycle; if (IncompleteLifecycles.TryGetValue(StreamToken.OldPointer, out Lifecycle)) { IncompleteLifecycles.Remove(StreamToken.OldPointer); Lifecycle.Realloc(StreamToken, this, out SizeChange); if (Lifecycle.bIsComplete) { if (FStreamInfo.GlobalInstance.CreationOptions.KeepLifecyclesCheckBox.Checked) { CompleteLifecycles.Add(Lifecycle); } } else { IncompleteLifecycles.Add(Lifecycle.LatestPointer, Lifecycle); } bFreshRealloc = false; Result = Lifecycle; } else { Debug.Assert(NewLifecycle != null); NewLifecycle.Malloc(StreamToken, PreviousCallStack, PreviousLifecycle); Result = NewLifecycle; NewLifecycle = null; IncompleteLifecycles.Add(Result.LatestPointer, Result); bFreshRealloc = true; SizeChange = StreamToken.Size; } LatestSize += SizeChange; if (LatestSize > MaxSize) { MaxSize = LatestSize; } // it's possible that this point was already added to the graph via realloc chain propagation if (SizeGraphPoints != null && (SizeGraphPoints.Count == 0 || SizeGraphPoints[SizeGraphPoints.Count - 1].StreamIndex != StreamToken.StreamIndex)) { SizeGraphPoints.Add(new FSizeGraphPoint(StreamToken.StreamIndex, SizeChange, bFreshRealloc)); } return Result; }
private static void AddCallStackToGraph( TreeNode RootNode, FCallStack CallStack, FCallStackAllocationInfo AllocationInfo, int ParentFunctionIndex, bool bInvertCallStacks ) { // Used to determine whether it is okay to add address to the graph. An index of -1 means we don't care about parenting. bool bAllowNodeUpdate = ParentFunctionIndex == -1; // Iterate over each address and add it to the tree view. TreeNode CurrentNode = RootNode; for( int AdressIndex = 0; AdressIndex < CallStack.AddressIndices.Count; AdressIndex++ ) { int AddressIndex; if( bInvertCallStacks ) { AddressIndex = CallStack.AddressIndices[ CallStack.AddressIndices.Count - 1 - AdressIndex ]; } else { AddressIndex = CallStack.AddressIndices[ AdressIndex ]; } // Filter based on function if wanted. This means we only include callstacks that contain the function // and we also reparent the callstack to start at the first occurence of the function. if( ParentFunctionIndex != -1 && !bAllowNodeUpdate ) { bAllowNodeUpdate = FStreamInfo.GlobalInstance.CallStackAddressArray[ AddressIndex ].FunctionIndex == ParentFunctionIndex; } if( bAllowNodeUpdate ) { // Update the node for this address. The return value of the function will be the new parent node. CurrentNode = UpdateNodeAndPayload( CurrentNode, AddressIndex, AllocationInfo ); } } }
public bool Matches(FCallStack CallStack) { if (StackFramePatterns.Length == 0) { return false; } int PatternIndex = 0; if( bUseRegexes ) { for( int i = 0; i < CallStack.AddressIndices.Count; i++ ) { string CallStackMethod = FStreamInfo.GlobalInstance.NameArray[ FStreamInfo.GlobalInstance.CallStackAddressArray[ CallStack.AddressIndices[ i ] ].FunctionIndex ]; if( Regexes[ PatternIndex ].Match( CallStackMethod ).Success ) { PatternIndex++; if( PatternIndex >= StackFramePatterns.Length ) { return true; } } } } else { for( int i = 0; i < CallStack.AddressIndices.Count; i++ ) { string CallStackMethod = FStreamInfo.GlobalInstance.NameArray[ FStreamInfo.GlobalInstance.CallStackAddressArray[ CallStack.AddressIndices[ i ] ].FunctionIndex ]; if( CallStackMethod == StackFramePatterns[ PatternIndex ] ) { PatternIndex++; if( PatternIndex >= StackFramePatterns.Length ) { return true; } } } } return false; }
public virtual void ResolveCallstackSymbolInfoAsync(ESymbolResolutionMode SymbolResolutionMode, FCallStack CallStack, ResolveCallstackSymbolInfoCallback Callback, bool bCancelCurrentWork) { if (bCancelCurrentWork) { foreach (var Worker in ResolveCallstackSymbolInfoAsyncTasks) { if (Worker.IsBusy && !Worker.CancellationPending) { Worker.CancelAsync(); } } } for (int WorkerIndex = ResolveCallstackSymbolInfoAsyncTasks.Count - 1; WorkerIndex >= 0; --WorkerIndex) { var Worker = ResolveCallstackSymbolInfoAsyncTasks[WorkerIndex]; if (!Worker.IsBusy) { ResolveCallstackSymbolInfoAsyncTasks.RemoveAt(WorkerIndex); } } var AsyncWorker = new BackgroundWorker(); AsyncWorker.DoWork += new DoWorkEventHandler(delegate(object Obj, DoWorkEventArgs Args) { var Worker = Obj as BackgroundWorker; foreach (int AddressIndex in CallStack.AddressIndices) { if (Worker.CancellationPending) { break; } FCallStackAddress Address = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex]; ResolveAddressSymbolInfo(SymbolResolutionMode, Address); } if (!Worker.CancellationPending) { Callback(CallStack); } }); AsyncWorker.RunWorkerAsync(); ResolveCallstackSymbolInfoAsyncTasks.Add(AsyncWorker); }
public virtual bool ResolveCallstackSymbolInfo(ESymbolResolutionMode SymbolResolutionMode, FCallStack CallStack) { bool bSuccess = true; foreach (int AddressIndex in CallStack.AddressIndices) { FCallStackAddress Address = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex]; bSuccess &= ResolveAddressSymbolInfo(SymbolResolutionMode, Address); } return bSuccess; }
/// <summary> Constructor, initializing all members with passed in values. </summary> public FCallGraphNode(FCallGraphNode InParent, int InAddressIndex, long InAllocationSize, int InAllocationCount, string InFunctionName, FCallStack CallStack) { Parent = InParent; if (Parent != null) { Parent.Children.Add(this); } AddressIndex = InAddressIndex; AllocationSize = InAllocationSize; AllocationCount = InAllocationCount; FunctionName = InFunctionName; CallStacks.Add(CallStack); }
/// <summary> Based on original callstack initializes a new callstack with decoded script callstack and script object type. </summary> public FCallStack(FCallStack InOriginal, FScriptCallStack InScriptCallStack, FScriptObjectType InScriptObjectType, int InCallStackIndex) : this() { Debug.Assert(InOriginal != null); Debug.Assert(ScriptCallStack == null || ScriptCallStack.Frames.Length > 0); Original = InOriginal; ScriptCallStack = InScriptCallStack; ScriptObjectType = InScriptObjectType; Original.Children.Add(this); Original.ChildIndices.Add(InCallStackIndex); CRC = Original.CRC; AddressIndices = new List<int>(Original.AddressIndices); FirstNonContainer = AddressIndices.Count - 1; bIsTruncated = Original.bIsTruncated; // If there is a script call stack, rename functions if (ScriptCallStack != null) { int ScriptFrameIndex = 0; for (int AddressIndex = AddressIndices.Count - 1; AddressIndex >= 0; AddressIndex--) { int FunctionNameIndex = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndices[AddressIndex]].FunctionIndex; if (FunctionNameIndex == FStreamInfo.GlobalInstance.ProcessInternalNameIndex) { AddressIndices[AddressIndex] = ScriptCallStack.Frames[ScriptFrameIndex].CallStackAddressIndex; ScriptFrameIndex++; if (ScriptFrameIndex >= ScriptCallStack.Frames.Length) { break; } } } } // If the call stack has a script type allocation, replace the StaticAllocateObject call with the appropriate type-tagged one if (ScriptObjectType != null) { for (int AddressIndex = AddressIndices.Count - 1; AddressIndex >= 0; AddressIndex--) { int FunctionNameIndex = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndices[AddressIndex]].FunctionIndex; if (FunctionNameIndex == FStreamInfo.GlobalInstance.StaticAllocateObjectNameIndex) { AddressIndices[AddressIndex] = ScriptObjectType.CallStackAddressIndex; break; } } } }
/// <summary> Constructor, initializing all members with passed in values. </summary> public FNodePayload( int InAddressIndex, long InAllocationSize, int InAllocationCount, FCallStack CallStack ) { AddressIndex = InAddressIndex; AllocationSize = InAllocationSize; AllocationCount = InAllocationCount; CallStacks.Add( CallStack ); }
/// <summary> Compares two callstacks for sorting. </summary> /// <param name="A"> First callstack to compare </param> /// <param name="B"> Second callstack to compare </param> public static int Compare(FCallStack A, FCallStack B) { // Not all callstacks have the same depth. Figure out min for comparision. int MinSize = Math.Min(A.AddressIndices.Count, B.AddressIndices.Count); // Iterate over matching size and compare. for (int i = 0; i < MinSize; i++) { // Sort by address if (A.AddressIndices[i] > B.AddressIndices[i]) { return 1; } else if (A.AddressIndices[i] < B.AddressIndices[i]) { return -1; } } // If we got here it means that the subset of addresses matches. In theory this means // that the callstacks should have the same size as you can't have the same address // doing the same thing, but let's simply be thorough and handle this case if the // stackwalker isn't 100% accurate. // Matching length means matching callstacks. if (A.AddressIndices.Count == B.AddressIndices.Count) { return 0; } // Sort by additional length. else { return A.AddressIndices.Count > B.AddressIndices.Count ? 1 : -1; } }
public virtual void AllocationEvent( FCallStack Callstack, EProfilingPayloadType EventType, long Size ) { }
/// <summary> Processes malloc operation for this allocation lifecycle. </summary> public void Malloc(FStreamToken StreamToken, FCallStack PreviousCallStack, FAllocationLifecycle PreviousLifecycle) { AllocEvent = new FAllocationEvent(StreamToken, PreviousCallStack, PreviousLifecycle); LatestPointer = AllocEvent.Pointer; // if PreviousCallStack != null, initial allocation was made by another callstack if (PreviousCallStack != null) { PreviousCallStack.PropagateSizeGraphPoint(PreviousLifecycle, StreamToken.StreamIndex, StreamToken.Size); } }
public virtual void NewCallstack( FCallStack Callstack ) { }
/// <summary> Constructor. </summary> public FReallocationEvent(FStreamToken StreamToken, FCallStack InCallstack) { StreamIndex = StreamToken.StreamIndex; NewPointer = StreamToken.NewPointer; NewSize = StreamToken.Size; }
public void AddCallStack(FCallStack NewCallStack) { CallStacks.Add(NewCallStack); CallStacksSet.Add(NewCallStack); }