public static void ParseSnapshot(List <FCallStackAllocationInfo> CallStackList, string FilterText) { // Progress bar long ProgressInterval = CallStackList.Count / 20; long NextProgressUpdate = ProgressInterval; int CallStackCurrent = 0; OwnerWindow.ToolStripProgressBar.Value = 0; OwnerWindow.ToolStripProgressBar.Visible = true; OwnerWindow.UpdateStatus("Updating histogram view for " + OwnerWindow.CurrentFilename); List <ClassGroup> CallStackGroups = OwnerWindow.Options.ClassGroups; List <FHistogramBar>[] Bars = new List <FHistogramBar> [NUM_MEMORY_BANKS]; for (int BankIndex = 0; BankIndex < Bars.Length; BankIndex++) { Bars[BankIndex] = new List <FHistogramBar>(); // The first bar in each column is for callstacks unmatched by any pattern. Bars[BankIndex].Add(new FHistogramBar("Other", Color.White)); // Add all groups to all memory bank columns. foreach (ClassGroup CallStackGroup in CallStackGroups) { var Bar = new FHistogramBar(CallStackGroup); Bar.BeginBatchAddition(); Bars[BankIndex].Add(Bar); } } using (FScopedLogTimer ParseTiming = new FScopedLogTimer("HistogramParser.ParseSnapshot")) { long Size = 0; int Count = 0; bool bFilterIn = OwnerWindow.IsFilteringIn(); 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); } } foreach (FCallStackAllocationInfo AllocationInfo in FilteredCallstackList) { // Update progress bar. if (CallStackCurrent >= NextProgressUpdate) { OwnerWindow.ToolStripProgressBar.PerformStep(); NextProgressUpdate += ProgressInterval; Debug.WriteLine("FHistogramParser.ParseSnapshot " + OwnerWindow.ToolStripProgressBar.Value + "/20"); } CallStackCurrent++; FCallStack OriginalCallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex]; if (OriginalCallStack.RunFilters(FilterText, CallStackGroups, bFilterIn, OwnerWindow.SelectedMemoryPool)) { bool bFound = false; int Column = FMemoryPoolInfo.GetMemoryPoolHistogramColumn(OriginalCallStack.MemoryPool); if (Column == -1) { // If the callstack is in multiple pools, just put it in the first bank. // The user has already been warned about multi-pool callstacks. Column = 0; } for (int GroupIndex = 0; GroupIndex < CallStackGroups.Count; GroupIndex++) { foreach (CallStackPattern CallStackPatternIt in CallStackGroups[GroupIndex].CallStackPatterns) { if (CallStackPatternIt.ContainsCallStack(FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex])) { Bars[Column][GroupIndex + 1].AddAllocation(AllocationInfo); bFound = true; goto HackyBreakAll; } } } HackyBreakAll: if (!bFound) { // No pattern matched this callstack, so add it to the Other bar Bars[Column][0].AddAllocation(AllocationInfo); } } Size += AllocationInfo.TotalSize; Count += AllocationInfo.TotalCount; } } // End the update batch and allow things to sort for (int BankIndex = 0; BankIndex < Bars.Length; BankIndex++) { foreach (ClassGroup CallStackGroup in CallStackGroups) { foreach (var Bar in Bars[BankIndex]) { Bar.EndBatchAddition(); } } } OwnerWindow.ToolStripProgressBar.Visible = false; HistogramBars = Bars; // Select first valid histogram bar. SelectFirstValidHistogramBar(); }
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; }
public static void ParseSnapshot(TreeView CallGraphTreeView, List <FCallStackAllocationInfo> CallStackList, bool bShouldSortBySize, string FilterText, bool bInvertCallStacks) { // Progress bar. OwnerWindow.ToolStripProgressBar.Value = 0; OwnerWindow.ToolStripProgressBar.Visible = true; long ProgressInterval = CallStackList.Count / 20; long NextProgressUpdate = ProgressInterval; int CallStackCurrent = 0; OwnerWindow.UpdateStatus("Updating call graph for " + OwnerWindow.CurrentFilename); CallGraphTreeView.BeginUpdate(); // Clear out existing nodes and add two root nodes. One for regular call stacks and one for truncated ones. CallGraphTreeView.Nodes.Clear(); TreeNode RegularNode = new TreeNode("Full Callstacks"); TreeNode TruncatedNode = new TreeNode("Truncated Callstacks"); CallGraphTreeView.Nodes.Add(RegularNode); CallGraphTreeView.Nodes.Add(TruncatedNode); using (FScopedLogTimer ParseTiming = new FScopedLogTimer("FCallGraphTreeViewParser.ParseSnapshot")) { // Iterate over all call graph paths and add them to the graph. foreach (FCallStackAllocationInfo AllocationInfo in CallStackList) { // Update progress bar. if (CallStackCurrent >= NextProgressUpdate) { OwnerWindow.ToolStripProgressBar.PerformStep(); NextProgressUpdate += ProgressInterval; Debug.WriteLine("FCallGraphTreeViewParser.ParseSnapshot " + OwnerWindow.ToolStripProgressBar.Value + "/20"); } CallStackCurrent++; // Add this call graph to the tree view. FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex]; // Split the tree into full and truncated callstacks. TreeNode RootNode = CallStack.bIsTruncated ? TruncatedNode : RegularNode; // Don't bother with callstacks that don't have a contribution. if (((AllocationInfo.Count != 0) || (AllocationInfo.Size != 0)) // Apply filter based on text representation of address. && CallStack.RunFilters(FilterText, OwnerWindow.Options.ClassGroups, OwnerWindow.IsFilteringIn(), OwnerWindow.SelectedMemoryPool)) { // Add call stack to proper part of graph. AddCallStackToGraph(RootNode, CallStack, AllocationInfo, ParentFunctionIndex, bInvertCallStacks); } } } // Update the node text by prepending memory usage and allocation count. UpdateNodeText(RegularNode); UpdateNodeText(TruncatedNode); // Last but not least, set the node sorter property to sort nodes. if (bShouldSortBySize) { CallGraphTreeView.TreeViewNodeSorter = new FNodeSizeSorter(); } else { CallGraphTreeView.TreeViewNodeSorter = new FNodeCountSorter(); } CallGraphTreeView.EndUpdate(); OwnerWindow.ToolStripProgressBar.Visible = false; }
public static void ParseSnapshot(TreeView CallGraphTreeView, List <FCallStackAllocationInfo> CallStackList, bool bShouldSortBySize, string FilterText, bool bInvertCallStacks) { // Progress bar. OwnerWindow.ToolStripProgressBar.Value = 0; OwnerWindow.ToolStripProgressBar.Visible = true; long ProgressInterval = CallStackList.Count / 20; long NextProgressUpdate = ProgressInterval; int CallStackCurrent = 0; OwnerWindow.UpdateStatus("Updating call graph for " + OwnerWindow.CurrentFilename); CallGraphTreeView.BeginUpdate(); CallGraphTreeView.TreeViewNodeSorter = null; // clear this to avoid a Sort for each call to Add Debug.WriteLine("FCallGraphTreeViewParser.ParseSnapshot - Building call graph tree for " + OwnerWindow.CurrentFilename); var TruncatedNode = new FCallGraphNode("Truncated Callstacks"); var RegularNode = new FCallGraphNode("Full Callstacks"); bool bFilterIn = OwnerWindow.IsFilteringIn(); using (FScopedLogTimer ParseTiming = new FScopedLogTimer("FCallGraphTreeViewParser.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); } } // Iterate over all call graph paths and add them to the graph. foreach (FCallStackAllocationInfo AllocationInfo in FilteredCallstackList) { // Update progress bar. if (CallStackCurrent >= NextProgressUpdate) { OwnerWindow.ToolStripProgressBar.PerformStep(); NextProgressUpdate += ProgressInterval; Debug.WriteLine("FCallGraphTreeViewParser.ParseSnapshot " + OwnerWindow.ToolStripProgressBar.Value + "/20"); } CallStackCurrent++; // Add this call graph to the tree view. FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex]; // Split the tree into full and truncated callstacks. var RootNode = CallStack.bIsTruncated ? TruncatedNode : RegularNode; // Apply filter based on text representation of address. if (CallStack.RunFilters(FilterText, OwnerWindow.Options.ClassGroups, bFilterIn, OwnerWindow.SelectedMemoryPool)) { // Add call stack to proper part of graph. AddCallStackToGraph(RootNode, CallStack, AllocationInfo, ParentFunctionIndex, bInvertCallStacks); } } } Debug.WriteLine("FCallGraphTreeViewParser.ParseSnapshot - Sorting call graph tree for " + OwnerWindow.CurrentFilename); // Sort the nodes before adding them to the tree (sorting when in the tree is slow!). SortNodes(TruncatedNode, bShouldSortBySize); SortNodes(RegularNode, bShouldSortBySize); Debug.WriteLine("FCallGraphTreeViewParser.ParseSnapshot - Populating call graph tree for " + OwnerWindow.CurrentFilename); // Clear out existing nodes and add two root nodes. One for regular call stacks and one for truncated ones. CallGraphTreeView.Nodes.Clear(); CallGraphTreeView.Tag = new FCallGraphTreeViewTag(); AddRootTreeNode(TruncatedNode, CallGraphTreeView); AddRootTreeNode(RegularNode, CallGraphTreeView); CallGraphTreeView.BeforeExpand -= HandlePreExpandTreeNode; CallGraphTreeView.BeforeExpand += HandlePreExpandTreeNode; CallGraphTreeView.EndUpdate(); OwnerWindow.ToolStripProgressBar.Visible = false; }