|
|
- using System;
- using Assets.Editor.Treemap;
- using UnityEditor;
- using UnityEngine;
- using UnityEditor.MemoryProfiler;
- using System.Linq;
- using System.Collections.Generic;
-
- namespace MemoryProfilerWindow
- {
- public class Inspector
- {
- ThingInMemory _selectedThing;
- private ThingInMemory[] _shortestPath;
- private ShortestPathToRootFinder _shortestPathToRootFinder;
- private static int s_InspectorWidth = 400;
- Vector2 _scrollPosition;
- MemoryProfilerWindow _hostWindow;
- CrawledMemorySnapshot _unpackedCrawl;
- PrimitiveValueReader _primitiveValueReader;
- Dictionary<ulong, ThingInMemory> objectCache = new Dictionary<ulong, ThingInMemory>();
- private Texture2D _textureObject;
- private int _prevInstance;
- private float _textureSize = 128.0f;
-
-
- static class Styles
- {
- public static GUIStyle entryEven = "OL EntryBackEven";
- public static GUIStyle entryOdd = "OL EntryBackOdd";
- }
-
- GUILayoutOption labelWidth = GUILayout.Width(150);
-
- public Inspector(MemoryProfilerWindow hostWindow, CrawledMemorySnapshot unpackedCrawl, PackedMemorySnapshot snapshot)
- {
- _unpackedCrawl = unpackedCrawl;
- _hostWindow = hostWindow;
- _shortestPathToRootFinder = new ShortestPathToRootFinder(unpackedCrawl);
- _primitiveValueReader = new PrimitiveValueReader(_unpackedCrawl.virtualMachineInformation, _unpackedCrawl.managedHeap);
- }
-
- public float width
- {
- get { return s_InspectorWidth; }
- }
-
- public void SelectThing(ThingInMemory thing)
- {
- _selectedThing = thing;
- _shortestPath = _shortestPathToRootFinder.FindFor(thing);
- }
-
- public void Draw()
- {
- GUILayout.BeginArea(new Rect(_hostWindow.position.width - s_InspectorWidth, 25, s_InspectorWidth, _hostWindow.position.height - 25f));
- _scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
-
- if (_selectedThing == null)
- GUILayout.Label("Select an object to see more info");
- else
- {
- var nativeObject = _selectedThing as NativeUnityEngineObject;
- if (nativeObject != null)
- {
- GUILayout.Label("NativeUnityEngineObject", EditorStyles.boldLabel);
- GUILayout.Space(5);
- EditorGUILayout.LabelField("Name", nativeObject.name);
- EditorGUILayout.LabelField("ClassName", nativeObject.className);
- EditorGUILayout.LabelField("ClassID", nativeObject.classID.ToString());
- EditorGUILayout.LabelField("instanceID", nativeObject.instanceID.ToString());
- EditorGUILayout.LabelField("isDontDestroyOnLoad", nativeObject.isDontDestroyOnLoad.ToString());
- EditorGUILayout.LabelField("isPersistent", nativeObject.isPersistent.ToString());
- EditorGUILayout.LabelField("isManager", nativeObject.isManager.ToString());
- EditorGUILayout.LabelField("hideFlags", nativeObject.hideFlags.ToString());
- EditorGUILayout.LabelField("hideFlags", nativeObject.size.ToString());
- DrawSpecificTexture2D(nativeObject);
- }
-
- var managedObject = _selectedThing as ManagedObject;
- if (managedObject != null)
- {
- GUILayout.Label("ManagedObject");
- EditorGUILayout.LabelField("Type", managedObject.typeDescription.name);
- EditorGUILayout.LabelField("Address", managedObject.address.ToString("X"));
- EditorGUILayout.LabelField("size", managedObject.size.ToString());
-
- if (managedObject.typeDescription.name == "System.String")
- EditorGUILayout.LabelField("value", StringTools.ReadString(_unpackedCrawl.managedHeap.Find(managedObject.address, _unpackedCrawl.virtualMachineInformation), _unpackedCrawl.virtualMachineInformation));
- DrawFields(managedObject);
-
- if (managedObject.typeDescription.isArray)
- {
- DrawArray(managedObject);
- }
- }
-
- if (_selectedThing is GCHandle)
- {
- GUILayout.Label("GCHandle");
- EditorGUILayout.LabelField("size", _selectedThing.size.ToString());
- }
-
- var staticFields = _selectedThing as StaticFields;
- if (staticFields != null)
- {
- GUILayout.Label("Static Fields");
- GUILayout.Label("Of type: " + staticFields.typeDescription.name);
- GUILayout.Label("size: " + staticFields.size);
-
- DrawFields(staticFields.typeDescription, new BytesAndOffset() { bytes = staticFields.typeDescription.staticFieldBytes, offset = 0, pointerSize = _unpackedCrawl.virtualMachineInformation.pointerSize}, true);
- }
-
- if (managedObject == null)
- {
- GUILayout.Space(10);
- GUILayout.BeginHorizontal();
- GUILayout.Label("References:", labelWidth);
- GUILayout.BeginVertical();
- DrawLinks(_selectedThing.references);
- GUILayout.EndVertical();
- GUILayout.EndHorizontal();
- }
-
- GUILayout.Space(10);
- GUILayout.Label("Referenced by:");
- DrawLinks(_selectedThing.referencedBy);
-
- GUILayout.Space(10);
- if (_shortestPath != null)
- {
- if (_shortestPath.Length > 1)
- {
- GUILayout.Label("ShortestPathToRoot");
- DrawLinks(_shortestPath);
- }
- string reason;
- _shortestPathToRootFinder.IsRoot(_shortestPath.Last(), out reason);
- GUILayout.Label("This is a root because:");
- GUILayout.TextArea(reason);
- }
- else
- {
- GUILayout.TextArea("No root is keeping this object alive. It will be collected next UnloadUnusedAssets() or scene load");
- }
- }
- GUILayout.EndScrollView();
- GUILayout.EndArea();
- }
-
- private void DrawSpecificTexture2D(NativeUnityEngineObject nativeObject)
- {
- if (nativeObject.className != "Texture2D")
- {
- _textureObject = null;
- return;
- }
- EditorGUILayout.HelpBox("Watching Texture Detail Data is only for Editor.", MessageType.Warning, true);
- if (_prevInstance != nativeObject.instanceID)
- {
- _textureObject = EditorUtility.InstanceIDToObject(nativeObject.instanceID) as Texture2D;
- _prevInstance = nativeObject.instanceID;
- }
- if (_textureObject != null)
- {
- EditorGUILayout.LabelField("textureInfo: " + _textureObject.width + "x" + _textureObject.height + " " + _textureObject.format);
- EditorGUILayout.ObjectField(_textureObject, typeof(Texture2D));
- _textureSize = EditorGUILayout.Slider(_textureSize, 100.0f, 1024.0f);
- GUILayout.Label(_textureObject, GUILayout.Width(_textureSize), GUILayout.Height(_textureSize * _textureObject.height / _textureObject.width));
- }
- else
- {
- EditorGUILayout.LabelField("Can't instance texture,maybe it was already released.");
- }
- }
-
- private void DrawArray(ManagedObject managedObject)
- {
- var typeDescription = managedObject.typeDescription;
- int elementCount = ArrayTools.ReadArrayLength(_unpackedCrawl.managedHeap, managedObject.address, typeDescription, _unpackedCrawl.virtualMachineInformation);
- GUILayout.Label("element count: " + elementCount);
- int rank = typeDescription.arrayRank;
- GUILayout.Label("arrayRank: " + rank);
- if (_unpackedCrawl.typeDescriptions[typeDescription.baseOrElementTypeIndex].isValueType)
- {
- GUILayout.Label("Cannot yet display elements of value type arrays");
- return;
- }
- if (rank != 1)
- {
- GUILayout.Label("Cannot display non rank=1 arrays yet.");
- return;
- }
-
- var pointers = new List<UInt64>();
- for (int i = 0; i != elementCount; i++)
- {
- pointers.Add(_primitiveValueReader.ReadPointer(managedObject.address + (UInt64)_unpackedCrawl.virtualMachineInformation.arrayHeaderSize + (UInt64)(i * _unpackedCrawl.virtualMachineInformation.pointerSize)));
- }
- GUILayout.Label("elements:");
- DrawLinks(pointers);
- }
-
- private void DrawFields(TypeDescription typeDescription, BytesAndOffset bytesAndOffset, bool useStatics = false)
- {
- int counter = 0;
-
- foreach (var field in TypeTools.AllFieldsOf(typeDescription, _unpackedCrawl.typeDescriptions, useStatics ? TypeTools.FieldFindOptions.OnlyStatic : TypeTools.FieldFindOptions.OnlyInstance))
- {
- counter++;
- var gUIStyle = counter % 2 == 0 ? Styles.entryEven : Styles.entryOdd;
- gUIStyle.margin = new RectOffset(0, 0, 0, 0);
- gUIStyle.overflow = new RectOffset(0, 0, 0, 0);
- gUIStyle.padding = EditorStyles.label.padding;
- GUILayout.BeginHorizontal(gUIStyle);
- GUILayout.Label(field.name, labelWidth);
- GUILayout.BeginVertical();
- DrawValueFor(field, bytesAndOffset.Add(field.offset));
- GUILayout.EndVertical();
- GUILayout.EndHorizontal();
- }
- }
-
- private void DrawFields(ManagedObject managedObject)
- {
- if (managedObject.typeDescription.isArray)
- return;
- GUILayout.Space(10);
- GUILayout.Label("Fields:");
- DrawFields(managedObject.typeDescription, _unpackedCrawl.managedHeap.Find(managedObject.address, _unpackedCrawl.virtualMachineInformation));
- }
-
- private void DrawValueFor(FieldDescription field, BytesAndOffset bytesAndOffset)
- {
- var typeDescription = _unpackedCrawl.typeDescriptions[field.typeIndex];
-
- switch (typeDescription.name)
- {
- case "System.Int32":
- GUILayout.Label(_primitiveValueReader.ReadInt32(bytesAndOffset).ToString());
- break;
- case "System.Int64":
- GUILayout.Label(_primitiveValueReader.ReadInt64(bytesAndOffset).ToString());
- break;
- case "System.UInt32":
- GUILayout.Label(_primitiveValueReader.ReadUInt32(bytesAndOffset).ToString());
- break;
- case "System.UInt64":
- GUILayout.Label(_primitiveValueReader.ReadUInt64(bytesAndOffset).ToString());
- break;
- case "System.Int16":
- GUILayout.Label(_primitiveValueReader.ReadInt16(bytesAndOffset).ToString());
- break;
- case "System.UInt16":
- GUILayout.Label(_primitiveValueReader.ReadUInt16(bytesAndOffset).ToString());
- break;
- case "System.Byte":
- GUILayout.Label(_primitiveValueReader.ReadByte(bytesAndOffset).ToString());
- break;
- case "System.SByte":
- GUILayout.Label(_primitiveValueReader.ReadSByte(bytesAndOffset).ToString());
- break;
- case "System.Char":
- GUILayout.Label(_primitiveValueReader.ReadChar(bytesAndOffset).ToString());
- break;
- case "System.Boolean":
- GUILayout.Label(_primitiveValueReader.ReadBool(bytesAndOffset).ToString());
- break;
- case "System.Single":
- GUILayout.Label(_primitiveValueReader.ReadSingle(bytesAndOffset).ToString());
- break;
- case "System.Double":
- GUILayout.Label(_primitiveValueReader.ReadDouble(bytesAndOffset).ToString());
- break;
- case "System.IntPtr":
- GUILayout.Label(_primitiveValueReader.ReadPointer(bytesAndOffset).ToString("X"));
- break;
- default:
-
- if (!typeDescription.isValueType)
- {
- ThingInMemory item = GetThingAt(bytesAndOffset.ReadPointer());
- if (item == null)
- {
- EditorGUI.BeginDisabledGroup(true);
- GUILayout.Button("Null");
- EditorGUI.EndDisabledGroup();
- }
- else
- {
- DrawLinks(new ThingInMemory[] { item });
- }
- }
- else
- {
- DrawFields(typeDescription, bytesAndOffset);
- }
- break;
- }
- }
-
- private ThingInMemory GetThingAt(ulong address)
- {
- if (!objectCache.ContainsKey(address))
- {
- objectCache[address] = _unpackedCrawl.allObjects.OfType<ManagedObject>().FirstOrDefault(mo => mo.address == address);
- }
-
- return objectCache[address];
- }
-
- /*
- private Item FindItemPointedToByManagedFieldAt(BytesAndOffset bytesAndOffset)
- {
- var stringAddress = _primitiveValueReader.ReadPointer(bytesAndOffset);
- return
- _items.FirstOrDefault(i =>
- {
- var m = i._thingInMemory as ManagedObject;
- if (m != null)
- {
- return m.address == stringAddress;
- }
- return false;
- });
- }*/
-
- private void DrawLinks(IEnumerable<UInt64> pointers)
- {
- DrawLinks(pointers.Select(p => GetThingAt(p)));
- }
-
- private void DrawLinks(IEnumerable<ThingInMemory> thingInMemories)
- {
- var c = GUI.backgroundColor;
- GUI.skin.button.alignment = TextAnchor.UpperLeft;
- foreach (var rb in thingInMemories)
- {
- EditorGUI.BeginDisabledGroup(rb == _selectedThing || rb == null);
-
- GUI.backgroundColor = ColorFor(rb);
-
- var caption = rb == null ? "null" : rb.caption;
-
- var managedObject = rb as ManagedObject;
- if (managedObject != null && managedObject.typeDescription.name == "System.String")
- caption = StringTools.ReadString(_unpackedCrawl.managedHeap.Find(managedObject.address, _unpackedCrawl.virtualMachineInformation), _unpackedCrawl.virtualMachineInformation);
-
- if (GUILayout.Button(caption))
- _hostWindow.SelectThing(rb);
- EditorGUI.EndDisabledGroup();
- }
- GUI.backgroundColor = c;
- }
-
- private Color ColorFor(ThingInMemory rb)
- {
- if (rb == null)
- return Color.gray;
- if (rb is NativeUnityEngineObject)
- return Color.red;
- if (rb is ManagedObject)
- return Color.Lerp(Color.blue, Color.white, 0.5f);
- if (rb is GCHandle)
- return Color.magenta;
- if (rb is StaticFields)
- return Color.yellow;
-
- throw new ArgumentException("Unexpected type: " + rb.GetType());
- }
- }
- }
|