/// <summary> Exports this snapshot to a CSV file of the passed in name. </summary> /// <param name="FileName"> File name to export to </param> /// <param name="bShouldExportActiveAllocations"> Whether to export active allocations or lifetime allocations </param> public void ExportToCSV(string FileName, bool bShouldExportActiveAllocations) { // Create stream writer used to output call graphs to CSV. StreamWriter CSVWriter = new StreamWriter(FileName); // Figure out which list to export. List <FCallStackAllocationInfo> CallStackList = null; if (bShouldExportActiveAllocations) { CallStackList = ActiveCallStackList; } else { CallStackList = LifetimeCallStackList; } // Iterate over each unique call graph and spit it out. The sorting is per call stack and not // allocation size. Excel can be used to sort by allocation if needed. This sorting is more robust // and also what the call graph parsing code needs. foreach (FCallStackAllocationInfo AllocationInfo in CallStackList) { // Skip callstacks with no contribution in this snapshot. if (AllocationInfo.Count > 0) { // Dump size first, followed by count. CSVWriter.Write(AllocationInfo.Size + "," + AllocationInfo.Count + ","); // Iterate over ach address in callstack and dump to CSV. FCallStack CallStack = FStreamInfo.GlobalInstance.CallStackArray[AllocationInfo.CallStackIndex]; foreach (int AddressIndex in CallStack.AddressIndices) { FCallStackAddress Address = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndex]; string SymbolFunctionName = FStreamInfo.GlobalInstance.NameArray[Address.FunctionIndex]; string SymbolFileName = FStreamInfo.GlobalInstance.NameArray[Address.FilenameIndex]; // Write out function followed by filename and then line number if valid if (SymbolFunctionName != "" || SymbolFileName != "") { if (FStreamInfo.GlobalInstance.Platform == EPlatformType.PS3) { CSVWriter.Write(SymbolFunctionName + ","); } else { CSVWriter.Write(SymbolFunctionName + " @ " + SymbolFileName + ":" + Address.LineNumber + ","); } } else { CSVWriter.Write("Unknown,"); } } CSVWriter.WriteLine(""); } } // Close the file handle now that we're done writing. CSVWriter.Close(); }
/// <summary> Adds callstack information into the listview. </summary> public void AddToListView(ListView CallStackListView, bool bShowFromBottomUp) { for (int AdressIndex = 0; AdressIndex < AddressIndices.Count; AdressIndex++) { // Handle iterating over addresses in reverse order. int AddressIndexIndex = bShowFromBottomUp ? AddressIndices.Count - 1 - AdressIndex : AdressIndex; FCallStackAddress Address = FStreamInfo.GlobalInstance.CallStackAddressArray[AddressIndices[AddressIndexIndex]]; string[] Row = new string[] { FStreamInfo.GlobalInstance.NameArray[Address.FunctionIndex], FStreamInfo.GlobalInstance.NameArray[Address.FilenameIndex], Address.LineNumber.ToString() }; CallStackListView.Items.Add(new ListViewItem(Row)); } }
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 virtual bool ResolveAddressSymbolInfo(ESymbolResolutionMode SymbolResolutionMode, FCallStackAddress Address) { if (Address.LineNumber == 0) { string Filename; string Function; int LineNumber; if (ResolveAddressToSymboInfo(SymbolResolutionMode, Address.ProgramCounter, out Filename, out Function, out LineNumber)) { if (Filename != null) { // Look up or add filename index. Address.FilenameIndex = FStreamInfo.GlobalInstance.GetNameIndex(Filename, true); } if (Function != null) { // Look up or add function index. Address.FunctionIndex = FStreamInfo.GlobalInstance.GetNameIndex(Function, true); } if (LineNumber != 0) { Address.LineNumber = LineNumber; } } else { return false; } } return true; }