Unity 性能分析小工具
下文有两个方法,分别是一段检测执行过程耗费时间的代码,还有一个是保存和加载Unity Profiler 的代码(因为UnityProfiler 只能显示一部分的数据,如果运行时间长的话有部分分析数据查看不到)
1. 检测执行耗费时间 代码如下:
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using UnityEngine; public class CustomTimer : IDisposable { private string m_timerName; private int m_numTests; private Stopwatch m_watch; public CustomTimer(string timerName,int numTests) { m_timerName = timerName; m_numTests = numTests; if (m_numTests <= 0) m_numTests = 1; m_watch = Stopwatch.StartNew(); } public void Dispose() { m_watch.Stop(); float ms = m_watch.ElapsedMilliseconds; UnityEngine.Debug.Log(string.Format("{0} finished: {1:0.00}ms total , {2:0.00000}ms per test for {3} tests", m_timerName, ms, ms / m_numTests, m_numTests)); } }
使用方法如下: 在程序块里放入自己要检测的代码,在循环使用的时候,把0改成循环的次数就可以了
using (new CustomTimer("My Test", 0)) { using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url)) { yield return request.SendWebRequest(); if (request.isHttpError || request.isNetworkError) { // 下载出错 print(request.error); } else { // 下载完成 AssetBundle assetBundle = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; GameObject obj = assetBundle.LoadAsset<GameObject>(assetBundle.GetAllAssetNames()[0]); GameObject obj2 = GameObject.Instantiate(obj); this.obj = obj2.transform; // 优先释放request 会降低内存峰值 request.Dispose(); } } }
2. Unity Profiler 保存方法:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Profiling; public class ProfilerDataSaverComponent : MonoBehaviour { int _count = 0; void Start() { Profiler.logFile = ""; } // Update is called once per frame void Update() { if(Input.GetKey(KeyCode.LeftControl)&& Input.GetKeyDown(KeyCode.H)) { StartCoroutine(SaveProfilerData()); } } IEnumerator SaveProfilerData() { while(true) { string filepath = Application.persistentDataPath + "/profilerLog" + _count; Profiler.logFile = filepath; Profiler.enableBinaryLog = true; Profiler.enabled = true; for (int i = 0; i < 300; i++) { yield return new WaitForEndOfFrame(); if(!Profiler.enabled) { Profiler.enabled = true; } } _count++; } } }
读取保存的UnityProfiler数据: 在Window/ProfilerDataLoader 内
using System.Collections; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; using UnityEngine.Profiling; public class ProfilerDataLoaderWindow : EditorWindow { static List<string> s_cachedFilePaths; static int s_chosenIndex = -1; [MenuItem("Window/ProfilerDataLoader")] static void Init() { ProfilerDataLoaderWindow window = (ProfilerDataLoaderWindow)EditorWindow.GetWindow(typeof(ProfilerDataLoaderWindow)); } static void ReadProfilerDataFiles() { Profiler.logFile = ""; string[] filePath = Directory.GetFiles(Application.persistentDataPath , "ProfilerLog*"); s_cachedFilePaths = new List<string>(); Regex test = new Regex(".data$"); for (int i = 0; i < filePath.Length; i++) { string thisPath = filePath[i]; Match match = test.Match(thisPath); if(!match.Success) { Debug.Log("Found file: " + thisPath); s_cachedFilePaths.Add(thisPath); } } s_chosenIndex = -1; } private void OnGUI() { if(GUILayout.Button("Find Files")) { ReadProfilerDataFiles(); } if (s_cachedFilePaths == null) return; EditorGUILayout.Space(); EditorGUILayout.LabelField("Files"); EditorGUILayout.BeginHorizontal(); GUIStyle defaultStyle = new GUIStyle(GUI.skin.button); defaultStyle.fixedWidth = 40; GUIStyle highlightedStyle = new GUIStyle(defaultStyle); highlightedStyle.normal.textColor = Color.red; for (int i = 0; i < s_cachedFilePaths.Count; i++) { if(i%5==0) { EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); } GUIStyle thisStyle = null; if(s_chosenIndex ==i) { thisStyle = highlightedStyle; } else { thisStyle = defaultStyle; } if (GUILayout.Button("" + i, thisStyle)) { Profiler.AddFramesFromFile(s_cachedFilePaths[i]); s_chosenIndex = i; } } EditorGUILayout.EndHorizontal(); } }