예제 #1
0
        private void OnTypeBulkType(GCBulkTypeTraceData data)
        {
            if (data.ProcessID != _processId)
            {
                return;
            }

            // keep track of the id/name type associations
            for (int currentType = 0; currentType < data.Count; currentType++)
            {
                GCBulkTypeValues value = data.Values(currentType);
                _types[value.TypeID] = string.Intern(value.TypeName);
            }
        }
예제 #2
0
        private void OnTypeBulkType(GCBulkTypeTraceData data)
        {
            if (FilterOutEvent(data))
            {
                return;
            }

            ProcessTypeMapping mapping = GetProcessTypesMapping(data.ProcessID);

            for (int currentType = 0; currentType < data.Count; currentType++)
            {
                GCBulkTypeValues value = data.Values(currentType);
                mapping[value.TypeID] = value.TypeName;
            }
        }
예제 #3
0
        private void OnEtwClassIDDefintion(GCBulkTypeTraceData data)
        {
            if (data.ProcessID != m_processID)
            {
                return;
            }

            if (m_useEtlClrProfilerEvents)
            {
                return;
            }

            for (int i = 0; i < data.Count; i++)
            {
                GCBulkTypeValues typeData = data.Values(i);
                var typeName = typeData.TypeName;
                if (typeData.TypeParameterCount != 0)
                {
                    typeName += "<";
                    for (int j = 0; j < typeData.TypeParameterCount; j++)
                    {
                        if (j != 0)
                        {
                            typeName += ",";
                        }

                        TypeInfo paramInfo;
                        if (m_classNamesAsFrames.TryGetValue(typeData.TypeParameterID(j), out paramInfo))
                        {
                            typeName += paramInfo.TypeName;
                        }
                    }
                    typeName += ">";
                }
                if (typeData.CorElementType == 0x1d)                // SZArray
                {
                    typeName += "[]";
                }
                // TODO FIX NOW make sure the COR_ELEMENT_TYPES are covered.

                m_classNamesAsFrames[typeData.TypeID] = new TypeInfo()
                {
                    TypeName = typeName, FrameIdx = m_stackSource.Interner.FrameIntern("Type " + typeName)
                };
            }
        }
    /// <summary>
    /// After reading the events the graph is not actually created, you need to post process the information we gathered
    /// from the events.  This is where that happens.   Thus 'SetupCallbacks, Process(), ConvertHeapDataToGraph()' is how
    /// you dump a heap.
    /// </summary>
    internal unsafe void ConvertHeapDataToGraph()
    {
        int maxNodeCount = 10_000_000;

        if (m_converted)
        {
            return;
        }

        m_converted = true;

        if (!m_seenStart)
        {
            if (m_processName != null)
            {
                throw new ApplicationException("ETL file did not include a Heap Dump for process " + m_processName);
            }

            throw new ApplicationException("ETL file did not include a Heap Dump for process ID " + m_processId);
        }

        if (!m_ignoreEvents)
        {
            throw new ApplicationException("ETL file shows the start of a heap dump but not its completion.");
        }

        m_log.WriteLine("Processing Heap Data, BulkTypeEventCount:{0}  BulkNodeEventCount:{1}  BulkEdgeEventCount:{2}",
                        m_typeBlocks.Count, m_nodeBlocks.Count, m_edgeBlocks.Count);

        // Process the type information (we can't do it on the fly because we need the module information, which may be
        // at the end of the trace.
        while (m_typeBlocks.Count > 0)
        {
            GCBulkTypeTraceData data = m_typeBlocks.Dequeue();
            for (int i = 0; i < data.Count; i++)
            {
                GCBulkTypeValues typeData = data.Values(i);
                var typeName = typeData.TypeName;
                if (IsProjectN)
                {
                    // For project N we only log the type ID and module base address.
                    Debug.Assert(typeName.Length == 0);
                    Debug.Assert((typeData.Flags & TypeFlags.ModuleBaseAddress) != 0);
                    var moduleBaseAddress = typeData.TypeID - (ulong)typeData.TypeNameID; // Tricky way of getting the image base.
                    Debug.Assert((moduleBaseAddress & 0xFFFF) == 0);                      // Image loads should be on 64K boundaries.

                    Module module = GetModuleForImageBase(moduleBaseAddress);
                    if (module.Path == null)
                    {
                        m_log.WriteLine("Error: Could not find DLL name for imageBase 0x{0:x} looking up typeID 0x{1:x} with TypeNameID {2:x}",
                                        moduleBaseAddress, typeData.TypeID, typeData.TypeNameID);
                    }

                    m_typeID2TypeIndex[typeData.TypeID] = m_graph.CreateType(typeData.TypeNameID, module);
                }
                else
                {
                    if (typeName.Length == 0)
                    {
                        if ((typeData.Flags & TypeFlags.Array) != 0)
                        {
                            typeName = "ArrayType(0x" + typeData.TypeNameID.ToString("x") + ")";
                        }
                        else
                        {
                            typeName = "Type(0x" + typeData.TypeNameID.ToString("x") + ")";
                        }
                    }
                    // TODO FIX NOW these are kind of hacks
                    typeName = Regex.Replace(typeName, @"`\d+", "");
                    typeName = typeName.Replace("[", "<");
                    typeName = typeName.Replace("]", ">");
                    typeName = typeName.Replace("<>", "[]");

                    string moduleName;
                    if (!m_moduleID2Name.TryGetValue(typeData.ModuleID, out moduleName))
                    {
                        moduleName = "Module(0x" + typeData.ModuleID.ToString("x") + ")";
                        m_moduleID2Name[typeData.ModuleID] = moduleName;
                    }

                    // Is this type a an RCW?   If so mark the type name that way.
                    if ((typeData.Flags & TypeFlags.ExternallyImplementedCOMObject) != 0)
                    {
                        typeName = "[RCW " + typeName + "]";
                    }

                    m_typeID2TypeIndex[typeData.TypeID] = CreateType(typeName, moduleName);
                    // Trace.WriteLine(string.Format("Type 0x{0:x} = {1}", typeData.TypeID, typeName));
                }
            }
        }

        // Process all the ccw root information (which also need the type information complete)
        var ccwRoot = m_root.FindOrCreateChild("[COM/WinRT Objects]");

        while (m_ccwBlocks.Count > 0)
        {
            GCBulkRootCCWTraceData    data        = m_ccwBlocks.Dequeue();
            GrowableArray <NodeIndex> ccwChildren = new GrowableArray <NodeIndex>(1);
            for (int i = 0; i < data.Count; i++)
            {
                unsafe
                {
                    GCBulkRootCCWValues ccwInfo = data.Values(i);
                    // TODO Debug.Assert(ccwInfo.IUnknown != 0);
                    if (ccwInfo.IUnknown == 0)
                    {
                        // TODO currently there are times when a CCWs IUnknown pointer is not set (it is set lazily).
                        // m_log.WriteLine("Warning seen a CCW with IUnknown == 0");
                        continue;
                    }

                    // Create a CCW node that represents the COM object that has one child that points at the managed object.
                    var ccwNode = m_graph.GetNodeIndex(ccwInfo.IUnknown);

                    var ccwTypeIndex = GetTypeIndex(ccwInfo.TypeID, 200);
                    var ccwType      = m_graph.GetType(ccwTypeIndex, m_typeStorage);

                    var typeName = "[CCW 0x" + ccwInfo.IUnknown.ToString("x") + " for type " + ccwType.Name + "]";
                    ccwTypeIndex = CreateType(typeName);

                    ccwChildren.Clear();
                    ccwChildren.Add(m_graph.GetNodeIndex(ccwInfo.ObjectID));
                    m_graph.SetNode(ccwNode, ccwTypeIndex, 200, ccwChildren);
                    ccwRoot.AddChild(ccwNode);
                }
            }
        }

        // Process all the static variable root information (which also need the module information complete
        var staticVarsRoot = m_root.FindOrCreateChild("[static vars]");

        while (m_staticVarBlocks.Count > 0)
        {
            GCBulkRootStaticVarTraceData data = m_staticVarBlocks.Dequeue();
            for (int i = 0; i < data.Count; i++)
            {
                GCBulkRootStaticVarValues staticVarData = data.Values(i);
                var rootToAddTo = staticVarsRoot;
                if ((staticVarData.Flags & GCRootStaticVarFlags.ThreadLocal) != 0)
                {
                    rootToAddTo = m_root.FindOrCreateChild("[thread static vars]");
                }

                // Get the type name.
                NodeTypeIndex typeIdx;
                string        typeName;
                if (m_typeID2TypeIndex.TryGetValue(staticVarData.TypeID, out typeIdx))
                {
                    var type = m_graph.GetType(typeIdx, m_typeStorage);
                    typeName = type.Name;
                }
                else
                {
                    typeName = "Type(0x" + staticVarData.TypeID.ToString("x") + ")";
                }

                string fullFieldName = typeName + "." + staticVarData.FieldName;

                rootToAddTo = rootToAddTo.FindOrCreateChild("[static var " + fullFieldName + "]");
                var nodeIdx = m_graph.GetNodeIndex(staticVarData.ObjectID);
                rootToAddTo.AddChild(nodeIdx);
            }
        }

        // var typeStorage = m_graph.AllocTypeNodeStorage();
        GCBulkNodeUnsafeNodes nodeStorage = new GCBulkNodeUnsafeNodes();

        // Process all the node and edge nodes we have collected.
        bool doCompletionCheck = true;

        for (; ;)
        {
            GCBulkNodeUnsafeNodes *node = GetNextNode(&nodeStorage);
            if (node == null)
            {
                break;
            }

            // Get the node index
            var nodeIdx = m_graph.GetNodeIndex((Address)node->Address);
            var objSize = (int)node->Size;
            Debug.Assert(node->Size < 0x1000000000);
            var typeIdx = GetTypeIndex(node->TypeID, objSize);

            // TODO FIX NOW REMOVE
            // var type = m_graph.GetType(typeIdx, typeStorage);
            // Trace.WriteLine(string.Format("Got Object 0x{0:x} Type {1} Size {2} #children {3}  nodeIdx {4}", (Address)node->Address, type.Name, objSize, node->EdgeCount, nodeIdx));

            // Process the edges (which can add children)
            m_children.Clear();
            for (int i = 0; i < node->EdgeCount; i++)
            {
                Address edge     = GetNextEdge();
                var     childIdx = m_graph.GetNodeIndex(edge);
                m_children.Add(childIdx);
                // Trace.WriteLine(string.Format("   Child 0x{0:x}", edge));
            }

            // TODO we can use the nodes type to see if this is an RCW before doing this lookup which may be a bit more efficient.
            RCWInfo info;
            if (m_objectToRCW.TryGetValue((Address)node->Address, out info))
            {
                // Add the COM object this RCW points at as a child of this node.
                m_children.Add(m_graph.GetNodeIndex(info.IUnknown));

                // We add 1000 to account for the overhead of the RCW that is NOT on the GC heap.
                objSize += 1000;
            }

            Debug.Assert(!m_graph.IsDefined(nodeIdx));
            m_graph.SetNode(nodeIdx, typeIdx, objSize, m_children);

            if (m_graph.NodeCount >= maxNodeCount)
            {
                doCompletionCheck = false;
                var userMessage = string.Format("Exceeded max node count {0}", maxNodeCount);
                m_log.WriteLine("[WARNING: ]", userMessage);
                break;
            }
        }

        if (doCompletionCheck && m_curEdgeBlock != null && m_curEdgeBlock.Count != m_curEdgeIdx)
        {
            throw new ApplicationException("Error: extra edge data.  Giving up on heap dump.");
        }

        m_root.Build();
        m_graph.RootIndex = m_root.Index;
    }