static internal List <ScenarioRun> FormatData(ETW telemetryData, MainWindow.UserInput userInput) { var scenario = new List <ScenarioRun>(); // Pair start/end events. var eventCount = telemetryData.Events.Count; var events = telemetryData.Events; var DesiredStartEvent = new TelemetryEvent(0, userInput.StartEventName, userInput.StartEventParameter1, userInput.StartEventParameter2); var DesiredEndEvent = new TelemetryEvent(0, userInput.EndEventName, userInput.EndEventParameter1, userInput.EndEventParameter2); for (int startEventIndex = 0; startEventIndex < eventCount; startEventIndex++) { if (events[startEventIndex].Equals(DesiredStartEvent)) { for (int endEventIndex = startEventIndex; endEventIndex < eventCount; endEventIndex++) { if (events[endEventIndex].Equals(DesiredEndEvent)) { scenario.Add(new ScenarioRun(events[startEventIndex], events[endEventIndex])); endEventIndex = eventCount; // Break the inner loop } } } } return(scenario); }
/// <summary> /// Given an .etl file, convert it into a .csv file. /// </summary> private string ConvertToCsv(MainWindow.UserInput userInput) { // Use WaitForExit to check for success, but process needs to be a variable for that to work // Might be worth registering the event and disabling UI elements so the app doesn't appear frozen. string csvFilePath = Path.ChangeExtension(userInput.TracePath, ".csv"); System.Diagnostics.Process.Start("CMD.exe", $"/C set _NT_SYMBOL_PATH=SRV*;{userInput.SymbolsPath}").WaitForExit(); System.Diagnostics.Process.Start("CMD.exe", $"/C xperf -symbols -i {userInput.TracePath} -o {csvFilePath}").WaitForExit(); return(csvFilePath); }
/// <summary> /// Given a .csv file, add all of the relevent events to an object list. /// </summary> private void ExtractDataFromCsv(string csvFilePath, MainWindow.UserInput userInput) { string line = string.Empty; using (StreamReader csv = new StreamReader(csvFilePath)) { while ((line = csv.ReadLine()) != null) { string[] partsOfLine = line.Split(','); for (int x = 0; x < partsOfLine.Length; x++) { partsOfLine[x] = partsOfLine[x].Trim(); } // Save start/end telemetry events to a list if (partsOfLine[0].Contains(userInput.StartEventName) || partsOfLine[0].Contains(userInput.EndEventName)) { // Line[0] is the name. // Line[1] is the time with the 7th digit being seconds. // Line[9] is the first optional parameter (modifier for a generic event). // Line[10] is the second optional parameter. bool result = int.TryParse(partsOfLine[1], out int time); if (result) { // The parameters are optional, so these checks handle when they are not present. string parameter1 = null; if (partsOfLine.Length > 9) { parameter1 = partsOfLine[9]; } string parameter2 = null; if (partsOfLine.Length > 10) { parameter2 = partsOfLine[10]; } Events.Add(new TelemetryEvent(time, partsOfLine[0], parameter1, parameter2)); } } } } }
/// <summary> /// Uses the telemetry data to create an report in excel. /// If the file already exists, it MUST be closed for this to work. /// </summary> static internal void Create(List <ScenarioRun> telemetryData, MainWindow.UserInput userInput) { Excel.Application excelApp = null; try { excelApp = new Excel.Application(); Excel._Worksheet workSheet; // Checks the provided name to see if it has a valid extension, and adds one if not. string extension = Path.GetExtension(userInput.ResultFileName); string excelExtension = ".xlsx"; string outputFilename; if (Path.GetExtension(userInput.ResultFileName) != excelExtension) { outputFilename = Path.ChangeExtension(userInput.ResultFileName, excelExtension); } else { outputFilename = userInput.ResultFileName; } // Checks if that excel file already exists. Use the existing report if it does, otherwise create a new one. int startColumnPosition = 1; if (File.Exists(outputFilename)) { // Makes sure the excel file isn't already open while (IsFileLocked(new FileInfo(outputFilename))) { MessageBox.Show("Excel file is already locked and cannot be edited! Make sure that file is closed."); } // Load the existing excel sheet workSheet = excelApp.Workbooks.Open(outputFilename).Sheets[1]; // Determine where the beginning of unused space is by checking the cells containing the scenario names. for (int columnIndex = 1; columnIndex <= workSheet.Columns.Count; columnIndex += 5) { if (workSheet.Cells[2, columnIndex].Value == null) { startColumnPosition = columnIndex; break; } } } else { excelApp.Workbooks.Add(); workSheet = (Excel.Worksheet)excelApp.ActiveSheet; } // Set up column positions. These values are shifted over as more scenarios are added to a report. int A = startColumnPosition; int B = startColumnPosition + 1; int C = startColumnPosition + 2; int D = startColumnPosition + 3; int eventCount = telemetryData.Count; // Generic formatting and labels workSheet.Cells[1, B] = userInput.BuildName; workSheet.Cells[2, A] = userInput.ScenarioName; workSheet.Cells[2, A].Font.Bold = true; workSheet.Cells[3, B] = "Start"; workSheet.Cells[3, B].Font.Bold = true; workSheet.Cells[3, C] = "End"; workSheet.Cells[3, C].Font.Bold = true; workSheet.Cells[3, D] = "Result"; workSheet.Cells[3, D].Font.Bold = true; Excel.Range formattingRange = workSheet.Range[workSheet.Cells[2, A], workSheet.Cells[eventCount + 8, D]]; formattingRange.NumberFormat = "0"; formattingRange.BorderAround2(); // Fill in the worksheet for (int y = 0; y < eventCount; y++) { int eventRow = y + 4; workSheet.Cells[eventRow, A] = y + 1; workSheet.Cells[eventRow, B] = telemetryData[y].Start.Time; workSheet.Cells[eventRow, C] = telemetryData[y].End.Time; workSheet.Cells[eventRow, D] = $"=({ExcelColumnFromNumber(C)}{eventRow} - {ExcelColumnFromNumber(B)}{eventRow})"; } int statsRow = telemetryData.Count + 5; Excel.Range statsLabelsFormattingRange = workSheet.Range[workSheet.Cells[statsRow, A], workSheet.Cells[statsRow + 3, A]]; statsLabelsFormattingRange.Font.Bold = true; string range = $"({ExcelColumnFromNumber(D)}{4}:{ExcelColumnFromNumber(D)}{eventCount + 3})"; workSheet.Cells[statsRow, A] = "High"; workSheet.Cells[statsRow, B] = $"=MAX{range}"; statsRow++; workSheet.Cells[statsRow, A] = "Median"; workSheet.Cells[statsRow, B] = $"=MEDIAN{range}"; statsRow++; workSheet.Cells[statsRow, A] = "Low"; workSheet.Cells[statsRow, B] = $"=MIN{range}"; statsRow++; workSheet.Cells[statsRow, A] = $"{eventCount}th - 2nd Diff"; workSheet.Cells[statsRow, B] = $"={ExcelColumnFromNumber(D)}{eventCount + 3}-{ExcelColumnFromNumber(D)}{5}"; // Only merge cells for notes if there are notes to add. Excel.Range notesCell = workSheet.Cells[statsRow + 2, A]; if (!string.IsNullOrEmpty(userInput.Notes)) { notesCell.Value = userInput.Notes; Excel.Range notes = workSheet.Range[workSheet.Cells[statsRow + 2, A], workSheet.Cells[statsRow + 2, D]].Merge(); } // Adjust column widths to fit the content. workSheet.Columns[A].ColumnWidth = 12; for (int x = B; x <= D; x++) { workSheet.Columns[x].ColumnWidth = 8; } // Save the file. workSheet.SaveAs(userInput.ResultFileName); } finally { excelApp.Workbooks.Close(); Marshal.ReleaseComObject(excelApp.Workbooks); excelApp.Quit(); Marshal.FinalReleaseComObject(excelApp); } }
internal ETW(MainWindow.UserInput userInput)//string etlFilePath, string symbolPath, string startEvent, string endEvent) { ExtractDataFromCsv(ConvertToCsv(userInput), userInput); }