Beispiel #1
0
        public static void Read(System.IO.BinaryReader reader, out PackedConnection[] value, out string stateString)
        {
            value       = new PackedConnection[0];
            stateString = "";

            var version = reader.ReadInt32();

            if (version >= 1)
            {
                var length = reader.ReadInt32();
                //stateString = string.Format("Loading {0} Object Connections", length);
                value = new PackedConnection[length];
                if (length == 0)
                {
                    return;
                }

                var onePercent = Math.Max(1, value.Length / 100);
                for (int n = 0, nend = value.Length; n < nend; ++n)
                {
                    if ((n % onePercent) == 0)
                    {
                        stateString = string.Format("Loading Object Connections\n{0}/{1}, {2:F0}% done", n + 1, length, ((n + 1) / (float)length) * 100);
                    }

                    value[n].from = reader.ReadInt32();
                    value[n].to   = reader.ReadInt32();
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Loads a memory snapshot from the specified 'filePath' and stores the result in 'snapshot'.
        /// </summary>
        /// <param name="filePath">Absolute file path</param>
        public bool LoadFromFile(string filePath)
        {
            busyString = "Loading";

            using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
            {
                using (var reader = new System.IO.BinaryReader(fileStream))
                {
                    try
                    {
                        PackedMemorySnapshotHeader.Read(reader, out header, out busyString);
                        if (!header.isValid)
                        {
                            throw new Exception("Invalid header.");
                        }

                        PackedNativeType.Read(reader, out nativeTypes, out busyString);
                        PackedNativeUnityEngineObject.Read(reader, out nativeObjects, out busyString);
                        PackedGCHandle.Read(reader, out gcHandles, out busyString);
                        PackedConnection.Read(reader, out connections, out busyString);
                        PackedMemorySection.Read(reader, out managedHeapSections, out busyString);
                        PackedManagedType.Read(reader, out managedTypes, out busyString);
                        PackedVirtualMachineInformation.Read(reader, out virtualMachineInformation, out busyString);
                    }
                    catch (System.Exception e)
                    {
                        Debug.LogException(e);
                        return(false);
                    }
                }
            }

            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Converts an Unity PackedMemorySnapshot to our own format.
        /// </summary>
        public static PackedMemorySnapshot FromMemoryProfiler(MemorySnapshotProcessingArgs args)
        {
            var source = args.source;

            var value = new PackedMemorySnapshot();

            try
            {
                VerifyMemoryProfilerSnapshot(source);

                value.busyString = "Loading Header";
                value.header     = PackedMemorySnapshotHeader.FromMemoryProfiler();

                value.busyString  = string.Format("Loading {0} Native Types", source.nativeTypes.Length);
                value.nativeTypes = PackedNativeType.FromMemoryProfiler(source.nativeTypes);

                value.busyString    = string.Format("Loading {0} Native Objects", source.nativeObjects.Length);
                value.nativeObjects = PackedNativeUnityEngineObject.FromMemoryProfiler(source.nativeObjects);

                value.busyString = string.Format("Loading {0} GC Handles", source.gcHandles.Length);
                value.gcHandles  = PackedGCHandle.FromMemoryProfiler(source.gcHandles);

                value.busyString = string.Format("Loading {0} Object Connections", source.connections.Length);
                if (args.excludeNativeFromConnections)
                {
                    value.connections = ConnectionsFromMemoryProfilerWithoutNativeHACK(value, source);
                }
                else
                {
                    value.connections = PackedConnection.FromMemoryProfiler(source.connections);
                }

                value.busyString          = string.Format("Loading {0} Managed Heap Sections", source.managedHeapSections.Length);
                value.managedHeapSections = PackedMemorySection.FromMemoryProfiler(source.managedHeapSections);

                value.busyString   = string.Format("Loading {0} Managed Types", source.typeDescriptions.Length);
                value.managedTypes = PackedManagedType.FromMemoryProfiler(source.typeDescriptions);

                value.busyString = "Loading VM Information";
                value.virtualMachineInformation = PackedVirtualMachineInformation.FromMemoryProfiler(source.virtualMachineInformation);
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
                value = null;
                throw;
            }
            return(value);
        }
Beispiel #4
0
 /// <summary>
 /// Saves the specfified memory snapshot as a file, using the specified 'filePath'.
 /// </summary>
 public void SaveToFile(string filePath)
 {
     using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.OpenOrCreate))
     {
         using (var writer = new System.IO.BinaryWriter(fileStream))
         {
             PackedMemorySnapshotHeader.Write(writer, header);
             PackedNativeType.Write(writer, nativeTypes);
             PackedNativeUnityEngineObject.Write(writer, nativeObjects);
             PackedGCHandle.Write(writer, gcHandles);
             PackedConnection.Write(writer, connections);
             PackedMemorySection.Write(writer, managedHeapSections);
             PackedManagedType.Write(writer, managedTypes);
             PackedVirtualMachineInformation.Write(writer, virtualMachineInformation);
         }
     }
 }
Beispiel #5
0
        // this method is a hack that excludes native object connections to workaround an unity bug.
        // https://forum.unity.com/threads/wip-heap-explorer-memory-profiler-debugger-and-analyzer-for-unity.527949/page-2#post-3615223
        static PackedConnection[] ConnectionsFromMemoryProfilerWithoutNativeHACK(PackedMemorySnapshot snapshot, UnityEditor.MemoryProfiler.PackedMemorySnapshot source)
        {
            var managedStart = 0;
            var managedEnd   = managedStart + source.gcHandles.Length;
            var nativeStart  = managedStart + managedEnd;
            var nativeEnd    = nativeStart + source.nativeObjects.Length;
            var output       = new List <PackedConnection>(1024 * 1024);

            for (int n = 0, nend = source.connections.Length; n < nend; ++n)
            {
                if ((n % (nend / 100)) == 0)
                {
                    var progress = ((n + 1.0f) / nend) * 100;
                    snapshot.busyString = string.Format("Analyzing GCHandle Connections\n{0}/{1}, {2:F0}% done", n + 1, source.connections.Length, progress);
                }

                var connection = new PackedConnection
                {
                    from = source.connections[n].from,
                    to   = source.connections[n].to,
                };

                connection.fromKind = PackedConnection.Kind.GCHandle;
                if (connection.from >= nativeStart && connection.from < nativeEnd)
                {
                    connection.from    -= nativeStart;
                    connection.fromKind = PackedConnection.Kind.Native;
                }

                connection.toKind = PackedConnection.Kind.GCHandle;
                if (connection.to >= nativeStart && connection.to < nativeEnd)
                {
                    connection.to    -= nativeStart;
                    connection.toKind = PackedConnection.Kind.Native;
                }

                if (connection.fromKind != PackedConnection.Kind.Native)
                {
                    output.Add(connection);
                }
            }

            snapshot.header.nativeObjectFromConnectionsExcluded = true;
            Debug.LogWarning("HeapExplorer: Native object 'from' connections are excluded due workaround an Unity bug. Thus the object connections in Heap Explorer show fewer connections than actually exist.\nhttps://forum.unity.com/threads/wip-heap-explorer-memory-profiler-debugger-and-analyzer-for-unity.527949/page-2#post-3615223");
            return(output.ToArray());
        }
        /// <summary>
        /// Add a connection between two objects, such as a connection from a native object to its managed counter-part.
        /// </summary>
        /// <param name="fromKind">The connection kind, that is pointing to another object.</param>
        /// <param name="fromIndex">An index into a snapshot array, depending on specified fromKind. If the kind would be 'Native', then it must be an index into the snapshot.nativeObjects array.</param>
        /// <param name="toKind">The connection kind, to which the 'from' object is pointing to.</param>
        /// <param name="toIndex">An index into a snapshot array, depending on the specified toKind. If the kind would be 'Native', then it must be an index into the snapshot.nativeObjects array.</param>
        public void AddConnection(PackedConnection.Kind fromKind, int fromIndex, PackedConnection.Kind toKind, int toIndex)
        {
            var connection = new PackedConnection
            {
                fromKind = fromKind,
                from     = fromIndex,
                toKind   = toKind,
                to       = toIndex
            };

            if (connection.fromKind != PackedConnection.Kind.None && connection.from != -1)
            {
                var key = ComputeConnectionKey(connection.fromKind, connection.from);

                List <PackedConnection> list;
                if (!m_ConnectionsFrom.TryGetValue(key, out list))
                {
                    m_ConnectionsFrom[key] = list = new List <PackedConnection>(1); // Capacity=1 to reduce memory usage on HUGE memory snapshots
                }
                list.Add(connection);
            }

            if (connection.toKind != PackedConnection.Kind.None && connection.to != -1)
            {
                if (connection.to < 0)
                {
                    connection.to = -connection.to;
                }

                var key = ComputeConnectionKey(connection.toKind, connection.to);

                List <PackedConnection> list;
                if (!m_ConnectionsTo.TryGetValue(key, out list))
                {
                    m_ConnectionsTo[key] = list = new List <PackedConnection>(1); // Capacity=1 to reduce memory usage on HUGE memory snapshots
                }
                list.Add(connection);
            }
        }
Beispiel #7
0
        public static               PackedConnection[] FromMemoryProfiler(UnityEditor.MemoryProfiler.Connection[] source)
        {
            PackedConnection[] value = null;
            try
            {
                value = new PackedConnection[source.Length];
            }
            catch
            {
                Debug.LogErrorFormat("HeapExplorer: Failed to allocate 'new PackedConnection[{0}]'.", source.Length);
                throw;
            }

            for (int n = 0, nend = source.Length; n < nend; ++n)
            {
                value[n] = new PackedConnection
                {
                    from = source[n].from,
                    to   = source[n].to,
                };
            }
            return(value);
        }
Beispiel #8
0
        public static       PackedConnection[] FromMemoryProfiler(UnityEditor.Profiling.Memory.Experimental.PackedMemorySnapshot snapshot)
        {
            var result         = new List <PackedConnection>(1024 * 1024);
            var invalidIndices = 0;

            // Get all NativeObject instanceIds
            var nativeObjects            = snapshot.nativeObjects;
            var nativeObjectsCount       = nativeObjects.GetNumEntries();
            var nativeObjectsInstanceIds = new int[nativeObjects.instanceId.GetNumEntries()];

            nativeObjects.instanceId.GetEntries(0, nativeObjects.instanceId.GetNumEntries(), ref nativeObjectsInstanceIds);

            // Create lookup table from instanceId to NativeObject arrayindex
            var instanceIdToNativeObjectIndex = new Dictionary <int, int>(nativeObjectsInstanceIds.Length);

            for (var n = 0; n < nativeObjectsInstanceIds.Length; ++n)
            {
                instanceIdToNativeObjectIndex.Add(nativeObjectsInstanceIds[n], n);
            }

            // Connect NativeObject with its GCHandle
            var nativeObjectsGCHandleIndices = new int[nativeObjects.gcHandleIndex.GetNumEntries()];

            nativeObjects.gcHandleIndex.GetEntries(0, nativeObjects.gcHandleIndex.GetNumEntries(), ref nativeObjectsGCHandleIndices);

            var gcHandles      = snapshot.gcHandles;
            var gcHandlesCount = gcHandles.GetNumEntries();

            for (var n = 0; n < nativeObjectsGCHandleIndices.Length; ++n)
            {
                // Unity 2019.4.7f1 and earlier (maybe also newer) versions seem to have this issue:
                // (Case 1269293) PackedMemorySnapshot: nativeObjects.gcHandleIndex contains -1 always
                if (nativeObjectsGCHandleIndices[n] < 0 || nativeObjectsGCHandleIndices[n] >= gcHandlesCount)
                {
                    if (nativeObjectsGCHandleIndices[n] != -1)
                    {
                        invalidIndices++; // I guess -1 means no connection to a gcHandle
                    }
                    continue;
                }

                var packed = new PackedConnection();
                packed.from     = n;                               // nativeObject index
                packed.fromKind = Kind.Native;
                packed.to       = nativeObjectsGCHandleIndices[n]; // gcHandle index
                packed.toKind   = Kind.GCHandle;

                result.Add(packed);
            }

            if (invalidIndices > 0)
            {
                Debug.LogErrorFormat("Reconstructing native to gchandle connections. Found {0} invalid indices into nativeObjectsGCHandleIndices[{1}] array.", invalidIndices, gcHandlesCount);
            }


            // Connect NativeObject with NativeObject

            var source = snapshot.connections;

            int[] sourceFrom = new int[source.from.GetNumEntries()];
            source.from.GetEntries(0, source.from.GetNumEntries(), ref sourceFrom);

            int[] sourceTo = new int[source.to.GetNumEntries()];
            source.to.GetEntries(0, source.to.GetNumEntries(), ref sourceTo);

            var invalidInstanceIDs = 0;

            invalidIndices = 0;

            for (int n = 0, nend = sourceFrom.Length; n < nend; ++n)
            {
                var packed = new PackedConnection();

                if (!instanceIdToNativeObjectIndex.TryGetValue(sourceFrom[n], out packed.from))
                {
                    invalidInstanceIDs++;
                    continue; // NativeObject InstanceID not found
                }

                if (!instanceIdToNativeObjectIndex.TryGetValue(sourceTo[n], out packed.to))
                {
                    invalidInstanceIDs++;
                    continue; // NativeObject InstanceID not found
                }

                if (packed.from < 0 || packed.from >= nativeObjectsCount)
                {
                    invalidIndices++;
                    continue; // invalid index into array
                }

                if (packed.to < 0 || packed.to >= nativeObjectsCount)
                {
                    invalidIndices++;
                    continue; // invalid index into array
                }

                packed.fromKind = Kind.Native;
                packed.toKind   = Kind.Native;

                result.Add(packed);
            }

            if (invalidIndices > 0)
            {
                Debug.LogErrorFormat("Reconstructing native to native object connections. Found {0} invalid indices into nativeObjectsCount[{1}] array.", invalidIndices, nativeObjectsCount);
            }

            if (invalidInstanceIDs > 0)
            {
                Debug.LogErrorFormat("Reconstructing native to native object connections. Found {0} invalid instanceIDs.", invalidInstanceIDs, nativeObjectsCount);
            }


            return(result.ToArray());
        }