//Uncomment the next line to enable debugging (also uncomment it in AstarPath.cs) //#define ProfileAstar //@SHOWINEDITOR //#define ASTAR_UNITY_PRO_PROFILER //@SHOWINEDITOR Requires ProfileAstar, profiles section of astar code which will show up in the Unity Pro Profiler. using System.Collections.Generic; using System; using UnityEngine; #if UNITY_5_5_OR_NEWER using UnityEngine.Profiling; #endif namespace Pathfinding { public class AstarProfiler { public class ProfilePoint { //public DateTime lastRecorded; //public TimeSpan totalTime; public System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); public int totalCalls; public long tmpBytes; public long totalBytes; } static readonly Dictionary profiles = new Dictionary(); static DateTime startTime = DateTime.UtcNow; public static ProfilePoint[] fastProfiles; public static string[] fastProfileNames; private AstarProfiler() { } [System.Diagnostics.Conditional("ProfileAstar")] public static void InitializeFastProfile (string[] profileNames) { fastProfileNames = new string[profileNames.Length+2]; Array.Copy(profileNames, fastProfileNames, profileNames.Length); fastProfileNames[fastProfileNames.Length-2] = "__Control1__"; fastProfileNames[fastProfileNames.Length-1] = "__Control2__"; fastProfiles = new ProfilePoint[fastProfileNames.Length]; for (int i = 0; i < fastProfiles.Length; i++) fastProfiles[i] = new ProfilePoint(); } [System.Diagnostics.Conditional("ProfileAstar")] public static void StartFastProfile (int tag) { //profiles.TryGetValue(tag, out point); fastProfiles[tag].watch.Start();//lastRecorded = DateTime.UtcNow; } [System.Diagnostics.Conditional("ProfileAstar")] public static void EndFastProfile (int tag) { /*if (!profiles.ContainsKey(tag)) * { * Debug.LogError("Can only end profiling for a tag which has already been started (tag was " + tag + ")"); * return; * }*/ ProfilePoint point = fastProfiles[tag]; point.totalCalls++; point.watch.Stop(); //DateTime now = DateTime.UtcNow; //point.totalTime += now - point.lastRecorded; //fastProfiles[tag] = point; } [System.Diagnostics.Conditional("ASTAR_UNITY_PRO_PROFILER")] public static void EndProfile () { Profiler.EndSample(); } [System.Diagnostics.Conditional("ProfileAstar")] public static void StartProfile (string tag) { #if ASTAR_UNITY_PRO_PROFILER Profiler.BeginSample(tag); #else //Console.WriteLine ("Profile Start - " + tag); ProfilePoint point; profiles.TryGetValue(tag, out point); if (point == null) { point = new ProfilePoint(); profiles[tag] = point; } point.tmpBytes = GC.GetTotalMemory(false); point.watch.Start(); //point.lastRecorded = DateTime.UtcNow; //Debug.Log ("Starting " + tag); #endif } [System.Diagnostics.Conditional("ProfileAstar")] public static void EndProfile (string tag) { #if !ASTAR_UNITY_PRO_PROFILER if (!profiles.ContainsKey(tag)) { Debug.LogError("Can only end profiling for a tag which has already been started (tag was " + tag + ")"); return; } //Console.WriteLine ("Profile End - " + tag); //DateTime now = DateTime.UtcNow; ProfilePoint point = profiles[tag]; //point.totalTime += now - point.lastRecorded; ++point.totalCalls; point.watch.Stop(); point.totalBytes += GC.GetTotalMemory(false) - point.tmpBytes; //profiles[tag] = point; //Debug.Log ("Ending " + tag); #else EndProfile(); #endif } [System.Diagnostics.Conditional("ProfileAstar")] public static void Reset () { profiles.Clear(); startTime = DateTime.UtcNow; if (fastProfiles != null) { for (int i = 0; i < fastProfiles.Length; i++) { fastProfiles[i] = new ProfilePoint(); } } } [System.Diagnostics.Conditional("ProfileAstar")] public static void PrintFastResults () { if (fastProfiles == null) return; StartFastProfile(fastProfiles.Length-2); for (int i = 0; i < 1000; i++) { StartFastProfile(fastProfiles.Length-1); EndFastProfile(fastProfiles.Length-1); } EndFastProfile(fastProfiles.Length-2); double avgOverhead = fastProfiles[fastProfiles.Length-2].watch.Elapsed.TotalMilliseconds / 1000.0; TimeSpan endTime = DateTime.UtcNow - startTime; var output = new System.Text.StringBuilder(); output.Append("============================\n\t\t\t\tProfile results:\n============================\n"); output.Append("Name | Total Time | Total Calls | Avg/Call | Bytes"); //foreach(KeyValuePair pair in profiles) for (int i = 0; i < fastProfiles.Length; i++) { string name = fastProfileNames[i]; ProfilePoint value = fastProfiles[i]; int totalCalls = value.totalCalls; double totalTime = value.watch.Elapsed.TotalMilliseconds - avgOverhead*totalCalls; if (totalCalls < 1) continue; output.Append("\n").Append(name.PadLeft(10)).Append("| "); output.Append(totalTime.ToString("0.0 ").PadLeft(10)).Append(value.watch.Elapsed.TotalMilliseconds.ToString("(0.0)").PadLeft(10)).Append("| "); output.Append(totalCalls.ToString().PadLeft(10)).Append("| "); output.Append((totalTime / totalCalls).ToString("0.000").PadLeft(10)); /* output.Append("\nProfile"); * output.Append(name); * output.Append(" took \t"); * output.Append(totalTime.ToString("0.0")); * output.Append(" ms to complete over "); * output.Append(totalCalls); * output.Append(" iteration"); * if (totalCalls != 1) output.Append("s"); * output.Append(", averaging \t"); * output.Append((totalTime / totalCalls).ToString("0.000")); * output.Append(" ms per call"); */ } output.Append("\n\n============================\n\t\tTotal runtime: "); output.Append(endTime.TotalSeconds.ToString("F3")); output.Append(" seconds\n============================"); Debug.Log(output.ToString()); } [System.Diagnostics.Conditional("ProfileAstar")] public static void PrintResults () { TimeSpan endTime = DateTime.UtcNow - startTime; var output = new System.Text.StringBuilder(); output.Append("============================\n\t\t\t\tProfile results:\n============================\n"); int maxLength = 5; foreach (KeyValuePair pair in profiles) { maxLength = Math.Max(pair.Key.Length, maxLength); } output.Append(" Name ".PadRight(maxLength)). Append("|").Append(" Total Time ".PadRight(20)). Append("|").Append(" Total Calls ".PadRight(20)). Append("|").Append(" Avg/Call ".PadRight(20)); foreach (var pair in profiles) { double totalTime = pair.Value.watch.Elapsed.TotalMilliseconds; int totalCalls = pair.Value.totalCalls; if (totalCalls < 1) continue; string name = pair.Key; output.Append("\n").Append(name.PadRight(maxLength)).Append("| "); output.Append(totalTime.ToString("0.0").PadRight(20)).Append("| "); output.Append(totalCalls.ToString().PadRight(20)).Append("| "); output.Append((totalTime / totalCalls).ToString("0.000").PadRight(20)); output.Append(AstarMath.FormatBytesBinary((int)pair.Value.totalBytes).PadLeft(10)); /*output.Append("\nProfile "); * output.Append(pair.Key); * output.Append(" took "); * output.Append(totalTime.ToString("0")); * output.Append(" ms to complete over "); * output.Append(totalCalls); * output.Append(" iteration"); * if (totalCalls != 1) output.Append("s"); * output.Append(", averaging "); * output.Append((totalTime / totalCalls).ToString("0.0")); * output.Append(" ms per call");*/ } output.Append("\n\n============================\n\t\tTotal runtime: "); output.Append(endTime.TotalSeconds.ToString("F3")); output.Append(" seconds\n============================"); Debug.Log(output.ToString()); } } }