public void Dispose() { if (m_ActivePerformanceTracker >= 0) { EditorPerformanceTracker.StopTracker(m_ActivePerformanceTracker); } }
public static void GetCallstack(string marker, Action <string> handler, bool formatForConsole = false) { EditorPerformanceTracker.GetCallstack(marker, (callstack => { handler(formatForConsole ? FormatCallstackForConsole(callstack) : callstack); })); }
private static void MonitorTrackers() { if (!PerformanceTrackerSettings.monitoringNeeded) { return; } var now = EditorApplication.timeSinceStartup; if (now < s_NextCheck) { return; } var trackerNames = EditorPerformanceTracker.GetAvailableTrackers(); using (new PerformanceTracker("Tracker.PerformNotifications")) { PerformNotifications(now, trackerNames); } using (new PerformanceTracker("Tracker.PerformSpikeWindowHighlight")) { PerformSpikeWindowHighlight(now, trackerNames); } s_NextCheck = now + PerformanceTrackerSettings.monitoringUpdateSpeed; }
public static bool RecordWithMarkerFilter(string markerName, Action toBenchmark, bool editorProfile = true, bool deepProfile = true, int count = 1, Action <EditorWindow> recordingDone = null) { if (!SupportsMarkerFiltering()) { return(false); } #if UNITY_2020_1_OR_NEWER if (!EditorPerformanceTracker.Exists(markerName)) { // Create Marker once so Profiler.SetMarkerFiltering will work using (new EditorPerformanceTracker(markerName)) { } } #endif return(StartProfilerRecording(markerName, editorProfile, deepProfile, () => { for (var i = 0; i < count; ++i) { toBenchmark(); } StopProfilerRecordingAndCreateReport(markerName, "", recordingDone); })); }
public static void PerformanceMetric(SearchColumn column) { column.getter = args => { switch (column.selector) { case "count": return(EditorPerformanceTracker.GetSampleCount(args.item.id)); case "peak": return(EditorPerformanceTracker.GetPeakTime(args.item.id)); case "avg": return(EditorPerformanceTracker.GetAverageTime(args.item.id)); case "total": return(EditorPerformanceTracker.GetTotalTime(args.item.id)); case "age": return(EditorPerformanceTracker.GetTimestamp(args.item.id)); } return(null); }; if (column.selector != "count") { column.drawer = args => { if (Utils.TryGetNumber(args.value, out var d)) { GUI.Label(args.rect, GetTimeLabel(d, 0.5d, 2.0d), ItemSelectors.GetItemContentStyle(column)); } return(args.value); }; } }
private void ResetAllCounters() { foreach (var trackerName in GetAllVisibleTrackerNames()) { EditorPerformanceTracker.Reset(trackerName); } RefreshTrackers(); }
static void ApplySpikeOverlay(SpikeWindowInfo info, Color spikeColor) { var spikeOverlayParent = info.spikeOverlayParent; if (info.isInspectorElement) { if (info.spikeOverlay == null) { info.spikeOverlay = CreateSpikeOverlay(); info.spikeOverlay.name = info.trackerName; spikeOverlayParent.Add(info.spikeOverlay); } var color = spikeColor; color.a = 0.05f; info.spikeOverlay.style.backgroundColor = color; } else { if (spikeOverlayParent == null) { return; } if (info.spikeOverlay == null) { info.spikeOverlay = CreateSpikeOverlay(); spikeOverlayParent.Add(info.spikeOverlay); } else { // Check if it is still the last element: var childCount = spikeOverlayParent.childCount; if (childCount > 0 && spikeOverlayParent.ElementAt(childCount - 1) == info.spikeOverlay) { // All is good, perf Overlay is the last item. Nothing to do. } else { // Ensure it is last: if (spikeOverlayParent.Contains(info.spikeOverlay)) { spikeOverlayParent.Remove(info.spikeOverlay); } spikeOverlayParent.Add(info.spikeOverlay); } } WindowBorderState.ApplyToStyle(info.spikeOverlay, spikeColor); } info.paintTriggeredByStateChanged = true; if (PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.AvgTime) { EditorPerformanceTracker.Reset(info.trackerName); } }
public bool MoveNext() { if (m_ActivePerformanceTracker >= 0) { EditorPerformanceTracker.StopTracker(m_ActivePerformanceTracker); } m_CurrentIndex++; m_ActivePerformanceTracker = m_CurrentIndex < m_Length?m_Delegate.StartTrackerAt(m_CurrentIndex, m_Scope) : -1; return(m_CurrentIndex < m_Length); }
public static string GetTrackersReport(IEnumerable <string> trackerNames, TrackerReportOptions options) { if (!ValidateReportOptions(options)) { return(null); } var sb = new StringBuilder(); var maxTrackerNameLength = trackerNames.Max(name => name.Length); var moreThanOneLine = false; foreach (var trackerName in trackerNames) { if (!EditorPerformanceTracker.Exists(trackerName)) { continue; } var shownTokens = new List <string>(); if (options.showSamples) { shownTokens.Add($"{EditorPerformanceTracker.GetSampleCount(trackerName)} samples"); } if (options.showPeak) { shownTokens.Add($"Peak {PtModel.ToEngineeringNotation(EditorPerformanceTracker.GetPeakTime(trackerName))}s"); } if (options.showAvg) { shownTokens.Add($"Avg. {PtModel.ToEngineeringNotation(EditorPerformanceTracker.GetAverageTime(trackerName))}s"); } if (options.showTotal) { shownTokens.Add($"Total {PtModel.ToEngineeringNotation(EditorPerformanceTracker.GetTotalTime(trackerName))}s"); } if (moreThanOneLine) { sb.AppendLine(); } sb.AppendFormat($"{{0,{maxTrackerNameLength}}}: ", trackerName); sb.Append(string.Join(", ", shownTokens)); moreThanOneLine = true; } return(sb.ToString()); }
static void PerformSpikeWindowHighlight(double now, string[] trackerNames) { if (!PerformanceTrackerSettings.spikeHighlightEnabled) { return; } var allEditorWindows = Resources.FindObjectsOfTypeAll <EditorWindow>(); foreach (var window in allEditorWindows) { var windowMarker = GetWindowPaintMarker(window); if (EditorPerformanceTracker.Exists(windowMarker)) { if (!s_SpikeWindowInfos.TryGetValue(windowMarker, out var spikeInfo)) { spikeInfo = new SpikeWindowInfo(window, windowMarker); s_SpikeWindowInfos.Add(windowMarker, spikeInfo); } UpdateSpikeWindow(now, spikeInfo); if (spikeInfo.isInspectorWindow && PerformanceTrackerSettings.inspectorSpikeHighlightEnabled) { using (new PerformanceTracker("Tracker.UpdateInspectors")) { UpdateInspectors(now, spikeInfo); } } } else if (s_SpikeWindowInfos.TryGetValue(windowMarker, out var spikeInfo)) { RemoveSpikeOverlay(spikeInfo); } } // Window is hidden or closed: clean up all spikeOverlay var infos = s_SpikeWindowInfos.Values.ToArray(); foreach (var info in infos) { if (!info.window) { RemoveSpikeOverlay(info); } } }
static void UpdateInspectors(double now, SpikeWindowInfo inspectorInfo) { var editorsList = inspectorInfo.window.rootVisualElement.Q(null, "unity-inspector-editors-list"); if (editorsList != null) { foreach (var editorElement in editorsList.Children()) { var name = editorElement.name; var markerName = $"Editor.{name}.OnInspectorGUI"; s_InspectorWindowInfos.TryGetValue(markerName, out var componentInfo); if (!EditorPerformanceTracker.Exists(markerName)) { if (componentInfo != null) { componentInfo.inUse = false; } continue; } if (componentInfo == null) { componentInfo = new SpikeWindowInfo(inspectorInfo.window, markerName, true, editorElement); s_InspectorWindowInfos.Add(markerName, componentInfo); } else if (editorElement != componentInfo.spikeOverlayParent) { InvalidateParent(componentInfo, editorElement); } componentInfo.inUse = true; UpdateSpikeWindow(now, componentInfo); } } var inspectorInfos = s_InspectorWindowInfos.Values.ToArray(); foreach (var info in inspectorInfos) { if (!info.inUse) { RemoveSpikeOverlay(info); } } }
public static PtInfo[] BuildTrackerList(PtInfo[] previousTrackers, ColumnId sortBy, bool sortAsc, bool sort = true) { var trackerNames = EditorPerformanceTracker.GetAvailableTrackers(); var trackers = new PtInfo[trackerNames.Length]; for (int i = 0; i < trackerNames.Length; ++i) { var trackerName = trackerNames[i]; if (!EditorPerformanceTracker.Exists(trackerName)) { continue; } trackers[i].name = trackerName; trackers[i].sampleCount = EditorPerformanceTracker.GetSampleCount(trackerName); trackers[i].peakTime = EditorPerformanceTracker.GetPeakTime(trackerName); trackers[i].avgTime = EditorPerformanceTracker.GetAverageTime(trackerName); trackers[i].totalTime = EditorPerformanceTracker.GetTotalTime(trackerName); trackers[i].lastTime = EditorPerformanceTracker.GetLastTime(trackerName); trackers[i].usage = EditorPerformanceTracker.GetTotalUsage(trackerName); trackers[i].timestamp = EditorPerformanceTracker.GetTimestamp(trackerName); trackers[i].updated = false; // Tracker previous changes var pti = FindTrackerIndex(trackerName, previousTrackers); if (pti == -1) { continue; } var ppt = previousTrackers[pti]; trackers[i].dtSampleCount = trackers[i].sampleCount - ppt.sampleCount; trackers[i].dtPeakTime = trackers[i].peakTime - ppt.peakTime; trackers[i].dtLastTime = trackers[i].lastTime - ppt.lastTime; trackers[i].dtAvgTime = trackers[i].avgTime - ppt.avgTime; trackers[i].updated = trackers[i].dtSampleCount > 0; } if (sort) { Sort(trackers, sortBy, sortAsc); } return(trackers); }
static void PerformNotifications(double now, string[] trackerNames) { if (!PerformanceTrackerSettings.notificationEnabled) { return; } if (now > s_NextCacheCleanup) { s_NotifChecks.Clear(); s_NextCacheCleanup = now + 60; } var notificationNames = PerformanceTrackerSettings.notificationNames; var thresholds = PerformanceTrackerSettings.notificationThresholds; for (int i = 0; i < notificationNames.Length; ++i) { var notifName = notificationNames[i]; foreach (var trackerName in trackerNames) { if (!trackerName.Contains(notifName)) { continue; } var checkKey = notifName.GetHashCode(); var avgTime = EditorPerformanceTracker.GetAverageTime(trackerName); if (!s_NotifChecks.TryGetValue(checkKey, out var threshold)) { threshold = thresholds[i]; } if (avgTime > threshold) { s_NotifChecks[checkKey] = avgTime; var avgString = PtModel.ToEngineeringNotation(avgTime); var thresholdString = PtModel.ToEngineeringNotation(thresholds[i]); Debug.LogFormat(LogType.Warning, LogOption.NoStacktrace, null, $"<b>{trackerName}</b> is slower than expected ({avgString}s > {thresholdString}s)"); EditorPerformanceTracker.LogCallstack(trackerName); } } } }
static void ResetSpikeOverlay(SpikeWindowInfo info, bool ignoreNextEvent = true) { info.spikeOverlay?.RemoveFromHierarchy(); info.spikeOverlay = null; info.lastSpikeTime = 0; info.lastTime = 0; if (ignoreNextEvent) { info.paintTriggeredByStateChanged = true; } if (info.window) { info.window.Repaint(); } if (PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.AvgTime) { EditorPerformanceTracker.Reset(info.trackerName); } }
public static SearchProvider CreateProvider() { var qe = BuildQueryEngine(); return(new SearchProvider(type, "Performance") { active = false, isExplicitProvider = true, fetchColumns = FetchColumns, fetchDescription = FetchDescription, fetchItems = (context, items, provider) => FetchItem(qe, context, provider), actions = new List <SearchAction>(new[] { new SearchAction("open", "Profile...", item => StartProfilerRecording(item.id, true, deepProfile: false), _ => !ProfilerDriver.deepProfiling && !ProfilerDriver.enabled), new SearchAction("select", "Stop profiling", (SearchItem item) => StopProfilerRecordingAndOpenProfiler(), _ => ProfilerDriver.enabled), new SearchAction("enable_deep", "Enable Deep Profiling...", _ => SetProfilerDeepProfile(true), _ => !ProfilerDriver.deepProfiling), new SearchAction("start_deep", "Deep Profile...", item => StartProfilerRecording(item.id, true, deepProfile: true), _ => ProfilerDriver.deepProfiling && !ProfilerDriver.enabled), new SearchAction("log", "Callstack", item => EditorPerformanceTracker.GetCallstack(item.id, cs => CaptureCallstack(item, cs))), new SearchAction("reset", "Reset", item => EditorPerformanceTracker.Reset(item.id)), }) }); }
public static BenchmarkResult BenchmarkMarker(string markerName, Action action, int count = 100) { var peak = 0.0; var min = 100000000.0; var samples = new double[count]; EditorPerformanceTracker.Reset(markerName); var sampleCount = EditorPerformanceTracker.GetSampleCount(markerName); for (var i = 0; i < count; ++i) { action(); sampleCount = EditorPerformanceTracker.GetSampleCount(markerName); var elapsed = EditorPerformanceTracker.GetLastTime(markerName) * 1000.0; samples[i] = elapsed; if (elapsed > peak) { peak = elapsed; } if (elapsed < min) { min = elapsed; } } Array.Sort(samples); var result = new BenchmarkResult(); result.sampleCount = count; result.avgInMs = EditorPerformanceTracker.GetAverageTime(markerName) * 1000.0; result.totalInSecond = EditorPerformanceTracker.GetTotalTime(markerName); result.peakInMs = peak; result.minInMs = min; result.medianInMs = samples[count / 2]; return(result); }
private VisualElement MakeItem() { var row = new VisualElement(); row.style.flexDirection = FlexDirection.Row; row.AddToClassList("perf-row"); var pinIcon = new VisualElement(); pinIcon.AddToClassList("perf-pin"); row.Add(pinIcon); var trackerName = new TextField { isReadOnly = true }; VisualElement column = trackerName; column.AddToClassList("perf-tracker-name"); row.Add(column); if (IsColumnVisible(ColumnId.SampleCount)) { column = new Button(); column.RegisterCallback <MouseUpEvent>(evt => { var tracker = GetTrackerInRowAtEvt(evt); EditorPerformanceTracker.Reset(tracker.name); RefreshTrackers(); SendAnalytics(Analytics.WindowUsageType.ResetSampleCount, tracker.name); }); column.AddToClassList("perf-sample-count"); row.Add(column); } if (IsColumnVisible(ColumnId.Age)) { column = new Label(); column.AddToClassList("perf-age"); row.Add(column); } if (IsColumnVisible(ColumnId.AvgTime)) { column = new Label(); column.AddToClassList("perf-avg-time"); row.Add(column); } if (IsColumnVisible(ColumnId.PeakTime)) { column = new Label(); column.AddToClassList("perf-peak-time"); row.Add(column); } if (IsColumnVisible(ColumnId.LastTime)) { column = new Label(); column.AddToClassList("perf-last-time"); row.Add(column); } if (IsColumnVisible(ColumnId.TotalTime)) { column = new Label(); column.AddToClassList("perf-total-time"); row.Add(column); } var actionBtn = new Button { text = "..." }; actionBtn.RegisterCallback <MouseUpEvent>(evt => { var btn = evt.target as Button; var tracker = GetTrackerInRowAtEvt(evt); if (tracker.name == m_CurrentProfileTag) { EndTrackerProfiling(evt.target as Button, tracker.name); } else { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Set as search filter"), false, () => { m_SearchField.value = tracker.name; SendAnalytics(Analytics.WindowUsageType.SetSearchFieldAction, tracker.name); }); menu.AddItem(new GUIContent("Add performance notification"), false, () => PerformanceTrackerActions.AddNewPerformanceNotification(tracker.name, (float)tracker.avgTime, Analytics.ActionSource.PerformanceTrackerWindow)); menu.AddItem(new GUIContent("LogCallstack"), false, () => PerformanceTrackerActions.LogCallstack(tracker.name, Analytics.ActionSource.PerformanceTrackerWindow)); if (String.IsNullOrEmpty(m_CurrentProfileTag)) { menu.AddSeparator(""); menu.AddItem(new GUIContent("Editmode Profile..."), false, () => StartTrackerProfiling(btn, tracker.name, false, true)); menu.AddItem(new GUIContent("Editmode Deep profile..."), false, () => StartTrackerProfiling(btn, tracker.name, true, true)); menu.AddSeparator(""); menu.AddItem(new GUIContent("Playmode Profile..."), false, () => StartTrackerProfiling(btn, tracker.name, false, false)); menu.AddItem(new GUIContent("Playmode Deep profile..."), false, () => StartTrackerProfiling(btn, tracker.name, true, false)); } menu.ShowAsContext(); } }); actionBtn.AddToClassList("perf-actions"); row.Add(actionBtn); return(row); }
static void UpdateSpikeWindow(double now, SpikeWindowInfo info) { var avgTime = EditorPerformanceTracker.GetAverageTime(info.trackerName); var trackerLastTime = EditorPerformanceTracker.GetLastTime(info.trackerName); var sampleCount = EditorPerformanceTracker.GetSampleCount(info.trackerName); var peakTime = EditorPerformanceTracker.GetPeakTime(info.trackerName); var spikeDuration = info.lastSpikeTime == 0 ? 0 : now - info.lastSpikeTime; var currentTime = PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.LastTime ? trackerLastTime : avgTime; var infoLastTime = PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.LastTime ? info.lastTime : info.lastAvgTime; if (info.isSpiking && info.spikeOverlay.parent != info.spikeOverlayParent) { // Spike Overlay is not attached to the right window: probably a window that got docked or undocked. InvalidateParent(info); } if (!info.isSpiking && sampleCount == info.lastSampleCount) { // Nothing to do } else if (info.isSpiking && sampleCount == info.lastSampleCount) { // Check if needs to fade out if (spikeDuration > PerformanceTrackerSettings.spikeDuration) { ResetSpikeOverlay(info); } // Do not fade if we are already long to redraw else if (currentTime < PerformanceTrackerSettings.spikeCriticalThreshold && info.supportsFading) { // Try to fade out gently: var alphaFading = (float)((PerformanceTrackerSettings.spikeDuration - spikeDuration) / PerformanceTrackerSettings.spikeDuration); var color = info.spikeOverlay.style.borderBottomColor.value; color.a = alphaFading; ApplySpikeOverlay(info, color); } } else { // We just had an update of sample count: if (info.paintTriggeredByStateChanged) { // Discard this Paint event since it was caused by one of our state change info.paintTriggeredByStateChanged = false; } else if (currentTime > PerformanceTrackerSettings.spikeCriticalThreshold) { if (!info.isSpiking) { ApplySpikeOverlay(info, ComputeSpikeColor((float)currentTime, PerformanceTrackerSettings.spikeCriticalThreshold, 10.0f, PtStyles.criticalColor, Color.black)); } info.lastSpikeTime = now; } else if (currentTime > PerformanceTrackerSettings.spikeWarningThreshold) { if (!info.isSpiking) { ApplySpikeOverlay(info, ComputeSpikeColor((float)currentTime, PerformanceTrackerSettings.spikeWarningThreshold, PerformanceTrackerSettings.spikeCriticalThreshold, PtStyles.warningColor, PtStyles.criticalColor)); } info.lastSpikeTime = now; } else if (infoLastTime > PerformanceTrackerSettings.spikeWarningThreshold) { ResetSpikeOverlay(info); } } info.lastAvgTime = avgTime; info.lastTime = trackerLastTime; info.lastSampleCount = sampleCount; info.lastPeakTime = peakTime; }