Example #1
0
        /// <summary>
        /// Diffs the two passed in callstack infos and returns the difference.
        /// </summary>
        /// <param name="New"> Newer callstack info to subtract older from </param>
        /// <param name="Old"> Older callstack info to subtract from older </param>
        public static FCallStackAllocationInfo Diff(FCallStackAllocationInfo New, FCallStackAllocationInfo Old)
        {
            if (New.CallStackIndex != Old.CallStackIndex)
            {
                throw new InvalidDataException();
            }

            FCallStackAllocationInfo DiffData = New.DeepCopy();

            DiffData.UntaggedAllocationInfo -= Old.UntaggedAllocationInfo;

            if (Old.TaggedAllocationInfo != null)
            {
                DiffData.EnsureTaggedAllocationsAvailable();

                foreach (var TaggedAllocationInfoPair in Old.TaggedAllocationInfo)
                {
                    FCallStackTagsAllocationInfo CurrentTagsAllocationInfo;
                    if (!DiffData.TaggedAllocationInfo.TryGetValue(TaggedAllocationInfoPair.Key, out CurrentTagsAllocationInfo))
                    {
                        CurrentTagsAllocationInfo = new FCallStackTagsAllocationInfo(0, 0);
                    }
                    DiffData.TaggedAllocationInfo[TaggedAllocationInfoPair.Key] = CurrentTagsAllocationInfo - TaggedAllocationInfoPair.Value;
                }
            }

            return(DiffData);
        }
Example #2
0
        public void FillActiveCallStackList(Dictionary <ulong, FCallStackAllocationInfo> PointerToPointerInfoMap)
        {
            ActiveCallStackList.Clear();
            ActiveCallStackList.Capacity = LifetimeCallStackList.Count;

            foreach (KeyValuePair <ulong, FCallStackAllocationInfo> PointerData in PointerToPointerInfoMap)
            {
                int  CallStackIndex = PointerData.Value.CallStackIndex;
                long Size           = PointerData.Value.Size;

                // make sure allocationInfoList is big enough
                while (CallStackIndex >= ActiveCallStackList.Count)
                {
                    ActiveCallStackList.Add(new FCallStackAllocationInfo(0, ActiveCallStackList.Count, 0));
                }

                FCallStackAllocationInfo NewAllocInfo = ActiveCallStackList[CallStackIndex];
                NewAllocInfo.Size += Size;
                NewAllocInfo.Count++;
                ActiveCallStackList[CallStackIndex] = NewAllocInfo;
            }

            // strip out any callstacks with no allocations
            ActiveCallStackList.RemoveAll(Item => Item.Count == 0);
            ActiveCallStackList.TrimExcess();
        }
Example #3
0
        /// <summary> Inserts the new allocation so that the list stays in size order. </summary>
        public void AddAllocation(FCallStackAllocationInfo AllocationInfo)
        {
            bool bInserted = false;

            if (BatchAddingCount == 0)
            {
                for (int Index = 0; Index < CallStackList.Count; Index++)
                {
                    if (CallStackList[Index].TotalSize > AllocationInfo.TotalSize)
                    {
                        CallStackList.Insert(Index, AllocationInfo);
                        bInserted = true;
                        break;
                    }
                }
            }

            if (!bInserted)
            {
                CallStackList.Add(AllocationInfo);
            }

            MemorySize      += AllocationInfo.TotalSize;
            AllocationCount += AllocationInfo.TotalCount;
        }
Example #4
0
 /// <summary>
 /// Diffs the two passed in callstack infos and returns the difference.
 /// </summary>
 /// <param name="New"> Newer callstack info to subtract older from </param>
 /// <param name="Old"> Older callstack info to subtract from older </param>
 public static FCallStackAllocationInfo Diff(FCallStackAllocationInfo New, FCallStackAllocationInfo Old)
 {
     if (New.CallStackIndex != Old.CallStackIndex)
     {
         throw new InvalidDataException();
     }
     return(new FCallStackAllocationInfo(New.Size - Old.Size, New.CallStackIndex, New.Count - Old.Count));
 }
Example #5
0
		/// <summary>
		/// Diffs the two passed in callstack infos and returns the difference.
		/// </summary>
		/// <param name="New"> Newer callstack info to subtract older from </param>
		/// <param name="Old"> Older callstack info to subtract from older </param>
        public static FCallStackAllocationInfo Diff( FCallStackAllocationInfo New, FCallStackAllocationInfo Old )
        {
            if( New.CallStackIndex != Old.CallStackIndex )
            {
                throw new InvalidDataException();
            }
            return new FCallStackAllocationInfo( New.Size - Old.Size, New.CallStackIndex, New.Count - Old.Count );
        }
Example #6
0
        /// <summary> Updates internal state with allocation. </summary>
        private static void HandleMalloc(FStreamToken StreamToken, FStreamSnapshot Snapshot, Dictionary <ulong, FCallStackAllocationInfo> PointerToPointerInfoMap)
        {
            // Keep track of size associated with pointer and also current callstack.
            FCallStackAllocationInfo PointerInfo = new FCallStackAllocationInfo(StreamToken.Size, StreamToken.CallStackIndex, 1);

            if (PointerToPointerInfoMap.ContainsKey(StreamToken.Pointer))
            {
                Debug.WriteLine("Same pointer malloced twice without being freed: " + StreamToken.Pointer + " in pool " + StreamToken.Pool);
                PointerToPointerInfoMap.Remove(StreamToken.Pointer);
            }

            PointerToPointerInfoMap.Add(StreamToken.Pointer, PointerInfo);

            if (StreamToken.CallStackIndex >= FStreamInfo.GlobalInstance.CallStackArray.Count)
            {
                Debug.WriteLine("CallStackIndex out of range!");
                return;
            }

            // Add size to lifetime churn tracking.
            while (StreamToken.CallStackIndex >= Snapshot.LifetimeCallStackList.Count)
            {
                Snapshot.LifetimeCallStackList.Add(new FCallStackAllocationInfo(0, Snapshot.LifetimeCallStackList.Count, 0));
            }

            //@todo: Sadly, we have to do all this ugly shuffling because of the way lists of structs work in C#
            Snapshot.LifetimeCallStackList[StreamToken.CallStackIndex] = Snapshot.LifetimeCallStackList[StreamToken.CallStackIndex].Add(StreamToken.Size, 1);

            if (Snapshot.AllocationSize > Snapshot.AllocationMaxSize)
            {
                Snapshot.AllocationMaxSize = Snapshot.AllocationSize;
            }

            // Maintain timeline view
            Snapshot.AllocationSize += PointerInfo.Size;
            Snapshot.AllocationCount++;
            if (Snapshot.AllocationCount % AllocationsPerSlice == 0)
            {
                FMemorySlice Slice = new FMemorySlice(Snapshot);
                Snapshot.OverallMemorySlice.Add(Slice);
                Snapshot.AllocationMaxSize = 0;
            }
        }
        /// <summary> Inserts the new allocation so that the list stays in size order. </summary>
        public void AddAllocation( FCallStackAllocationInfo AllocationInfo )
        {
            bool bInserted = false;
            for( int Index = 0; Index < CallStackList.Count; Index++ )
            {
                if( CallStackList[ Index ].Size > AllocationInfo.Size )
                {
                    CallStackList.Insert( Index, AllocationInfo );
                    bInserted = true;
                    break;
                }
            }

            if( !bInserted )
            {
                CallStackList.Add( AllocationInfo );
            }

            MemorySize += AllocationInfo.Size;
            AllocationCount += AllocationInfo.Count;
        }
Example #8
0
        /// <summary>
        /// Adds the passed callstack info to this callstack info.
        /// </summary>
        /// <param name="InOther"> Callstack info to add </param>
        public void Add(FCallStackAllocationInfo InOther)
        {
            if (CallStackIndex != InOther.CallStackIndex)
            {
                throw new InvalidDataException();
            }

            UntaggedAllocationInfo += InOther.UntaggedAllocationInfo;

            if (InOther.TaggedAllocationInfo != null)
            {
                EnsureTaggedAllocationsAvailable();

                foreach (var TaggedAllocationInfoPair in InOther.TaggedAllocationInfo)
                {
                    FCallStackTagsAllocationInfo CurrentTagsAllocationInfo;
                    if (!TaggedAllocationInfo.TryGetValue(TaggedAllocationInfoPair.Key, out CurrentTagsAllocationInfo))
                    {
                        CurrentTagsAllocationInfo = new FCallStackTagsAllocationInfo(0, 0);
                    }
                    TaggedAllocationInfo[TaggedAllocationInfoPair.Key] = CurrentTagsAllocationInfo + TaggedAllocationInfoPair.Value;
                }
            }
        }
        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);
                }
            }
        }
 /// <summary> Compare helper function, sorting FCallStackAllocation by count. </summary>
 private static int CompareCount(FCallStackAllocationInfo A, FCallStackAllocationInfo B)
 {
     return(Math.Sign(B.TotalCount - A.TotalCount));
 }
		/// <summary> Updates internal state with free. </summary>
        private static bool HandleFree(FStreamToken StreamToken, FStreamSnapshot Snapshot, Dictionary<ulong, FCallStackAllocationInfo> PointerToPointerInfoMap, out FCallStackAllocationInfo FreedAllocInfo)
		{
            if (!PointerToPointerInfoMap.TryGetValue(StreamToken.Pointer, out FreedAllocInfo))
            {
                Debug.WriteLine("Free without malloc: " + StreamToken.Pointer + " in pool " + StreamToken.Pool);
                return false;
            }

			// Maintain timeline view
            Snapshot.AllocationSize -= FreedAllocInfo.Size;
			Snapshot.AllocationCount++;
			if (Snapshot.AllocationCount % AllocationsPerSlice == 0)
			{
				FMemorySlice Slice = new FMemorySlice( Snapshot );
				Snapshot.OverallMemorySlice.Add( Slice );
			}

			// Remove freed pointer if it is in the array.
			PointerToPointerInfoMap.Remove(StreamToken.Pointer);

            return true;
		}
		/// <summary> Updates internal state with allocation. </summary>
        private static void HandleMalloc(FStreamToken StreamToken, FStreamSnapshot Snapshot, Dictionary<ulong, FCallStackAllocationInfo> PointerToPointerInfoMap)
		{
			// Keep track of size associated with pointer and also current callstack.
            FCallStackAllocationInfo PointerInfo = new FCallStackAllocationInfo(StreamToken.Size, StreamToken.CallStackIndex, 1);

            if (PointerToPointerInfoMap.ContainsKey(StreamToken.Pointer))
            {
                Debug.WriteLine("Same pointer malloced twice without being freed: " + StreamToken.Pointer + " in pool " + StreamToken.Pool);
                PointerToPointerInfoMap.Remove(StreamToken.Pointer);
            }

            PointerToPointerInfoMap.Add(StreamToken.Pointer, PointerInfo);

            if (StreamToken.CallStackIndex >= FStreamInfo.GlobalInstance.CallStackArray.Count)
            {
                Debug.WriteLine("CallStackIndex out of range!");
                return;
            }
            
            // Add size to lifetime churn tracking.
            while (StreamToken.CallStackIndex >= Snapshot.LifetimeCallStackList.Count)
			{
                Snapshot.LifetimeCallStackList.Add(new FCallStackAllocationInfo(0, Snapshot.LifetimeCallStackList.Count, 0));
			}

            //@todo: Sadly, we have to do all this ugly shuffling because of the way lists of structs work in C#
			Snapshot.LifetimeCallStackList[ StreamToken.CallStackIndex ] = Snapshot.LifetimeCallStackList[ StreamToken.CallStackIndex ].Add( StreamToken.Size, 1 );

			if( Snapshot.AllocationSize > Snapshot.AllocationMaxSize )
			{
				Snapshot.AllocationMaxSize = Snapshot.AllocationSize;
			}

			// Maintain timeline view
			Snapshot.AllocationSize += PointerInfo.Size;
			Snapshot.AllocationCount++;
			if (Snapshot.AllocationCount % AllocationsPerSlice == 0)
			{
				FMemorySlice Slice = new FMemorySlice( Snapshot );
				Snapshot.OverallMemorySlice.Add( Slice );
				Snapshot.AllocationMaxSize = 0;
			}
		}
        private static TreeNode UpdateNodeAndPayload( TreeNode ParentNode, int AddressIndex, FCallStackAllocationInfo AllocationInfo )
        {
            FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex];

            // Iterate over existing nodes to see whether there is a match.
            foreach( TreeNode Node in ParentNode.Nodes )
            {
                FNodePayload Payload = (FNodePayload) Node.Tag;
                // If there is a match, update the allocation size and return the current node.
                if( FStreamInfo.GlobalInstance.CallStackAddressArray[Payload.AddressIndex].FunctionIndex == FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex].FunctionIndex )
                {
                    Payload.AllocationSize += AllocationInfo.Size;
                    Payload.AllocationCount += AllocationInfo.Count;
                    Payload.CallStacks.Add(CallStack);
                    // Return current node as parent for next iteration.
                    return Node;
                }
            }

            // If we made it here it means that we need to add a new node.
            string NodeName = FStreamInfo.GlobalInstance.NameArray[FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex].FunctionIndex];
            TreeNode NewNode = new TreeNode( NodeName );

            // Create payload for the node and associate it.
            FNodePayload NewPayload = new FNodePayload(AddressIndex, AllocationInfo.Size, AllocationInfo.Count, CallStack);
            NewNode.Tag = NewPayload;

            // Add to parent node and return new node as subsequent parent.
            ParentNode.Nodes.Add( NewNode );
            return NewNode;
        }
        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 );
                }
            }
        }
Example #15
0
        /// <summary> Updates internal state with free. </summary>
        private static bool HandleFree(FStreamToken StreamToken, FStreamSnapshot Snapshot, Dictionary <ulong, FCallStackAllocationInfo> PointerToPointerInfoMap, out FCallStackAllocationInfo FreedAllocInfo)
        {
            if (!PointerToPointerInfoMap.TryGetValue(StreamToken.Pointer, out FreedAllocInfo))
            {
                Debug.WriteLine("Free without malloc: " + StreamToken.Pointer + " in pool " + StreamToken.Pool);
                return(false);
            }

            // Maintain timeline view
            Snapshot.AllocationSize -= FreedAllocInfo.Size;
            Snapshot.AllocationCount++;
            if (Snapshot.AllocationCount % AllocationsPerSlice == 0)
            {
                FMemorySlice Slice = new FMemorySlice(Snapshot);
                Snapshot.OverallMemorySlice.Add(Slice);
            }

            // Remove freed pointer if it is in the array.
            PointerToPointerInfoMap.Remove(StreamToken.Pointer);

            return(true);
        }
Example #16
0
		// 0 == deepest part of callstack
		void OpenCallstackEntryInVS( FCallStackAllocationInfo AllocationInfo, int Index )
		{
			FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[ AllocationInfo.CallStackIndex ];
			FCallStackAddress Address = FStreamInfo.GlobalInstance.CallStackAddressArray[ CallStack.AddressIndices[ CallStack.AddressIndices.Count - 1 - Index ] ];
			string Filename = FStreamInfo.GlobalInstance.NameArray[ Address.FilenameIndex ];

			try
			{
				OpenFileInVisualStudio( Filename, Address.LineNumber );
			}
			catch( Exception )
			{
			}
		}
 /// <summary> Compare helper function, sorting FCallStackAllocation by abs(size). </summary>
 private static int CompareAbsSize(FCallStackAllocationInfo A, FCallStackAllocationInfo B)
 {
     return(Math.Sign(Math.Abs(B.TotalSize) - Math.Abs(A.TotalSize)));
 }
        private static FCallGraphNode UpdateNodeAndPayload(FCallGraphNode ParentNode, int AddressIndex, FCallStackAllocationInfo AllocationInfo)
        {
            int        FunctionIndex = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex].FunctionIndex;
            FCallStack CallStack     = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex];

            var TotalAllocationSize  = AllocationInfo.TotalSize;
            var TotalAllocationCount = AllocationInfo.TotalCount;

            // Iterate over existing nodes to see whether there is a match.
            foreach (FCallGraphNode Node in ParentNode.Children)
            {
                // If there is a match, update the allocation size and return the current node.
                if (FStreamInfo.GlobalInstance.CallStackAddressArray[Node.AddressIndex].FunctionIndex == FunctionIndex)
                {
                    Node.AllocationSize  += TotalAllocationSize;
                    Node.AllocationCount += TotalAllocationCount;
                    Node.CallStacks.Add(CallStack);

                    // Return current node as parent for next iteration.
                    return(Node);
                }
            }

            // If we made it here it means that we need to add a new node.
            string         FunctionName = FStreamInfo.GlobalInstance.NameArray[FunctionIndex];
            FCallGraphNode NewNode      = new FCallGraphNode(ParentNode, AddressIndex, TotalAllocationSize, TotalAllocationCount, FunctionName, CallStack);

            return(NewNode);
        }
        public static void ParseSnapshot(ListViewEx ExclusiveListView, List <FCallStackAllocationInfo> CallStackList, bool bShouldSortBySize, string FilterText)
        {
            const int MaximumEntries = 400;

            // Progress bar.
            long ProgressInterval   = MaximumEntries / 20;
            long NextProgressUpdate = ProgressInterval;
            int  CallStackCurrent   = 0;

            OwnerWindow.ToolStripProgressBar.Value   = 0;
            OwnerWindow.ToolStripProgressBar.Visible = true;

            OwnerWindow.UpdateStatus("Updating exclusive list view for " + OwnerWindow.CurrentFilename);

            ExclusiveListView.BeginUpdate();

            ExclusiveListView.ListViewItemSorter = null;             // clear this to avoid a Sort for each call to Add

            bool bFilterIn = OwnerWindow.IsFilteringIn();

            using (FScopedLogTimer ParseTiming = new FScopedLogTimer("FExclusiveListViewParser.ParseSnapshot"))
            {
                var FilteredCallstackList = new List <FCallStackAllocationInfo>(CallStackList.Count);
                foreach (var AllocationInfo in CallStackList)
                {
                    var FilteredAllocationInfo = AllocationInfo.GetAllocationInfoForTags(OwnerWindow.GetTagsFilter(), bFilterIn);
                    if (FilteredAllocationInfo.TotalCount != 0)
                    {
                        FilteredCallstackList.Add(FilteredAllocationInfo);
                    }
                }

                // Sort based on passed in metric.
                if (bShouldSortBySize)
                {
                    FilteredCallstackList.Sort(CompareAbsSize);
                }
                else
                {
                    FilteredCallstackList.Sort(CompareCount);
                }

                // Figure out total size and count for percentages.
                long TotalSize  = 0;
                long TotalCount = 0;
                foreach (FCallStackAllocationInfo AllocationInfo in FilteredCallstackList)
                {
                    // Apply optional filter.
                    if (FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex].RunFilters(FilterText, OwnerWindow.Options.ClassGroups, bFilterIn, OwnerWindow.SelectedMemoryPool))
                    {
                        TotalSize  += AllocationInfo.TotalSize;
                        TotalCount += AllocationInfo.TotalCount;
                    }
                }

                // Clear out existing entries and add top 400.
                ExclusiveListView.Items.Clear();
                for (int CallStackIndex = 0; CallStackIndex < FilteredCallstackList.Count && ExclusiveListView.Items.Count <= MaximumEntries; CallStackIndex++)
                {
                    // Update progress bar.
                    if (CallStackCurrent >= NextProgressUpdate)
                    {
                        OwnerWindow.ToolStripProgressBar.PerformStep();
                        NextProgressUpdate += ProgressInterval;
                        Debug.WriteLine("FExclusiveListViewParser.ParseSnapshot " + OwnerWindow.ToolStripProgressBar.Value + "/20");
                    }
                    CallStackCurrent++;

                    FCallStackAllocationInfo AllocationInfo = FilteredCallstackList[CallStackIndex];

                    // Apply optional filter.
                    FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex];
                    if (CallStack.RunFilters(FilterText, OwnerWindow.Options.ClassGroups, bFilterIn, OwnerWindow.SelectedMemoryPool))
                    {
                        string FunctionName = "";
                        int    FirstStackFrameIndex;
                        if (OwnerWindow.ContainersSplitButton.Text == " Show Containers")
                        {
                            FirstStackFrameIndex = CallStack.AddressIndices.Count - 1;
                        }
                        else
                        {
                            FirstStackFrameIndex = CallStack.FirstNonContainer;
                        }

                        do
                        {
                            FCallStackAddress Address = FStreamInfo.GlobalInstance.CallStackAddressArray[CallStack.AddressIndices[FirstStackFrameIndex]];
                            FunctionName = FStreamInfo.GlobalInstance.NameArray[Address.FunctionIndex];

                            FirstStackFrameIndex--;
                        }while(UnhelpfulCallSites.Contains(FunctionName) && FirstStackFrameIndex > 0);

                        var AllocationSize  = AllocationInfo.TotalSize;
                        var AllocationCount = AllocationInfo.TotalCount;

                        string SizeInKByte  = String.Format("{0:0}", ( float )AllocationSize / 1024).PadLeft(10, ' ');
                        string SizePercent  = String.Format("{0:0.00}", ( float )AllocationSize / TotalSize * 100).PadLeft(10, ' ');
                        string Count        = String.Format("{0:0}", AllocationCount).PadLeft(10, ' ');
                        string CountPercent = String.Format("{0:0.00}", ( float )AllocationCount / TotalCount * 100).PadLeft(10, ' ');
                        string GroupName    = (CallStack.Group != null) ? CallStack.Group.Name : "Ungrouped";

                        string[] Row = new string[]
                        {
                            SizeInKByte,
                            SizePercent,
                            Count,
                            CountPercent,
                            GroupName,
                            FunctionName
                        };

                        ListViewItem Item = new ListViewItem(Row);
                        Item.Tag = AllocationInfo;
                        ExclusiveListView.Items.Add(Item);
                    }
                }
            }

            var ColumnSorter = new MainWindow.FColumnSorter();

            ColumnSorter.ColumnSortModeAscending = false;
            ColumnSorter.ColumnToSortBy          = 0;
            ExclusiveListView.ListViewItemSorter = ColumnSorter;             // Assignment automatically calls Sort

            ExclusiveListView.SetSortArrow(ColumnSorter.ColumnToSortBy, ColumnSorter.ColumnSortModeAscending);
            ExclusiveListView.EndUpdate();

            OwnerWindow.ToolStripProgressBar.Visible = false;
        }
		/// <summary> Compare helper function, sorting FCallStackAllocation by size. </summary>
		private static int CompareSize( FCallStackAllocationInfo A, FCallStackAllocationInfo B )
		{
			return Math.Sign( B.Size - A.Size );
		}
        private static TreeNode UpdateNodeAndPayload(TreeNode ParentNode, int AddressIndex, FCallStackAllocationInfo AllocationInfo)
        {
            FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex];

            // Iterate over existing nodes to see whether there is a match.
            foreach (TreeNode Node in ParentNode.Nodes)
            {
                FNodePayload Payload = (FNodePayload)Node.Tag;
                // If there is a match, update the allocation size and return the current node.
                if (FStreamInfo.GlobalInstance.CallStackAddressArray[Payload.AddressIndex].FunctionIndex == FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex].FunctionIndex)
                {
                    Payload.AllocationSize  += AllocationInfo.Size;
                    Payload.AllocationCount += AllocationInfo.Count;
                    Payload.CallStacks.Add(CallStack);
                    // Return current node as parent for next iteration.
                    return(Node);
                }
            }

            // If we made it here it means that we need to add a new node.
            string   NodeName = FStreamInfo.GlobalInstance.NameArray[FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex].FunctionIndex];
            TreeNode NewNode  = new TreeNode(NodeName);

            // Create payload for the node and associate it.
            FNodePayload NewPayload = new FNodePayload(AddressIndex, AllocationInfo.Size, AllocationInfo.Count, CallStack);

            NewNode.Tag = NewPayload;

            // Add to parent node and return new node as subsequent parent.
            ParentNode.Nodes.Add(NewNode);
            return(NewNode);
        }
		/// <summary> Compare helper function, sorting FCallStackAllocation by abs(size). </summary>
        private static int CompareAbsSize(FCallStackAllocationInfo A, FCallStackAllocationInfo B)
        {
            return Math.Sign(Math.Abs(B.Size) - Math.Abs(A.Size));
        }
Example #23
0
        /// <summary> Diffs two snapshots and creates a result one. </summary>
        public static FStreamSnapshot DiffSnapshots(FStreamSnapshot Old, FStreamSnapshot New)
        {
            // Create result snapshot object.
            FStreamSnapshot ResultSnapshot = new FStreamSnapshot("Diff " + Old.Description + " <-> " + New.Description);

            using (FScopedLogTimer LoadingTime = new FScopedLogTimer("FStreamSnapshot.DiffSnapshots"))
            {
                // Copy over allocation count so we can track where the graph starts
                ResultSnapshot.AllocationCount = Old.AllocationCount;

                Debug.Assert(Old.MetricArray.Count == New.MetricArray.Count);
                ResultSnapshot.MetricArray = new List <long>(Old.MetricArray.Count);
                for (int CallstackIndex = 0; CallstackIndex < Old.MetricArray.Count; CallstackIndex++)
                {
                    ResultSnapshot.MetricArray.Add(New.MetricArray[CallstackIndex] - Old.MetricArray[CallstackIndex]);
                }


                ResultSnapshot.MemoryAllocationStats3 = FMemoryAllocationStatsV3.Diff(Old.MemoryAllocationStats3, New.MemoryAllocationStats3);
                ResultSnapshot.MemoryAllocationStats4 = FMemoryAllocationStatsV4.Diff(Old.MemoryAllocationStats4, New.MemoryAllocationStats4);

                ResultSnapshot.StreamIndex   = New.StreamIndex;
                ResultSnapshot.bIsDiffResult = true;

                ResultSnapshot.AllocationMaxSize = New.AllocationMaxSize - Old.AllocationMaxSize;
                ResultSnapshot.AllocationSize    = New.AllocationSize - Old.AllocationSize;
                ResultSnapshot.CurrentTime       = 0;
                ResultSnapshot.ElapsedTime       = New.CurrentTime - Old.CurrentTime;
                ResultSnapshot.FrameNumber       = New.FrameNumber - Old.FrameNumber;
                ResultSnapshot.LoadedLevels      = New.LoadedLevels;

                // These lists are guaranteed to be sorted by callstack index.
                List <FCallStackAllocationInfo> OldActiveCallStackList    = Old.ActiveCallStackList;
                List <FCallStackAllocationInfo> NewActiveCallStackList    = New.ActiveCallStackList;
                List <FCallStackAllocationInfo> ResultActiveCallStackList = new List <FCallStackAllocationInfo>(FStreamInfo.GlobalInstance.CallStackArray.Count);

                int OldIndex = 0;
                int NewIndex = 0;
                while (true)
                {
                    FCallStackAllocationInfo OldAllocInfo = OldActiveCallStackList[OldIndex];
                    FCallStackAllocationInfo NewAllocInfo = NewActiveCallStackList[NewIndex];

                    if (OldAllocInfo.CallStackIndex == NewAllocInfo.CallStackIndex)
                    {
                        long ResultSize  = NewAllocInfo.Size - OldAllocInfo.Size;
                        int  ResultCount = NewAllocInfo.Count - OldAllocInfo.Count;

                        if (ResultSize != 0 || ResultCount != 0)
                        {
                            ResultActiveCallStackList.Add(new FCallStackAllocationInfo(ResultSize, NewAllocInfo.CallStackIndex, ResultCount));
                        }

                        OldIndex++;
                        NewIndex++;
                    }
                    else if (OldAllocInfo.CallStackIndex > NewAllocInfo.CallStackIndex)
                    {
                        ResultActiveCallStackList.Add(NewAllocInfo);
                        NewIndex++;
                    }
                    else                     // OldAllocInfo.CallStackIndex < NewAllocInfo.CallStackIndex
                    {
                        ResultActiveCallStackList.Add(new FCallStackAllocationInfo(-OldAllocInfo.Size, OldAllocInfo.CallStackIndex, -OldAllocInfo.Count));
                        OldIndex++;
                    }

                    if (OldIndex >= OldActiveCallStackList.Count)
                    {
                        for ( ; NewIndex < NewActiveCallStackList.Count; NewIndex++)
                        {
                            ResultActiveCallStackList.Add(NewActiveCallStackList[NewIndex]);
                        }
                        break;
                    }

                    if (NewIndex >= NewActiveCallStackList.Count)
                    {
                        for ( ; OldIndex < OldActiveCallStackList.Count; OldIndex++)
                        {
                            ResultActiveCallStackList.Add(OldActiveCallStackList[OldIndex]);
                        }
                        break;
                    }
                }

                // Check that list was correctly constructed.
                for (int CallstackIndex = 0; CallstackIndex < ResultActiveCallStackList.Count - 1; CallstackIndex++)
                {
                    Debug.Assert(ResultActiveCallStackList[CallstackIndex].CallStackIndex < ResultActiveCallStackList[CallstackIndex + 1].CallStackIndex);
                }

                ResultActiveCallStackList.TrimExcess();
                ResultSnapshot.ActiveCallStackList = ResultActiveCallStackList;

                // Iterate over new lifetime callstack info and subtract previous one.
                for (int CallStackIndex = 0; CallStackIndex < New.LifetimeCallStackList.Count; CallStackIndex++)
                {
                    ResultSnapshot.LifetimeCallStackList[CallStackIndex] = FCallStackAllocationInfo.Diff(
                        New.LifetimeCallStackList[CallStackIndex],
                        Old.LifetimeCallStackList[CallStackIndex]);
                }

                // Handle overall memory timeline
                if (New.OverallMemorySlice.Count > Old.OverallMemorySlice.Count)
                {
                    ResultSnapshot.OverallMemorySlice = new List <FMemorySlice>(New.OverallMemorySlice);
                    ResultSnapshot.OverallMemorySlice.RemoveRange(0, Old.OverallMemorySlice.Count);
                }
                else
                {
                    ResultSnapshot.OverallMemorySlice = new List <FMemorySlice>(Old.OverallMemorySlice);
                    ResultSnapshot.OverallMemorySlice.RemoveRange(0, New.OverallMemorySlice.Count);
                    ResultSnapshot.OverallMemorySlice.Reverse();
                }
            }

            return(ResultSnapshot);
        }
		/// <summary> Compare helper function, sorting FCallStackAllocation by count. </summary>
		private static int CompareCount( FCallStackAllocationInfo A, FCallStackAllocationInfo B )
		{
			return Math.Sign( B.Count - A.Count );
		}	
 /// <summary> Compare helper function, sorting FCallStackAllocation by size. </summary>
 private static int CompareSize(FCallStackAllocationInfo A, FCallStackAllocationInfo B)
 {
     return(Math.Sign(B.Size - A.Size));
 }
		private static FCallGraphNode UpdateNodeAndPayload( FCallGraphNode ParentNode, int AddressIndex, FCallStackAllocationInfo AllocationInfo )
		{
			int FunctionIndex = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex].FunctionIndex;
			FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex];

			// Iterate over existing nodes to see whether there is a match.
			foreach (FCallGraphNode Node in ParentNode.Children)
			{
				// If there is a match, update the allocation size and return the current node.
				if (FStreamInfo.GlobalInstance.CallStackAddressArray[Node.AddressIndex].FunctionIndex == FunctionIndex)
				{
					Node.AllocationSize += AllocationInfo.Size;
					Node.AllocationCount += AllocationInfo.Count;
					Node.CallStacks.Add(CallStack);

					// Return current node as parent for next iteration.
					return Node;
				}
			}

			// If we made it here it means that we need to add a new node.
			string FunctionName = FStreamInfo.GlobalInstance.NameArray[FunctionIndex];
			FCallGraphNode NewNode = new FCallGraphNode(ParentNode, AddressIndex, AllocationInfo.Size, AllocationInfo.Count, FunctionName, CallStack);
			return NewNode;
		}