using UnityEngine; using System.IO; using System; using System.Collections.Generic; using System.Globalization; namespace UnityEditor.Performance.ProfileAnalyzer { internal class ProfileAnalyzerExportWindow : EditorWindow { internal static class Styles { public static readonly GUIContent markerTable = new GUIContent("Marker table", "Export data from the single view marker table"); public static readonly GUIContent singleFrameTimes = new GUIContent("Single Frame Times", "Export frame time data from the single view"); public static readonly GUIContent comparisonTables = new GUIContent("Comparison table", "Export data from the comparsion view marker table"); public static readonly GUIContent comparisonFrameTimes = new GUIContent("Comparison Frame Times", "Export frame time data from the comparison view"); } ProfileAnalyzerWindow m_ProfileAnalyzerWindow; ProfileDataView m_ProfileDataView; ProfileDataView m_LeftDataView; ProfileDataView m_RightDataView; static public ProfileAnalyzerExportWindow FindOpenWindow() { UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(typeof(ProfileAnalyzerExportWindow)); if (windows != null && windows.Length > 0) return windows[0] as ProfileAnalyzerExportWindow; return null; } static public bool IsOpen() { if (FindOpenWindow() != null) return true; return false; } static public ProfileAnalyzerExportWindow Open(float screenX, float screenY, ProfileDataView profileSingleView, ProfileDataView profileLeftView, ProfileDataView profileRightView, ProfileAnalyzerWindow profileAnalyzerWindow) { ProfileAnalyzerExportWindow window = GetWindow("Export"); window.minSize = new Vector2(200, 180); window.position = new Rect(screenX, screenY, 200, 180); window.m_ProfileAnalyzerWindow = profileAnalyzerWindow; window.SetData(profileSingleView, profileLeftView, profileRightView); window.Show(); return window; } static public void CloseAll() { ProfileAnalyzerExportWindow window = GetWindow("Export"); window.Close(); } public void SetData(ProfileDataView profileDataView, ProfileDataView leftDataView, ProfileDataView rightDataView) { m_ProfileDataView = profileDataView; m_LeftDataView = leftDataView; m_RightDataView = rightDataView; } void OnGUI() { EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true)); GUILayout.Label("Export as CSV:"); GUILayout.Label(""); GUILayout.Label("Single View"); bool enabled = GUI.enabled; if (m_ProfileDataView == null || !m_ProfileDataView.IsDataValid()) GUI.enabled = false; if (GUILayout.Button(Styles.markerTable)) SaveMarkerTableCSV(); GUI.enabled = enabled; if (m_ProfileDataView == null || m_ProfileDataView.analysis == null) GUI.enabled = false; if (GUILayout.Button(Styles.singleFrameTimes)) SaveFrameTimesCSV(); GUI.enabled = enabled; GUILayout.Label("Comparison View"); if (!m_ProfileAnalyzerWindow.CanExportComparisonTable()) GUI.enabled = false; if (GUILayout.Button(Styles.comparisonTables)) SaveComparisonTableCSV(); GUI.enabled = enabled; if (m_LeftDataView == null || !m_LeftDataView.IsDataValid() || m_RightDataView == null || !m_RightDataView.IsDataValid()) GUI.enabled = false; if (GUILayout.Button(Styles.comparisonFrameTimes)) SaveComparisonFrameTimesCSV(); GUI.enabled = enabled; EditorGUILayout.EndVertical(); } void SaveMarkerTableCSV() { if (m_ProfileDataView.analysis == null) return; string path = EditorUtility.SaveFilePanel("Save marker table CSV data", "", "markerTable.csv", "csv"); if (path.Length != 0) { var analytic = ProfileAnalyzerAnalytics.BeginAnalytic(); using (StreamWriter file = new StreamWriter(path)) { file.Write("Name; "); file.Write("Median Time; Min Time; Max Time; "); file.Write("Median Frame Index; Min Frame Index; Max Frame Index; "); file.Write("Min Depth; Max Depth; "); file.Write("Total Time; "); file.Write("Mean Time; Time Lower Quartile; Time Upper Quartile; "); file.Write("Count Total; Count Median; Count Min; Count Max; "); file.Write("Number of frames containing Marker; "); file.Write("First Frame Index; "); file.Write("Time Min Individual; Time Max Individual; "); file.Write("Min Individual Frame; Max Individual Frame; "); file.WriteLine("Time at Median Frame"); List markerData = m_ProfileDataView.analysis.GetMarkers(); markerData.Sort(); foreach (MarkerData marker in markerData) { var markerName = marker.name; if (markerName.IndexOf('\"') >= 0) // replace all double quotation marks with single ones to avoid this breaking the escaping with double quotation marks markerName = markerName.Replace('\"', '\''); int medianFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.medianFrameIndex, m_ProfileDataView); int minFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.minFrameIndex, m_ProfileDataView); int maxFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.maxFrameIndex, m_ProfileDataView); int firstFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.firstFrameIndex, m_ProfileDataView); int minIndividualFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.minIndividualFrameIndex, m_ProfileDataView); int maxIndividualFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.maxIndividualFrameIndex, m_ProfileDataView); // "Escape" marker names in case it has commas in it. file.Write("\"{0}\";", markerName); file.Write(string.Format(CultureInfo.InvariantCulture,"{0};{1};{2};", marker.msMedian, marker.msMin, marker.msMax)); file.Write("{0};{1};{2};", medianFrameIndex, minFrameIndex, maxFrameIndex); file.Write("{0};{1};", marker.minDepth, marker.maxDepth); file.Write(string.Format(CultureInfo.InvariantCulture, "{0};", marker.msTotal)); file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};{2};", marker.msMean, marker.msLowerQuartile, marker.msUpperQuartile)); file.Write("{0};{1};{2};{3};", marker.count, marker.countMedian, marker.countMin, marker.countMax); file.Write("{0};", marker.presentOnFrameCount); file.Write("{0};", firstFrameIndex); file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};", marker.msMinIndividual, marker.msMaxIndividual)); file.Write("{0};{1};", minIndividualFrameIndex, maxIndividualFrameIndex); file.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", marker.msAtMedian)); } } ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportSingleFrames, analytic); } } void SaveFrameTimesCSV() { if (m_ProfileDataView == null) return; if (!m_ProfileDataView.IsDataValid()) return; string path = EditorUtility.SaveFilePanel("Save frame time CSV data", "", "frameTime.csv", "csv"); if (path.Length != 0) { var analytic = ProfileAnalyzerAnalytics.BeginAnalytic(); using (StreamWriter file = new StreamWriter(path)) { file.WriteLine("Frame Offset; Frame Index; Frame Time (ms); Time from first frame (ms)"); float maxFrames = m_ProfileDataView.data.GetFrameCount(); var frame = m_ProfileDataView.data.GetFrame(0); // msStartTime isn't very accurate so we don't use it double msTimePassed = 0.0; for (int frameOffset = 0; frameOffset < maxFrames; frameOffset++) { frame = m_ProfileDataView.data.GetFrame(frameOffset); int frameIndex = m_ProfileDataView.data.OffsetToDisplayFrame(frameOffset); frameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(frameIndex, m_ProfileDataView); float msFrame = frame.msFrame; file.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0};{1};{2};{3}", frameOffset, frameIndex, msFrame, msTimePassed)); msTimePassed += msFrame; } } ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportSingleFrames, analytic); } } void SaveComparisonFrameTimesCSV() { if (m_LeftDataView == null || m_RightDataView == null) return; if (!m_LeftDataView.IsDataValid() || !m_RightDataView.IsDataValid()) return; string path = EditorUtility.SaveFilePanel("Save comparison frame time CSV data", "", "frameTimeComparison.csv", "csv"); if (path.Length != 0) { var analytic = ProfileAnalyzerAnalytics.BeginAnalytic(); using (StreamWriter file = new StreamWriter(path)) { file.Write("Frame Offset; "); file.Write("Left Frame Index; Right Frame Index; "); file.Write("Left Frame Time (ms); Left time from first frame (ms); "); file.Write("Right Frame Time (ms); Right time from first frame (ms); "); file.WriteLine("Frame Time Diff (ms)"); float maxFrames = Math.Max(m_LeftDataView.data.GetFrameCount(), m_RightDataView.data.GetFrameCount()); var leftFrame = m_LeftDataView.data.GetFrame(0); var rightFrame = m_RightDataView.data.GetFrame(0); // msStartTime isn't very accurate so we don't use it double msTimePassedLeft = 0.0; double msTimePassedRight = 0.0; for (int frameOffset = 0; frameOffset < maxFrames; frameOffset++) { leftFrame = m_LeftDataView.data.GetFrame(frameOffset); rightFrame = m_RightDataView.data.GetFrame(frameOffset); int leftFrameIndex = m_LeftDataView.data.OffsetToDisplayFrame(frameOffset); leftFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(leftFrameIndex, m_LeftDataView); int rightFrameIndex = m_RightDataView.data.OffsetToDisplayFrame(frameOffset); rightFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(rightFrameIndex, m_RightDataView); float msFrameLeft = leftFrame != null ? leftFrame.msFrame : 0; float msFrameRight = rightFrame != null ? rightFrame.msFrame : 0; float msFrameDiff = msFrameRight - msFrameLeft; file.Write("{0};", frameOffset); file.Write("{0};{1};", leftFrameIndex, rightFrameIndex); file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};", msFrameLeft, msTimePassedLeft)); file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};", msFrameRight, msTimePassedRight)); file.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", msFrameDiff)); msTimePassedLeft += msFrameLeft; msTimePassedRight += msFrameRight; } } ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportComparisonFrames, analytic); } } void SaveComparisonTableCSV() { if (m_LeftDataView == null || m_RightDataView == null) return; if (!m_LeftDataView.IsDataValid() || !m_RightDataView.IsDataValid()) return; string path = EditorUtility.SaveFilePanel("Save comparison table CSV data", "", "tableComparison.csv", "csv"); if (path.Length != 0) { var analytic = ProfileAnalyzerAnalytics.BeginAnalytic(); using (StreamWriter file = new StreamWriter(path)) { m_ProfileAnalyzerWindow.TryExportComparisonTable(file); } ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportComparisonFrames, analytic); } } } }