summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-05-23 10:08:29 +0800
committerchai <215380520@qq.com>2024-05-23 10:08:29 +0800
commit8722a9920c1f6119bf6e769cba270e63097f8e25 (patch)
tree2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs
parent3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff)
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs344
1 files changed, 344 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs
new file mode 100644
index 0000000..b6fac64
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/Misc/AstarDebugger.cs
@@ -0,0 +1,344 @@
+//#define ProfileAstar
+
+using UnityEngine;
+using System.Text;
+
+namespace Pathfinding {
+ [AddComponentMenu("Pathfinding/Pathfinding Debugger")]
+ [ExecuteInEditMode]
+ /// <summary>
+ /// Debugger for the A* Pathfinding Project.
+ /// This class can be used to profile different parts of the pathfinding system
+ /// and the whole game as well to some extent.
+ ///
+ /// Clarification of the labels shown when enabled.
+ /// All memory related things profiles <b>the whole game</b> not just the A* Pathfinding System.
+ /// - Currently allocated: memory the GC (garbage collector) says the application has allocated right now.
+ /// - Peak allocated: maximum measured value of the above.
+ /// - Last collect peak: the last peak of 'currently allocated'.
+ /// - Allocation rate: how much the 'currently allocated' value increases per second. This value is not as reliable as you can think
+ /// it is often very random probably depending on how the GC thinks this application is using memory.
+ /// - Collection frequency: how often the GC is called. Again, the GC might decide it is better with many small collections
+ /// or with a few large collections. So you cannot really trust this variable much.
+ /// - Last collect fps: FPS during the last garbage collection, the GC will lower the fps a lot.
+ ///
+ /// - FPS: current FPS (not updated every frame for readability)
+ /// - Lowest FPS (last x): As the label says, the lowest fps of the last x frames.
+ ///
+ /// - Size: Size of the path pool.
+ /// - Total created: Number of paths of that type which has been created. Pooled paths are not counted twice.
+ /// If this value just keeps on growing and growing without an apparent stop, you are are either not pooling any paths
+ /// or you have missed to pool some path somewhere in your code.
+ ///
+ /// See: pooling
+ ///
+ /// TODO: Add field showing how many graph updates are being done right now
+ /// </summary>
+ [HelpURL("https://arongranberg.com/astar/documentation/stable/astardebugger.html")]
+ public class AstarDebugger : VersionedMonoBehaviour {
+ public int yOffset = 5;
+
+ public bool show = true;
+ public bool showInEditor = false;
+
+ public bool showFPS = false;
+ public bool showPathProfile = false;
+ public bool showMemProfile = false;
+ public bool showGraph = false;
+
+ public int graphBufferSize = 200;
+
+ /// <summary>
+ /// Font to use.
+ /// A monospaced font is the best
+ /// </summary>
+ public Font font = null;
+ public int fontSize = 12;
+
+ StringBuilder text = new StringBuilder();
+ string cachedText;
+ float lastUpdate = -999;
+
+ private GraphPoint[] graph;
+
+ struct GraphPoint {
+ public float fps, memory;
+ public bool collectEvent;
+ }
+
+ private float delayedDeltaTime = 1;
+ private float lastCollect = 0;
+ private float lastCollectNum = 0;
+ private float delta = 0;
+ private float lastDeltaTime = 0;
+ private int allocRate = 0;
+ private int lastAllocMemory = 0;
+ private float lastAllocSet = -9999;
+ private int allocMem = 0;
+ private int collectAlloc = 0;
+ private int peakAlloc = 0;
+
+ private int fpsDropCounterSize = 200;
+ private float[] fpsDrops;
+
+ private Rect boxRect;
+
+ private GUIStyle style;
+
+ private Camera cam;
+
+ float graphWidth = 100;
+ float graphHeight = 100;
+ float graphOffset = 50;
+
+ public void Start () {
+ useGUILayout = false;
+
+ fpsDrops = new float[fpsDropCounterSize];
+
+ cam = GetComponent<Camera>();
+ if (cam == null) {
+ cam = Camera.main;
+ }
+
+ graph = new GraphPoint[graphBufferSize];
+
+ if (Time.unscaledDeltaTime > 0) {
+ for (int i = 0; i < fpsDrops.Length; i++) {
+ fpsDrops[i] = 1F / Time.unscaledDeltaTime;
+ }
+ }
+ }
+
+ int maxVecPool = 0;
+ int maxNodePool = 0;
+
+ PathTypeDebug[] debugTypes = new PathTypeDebug[] {
+ new PathTypeDebug("ABPath", () => PathPool.GetSize(typeof(ABPath)), () => PathPool.GetTotalCreated(typeof(ABPath)))
+ ,
+ new PathTypeDebug("MultiTargetPath", () => PathPool.GetSize(typeof(MultiTargetPath)), () => PathPool.GetTotalCreated(typeof(MultiTargetPath))),
+ new PathTypeDebug("RandomPath", () => PathPool.GetSize(typeof(RandomPath)), () => PathPool.GetTotalCreated(typeof(RandomPath))),
+ new PathTypeDebug("FleePath", () => PathPool.GetSize(typeof(FleePath)), () => PathPool.GetTotalCreated(typeof(FleePath))),
+ new PathTypeDebug("ConstantPath", () => PathPool.GetSize(typeof(ConstantPath)), () => PathPool.GetTotalCreated(typeof(ConstantPath))),
+ new PathTypeDebug("FloodPath", () => PathPool.GetSize(typeof(FloodPath)), () => PathPool.GetTotalCreated(typeof(FloodPath))),
+ new PathTypeDebug("FloodPathTracer", () => PathPool.GetSize(typeof(FloodPathTracer)), () => PathPool.GetTotalCreated(typeof(FloodPathTracer)))
+ };
+
+ struct PathTypeDebug {
+ string name;
+ System.Func<int> getSize;
+ System.Func<int> getTotalCreated;
+ public PathTypeDebug (string name, System.Func<int> getSize, System.Func<int> getTotalCreated) {
+ this.name = name;
+ this.getSize = getSize;
+ this.getTotalCreated = getTotalCreated;
+ }
+
+ public void Print (StringBuilder text) {
+ int totCreated = getTotalCreated();
+
+ if (totCreated > 0) {
+ text.Append("\n").Append((" " + name).PadRight(25)).Append(getSize()).Append("/").Append(totCreated);
+ }
+ }
+ }
+
+ public void LateUpdate () {
+ if (!show || (!Application.isPlaying && !showInEditor)) return;
+
+ if (Time.unscaledDeltaTime <= 0.0001f)
+ return;
+
+ int collCount = System.GC.CollectionCount(0);
+
+ if (lastCollectNum != collCount) {
+ lastCollectNum = collCount;
+ delta = Time.realtimeSinceStartup-lastCollect;
+ lastCollect = Time.realtimeSinceStartup;
+ lastDeltaTime = Time.unscaledDeltaTime;
+ collectAlloc = allocMem;
+ }
+
+ allocMem = (int)System.GC.GetTotalMemory(false);
+
+ bool collectEvent = allocMem < peakAlloc;
+ peakAlloc = !collectEvent ? allocMem : peakAlloc;
+
+ if (Time.realtimeSinceStartup - lastAllocSet > 0.3F || !Application.isPlaying) {
+ int diff = allocMem - lastAllocMemory;
+ lastAllocMemory = allocMem;
+ lastAllocSet = Time.realtimeSinceStartup;
+ delayedDeltaTime = Time.unscaledDeltaTime;
+
+ if (diff >= 0) {
+ allocRate = diff;
+ }
+ }
+
+ if (Application.isPlaying) {
+ fpsDrops[Time.frameCount % fpsDrops.Length] = Time.unscaledDeltaTime > 0.00001f ? 1F / Time.unscaledDeltaTime : 0;
+ int graphIndex = Time.frameCount % graph.Length;
+ graph[graphIndex].fps = Time.unscaledDeltaTime < 0.00001f ? 1F / Time.unscaledDeltaTime : 0;
+ graph[graphIndex].collectEvent = collectEvent;
+ graph[graphIndex].memory = allocMem;
+ }
+
+ if (Application.isPlaying && cam != null && showGraph) {
+ graphWidth = cam.pixelWidth*0.8f;
+
+
+ float minMem = float.PositiveInfinity, maxMem = 0, minFPS = float.PositiveInfinity, maxFPS = 0;
+ for (int i = 0; i < graph.Length; i++) {
+ minMem = Mathf.Min(graph[i].memory, minMem);
+ maxMem = Mathf.Max(graph[i].memory, maxMem);
+ minFPS = Mathf.Min(graph[i].fps, minFPS);
+ maxFPS = Mathf.Max(graph[i].fps, maxFPS);
+ }
+
+ int currentGraphIndex = Time.frameCount % graph.Length;
+
+ Matrix4x4 m = Matrix4x4.TRS(new Vector3((cam.pixelWidth - graphWidth)/2f, graphOffset, 1), Quaternion.identity, new Vector3(graphWidth, graphHeight, 1));
+
+ for (int i = 0; i < graph.Length-1; i++) {
+ if (i == currentGraphIndex) continue;
+
+ DrawGraphLine(i, m, i/(float)graph.Length, (i+1)/(float)graph.Length, Mathf.InverseLerp(minMem, maxMem, graph[i].memory), Mathf.InverseLerp(minMem, maxMem, graph[i+1].memory), Color.blue);
+ DrawGraphLine(i, m, i/(float)graph.Length, (i+1)/(float)graph.Length, Mathf.InverseLerp(minFPS, maxFPS, graph[i].fps), Mathf.InverseLerp(minFPS, maxFPS, graph[i+1].fps), Color.green);
+ }
+ }
+ }
+
+ void DrawGraphLine (int index, Matrix4x4 m, float x1, float x2, float y1, float y2, Color color) {
+ Debug.DrawLine(cam.ScreenToWorldPoint(m.MultiplyPoint3x4(new Vector3(x1, y1))), cam.ScreenToWorldPoint(m.MultiplyPoint3x4(new Vector3(x2, y2))), color);
+ }
+
+ public void OnGUI () {
+ if (!show || (!Application.isPlaying && !showInEditor)) return;
+
+ if (style == null) {
+ style = new GUIStyle();
+ style.normal.textColor = Color.white;
+ style.padding = new RectOffset(5, 5, 5, 5);
+ }
+
+ if (Time.realtimeSinceStartup - lastUpdate > 0.5f || cachedText == null || !Application.isPlaying) {
+ lastUpdate = Time.realtimeSinceStartup;
+
+ boxRect = new Rect(5, yOffset, 310, 40);
+
+ text.Length = 0;
+ text.AppendLine("A* Pathfinding Project Debugger");
+ text.Append("A* Version: ").Append(AstarPath.Version.ToString());
+
+ if (showMemProfile) {
+ boxRect.height += 200;
+
+ text.AppendLine();
+ text.AppendLine();
+ text.Append("Currently allocated".PadRight(25));
+ text.Append((allocMem/1000000F).ToString("0.0 MB"));
+ text.AppendLine();
+
+ text.Append("Peak allocated".PadRight(25));
+ text.Append((peakAlloc/1000000F).ToString("0.0 MB")).AppendLine();
+
+ text.Append("Last collect peak".PadRight(25));
+ text.Append((collectAlloc/1000000F).ToString("0.0 MB")).AppendLine();
+
+
+ text.Append("Allocation rate".PadRight(25));
+ text.Append((allocRate/1000000F).ToString("0.0 MB")).AppendLine();
+
+ text.Append("Collection frequency".PadRight(25));
+ text.Append(delta.ToString("0.00"));
+ text.Append("s\n");
+
+ text.Append("Last collect fps".PadRight(25));
+ text.Append((1F/lastDeltaTime).ToString("0.0 fps"));
+ text.Append(" (");
+ text.Append(lastDeltaTime.ToString("0.000 s"));
+ text.Append(")");
+ }
+
+ if (showFPS) {
+ text.AppendLine();
+ text.AppendLine();
+ var delayedFPS = delayedDeltaTime > 0.00001f ? 1F/delayedDeltaTime : 0;
+ text.Append("FPS".PadRight(25)).Append(delayedFPS.ToString("0.0 fps"));
+
+
+ float minFps = Mathf.Infinity;
+
+ for (int i = 0; i < fpsDrops.Length; i++) if (fpsDrops[i] < minFps) minFps = fpsDrops[i];
+
+ text.AppendLine();
+ text.Append(("Lowest fps (last " + fpsDrops.Length + ")").PadRight(25)).Append(minFps.ToString("0.0"));
+ }
+
+ if (showPathProfile) {
+ AstarPath astar = AstarPath.active;
+
+ text.AppendLine();
+
+ if (astar == null) {
+ text.Append("\nNo AstarPath Object In The Scene");
+ } else {
+#if ProfileAstar
+ double searchSpeed = (double)AstarPath.TotalSearchedNodes*10000 / (double)AstarPath.TotalSearchTime;
+ text.Append("\nSearch Speed (nodes/ms) ").Append(searchSpeed.ToString("0")).Append(" ("+AstarPath.TotalSearchedNodes+" / ").Append(((double)AstarPath.TotalSearchTime/10000F).ToString("0")+")");
+#endif
+
+ if (Pathfinding.Util.ListPool<Vector3>.GetSize() > maxVecPool) maxVecPool = Pathfinding.Util.ListPool<Vector3>.GetSize();
+ if (Pathfinding.Util.ListPool<Pathfinding.GraphNode>.GetSize() > maxNodePool) maxNodePool = Pathfinding.Util.ListPool<Pathfinding.GraphNode>.GetSize();
+
+ text.Append("\nPool Sizes (size/total created)");
+
+ for (int i = 0; i < debugTypes.Length; i++) {
+ debugTypes[i].Print(text);
+ }
+ }
+ }
+
+ cachedText = text.ToString();
+ }
+
+
+ if (font != null) {
+ style.font = font;
+ style.fontSize = fontSize;
+ }
+
+ boxRect.height = style.CalcHeight(new GUIContent(cachedText), boxRect.width);
+
+ GUI.Box(boxRect, "");
+ GUI.Label(boxRect, cachedText, style);
+
+ if (showGraph) {
+ float minMem = float.PositiveInfinity, maxMem = 0, minFPS = float.PositiveInfinity, maxFPS = 0;
+ for (int i = 0; i < graph.Length; i++) {
+ minMem = Mathf.Min(graph[i].memory, minMem);
+ maxMem = Mathf.Max(graph[i].memory, maxMem);
+ minFPS = Mathf.Min(graph[i].fps, minFPS);
+ maxFPS = Mathf.Max(graph[i].fps, maxFPS);
+ }
+
+ float line;
+ GUI.color = Color.blue;
+ // Round to nearest x.x MB
+ line = Mathf.RoundToInt(maxMem/(100.0f*1000));
+ GUI.Label(new Rect(5, Screen.height - AstarMath.MapTo(minMem, maxMem, 0 + graphOffset, graphHeight + graphOffset, line*1000*100) - 10, 100, 20), (line/10.0f).ToString("0.0 MB"));
+
+ line = Mathf.Round(minMem/(100.0f*1000));
+ GUI.Label(new Rect(5, Screen.height - AstarMath.MapTo(minMem, maxMem, 0 + graphOffset, graphHeight + graphOffset, line*1000*100) - 10, 100, 20), (line/10.0f).ToString("0.0 MB"));
+
+ GUI.color = Color.green;
+ // Round to nearest x.x MB
+ line = Mathf.Round(maxFPS);
+ GUI.Label(new Rect(55, Screen.height - AstarMath.MapTo(minFPS, maxFPS, 0 + graphOffset, graphHeight + graphOffset, line) - 10, 100, 20), line.ToString("0 FPS"));
+
+ line = Mathf.Round(minFPS);
+ GUI.Label(new Rect(55, Screen.height - AstarMath.MapTo(minFPS, maxFPS, 0 + graphOffset, graphHeight + graphOffset, line) - 10, 100, 20), line.ToString("0 FPS"));
+ }
+ }
+ }
+}