public void Dispose()
 {
     if (m_ActivePerformanceTracker >= 0)
     {
         EditorPerformanceTracker.StopTracker(m_ActivePerformanceTracker);
     }
 }
示例#2
0
 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;
        }
示例#4
0
        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);
                };
            }
        }
示例#6
0
 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);
            }
示例#9
0
        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);
                }
            }
        }
示例#12
0
        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)),
                })
            });
        }
示例#16
0
        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);
        }
示例#17
0
        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;
        }