From cc3ed9c30acf8d102d2f71c2baf6bff94deba09c Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sun, 22 Jan 2017 13:20:15 +0000 Subject: [PATCH] Revert "delete engine profiler because was relying on the Tickable system, now only the TaskRunner profiler must be used" This reverts commit 4089cd73099ca210b1aca8fdebe0bb641897cfdc. --- ECS/EnginesRoot.cs | 9 +- ECS/Profiler.meta | 9 + ECS/Profiler/Editor.meta | 9 + ECS/Profiler/Editor/EngineProfiler.meta | 9 + .../EngineProfiler/EngineProfilerInspector.cs | 250 ++++++++++++++++++ .../EngineProfilerInspector.cs.meta | 12 + .../EngineProfiler/EngineProfilerMenuItem.cs | 22 ++ .../EngineProfilerMenuItem.cs.meta | 12 + .../Editor/EngineProfiler/EnginesMonitor.cs | 132 +++++++++ .../EngineProfiler/EnginesMonitor.cs.meta | 12 + .../EngineProfiler/ProfilerEditorLayout.cs | 65 +++++ .../ProfilerEditorLayout.cs.meta | 12 + ECS/Profiler/EngineInfo.cs | 167 ++++++++++++ ECS/Profiler/EngineInfo.cs.meta | 12 + ECS/Profiler/EngineProfiler.cs | 61 +++++ ECS/Profiler/EngineProfiler.cs.meta | 12 + ECS/Profiler/EngineProfilerBehaviour.cs | 19 ++ ECS/Profiler/EngineProfilerBehaviour.cs.meta | 12 + 18 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 ECS/Profiler.meta create mode 100644 ECS/Profiler/Editor.meta create mode 100644 ECS/Profiler/Editor/EngineProfiler.meta create mode 100644 ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs create mode 100644 ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs.meta create mode 100644 ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs create mode 100644 ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs.meta create mode 100644 ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs create mode 100644 ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs.meta create mode 100644 ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs create mode 100644 ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta create mode 100644 ECS/Profiler/EngineInfo.cs create mode 100644 ECS/Profiler/EngineInfo.cs.meta create mode 100644 ECS/Profiler/EngineProfiler.cs create mode 100644 ECS/Profiler/EngineProfiler.cs.meta create mode 100644 ECS/Profiler/EngineProfilerBehaviour.cs create mode 100644 ECS/Profiler/EngineProfilerBehaviour.cs.meta diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index 6d43243..dfec6e4 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -46,8 +46,13 @@ namespace Svelto.ECS go.AddComponent().OnTick += SubmitNodes; #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - GameObject debugEngineObject = new GameObject("Engine Debugger"); - debugEngineObject.gameObject.AddComponent(); + var debugEngineObject = GameObject.Find("Svelto.ECS.Profiler"); + if (debugEngineObject == null) + { + debugEngineObject = new GameObject("Svelto.ECS.Profiler"); + debugEngineObject.gameObject.AddComponent(); + UnityEngine.Object.DontDestroyOnLoad(debugEngineObject); + } #endif } diff --git a/ECS/Profiler.meta b/ECS/Profiler.meta new file mode 100644 index 0000000..3a39d53 --- /dev/null +++ b/ECS/Profiler.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8d07544bb8b417f4a9eaefe0d4771d89 +folderAsset: yes +timeCreated: 1462355668 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor.meta b/ECS/Profiler/Editor.meta new file mode 100644 index 0000000..48dd9b3 --- /dev/null +++ b/ECS/Profiler/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 71a4fc836cd9bde4bbb936a073804ec5 +folderAsset: yes +timeCreated: 1480683133 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor/EngineProfiler.meta b/ECS/Profiler/Editor/EngineProfiler.meta new file mode 100644 index 0000000..b802d05 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 777a9420fd80746428f9d2c5b718fd2f +folderAsset: yes +timeCreated: 1462351213 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs new file mode 100644 index 0000000..f613f61 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + [CustomEditor(typeof (EngineProfilerBehaviour))] + public class EngineProfilerInspector : Editor + { + enum SORTING_OPTIONS + { + AVERAGE, + MIN, + MAX, + NAME, + NONE + } + + static bool _hideEmptyEngines = true; + static bool _showTickEngines; + static bool _showAddEngines; + static bool _showRemoveEngines; + + static string _systemNameSearchTerm = string.Empty; + + float _axisUpperBounds = 2f; + + string updateTitle = "Update".PadRight(15, ' '); + string lateUpdateTitle = "Late".PadRight(13, ' '); + string fixedupdateTitle = "Fixed".PadRight(15, ' '); + string minTitle = "Min".PadRight(15, ' '); + string maxTitle = "Max".PadRight(15, ' '); + string avgTitle = "Avg".PadRight(15, ' '); + + EnginesMonitor _enginesMonitor; + Queue _engineMonitorData; + const int SYSTEM_MONITOR_DATA_LENGTH = 300; + SORTING_OPTIONS _sortingOption = SORTING_OPTIONS.AVERAGE; + + public override void OnInspectorGUI() + { + var engineProfilerBehaviour = (EngineProfilerBehaviour) target; + EngineInfo[] engines = new EngineInfo[engineProfilerBehaviour.engines.Count]; + engineProfilerBehaviour.engines.CopyTo(engines, 0); + + DrawEngineList(engineProfilerBehaviour, engines); + EditorUtility.SetDirty(target); + } + + void DrawEngineList(EngineProfilerBehaviour engineProfilerBehaviour, EngineInfo[] engines) + { + ProfilerEditorLayout.BeginVerticalBox(); + { + ProfilerEditorLayout.BeginHorizontal(); + { + if (GUILayout.Button("Reset Durations", GUILayout.Width(120), GUILayout.Height(14))) + { + engineProfilerBehaviour.ResetDurations(); + } + } + ProfilerEditorLayout.EndHorizontal(); + + _sortingOption = (SORTING_OPTIONS) EditorGUILayout.EnumPopup("Sort By:", _sortingOption); + + _hideEmptyEngines = EditorGUILayout.Toggle("Hide empty systems", _hideEmptyEngines); + EditorGUILayout.Space(); + + ProfilerEditorLayout.BeginHorizontal(); + { + _systemNameSearchTerm = EditorGUILayout.TextField("Search", _systemNameSearchTerm); + + const string clearButtonControlName = "Clear Button"; + GUI.SetNextControlName(clearButtonControlName); + if (GUILayout.Button("x", GUILayout.Width(19), GUILayout.Height(14))) + { + _systemNameSearchTerm = string.Empty; + GUI.FocusControl(clearButtonControlName); + } + } + ProfilerEditorLayout.EndHorizontal(); + + _showAddEngines = EditorGUILayout.Foldout(_showAddEngines, "Engines Add"); + if (_showAddEngines && ShouldShowSystems(engines)) + { + ProfilerEditorLayout.BeginVerticalBox(); + { + var systemsDrawn = DrawAddEngineInfos(engines); + if (systemsDrawn == 0) + { + EditorGUILayout.LabelField(string.Empty); + } + } + ProfilerEditorLayout.EndVertical(); + } + + _showRemoveEngines = EditorGUILayout.Foldout(_showRemoveEngines, "Engines Remove"); + if (_showRemoveEngines && ShouldShowSystems(engines)) + { + ProfilerEditorLayout.BeginVerticalBox(); + { + var systemsDrawn = DrawRemoveEngineInfos(engines); + if (systemsDrawn == 0) + { + EditorGUILayout.LabelField(string.Empty); + } + } + ProfilerEditorLayout.EndVertical(); + } + } + ProfilerEditorLayout.EndVertical(); + } + + int DrawAddEngineInfos(EngineInfo[] engines) + { + if (_sortingOption != SORTING_OPTIONS.NONE) + { + SortAddEngines(engines); + } + + string title = avgTitle.FastConcat(minTitle).FastConcat(maxTitle); + EditorGUILayout.LabelField("Engine Name", title, EditorStyles.boldLabel); + + int enginesDrawn = 0; + for (int i = 0; i < engines.Length; i++) + { + EngineInfo engineInfo = engines[i]; + if (engineInfo.engineName.ToLower().Contains(_systemNameSearchTerm.ToLower()) && + !engineInfo.minAddDuration.Equals(0) && !engineInfo.maxAddDuration.Equals(0)) + { + ProfilerEditorLayout.BeginHorizontal(); + { + var avg = string.Format("{0:0.000}", engineInfo.averageAddDuration).PadRight(15); + var min = string.Format("{0:0.000}", engineInfo.minAddDuration).PadRight(15); + var max = string.Format("{0:0.000}", engineInfo.maxAddDuration); + + string output = avg.FastConcat(min).FastConcat(max); + + EditorGUILayout.LabelField(engineInfo.engineName, output, GetEngineStyle()); + } + ProfilerEditorLayout.EndHorizontal(); + + enginesDrawn += 1; + } + } + return enginesDrawn; + } + + int DrawRemoveEngineInfos(EngineInfo[] engines) + { + if (_sortingOption != SORTING_OPTIONS.NONE) + { + SortRemoveEngines(engines); + } + + string title = avgTitle.FastConcat(minTitle).FastConcat(maxTitle); + EditorGUILayout.LabelField("Engine Name", title, EditorStyles.boldLabel); + + int enginesDrawn = 0; + for (int i = 0; i < engines.Length; i++) + { + EngineInfo engineInfo = engines[i]; + if (engineInfo.engineName.ToLower().Contains(_systemNameSearchTerm.ToLower()) && + !engineInfo.minRemoveDuration.Equals(0) && !engineInfo.maxRemoveDuration.Equals(0)) + { + ProfilerEditorLayout.BeginHorizontal(); + { + var avg = string.Format("{0:0.000}", engineInfo.averageRemoveDuration).PadRight(15); + var min = string.Format("{0:0.000}", engineInfo.minRemoveDuration).PadRight(15); + var max = string.Format("{0:0.000}", engineInfo.maxRemoveDuration); + + string output = avg.FastConcat(min).FastConcat(max); + + EditorGUILayout.LabelField(engineInfo.engineName, output, GetEngineStyle()); + } + ProfilerEditorLayout.EndHorizontal(); + + enginesDrawn += 1; + } + } + return enginesDrawn; + } + + static GUIStyle GetEngineStyle() + { + var style = new GUIStyle(GUI.skin.label); + var color = EditorGUIUtility.isProSkin ? Color.white : style.normal.textColor; + + style.normal.textColor = color; + + return style; + } + + static bool ShouldShowSystems(EngineInfo[] engines) + { + return engines.Length > 0; + } + +#region Sorting Engines + void SortAddEngines(EngineInfo[] engines) + { + switch (_sortingOption) + { + case SORTING_OPTIONS.AVERAGE: + Array.Sort(engines, + (engine1, engine2) => engine2.averageAddDuration.CompareTo(engine1.averageAddDuration)); + break; + case SORTING_OPTIONS.MIN: + Array.Sort(engines, + (engine1, engine2) => engine2.minAddDuration.CompareTo(engine1.minAddDuration)); + break; + case SORTING_OPTIONS.MAX: + Array.Sort(engines, + (engine1, engine2) => engine2.maxAddDuration.CompareTo(engine1.maxAddDuration)); + break; + case SORTING_OPTIONS.NAME: + Array.Sort(engines, + (engine1, engine2) => String.Compare(engine1.engineName, engine2.engineName, StringComparison.Ordinal)); + break; + } + } + + void SortRemoveEngines(EngineInfo[] engines) + { + switch (_sortingOption) + { + case SORTING_OPTIONS.AVERAGE: + Array.Sort(engines, + (engine1, engine2) => engine2.averageRemoveDuration.CompareTo(engine1.averageRemoveDuration)); + break; + case SORTING_OPTIONS.MIN: + Array.Sort(engines, + (engine1, engine2) => engine2.minRemoveDuration.CompareTo(engine1.minRemoveDuration)); + break; + case SORTING_OPTIONS.MAX: + Array.Sort(engines, + (engine1, engine2) => engine2.maxRemoveDuration.CompareTo(engine1.maxRemoveDuration)); + break; + case SORTING_OPTIONS.NAME: + Array.Sort(engines, + (engine1, engine2) => String.Compare(engine1.engineName, engine2.engineName, StringComparison.Ordinal)); + break; + } + } + } +#endregion +} diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs.meta b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs.meta new file mode 100644 index 0000000..02c6f19 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a2202d1747b86dc428310091a9c1a7ef +timeCreated: 1462469401 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs new file mode 100644 index 0000000..2c20e59 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs @@ -0,0 +1,22 @@ +using UnityEditor; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + internal class EngineProfilerMenuItem + { + [MenuItem("Engines/Enable Profiler")] + public static void EnableProfiler() + { + PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "ENGINE_PROFILER_ENABLED"); + } + + [MenuItem("Engines/Disable Profiler")] + public static void DisableProfiler() + { + PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, ""); + } + } +} diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs.meta b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs.meta new file mode 100644 index 0000000..b487da4 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e7b6bbeaaa16ab84aaa99c3311199efa +timeCreated: 1462351229 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs b/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs new file mode 100644 index 0000000..0d568a4 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs @@ -0,0 +1,132 @@ +using System.Linq; +using UnityEditor; +using UnityEngine; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + public class EnginesMonitor + { + public float xBorder = 48; + public float yBorder = 20; + public int rightLinePadding = -15; + public string labelFormat = "{0:0.0}"; + public string axisFormat = "{0:0.0}"; + public int gridLines = 1; + public float axisRounding = 5f; + public float anchorRadius = 1f; + public Color lineColor = Color.magenta; + + readonly GUIStyle _labelTextStyle; + readonly GUIStyle _centeredStyle; + readonly Vector3[] _cachedLinePointVerticies; + readonly Vector3[] _linePoints; + + public EnginesMonitor(int dataLength) + { + _labelTextStyle = new GUIStyle(GUI.skin.label); + _labelTextStyle.alignment = TextAnchor.UpperRight; + _centeredStyle = new GUIStyle(); + _centeredStyle.alignment = TextAnchor.UpperCenter; + _centeredStyle.normal.textColor = Color.white; + _linePoints = new Vector3[dataLength]; + _cachedLinePointVerticies = new[] + { + new Vector3(-1, 1, 0)*anchorRadius, + new Vector3(1, 1, 0)*anchorRadius, + new Vector3(1, -1, 0)*anchorRadius, + new Vector3(-1, -1, 0)*anchorRadius, + }; + } + + public void Draw(float[] data, float height, float axisUpperBounds) + { + axisRounding = axisUpperBounds; + var rect = GUILayoutUtility.GetRect(EditorGUILayout.GetControlRect().width, height); + var top = rect.y + yBorder; + var floor = rect.y + rect.height - yBorder; + var availableHeight = floor - top; + var max = data.Length != 0 ? data.Max() : 0f; + if (max%axisRounding != 0) + { + max = max + axisRounding - (max%axisRounding); + } + + drawGridLines(top, rect.width, availableHeight, max); + drawLine(data, floor, rect.width, availableHeight, max); + } + + void drawGridLines(float top, float width, float availableHeight, float max) + { + var handleColor = Handles.color; + Handles.color = Color.grey; + var n = gridLines + 1; + var lineSpacing = availableHeight/n; + for (int i = 0; i <= n; i++) + { + var lineY = top + (lineSpacing*i); + Handles.DrawLine( + new Vector2(xBorder, lineY), + new Vector2(width - rightLinePadding, lineY) + ); + GUI.Label( + new Rect(0, lineY - 8, xBorder - 2, 50), + string.Format(axisFormat, max*(1f - ((float) i/(float) n))), + _labelTextStyle + ); + } + Handles.color = handleColor; + } + + void drawLine(float[] data, float floor, float width, float availableHeight, float max) + { + var lineWidth = (float) (width - xBorder - rightLinePadding)/data.Length; + var handleColor = Handles.color; + var labelRect = new Rect(); + Vector2 newLine; + bool mousePositionDiscovered = false; + float mouseHoverDataValue = 0; + float linePointScale; + Handles.color = lineColor; + Handles.matrix = Matrix4x4.identity; + HandleUtility.handleMaterial.SetPass(0); + for (int i = 0; i < data.Length; i++) + { + var value = data[i]; + var lineTop = floor - (availableHeight*(value/max)); + newLine = new Vector2(xBorder + (lineWidth*i), lineTop); + _linePoints[i] = new Vector3(newLine.x, newLine.y, 0); + linePointScale = 1f; + if (!mousePositionDiscovered) + { + var anchorPosRadius3 = anchorRadius*3; + var anchorPosRadius6 = anchorRadius*6; + var anchorPos = newLine - (Vector2.up*0.5f); + labelRect = new Rect(anchorPos.x - anchorPosRadius3, anchorPos.y - anchorPosRadius3, + anchorPosRadius6, anchorPosRadius6); + if (labelRect.Contains(Event.current.mousePosition)) + { + mousePositionDiscovered = true; + mouseHoverDataValue = value; + linePointScale = 3f; + } + } + Handles.matrix = Matrix4x4.TRS(_linePoints[i], Quaternion.identity, Vector3.one*linePointScale); + Handles.DrawAAConvexPolygon(_cachedLinePointVerticies); + } + Handles.matrix = Matrix4x4.identity; + Handles.DrawAAPolyLine(2f, data.Length, _linePoints); + + if (mousePositionDiscovered) + { + labelRect.y -= 16; + labelRect.width += 50; + labelRect.x -= 25; + GUI.Label(labelRect, string.Format(labelFormat, mouseHoverDataValue), _centeredStyle); + } + Handles.color = handleColor; + } + } +} diff --git a/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs.meta b/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs.meta new file mode 100644 index 0000000..aee00e5 --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 30f9f7f6468a96d4da2525c65ecfe637 +timeCreated: 1467633311 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs b/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs new file mode 100644 index 0000000..d012cac --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs @@ -0,0 +1,65 @@ +using UnityEditor; +using UnityEngine; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + public static class ProfilerEditorLayout + { + public static void ShowWindow(string title) where T : EditorWindow + { + var window = EditorWindow.GetWindow(true, title); + window.minSize = window.maxSize = new Vector2(415f, 520f); + window.Show(); + } + + public static Texture2D LoadTexture(string label) + { + var guid = AssetDatabase.FindAssets(label)[0]; + if (guid != null) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + return AssetDatabase.LoadAssetAtPath(path); + } + return null; + } + + public static float DrawHeaderTexture(EditorWindow window, Texture2D texture) + { + const int scollBarWidth = 15; + var ratio = texture.width/texture.height; + var width = window.position.width - 8 - scollBarWidth; + var height = width/ratio; + GUI.DrawTexture(new Rect(4, 2, width, height), texture, ScaleMode.ScaleToFit); + + return height; + } + + public static Rect BeginVertical() + { + return EditorGUILayout.BeginVertical(); + } + + public static Rect BeginVerticalBox(GUIStyle style = null) + { + return EditorGUILayout.BeginVertical(style ?? GUI.skin.box); + } + + public static void EndVertical() + { + EditorGUILayout.EndVertical(); + } + + public static Rect BeginHorizontal() + { + return EditorGUILayout.BeginHorizontal(); + } + + public static void EndHorizontal() + { + EditorGUILayout.EndHorizontal(); + } + } +} diff --git a/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta b/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta new file mode 100644 index 0000000..489305b --- /dev/null +++ b/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3e961e5c8cc40064fa25092d835d1a80 +timeCreated: 1462527509 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/EngineInfo.cs b/ECS/Profiler/EngineInfo.cs new file mode 100644 index 0000000..ceffef9 --- /dev/null +++ b/ECS/Profiler/EngineInfo.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + public sealed class EngineInfo + { + enum UpdateType + { + Update = 0, + LateUpdate = 1, + FixedUpdate = 2, + } + + readonly IEngine _engine; + readonly string _engineName; + readonly Type _engineType; + + const int NUM_UPDATE_TYPES = 3; + const int NUM_FRAMES_TO_AVERAGE = 10; + + //use a queue to averave out the last 30 frames + Queue[] _updateFrameTimes = new Queue[NUM_UPDATE_TYPES]; + readonly double[] _accumulatedUpdateDuration = new double[NUM_UPDATE_TYPES]; + readonly double[] _lastUpdateDuration = new double[NUM_UPDATE_TYPES]; + + readonly double[] _minUpdateDuration = new double[NUM_UPDATE_TYPES]; + readonly double[] _maxUpdateDuration = new double[NUM_UPDATE_TYPES]; + + double _accumulatedAddDuration; + double _minAddDuration; + double _maxAddDuration; + int _nodesAddedCount; + + double _accumulatedRemoveDuration; + double _minRemoveDuration; + double _maxRemoveDuration; + int _nodesRemovedCount; + + public IEngine engine { get { return _engine; } } + public string engineName { get { return _engineName; } } + public Type engineType { get { return _engineType; } } + + public double lastUpdateDuration { get { return _lastUpdateDuration[(int) UpdateType.Update]; } } + public double lastFixedUpdateDuration { get { return _lastUpdateDuration[(int)UpdateType.LateUpdate]; } } + public double lastLateUpdateDuration { get { return _lastUpdateDuration[(int)UpdateType.FixedUpdate]; } } + + public double minAddDuration { get { return _minAddDuration; } } + public double minRemoveDuration { get { return _minRemoveDuration; } } + public double minUpdateDuration { get { return _minUpdateDuration[(int)UpdateType.Update]; } } + + public double maxAddDuration { get { return _maxAddDuration; } } + public double maxRemoveDuration { get { return _maxRemoveDuration; } } + public double maxUpdateDuration { get { return _maxUpdateDuration[(int)UpdateType.Update]; } } + + public double averageAddDuration { get { return _nodesAddedCount == 0 ? 0 : _accumulatedAddDuration / _nodesAddedCount; } } + public double averageRemoveDuration { get { return _nodesRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _nodesRemovedCount; } } + public double averageUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.Update].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.Update] / _updateFrameTimes[(int)UpdateType.Update].Count; } } + public double averageLateUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.LateUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.LateUpdate] / _updateFrameTimes[(int)UpdateType.LateUpdate].Count; } } + public double averageFixedUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.FixedUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.FixedUpdate] / _updateFrameTimes[(int)UpdateType.FixedUpdate].Count; } } + + public EngineInfo(IEngine engine) + { + _engine = engine; + _engineName = _engine.ToString(); + + int foundNamespace = _engineName.LastIndexOf("."); + _engineName = _engineName.Remove(0, foundNamespace + 1); + + _engineType = engine.GetType(); + + for (int i = 0; i < NUM_UPDATE_TYPES; i++) + { + _updateFrameTimes[i] = new Queue(); + } + ResetDurations(); + } + + public void AddUpdateDuration(double updateDuration) + { + AddUpdateDurationForType(updateDuration, (int)UpdateType.Update); + } + + public void AddLateUpdateDuration(double updateDuration) + { + AddUpdateDurationForType(updateDuration, (int)UpdateType.LateUpdate); + } + + public void AddFixedUpdateDuration(double updateDuration) + { + AddUpdateDurationForType(updateDuration, (int)UpdateType.FixedUpdate); + } + + void AddUpdateDurationForType(double updateDuration, int updateType) + { + if (updateDuration < _minUpdateDuration[updateType] || _minUpdateDuration[updateType] == 0) + { + _minUpdateDuration[updateType] = updateDuration; + } + if (updateDuration > _maxUpdateDuration[updateType]) + { + _maxUpdateDuration[updateType] = updateDuration; + } + + if (_updateFrameTimes[updateType].Count == NUM_FRAMES_TO_AVERAGE) + { + _accumulatedUpdateDuration[updateType] -= _updateFrameTimes[updateType].Dequeue(); + } + + _accumulatedUpdateDuration[updateType] += updateDuration; + _updateFrameTimes[updateType].Enqueue(updateDuration); + _lastUpdateDuration[updateType] = updateDuration; + } + + public void AddAddDuration(double duration) + { + if (duration < _minAddDuration || _minAddDuration == 0) + { + _minAddDuration = duration; + } + if (duration > _maxAddDuration) + { + _maxAddDuration = duration; + } + _accumulatedAddDuration += duration; + _nodesAddedCount += 1; + } + + public void AddRemoveDuration(double duration) + { + if (duration < _minRemoveDuration || _minRemoveDuration == 0) + { + _minRemoveDuration = duration; + } + if (duration > _maxRemoveDuration) + { + _maxRemoveDuration = duration; + } + _accumulatedRemoveDuration += duration; + _nodesRemovedCount += 1; + } + + public void ResetDurations() + { + for (int i = 0; i < NUM_UPDATE_TYPES; i++) + { + _accumulatedUpdateDuration[i] = 0; + _minUpdateDuration[i] = 0; + _maxUpdateDuration[i] = 0; + _updateFrameTimes[i].Clear(); + } + + _accumulatedAddDuration = 0; + _minAddDuration = 0; + _maxAddDuration = 0; + _nodesAddedCount = 0; + + _accumulatedRemoveDuration = 0; + _minRemoveDuration = 0; + _maxRemoveDuration = 0; + _nodesRemovedCount = 0; + } + } +} diff --git a/ECS/Profiler/EngineInfo.cs.meta b/ECS/Profiler/EngineInfo.cs.meta new file mode 100644 index 0000000..2463af8 --- /dev/null +++ b/ECS/Profiler/EngineInfo.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 93c5ba48b51186e44b7094eef7028c90 +timeCreated: 1462357591 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs new file mode 100644 index 0000000..f055f3d --- /dev/null +++ b/ECS/Profiler/EngineProfiler.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + public sealed class EngineProfiler + { + static readonly Stopwatch _stopwatch = new Stopwatch(); + + public static void MonitorAddDuration(Action, INode> addingFunc, INodeEngine engine, INode node) + { + EngineInfo info; + if (engineInfos.TryGetValue(engine.GetType(), out info)) + { + _stopwatch.Reset(); + _stopwatch.Start(); + addingFunc(engine, node); + _stopwatch.Stop(); + + info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); + } + } + + public static void MonitorRemoveDuration(Action, INode> removeFunc, INodeEngine engine, INode node) + { + EngineInfo info; + if (engineInfos.TryGetValue(engine.GetType(), out info)) + { + _stopwatch.Reset(); + _stopwatch.Start(); + removeFunc(engine, node); + engine.Remove(node); + _stopwatch.Stop(); + + info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); + } + } + + public static void AddEngine(IEngine engine) + { + if (engineInfos.ContainsKey(engine.GetType()) == false) + { + engineInfos.Add(engine.GetType(), new EngineInfo(engine)); + } + } + + public static void ResetDurations() + { + foreach (var engine in engineInfos) + { + engine.Value.ResetDurations(); + } + } + + public static readonly Dictionary engineInfos = new Dictionary(); + } +} diff --git a/ECS/Profiler/EngineProfiler.cs.meta b/ECS/Profiler/EngineProfiler.cs.meta new file mode 100644 index 0000000..7c2b637 --- /dev/null +++ b/ECS/Profiler/EngineProfiler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 74b59045fe5033b4b98facadd4d6b114 +timeCreated: 1462355668 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/EngineProfilerBehaviour.cs b/ECS/Profiler/EngineProfilerBehaviour.cs new file mode 100644 index 0000000..9039a2a --- /dev/null +++ b/ECS/Profiler/EngineProfilerBehaviour.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +//This profiler is based on the Entitas Visual Debugging tool +//https://github.com/sschmid/Entitas-CSharp + +namespace Svelto.ECS.Profiler +{ + public class EngineProfilerBehaviour : MonoBehaviour + { + public Dictionary.ValueCollection engines { get { return EngineProfiler.engineInfos.Values; } } + + public void ResetDurations() + { + EngineProfiler.ResetDurations(); + } + } +} diff --git a/ECS/Profiler/EngineProfilerBehaviour.cs.meta b/ECS/Profiler/EngineProfilerBehaviour.cs.meta new file mode 100644 index 0000000..17446f2 --- /dev/null +++ b/ECS/Profiler/EngineProfilerBehaviour.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 688f5cf68b171ef4fa0f6aab49644c48 +timeCreated: 1462469401 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: