Exemple #1
0
        public void RemoveItemTest()
        {
            GrowableArray <int> tester = new GrowableArray <int>();


            Assert.Fail();
        }
Exemple #2
0
        static void Main()
        {
            int         expectedNumberOfNodes = 1000;
            MemoryGraph memoryGraph           = new MemoryGraph(expectedNumberOfNodes);

            GrowableArray <NodeIndex> tempForChildren = new GrowableArray <NodeIndex>();


            // We can make a new Node index
            NodeIndex newNodeIdx = memoryGraph.CreateNode();

            NodeIndex childIdx = memoryGraph.CreateNode();


            //
            NodeTypeIndex newNodeType = memoryGraph.CreateType("MyChild");



            memoryGraph.SetNode(childIdx, newType, 100, tempForChildren);



            memoryGraph.AllowReading();

            // Serialize to a file
            memoryGraph.WriteAsBinaryFile("file.gcHeap");



            // Can unserialize easily.
            // var readBackIn = MemoryGraph.ReadFromBinaryFile("file.gcHeap");
        }
Exemple #3
0
 /// <summary>
 /// TraceProcesses represents the entire ETL moduleFile log.   At the node level it is organized by threads.
 ///
 /// The TraceProcesses also is where we put various caches that are independent of the process involved.
 /// These include a cache for TraceModuleFile that represent native images that can be loaded into a
 /// process, as well as the process lookup tables and a cache that remembers the last calls to
 /// GetNameForAddress().
 /// </summary>
 internal TraceProcesses(TraceLog log, TraceEventDispatcher source)
 {
     this.log       = log;
     this.source    = source;
     processes      = new GrowableArray <TraceProcess>(64);
     processesByPID = new GrowableArray <TraceProcess>(64);
 }
Exemple #4
0
 public PrimeSieve2(long upTo)
 {
     primes = new GrowableArray<bool>(upTo);
     primes.Set(0, true);
     primes.Set(1, true);
     PopulateSieveFrom(primes);
 }
Exemple #5
0
        public GCSimulation(ClrProfilerParser profiler)
        {
            m_clrProfiler = profiler;
            m_relocs      = new GrowableArray <Relocation>(256);
            Allocs        = new GrowableArray <AllocInfo>(100000);

            m_clrProfiler.GCStart               += new ClrProfilerParser.GCEventHandler(this.GCStart);
            m_clrProfiler.GCEnd                 += new ClrProfilerParser.GCEventHandler(this.GCEnd);
            m_clrProfiler.ObjectRangeLive       += new ClrProfilerParser.LiveObjectRangeHandler(this.ObjectRangeLive);
            m_clrProfiler.ObjectRangeRelocation += new ClrProfilerParser.RelocationEventHandler(this.ObjectRangeRelocation);

            // TODO expose the thread information
            AllocInfo info = new AllocInfo();

            m_clrProfiler.Allocation += delegate(ProfilerAllocID allocId, Address objectAddress, uint threadId)
            {
                Debug.Assert(allocId != ProfilerAllocID.Null);
                info.Size    = (int)m_clrProfiler.GetAllocSize(allocId);
                info.AllocId = allocId;

                var stackId = m_clrProfiler.GetAllocStack(allocId);
                info.MsecFromStart = CurrentTimeMSec;

                info.ObjectAddress = objectAddress;
                Allocs.Add(info);
                m_numAllocs++;
            };

            m_clrProfiler.Tick += delegate(int milliSecondsSinceStart)
            {
                CurrentTimeMSec = milliSecondsSinceStart;
            };
        }
        static void main2()
        {
            GrowableArray <double> ga = new GrowableArray <double>();
            int i = 7;

            ga.AddElement(i);
        }
        public GrowableArrayGenericUser()
        {
            GrowableArray <int> ga = new GrowableArray <int>();
            int num = 10;

            ga.AddElement(num);                 //no boxing operation here
            int newNum = (int)ga.GetElement(0); //type safety and no unboxing operation
            // string str = (string)ga.GetElement(0); //would not compile
        }
Exemple #8
0
        public void AddTest()
        {
            GrowableArray <int> tester = new GrowableArray <int>
            {
                5
            };

            Assert.Equals(tester.list, new int[] { 5 });
        }
        public GrowableArrayUser()
        {
            GrowableArray ga  = new GrowableArray();
            int           num = 10;

            ga.AddElement(num);                       //boxing operation here
            int    newNum = (int)ga.GetElement(0);    //no type safety and unboxing operation
            string str    = (string)ga.GetElement(0); //runtime error here
        }
Exemple #10
0
 private void GetChildrenForAddresses(ref GrowableArray <NodeIndex> children, string to)
 {
     // TODO inefficient
     foreach (var numStr in to.Split(' '))
     {
         int num;
         if (int.TryParse(numStr, NumberStyles.HexNumber, null, out num))
         {
             children.Add(GetNodeIndex((Address)num));
         }
     }
 }
    public static MemoryGraph Create(string dllPath, SymbolReader symbolReader)
    {
        var ret = new MemoryGraph(1000);

        string pdbPath = symbolReader.FindSymbolFilePathForModule(dllPath);

        symbolReader.Log.WriteLine("Got PDB path {0}", pdbPath);

        NativeSymbolModule module  = symbolReader.OpenNativeSymbolFile(pdbPath);
        List <Symbol>      symbols = new List <Symbol>();

        AddAllChildren(symbols, module.GlobalSymbol);

        symbols.Sort();

        /****** Make a graph out of the symbols ******/
        // Put all nodes under this root.
        var rootChildren = new GrowableArray <NodeIndex>(1000);

        // Create a node for each symbol
        uint   lastRVA  = 0;
        string lastName = "Header";
        var    empty    = new GrowableArray <NodeIndex>();

        foreach (var symbol in symbols)
        {
            var symRVA   = symbol.RVA;
            int lastSize = (int)symRVA - (int)lastRVA;

            NodeTypeIndex typeIdx = ret.CreateType(lastName, null, lastSize);
            NodeIndex     nodeIdx = ret.CreateNode();
            ret.SetNode(nodeIdx, typeIdx, lastSize, empty);
            rootChildren.Add(nodeIdx);

            lastName = symbol.Name;
            lastRVA  = symRVA;
        }
        // TODO FIX NOW dropping the last symbol.

        // Create the root node.
        NodeIndex     rootIdx     = ret.CreateNode();
        NodeTypeIndex rootTypeIdx = ret.CreateType("METHODS");

        ret.SetNode(rootIdx, rootTypeIdx, 0, rootChildren);
        ret.RootIndex = rootIdx;

        ret.AllowReading();

        return(ret);
    }
Exemple #12
0
 public void TestArrayAccess()
 {
     int sz = 100;
     GrowableArray<int> ga = new GrowableArray<int>(sz);
     for(int i = 0; i < 2 * sz; ++i)
     {
         ga.Set(i, 13*i);
         Assert.AreEqual(i < sz ? sz : 2 * sz, ga.LongLength);
     }
     for(int i = 0; i < 2 * sz; ++i)
     {
         Assert.AreEqual(i*13, ga.Get(i));
     }
 }
Exemple #13
0
 private static void PopulateSieveFrom(GrowableArray<bool> sieve, long from = 2)
 {
     long upTo = (long)Math.Sqrt(sieve.LongLength) + 1;
     for (long i = 2; i < upTo; i++)
     {
         if (!sieve.Get(i))
         {
             var k = (i < from) ? FirstK(i, from) : 2 * i;
             while (k < sieve.LongLength)
             {
                 sieve.Set(k,true);
                 k += i;
             }
         }
     }
 }
Exemple #14
0
        void IFastSerializable.FromStream(Deserializer deserializer)
        {
            base.FromStream(deserializer);
            // Read in the Memory addresses of each object
            int addressCount = deserializer.ReadInt();

            m_nodeAddresses = new GrowableArray <Address>(addressCount);
            for (int i = 0; i < addressCount; i++)
            {
                m_nodeAddresses.Add((Address)deserializer.ReadInt64());
            }

            bool is64bit = false;

            deserializer.TryReadTagged(ref is64bit);
            Is64Bit = is64bit;
        }
Exemple #15
0
 public ClrProfilerMethodSizeStackSource(string clrProfilerFileName)
 {
     m_fileName          = clrProfilerFileName;
     m_clrProfiler       = new ClrProfilerParser();
     m_calls             = new GrowableArray <int>(1000000);
     m_clrProfiler.Call += delegate(ProfilerStackTraceID stackId, uint threadId)
     {
         m_calls.Add((int)stackId);
         var method = m_clrProfiler.Method(stackId);
         var stats  = (MethodStats)method.UserData;
         if (stats == null)
         {
             m_totalMethodSize += (int)method.size;
             m_totalMethodCount++;
             method.UserData = stats = new MethodStats();
             // Debug.WriteLine(string.Format("METHOD Size {1,6}: {0}", method.name, method.size));
         }
         stats.count++;
     };
     m_clrProfiler.ReadFile(m_fileName);
     // Debug.WriteLine(string.Format("MethodSize {0} MethodCount {1} callCount {2}", m_totalMethodSize, m_totalMethodCount, m_calls.Count));
 }
Exemple #16
0
        public ClrProfilerMemoryGraph(string profilerFile)
            : base(10000)
        {
            // Needed for the callback in ReadFile
            m_tempChildren = new GrowableArray <NodeIndex>(1000);
            ClearWorker();

            m_clrProfilerParser = new ClrProfilerParser();
            m_clrProfilerParser.ObjectDescription += OnObjectDescription;
            m_clrProfilerParser.GCRoot            += OnGCRoot;
            m_clrProfilerParser.HeapDump          += OnHeapDump;
            m_clrProfilerParser.StaticVar         += OnStaticVar;
            m_clrProfilerParser.LocalVar          += OnLocalVar;

            m_clrProfilerParser.ReadFile(profilerFile);

            // set the module names on every type if present.
            var nodeTypeStorage = AllocTypeNodeStorage();

            for (var profilerTypeId = 0; profilerTypeId < (int)m_clrProfilerParser.TypeIdLimit; profilerTypeId++)
            {
                var profilerType = m_clrProfilerParser.GetTypeById((ProfilerTypeID)profilerTypeId);
                if (profilerType == null)
                {
                    continue;
                }
                var module = profilerType.Module;
                if (module != null && profilerTypeId < m_profilerTypeToNodeType.Count)
                {
                    var nodeTypeId = m_profilerTypeToNodeType[profilerTypeId];
                    if (nodeTypeId != NodeTypeIndex.Invalid)
                    {
                        var nodeType = GetType((NodeTypeIndex)nodeTypeId, nodeTypeStorage);
                        nodeType.ModuleName = profilerType.Module.name;
                    }
                }
            }

            // Now we have module information, process the defer local and static processing
            foreach (var deferedRoot in m_deferedRoots)
            {
                ProfilerType profilerType  = m_clrProfilerParser.GetTypeById(deferedRoot.typeID);
                var          appDomainNode = m_rootNode.FindOrCreateChild("[appdomain " + deferedRoot.appDomainName + "]");
                var          varKindNode   = appDomainNode.FindOrCreateChild("[" + deferedRoot.prefix + " vars]");
                var          moduleName    = System.IO.Path.GetFileNameWithoutExtension(profilerType.ModuleName);
                var          moduleNode    = varKindNode.FindOrCreateChild("[" + deferedRoot.prefix + " vars " + moduleName + "]");
                var          typeNode      = moduleNode.FindOrCreateChild("[" + deferedRoot.prefix + " vars " + profilerType.name + "]");
                var          node          = typeNode.FindOrCreateChild(
                    profilerType.name + "+" + deferedRoot.name + " [" + deferedRoot.prefix + " var]", profilerType.ModuleName);
                node.AddChild(deferedRoot.nodeIndex);
            }

            // finish off the root nodes.
            RootIndex = m_rootNode.Build();
            AllowReading();

            // These are only needed for the callbacks in 'ReadFile' save space by clearing them out.
            m_clrProfilerParser      = null;
            m_tempChildren           = new GrowableArray <NodeIndex>();     // Clear the array
            m_profilerTypeToNodeType = new GrowableArray <NodeTypeIndex>(); // Clear the array
            m_rootNode = null;
            m_rootNodeForUnknownRoot = null;
            m_addressToNodeIndex     = null;
            m_deferedRoots           = null;
        }
Exemple #17
0
        public GCHeapGraph(GCHeap heap)
            : base((int)heap.NumberOfObjects)
        {
            // TODO is basically nodes that have not had 'SetNode' done to them.  Thus the node index has been
            // allocated, but we have not processed the defintion of the node.
            // This list should NEVER contain duplicates (you should test if you already processed the node before
            // adding to this queue.
            Queue <NodeIndex> toDo = new Queue <NodeIndex>();

            // Create the root node.
            var root = new MemoryNodeBuilder(this, "[root]");

            // Create categories for the roots.
            var nodeForKind = new MemoryNodeBuilder[((int)GCRootKind.Max) + 1];

            var otherRoots = root.FindOrCreateChild("[other roots]");

            nodeForKind[(int)GCRootKind.LocalVar] = otherRoots.FindOrCreateChild("[unknown local vars]");
            for (int i = 0; i < nodeForKind.Length; i++)
            {
                if (nodeForKind[i] == null)
                {
                    nodeForKind[i] = otherRoots.FindOrCreateChild("[" + ((GCRootKind)i).ToString().ToLower() + " handles]");
                }
            }
            var unreachable = root.FindOrCreateChild("[unreachable but not yet collected]");

            foreach (var gcRoot in heap.Roots)
            {
                if (gcRoot.HeapReference == 0)
                {
                    continue;
                }

                // TODO FIX NOW condition should not be needed, should be able to assert it.
                if (!heap.IsInHeap(gcRoot.HeapReference))
                {
                    continue;
                }
                Debug.Assert(heap.IsInHeap(gcRoot.HeapReference));

                // Make a node for it, and notice if the root is already in the heap.
                var lastLimit  = NodeIndexLimit;
                var newNodeIdx = GetNodeIndex(gcRoot.HeapReference);

                var nodeForGcRoot = nodeForKind[(int)gcRoot.Kind];
                if (gcRoot.Type != null)
                {
                    var prefix = "other";
                    if (gcRoot.Kind == GCRootKind.StaticVar)
                    {
                        prefix = "static";
                    }
                    else if (gcRoot.Kind == GCRootKind.LocalVar)
                    {
                        prefix = "local";
                    }
                    var appDomainNode = root.FindOrCreateChild("[appdomain " + gcRoot.AppDomainName + "]");
                    var varKindNode   = appDomainNode.FindOrCreateChild("[" + prefix + " vars]");
                    var moduleName    = Path.GetFileNameWithoutExtension(gcRoot.Type.ModuleFilePath);
                    var moduleNode    = varKindNode.FindOrCreateChild("[" + prefix + " vars " + moduleName + "]");
                    var typeNode      = moduleNode.FindOrCreateChild("[" + prefix + " vars " + gcRoot.Type.Name + "]");
                    var name          = gcRoot.Type.Name + "+" + gcRoot.Name + " [" + prefix + " var]";
                    nodeForGcRoot = typeNode.FindOrCreateChild(name, gcRoot.Type.ModuleFilePath);

                    // TODO REMOVE
                    // if (nodeForGcRoot.Size == 0)
                    //    nodeForGcRoot.Size = 4;
                }

                // Give the user a bit more information about runtime internal handles
                if (gcRoot.Kind == GCRootKind.Pinning)
                {
                    var pinnedType = heap.GetObjectType(gcRoot.HeapReference);
                    if (pinnedType.Name == "System.Object []")
                    {
                        // Traverse pinned object arrays a bit 'manually' here so we tell the users they are likely handles.
                        var handleArray = new MemoryNodeBuilder(
                            this, "[likely runtime object array handle table]", pinnedType.ModuleFilePath, newNodeIdx);
                        handleArray.Size = pinnedType.GetSize(gcRoot.HeapReference);
                        nodeForGcRoot.AddChild(handleArray);

                        pinnedType.EnumerateRefsOfObjectCarefully(gcRoot.HeapReference, delegate(Address childRef, int childFieldOffset)
                        {
                            // Poor man's visited bit.  If we did not need to add a node, then we have visited it.
                            var childLastLimit = NodeIndexLimit;
                            var childNodeIdx   = GetNodeIndex(childRef);
                            if (childNodeIdx < childLastLimit)       // Already visited, simply add the child and move one
                            {
                                handleArray.AddChild(childNodeIdx);
                                return;
                            }

                            var childType = heap.GetObjectType(childRef);
                            if (childType.Name == "System.String")
                            {
                                // TODO FIX NOW:  Only want to morph the name if something else does not point at it.
                                var literal = new MemoryNodeBuilder(
                                    this, "[likely string literal]", childType.ModuleFilePath, childNodeIdx);
                                literal.Size = childType.GetSize(childRef);
                                handleArray.AddChild(literal);
                            }
                            else
                            {
                                handleArray.AddChild(childNodeIdx);
                                toDo.Enqueue(childNodeIdx);
                            }
                        });
                        continue;       // we are done processing this node.
                    }
                }

                nodeForGcRoot.AddChild(newNodeIdx);
                if (newNodeIdx >= lastLimit)      // have not been visited.
                {
                    toDo.Enqueue(newNodeIdx);
                }
            }

            root.AllocateTypeIndexes();

            // Create the necessary types.
            int memoryTypesStart = (int)NodeTypeIndexLimit;

            foreach (var type in heap.Types)
            {
                NodeTypeIndex nodeType = CreateType(type.Name, type.ModuleFilePath);
                Debug.Assert((int)nodeType == (int)type.Index + memoryTypesStart);
            }

            var children = new GrowableArray <NodeIndex>();

            while (toDo.Count > 0)
            {
                var nodeIndex = toDo.Dequeue();
                var objRef    = GetAddress(nodeIndex);

                children.Clear();
                GCHeapType objType = heap.GetObjectType(objRef);
                objType.EnumerateRefsOfObjectCarefully(objRef, delegate(Address childRef, int childFieldOffset)
                {
                    Debug.Assert(heap.IsInHeap(childRef));
                    var lastLimit    = NodeIndexLimit;
                    var childNodeIdx = GetNodeIndex(childRef);
                    children.Add(childNodeIdx);

                    // Poor man's visited bit.  If the index we just asked for is a new node, put it in the work queue
                    if (childNodeIdx >= lastLimit)
                    {
                        toDo.Enqueue(childNodeIdx);
                    }
                });

                int objSize = objType.GetSize(objRef);
                Debug.Assert(objSize > 0);
                SetNode(nodeIndex, (NodeTypeIndex)((int)objType.Index + memoryTypesStart), objSize, children);
            }

            long unreachableSize = (heap.TotalSize - TotalSize);

            unreachable.Size = (int)unreachableSize;
            if (unreachable.Size != unreachableSize)
            {
                unreachable.Size = int.MaxValue;        // TODO not correct on overflow
            }
            // We are done!
            RootIndex = root.Build();
            AllowReading();
        }
Exemple #18
0
    public PdbScopeMemoryGraph(string pdbScopeFile)
        : base(10000)
    {
        var children = new GrowableArray <NodeIndex>(1000);
        Dictionary <string, NodeTypeIndex> knownTypes = new Dictionary <string, NodeTypeIndex>(1000);

        XmlReaderSettings settings = new XmlReaderSettings()
        {
            IgnoreWhitespace = true, IgnoreComments = true
        };

        using (XmlReader reader = XmlReader.Create(pdbScopeFile, settings))
        {
            int     foundBestRoot     = int.MaxValue; // it is zero when when we find the best root.
            Address imageBase         = 0;
            uint    sizeOfImageHeader = 0;
            Address lastAddress       = 0;
            int     badValues         = 0;

            Queue <Section> sections     = new Queue <Section>();
            Address         prevAddr     = 0;
            Address         expectedAddr = 0;
            RootIndex = NodeIndex.Invalid;
            NodeIndex firstNodeIndex = NodeIndex.Invalid;
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    switch (reader.Name)
                    {
                    case "Section":
                    {
                        Section section = new Section();
                        section.Start = Address.Parse(reader.GetAttribute("Start"));
                        section.Size  = uint.Parse(reader.GetAttribute("Size"));
                        section.Name  = reader.GetAttribute("Name");
                        sections.Enqueue(section);
                        lastAddress = Math.Max(lastAddress, section.EndRoundedUpToPage);
                    } break;

                    case "Module":
                        if (imageBase == 0)
                        {
                            imageBase         = Address.Parse(reader.GetAttribute("Base"));
                            sizeOfImageHeader = 1024;            // We are using the file size number
                            NodeIndex     nodeIndex = GetNodeIndex(imageBase);
                            NodeTypeIndex typeIndex = CreateType("Image Header");
                            children.Clear();
                            SetNode(nodeIndex, typeIndex, (int)sizeOfImageHeader, children);
                            expectedAddr = imageBase + 0x1000;

                            DebugWriteLine("Loading Module Map table used to decode $N symbol prefixes.");
                            string dllFilePath = reader.GetAttribute("FilePath");
                            if (dllFilePath != null)
                            {
                                LoadModuleMap(dllFilePath, pdbScopeFile);
                            }
                            else
                            {
                                DebugWriteLine("Could not find path to original DLL being analyzed.");
                            }

                            if (m_moduleMap != null)
                            {
                                DebugWriteLine("Loaded Module Map of " + m_moduleMap.Count + " Project N style IL modules to unmangled $N_ prefixes.");
                            }
                            else
                            {
                                DebugWriteLine("Warning: No Module Map Found: $N_ prefixes will not be unmangled.");
                            }
                        }
                        break;

                    case "ObjectTypes":
                    case "Type":
                    case "Dicectory":
                    case "Sections":
                    case "PdbscopeReport":
                    case "Symbols":
                    case "SourceFiles":
                    case "File":
                        break;

                    case "Symbol":
                        string  addrStr = reader.GetAttribute("addr");
                        Address addr;
                        if (addrStr != null && Address.TryParse(addrStr, NumberStyles.AllowHexSpecifier, null, out addr))
                        {
                            if (addr < lastAddress)
                            {
                                // Get Size
                                string sizeStr = reader.GetAttribute("size");
                                uint   size    = 0;
                                if (sizeStr != null)
                                {
                                    uint.TryParse(sizeStr, out size);
                                }

                                // Get Children
                                children.Clear();
                                string to = reader.GetAttribute("to");
                                if (to != null)
                                {
                                    GetChildrenForAddresses(ref children, to);
                                }

                                // Get Name, make a type out of it
                                string        name;
                                NodeTypeIndex typeIndex = GetTypeForXmlElement(knownTypes, reader, size, out name);

                                // Currently PdbScope files have extra information lines where it shows the different generic instantiations associated
                                // with a given symbol.  These ways have the same address as the previous entry and have no size (size will be 0) so
                                // we filter these lines out with the following condition.
                                if (prevAddr != addr || size != 0)
                                {
                                    prevAddr = addr;

                                    if (addr < expectedAddr)
                                    {
                                        DebugWriteLine(string.Format("Got Address {0:x} which is less than the expected address {1:x}.  Discarding {2}",
                                                                     addr, expectedAddr, name));
                                        badValues++;
                                        if (50 < badValues)
                                        {
                                            throw new ApplicationException("Too many cases where the addresses were not ascending in the file");
                                        }
                                        continue;               // discard
                                    }
                                    /*** We want to make sure we account for all bytes, so log when we see gaps ***/
                                    // If we don't match see if it is because of section boundary.
                                    if (addr != expectedAddr)
                                    {
                                        EmitNodesForGaps(sections, expectedAddr, addr);
                                    }

                                    expectedAddr = addr + size;

                                    NodeIndex nodeIndex = GetNodeIndex((Address)addr);
                                    SetNode(nodeIndex, typeIndex, (int)size, children);

                                    // See if this is a good root
                                    if (foundBestRoot != 0 && name != null)
                                    {
                                        if (name == "RHBinder__ShimExeMain")
                                        {
                                            RootIndex     = nodeIndex;
                                            foundBestRoot = 0;
                                        }
                                        else if (0 < foundBestRoot && name.Contains("ILT$Main"))
                                        {
                                            RootIndex     = nodeIndex;
                                            foundBestRoot = 1;
                                        }
                                        else if (1 < foundBestRoot & name.Contains("DllMainCRTStartup"))
                                        {
                                            RootIndex     = nodeIndex;
                                            foundBestRoot = 1;
                                        }
                                        else if (2 < foundBestRoot & name.Contains("Main"))
                                        {
                                            RootIndex     = nodeIndex;
                                            foundBestRoot = 2;
                                        }
                                    }

                                    // Remember first node.
                                    if (firstNodeIndex == NodeIndex.Invalid)
                                    {
                                        firstNodeIndex = nodeIndex;
                                    }
                                }
                            }
                            else
                            {
                                DebugWriteLine(string.Format("Warning Discarding Symbol node {0:x} outside the last address in the image {1:x}", addr, lastAddress));
                            }
                        }
                        else
                        {
                            DebugWriteLine("Error: symbol without addr");
                        }
                        break;

                    default:
                        DebugWriteLine(string.Format("Skipping unknown element {0}", reader.Name));
                        break;
                    }
                }
            }

            EmitNodesForGaps(sections, expectedAddr, lastAddress);

            if (RootIndex == NodeIndex.Invalid)
            {
                RootIndex = firstNodeIndex;
            }
            DebugWriteLine(string.Format("Image Base {0:x} LastAddress {1:x}", imageBase, lastAddress));
            DebugWriteLine(string.Format("Total Virtual Size {0} ({0:x})", lastAddress - imageBase));
            DebugWriteLine(string.Format("Total File Size    {0} ({0:x})", TotalSize));
        }
        AllowReading();
    }
Exemple #19
0
    /// <summary>
    /// This demo shows you how to create a a graph of memory and turn it into a stackSource with MemoryGraphStackSource.
    /// </summary>
    public void DemoMemoryGraph()
    {
        // Make a custom stack source that was created out of nothing.   InternStackSouce is your friend here.
        MemoryGraph myGraph = new MemoryGraph(1000);

        // Create a memory graph out of 'nothing'.  In the example below we create a graph where the root which points at
        // 'base' which has a bunch of children, each of which have a child that points back to the base node (thus it has lots of cycles)

        var baseIdx = myGraph.GetNodeIndex(0);                                       // Define the NAME (index) for the of the graph (but we have not defined what is in it)

        GrowableArray <NodeIndex> children     = new GrowableArray <NodeIndex>(1);   // This array is reused again and again for each child.
        GrowableArray <NodeIndex> rootChildren = new GrowableArray <NodeIndex>(100); // This is used to create the children of the root;

        //Here I make up a graph of memory addresses at made up locations
        for (Address objAddr = 0x100000; objAddr < 0x200000; objAddr += 0x10000)
        {
            NodeIndex nodeIdx = myGraph.GetNodeIndex(objAddr);                          // Create the name (node index) for the child
            // Make a type for the child.  In this case we make a new type for each node, normally you keep these in a interning table so that
            // every distinct type name has exactly one type index.   Interning is not STRICTLLY needed, but the representation assumes that
            // there are many more nodes than there are types.
            NodeTypeIndex nodeTypeIdx = myGraph.CreateType("MyType_" + objAddr.ToString(), "MyModule");
            // Create a list of children for this node in this case, each node has exactly one child, which is the root node.
            children.Clear();
            children.Add(baseIdx);
            // Actually define the node with the given name (nodeIdx), type, size (100 in our case) and children;
            myGraph.SetNode(nodeIdx, nodeTypeIdx, 100, children);

            rootChildren.Add(nodeIdx);      // Remember this node name as belonging to the things that the root points at.
        }

        // At this point we have everything we need to define the base node, do it here.
        myGraph.SetNode(baseIdx, myGraph.CreateType("[Base]"), 0, rootChildren);

        // Create a root node that points at the base node.
        myGraph.RootIndex = myGraph.GetNodeIndex(1);
        children.Clear();
        children.Add(baseIdx);
        myGraph.SetNode(myGraph.RootIndex, myGraph.CreateType("[ROOT]"), 0, children);

        // Note that the raw graph APIs force you to know all the children of a particular node before you can define
        // the node.  There is a class call MemoryNodeBuilder which makes this a bit nicer in that you can incrementally
        // add children to nodes and then 'finalize' them all at once at the end.   Ideally, however you don't have many
        // nodes that need MemoryNodeBuilder as they are more expensive to build.

        // So far, the graph is in 'write mode' where only creation APIs are allowed.   Change to 'Read Mode' which no writes
        // are allowed by read APIs are allowed.  (We may lift this restriction at some point).
        myGraph.AllowReading();

        // I can  dump it as XML to look at it.
        using (var writer = File.CreateText("MyGraph.dump.xml"))
        {
            myGraph.WriteXml(writer);
        }

        // I can write the graph out as a file and read it back in later.
        // myGraph.WriteAsBinaryFile("myGraph.gcGraph");
        // var roundTrip = MemoryGraph.ReadFromBinaryFile("myGraph.gcGraph");

        // OK we have a graph, turn it into a stack source so that I can view it.
        MemoryGraphStackSource myStackSource = new MemoryGraphStackSource(myGraph, LogFile);

        // Create a Stacks class (which remembers all the Filters, Scaling policy and other things the viewer wants.
        Stacks stacks = new Stacks(myStackSource);

        // If you wanted to, you can change the filtering ...
        stacks.Filter.GroupRegExs             = "";
        stacks.Filter.MinInclusiveTimePercent = "";

        // And view it.
        OpenStackViewer(stacks);
    }
Exemple #20
0
        void Read(TextReader reader)
        {
            // TODO this is relatively inefficient.
            var regEx = new Regex(@"^\s*(\d+)\s*(\d+)\s*\[\s*(\d+)\s*\]\s*(\S*?)!?(.*)");

            var         stack  = new GrowableArray <WTStackElem>();
            WTStackElem elem   = new WTStackElem();
            long        time   = 0;
            var         sample = new StackSourceSample(this);

            for (; ;)
            {
                var line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }
                var match = regEx.Match(line);
                if (match.Success)
                {
                    // Parse the line.
                    int    excInstrSoFar = int.Parse(match.Groups[1].Value);
                    int    depth         = int.Parse(match.Groups[3].Value);
                    string module        = match.Groups[4].Value;
                    string method        = match.Groups[5].Value;

                    // Form the name for this line
                    var moduleIndex = Interner.ModuleIntern(module);
                    var frameIndex  = Interner.FrameIntern(method, moduleIndex);

                    // Get the parent stack for this line
                    var parent = StackSourceCallStackIndex.Invalid;
                    if (depth > 0)
                    {
                        parent = stack[depth - 1].FirstCallStackIndex;    // TODO handle out of range
                    }
                    // Form the stack for this entry
                    var callStackIndex = Interner.CallStackIntern(frameIndex, parent);

                    int exclInstr;                              // Number of instructions executed on this line
                    int extra = stack.Count - depth;            // The number of frames we need to pop off (including me)
                    if (extra > 0)
                    {
                        // We returned from one or more methods OR we have not left the current method
                        //
                        elem = stack[depth];

                        // We expect to return to the same method we were at at this depth.
                        if (callStackIndex == elem.CallStackIndex)
                        {
                            exclInstr = excInstrSoFar - elem.ExclInstrSoFar;    // We are continuing the function
                        }
                        else
                        {
                            // We are tail-calling to another routine.
                            exclInstr           = excInstrSoFar;
                            elem.CallStackIndex = callStackIndex;
                        }

                        // Pop off all the frames we returned from
                        Debug.Assert(exclInstr >= 0);
                        stack.RemoveRange(depth, extra);
                    }
                    else
                    {
                        // Means we are adding a new frame (we called someone)
                        Debug.Assert(extra == 0);       // We always add only one more frame (e.g. we never go from depth 2 to 4)
                        elem.CallStackIndex      = callStackIndex;
                        elem.FirstCallStackIndex = callStackIndex;
                        exclInstr = excInstrSoFar;
                    }
                    elem.ExclInstrSoFar = excInstrSoFar;
                    stack.Add(elem);

                    time += exclInstr;

                    sample.Metric           = exclInstr;
                    sample.TimeRelativeMSec = time - exclInstr;
                    sample.StackIndex       = elem.FirstCallStackIndex;
                    AddSample(sample);
                }
            }
            Interner.DoneInterning();
        }
Exemple #21
0
        void Read(TextReader reader)
        {
            // TODO this is relatively inefficient.
            var regEx = new Regex(@"^\s*(\d+)\s*(\d+)\s*\[\s*(\d+)\s*\]\s*(\S*?)!?(.*)");

            var         stack = new GrowableArray <WTStackElem>();
            WTStackElem elem  = new WTStackElem();
            long        time  = 0;

            for (; ;)
            {
                var line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }
                var match = regEx.Match(line);
                if (match.Success)
                {
                    int    excInstrSoFar = int.Parse(match.Groups[1].Value);
                    int    depth         = int.Parse(match.Groups[3].Value);
                    string module        = match.Groups[4].Value;
                    string method        = match.Groups[5].Value;

                    var moduleIndex = ModuleIntern(module);
                    var frameIndex  = FrameIntern(method, moduleIndex);

                    var parent = StackSourceCallStackIndex.Invalid;
                    if (depth > 0)
                    {
                        parent = stack[depth - 1].FirstCallStackIndex;    // TODO handle out of range
                    }
                    var callStackIndex = CallStackIntern(frameIndex, parent);

                    int extra = stack.Count - depth;
                    int exclInstr;
                    if (extra > 0)
                    {
                        elem = stack[depth];

                        if (callStackIndex == elem.CallStackIndex)
                        {
                            exclInstr = excInstrSoFar - elem.ExclInstrSoFar;
                        }
                        else
                        {
                            exclInstr           = excInstrSoFar;
                            elem.CallStackIndex = callStackIndex;
                        }
                        Debug.Assert(exclInstr >= 0);
                        stack.RemoveRange(depth, extra);
                    }
                    else
                    {
                        elem.CallStackIndex      = callStackIndex;
                        elem.FirstCallStackIndex = callStackIndex;
                        Debug.Assert(extra == 0);
                        exclInstr = excInstrSoFar;
                    }
                    elem.ExclInstrSoFar = excInstrSoFar;
                    stack.Add(elem);

                    time += exclInstr;

                    var sample = new StackSourceSample(this);
                    sample.SampleIndex = (StackSourceSampleIndex)m_samples.Count;
                    sample.Metric      = exclInstr;
                    sample.TimeRelMSec = time - exclInstr;
                    sample.StackIndex  = elem.FirstCallStackIndex;

                    // Break long sequences of instructions into individual samples.   This
                    // makes timeline work well.
                    // TODO this bloats the data, not clear if this is the right tradeoff ....
                    const int maxSize = 20;
                    while (sample.Metric > maxSize)
                    {
                        var subSample = new StackSourceSample(sample);
                        subSample.Metric    = maxSize;
                        sample.Metric      -= maxSize;
                        sample.TimeRelMSec += maxSize;
                        m_samples.Add(subSample);
                        sample.SampleIndex = (StackSourceSampleIndex)m_samples.Count;
                    }

                    m_samples.Add(sample);
#if DEBUG
                    var sampleStr = this.ToString(sample);
                    Debug.WriteLine(sampleStr);
#endif
                }
            }
            m_sampleTimeRelMSecLimit = time;
            CompletedReading();
        }
Exemple #22
0
        void Read(TextReader reader)
        {
            var framePattern = new Regex(@"\b(\w+?)\!(\S\(?[\S\s]*\)?)");
            var stackStart   = new Regex(@"Call Site");

            // the call stack from the debugger kc command looksl like this
            //Call Site
            //coreclr!JIT_MonEnterWorker_Portable
            //System_Windows_ni!MS.Internal.ManagedPeerTable.TryGetManagedPeer(IntPtr, Boolean, System.Object ByRef)
            //System_Windows_ni!MS.Internal.ManagedPeerTable.EnsureManagedPeer(IntPtr, Int32, System.Type, Boolean)
            //System_Windows_ni!MS.Internal.FrameworkCallbacks.CheckPeerType(IntPtr, System.String, Boolean)
            //System_Windows_ni!DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int32, IntPtr, Int32)
            //coreclr!UM2MThunk_WrapperHelper
            //coreclr!UMThunkStubWorker
            //coreclr!UMThunkStub
            //agcore!CParser::StartObjectElement
            //agcore!CParser::Attribute
            //agcore!CParser::LoadXaml

            var   stack             = new GrowableArray <DebuggerCallStackFrame>();
            bool  newCallStackFound = false;
            var   sample            = new StackSourceSample(this);
            float time = 0;

            for (; ;)
            {
                var line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }
                var match = framePattern.Match(line);
                if (match.Success && newCallStackFound)
                {
                    var module     = match.Groups[1].Value;
                    var methodName = match.Groups[2].Value;

                    // trim the methodName if it has file name info (if the trace is collected with kv instead of kc)
                    int index = methodName.LastIndexOf(")+");
                    if (index != -1)
                    {
                        methodName = methodName.Substring(0, index + 1);
                    }


                    var moduleIndex = Interner.ModuleIntern(module);
                    var frameIndex  = Interner.FrameIntern(methodName, moduleIndex);

                    DebuggerCallStackFrame frame = new DebuggerCallStackFrame();
                    frame.frame = frameIndex;
                    stack.Add(frame);
                }
                else
                {
                    var stackStartMatch = stackStart.Match(line);
                    if (stackStartMatch.Success)
                    {
                        // start a new sample.
                        // add the previous sample
                        // clear the stack
                        if (stack.Count != 0)
                        {
                            StackSourceCallStackIndex parent = StackSourceCallStackIndex.Invalid;
                            for (int i = stack.Count - 1; i >= 0; --i)
                            {
                                parent = Interner.CallStackIntern(stack[i].frame, parent);
                            }
                            stack.Clear();

                            sample.StackIndex       = parent;
                            sample.TimeRelativeMSec = time;
                            time++;
                            AddSample(sample);
                        }
                        newCallStackFound = true;
                    }
                }
            }
            Interner.DoneInterning();
        }
Exemple #23
0
        private void Read(Stream rawStream)
        {
            XmlReaderSettings settings = new XmlReaderSettings()
            {
                IgnoreWhitespace = true, IgnoreComments = true
            };
            XmlReader reader           = XmlTextReader.Create(rawStream, settings);
            var       stack            = new GrowableArray <StackSourceSample>();
            bool      metricsInclusive = false; // If true, we need to convert them to exclusive as part of processing

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    if (reader.Name == "node")
                    {
                        var    sample   = new StackSourceSample(this);
                        string callTree = reader.GetAttribute("call_tree");

                        // Case for allocation stacks
                        string sizeStr = reader.GetAttribute("size");
                        if (sizeStr != null)
                        {
                            metricsInclusive = true;        // allocation numbers are inclusive
                            int size = 0;
                            int.TryParse(sizeStr, out size);
                            sample.Metric = size;

                            string recoredObectsStr = reader.GetAttribute("recorded_objects");
                            int    recoredObects    = 0;
                            if (recoredObectsStr != null)
                            {
                                int.TryParse(recoredObectsStr, out recoredObects);
                            }

                            sample.Count = recoredObects;
                        }
                        else
                        {
                            Debug.Assert(metricsInclusive == false);        // CPU time is exclusive.
                            // For CPU
                            string own_time_msStr = reader.GetAttribute("own_time_ms");
                            if (own_time_msStr != null)
                            {
                                int own_time_ms;
                                int.TryParse(own_time_msStr, out own_time_ms);
                                sample.Metric = own_time_ms;

                                string countStr = reader.GetAttribute("count");
                                int    count    = 0;
                                if (countStr != null)
                                {
                                    int.TryParse(countStr, out count);
                                }

                                sample.Count = count;
                            }
                        }

                        // Get the parent stack for this line
                        var parentStackIndex = StackSourceCallStackIndex.Invalid;
                        int depth            = stack.Count;
                        if (depth > 0)
                        {
                            StackSourceSample parent = stack[depth - 1];
                            parentStackIndex = parent.StackIndex;

                            if (metricsInclusive)
                            {
                                // The values are inclusive, but StackSoruceSamples are the exclusive amounts, so remove children.
                                parent.Count  -= sample.Count;
                                parent.Metric -= sample.Metric;
                            }
                        }
                        if (callTree != null)
                        {
                            var frameIndex = Interner.FrameIntern(callTree);
                            sample.StackIndex = Interner.CallStackIntern(frameIndex, parentStackIndex);
                        }
                        stack.Add(sample);
                    }
                }
                if (reader.NodeType == XmlNodeType.EndElement || reader.IsEmptyElement)
                {
                    if (reader.Name == "node")
                    {
                        StackSourceSample sample = stack.Pop();
                        if ((sample.Count > 0 || sample.Metric > 0) && sample.StackIndex != StackSourceCallStackIndex.Invalid)
                        {
                            AddSample(sample);
                        }
                    }
                }
            }

            Debug.Assert(stack.Count == 0);
            Interner.DoneInterning();
        }
        void Read(TextReader reader)
        {
            var stack = new GrowableArray <StackSourceCallStackIndex>();


            var line   = reader.ReadLine(); // Skip the first line, which is column headers.
            var sample = new StackSourceSample(this);

            for (; ;)
            {
                line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }
                //   0       1           2             3          4       5        6         7          8
                // Order, # of Calls, % Incl Time, % Excl Time, Depth, Function, Module, Incl Time, Excl Time,% Sw. Out, Incl Switched Out, Type, Comments	Min	Avg	Max	Excl Switched Out

                int    idx    = 0;
                int    depth  = 0;
                string method = null;
                string module = null;
                int    intVal;
                long   longVal;
                for (int col = 0; col <= 8; col++)
                {
                    var newIdx = line.IndexOf('\t', idx);
                    Debug.Assert(0 < newIdx);
                    if (newIdx < 0)
                    {
                        goto SKIP;
                    }

                    switch (col)
                    {
                    case 1:
                        int.TryParse(line.Substring(idx, newIdx - idx), System.Globalization.NumberStyles.Number, null, out intVal);
                        sample.Count = intVal;
                        break;

                    case 4:
                        int.TryParse(line.Substring(idx, newIdx - idx), System.Globalization.NumberStyles.Number, null, out depth);
                        break;

                    case 5:
                        while (idx < newIdx)
                        {
                            if (line[idx] != ' ')
                            {
                                break;
                            }
                            idx++;
                        }
                        method = line.Substring(idx, newIdx - idx);
                        method = method.Replace((char)0xFFFD, '@');          // They used this character to separate the method name from signature.
                        break;

                    case 6:
                        module = "";
                        if (depth != 0)
                        {
                            module = line.Substring(idx, newIdx - idx);
                        }
                        break;

                    case 8:
                        long.TryParse(line.Substring(idx, newIdx - idx), System.Globalization.NumberStyles.Number, null, out longVal);
                        sample.Metric = longVal / 1000000;     // TODO what is the metric?
                        break;
                    }
                    idx = newIdx + 1;
                }
                var moduleIdx = Interner.ModuleIntern(module);
                var frameIdx  = Interner.FrameIntern(method, moduleIdx);
                var prevFrame = StackSourceCallStackIndex.Invalid;
                if (0 < depth && depth <= stack.Count)
                {
                    prevFrame = stack[depth - 1];
                }
                var callStackIdx = Interner.CallStackIntern(frameIdx, prevFrame);

                if (depth < stack.Count)
                {
                    stack.Count = depth;
                }
                stack.Add(callStackIdx);

                sample.StackIndex = callStackIdx;
                AddSample(sample);
                SKIP :;
            }
            Interner.DoneInterning();
        }
Exemple #25
0
    /// <summary>
    /// Reads the Nodes Element
    /// </summary>
    private static void ReadNodesFromXml(XmlReader reader, MemoryGraph graph)
    {
        Debug.Assert(reader.NodeType == XmlNodeType.Element);
        var inputDepth = reader.Depth;

        reader.Read();      // Advance to children

        var children    = new GrowableArray <NodeIndex>(1000);
        var typeStorage = graph.AllocTypeNodeStorage();

        while (inputDepth < reader.Depth)
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.Name)
                {
                case "Node":
                {
                    NodeIndex     readNodeIndex = (NodeIndex)FetchInt(reader, "Index", -1);
                    NodeTypeIndex typeIndex     = (NodeTypeIndex)FetchInt(reader, "TypeIndex", -1);
                    int           size          = FetchInt(reader, "Size");

                    if (readNodeIndex == NodeIndex.Invalid)
                    {
                        throw new ApplicationException("Node element does not have a Index attribute.");
                    }

                    if (typeIndex == NodeTypeIndex.Invalid)
                    {
                        throw new ApplicationException("Node element does not have a TypeIndex attribute.");
                    }

                    // TODO FIX NOW very inefficient.   Use ReadValueChunk and FastStream to make more efficient.
                    children.Clear();
                    var body = reader.ReadElementContentAsString();
                    foreach (var num in Regex.Split(body, @"\s+"))
                    {
                        if (num.Length > 0)
                        {
                            children.Add((NodeIndex)int.Parse(num));
                        }
                    }

                    if (size == 0)
                    {
                        size = graph.GetType(typeIndex, typeStorage).Size;
                    }

                    // TODO should probably just reserve node index 0 to be an undefined object?
                    NodeIndex nodeIndex = 0;
                    if (readNodeIndex != 0)
                    {
                        nodeIndex = graph.CreateNode();
                    }

                    if (readNodeIndex != nodeIndex)
                    {
                        throw new ApplicationException("Node Indexes do not start at 0 or 1 and increase consecutively.");
                    }

                    graph.SetNode(nodeIndex, typeIndex, size, children);
                }
                break;

                default:
                    Debug.WriteLine("Skipping unknown element {0}", reader.Name);
                    reader.Skip();
                    break;
                }
            }
            else if (!reader.Read())
            {
                break;
            }
        }
    }
 public void MethodOne(GrowableArray <double> gad)
 {
     ;
 }
 public void MethodTwo(GrowableArray <object> gad)
 {
     ;
 }
 static void main()
 {
     GrowableArray <int> ga = new GrowableArray <int>();
     //MethodOne(ga);  //wil NOT compile
     //MethodTwo(ga);  //wil NOT compile
 }
Exemple #29
0
 public MemoryGraph(int expectedSize)
     : base(expectedSize)
 {
     m_addressToNodeIndex = new Dictionary <Address, NodeIndex>(expectedSize);
     m_nodeAddresses      = new GrowableArray <Address>(expectedSize);
 }
    /// <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;
    }
Exemple #31
0
        private void Read(XmlReader reader)
        {
            Stack <string> frameStack = null;
            // We use the invarient culture, otherwise if we encode in france and decode
            // in english we get parse errors (this happened!);
            var invariantCulture = CultureInfo.InvariantCulture;
            var inputDepth       = reader.Depth;
            var depthForSamples  = 0;

            while (reader.Read())
            {
PROCESS_NODE:
                switch (reader.NodeType)
                {
                case XmlNodeType.Element:
                    if (reader.Name == "Sample")
                    {
                        var sample = new StackSourceSample(this);
                        sample.Metric = 1;
                        if (reader.MoveToFirstAttribute())
                        {
                            do
                            {
                                if (reader.Name == "Time")
                                {
                                    sample.TimeRelativeMSec = double.Parse(reader.ReadContentAsString(), invariantCulture);
                                }
                                else if (reader.Name == "StackID")
                                {
                                    sample.StackIndex = (StackSourceCallStackIndex)reader.ReadContentAsInt();
                                }
                                else if (reader.Name == "Metric")
                                {
                                    sample.Metric = float.Parse(reader.ReadContentAsString(), invariantCulture);
                                }
                            } while (reader.MoveToNextAttribute());
                        }
                        sample.SampleIndex = (StackSourceSampleIndex)m_curSample;
                        m_samples.Set(m_curSample++, sample);
                        if (sample.TimeRelativeMSec > m_maxTime)
                        {
                            m_maxTime = sample.TimeRelativeMSec;
                        }

                        // See if there is a literal stack present as the body of
                        if (!reader.Read())
                        {
                            break;
                        }

                        if (reader.NodeType != XmlNodeType.Text)
                        {
                            goto PROCESS_NODE;
                        }

                        string rawStack = reader.Value.Trim();
                        if (0 < rawStack.Length)
                        {
                            InitInterner();

                            StackSourceCallStackIndex stackIdx = StackSourceCallStackIndex.Invalid;
                            string[] frames = rawStack.Split('\n');
                            for (int i = frames.Length - 1; 0 <= i; --i)
                            {
                                var frameIdx = m_interner.FrameIntern(frames[i].Trim());
                                stackIdx = m_interner.CallStackIntern(frameIdx, stackIdx);
                            }
                            sample.StackIndex = stackIdx;
                        }
                    }
                    else if (reader.Name == "Stack")
                    {
                        int stackID  = -1;
                        int callerID = -1;
                        int frameID  = -1;
                        if (reader.MoveToFirstAttribute())
                        {
                            do
                            {
                                if (reader.Name == "ID")
                                {
                                    stackID = reader.ReadContentAsInt();
                                }
                                else if (reader.Name == "FrameID")
                                {
                                    frameID = reader.ReadContentAsInt();
                                }
                                else if (reader.Name == "CallerID")
                                {
                                    callerID = reader.ReadContentAsInt();
                                }
                            } while (reader.MoveToNextAttribute());
                            if (0 <= stackID)
                            {
                                m_stacks.Set(stackID, new Frame(frameID, callerID));
                            }
                        }
                    }
                    else if (reader.Name == "Frame")
                    {
                        var frameID = -1;
                        if (reader.MoveToFirstAttribute())
                        {
                            do
                            {
                                if (reader.Name == "ID")
                                {
                                    frameID = reader.ReadContentAsInt();
                                }
                            } while (reader.MoveToNextAttribute());
                        }
                        reader.Read();          // Move on to body of the element
                        var frameName = reader.ReadContentAsString();
                        m_frames.Set(frameID, frameName);
                    }
                    else if (reader.Name == "Frames")
                    {
                        var count = reader.GetAttribute("Count");
                        if (count != null && m_frames.Count == 0)
                        {
                            m_frames = new GrowableArray <string>(int.Parse(count));
                        }
                    }
                    else if (reader.Name == "Stacks")
                    {
                        var count = reader.GetAttribute("Count");
                        if (count != null && m_stacks.Count == 0)
                        {
                            m_stacks = new GrowableArray <Frame>(int.Parse(count));
                        }
#if DEBUG
                        for (int i = 0; i < m_stacks.Count; i++)
                        {
                            m_stacks[i] = new Frame(int.MinValue, int.MinValue);
                        }
#endif
                    }
                    else if (reader.Name == "Samples")
                    {
                        var count = reader.GetAttribute("Count");
                        if (count != null && m_samples.Count == 0)
                        {
                            m_samples = new GrowableArray <StackSourceSample>(int.Parse(count));
                        }

                        depthForSamples = reader.Depth;
                    }
                    // This is the logic for the JSON case.  These are the anonymous object representing a sample.
                    else if (reader.Name == "item")
                    {
                        // THis is an item which is an element of the 'Samples' array.
                        if (reader.Depth == depthForSamples + 1)
                        {
                            var sample = new StackSourceSample(this);
                            sample.Metric = 1;

                            InitInterner();
                            int depthForSample = reader.Depth;
                            if (frameStack == null)
                            {
                                frameStack = new Stack <string>();
                            }

                            frameStack.Clear();

                            while (reader.Read())
                            {
PROCESS_NODE_SAMPLE:
                                if (reader.Depth <= depthForSample)
                                {
                                    break;
                                }

                                if (reader.NodeType == XmlNodeType.Element)
                                {
                                    if (reader.Name == "Time")
                                    {
                                        sample.TimeRelativeMSec = reader.ReadElementContentAsDouble();
                                        goto PROCESS_NODE_SAMPLE;
                                    }
                                    else if (reader.Name == "Metric")
                                    {
                                        sample.Metric = (float)reader.ReadElementContentAsDouble();
                                        goto PROCESS_NODE_SAMPLE;
                                    }
                                    else if (reader.Name == "item")
                                    {
                                        // Item is a string under stack under the sample.
                                        if (reader.Depth == depthForSample + 2)
                                        {
                                            frameStack.Push(reader.ReadElementContentAsString());
                                            goto PROCESS_NODE_SAMPLE;
                                        }
                                    }
                                }
                            }

                            // Reverse the order of the frames in the stack.
                            sample.StackIndex = StackSourceCallStackIndex.Invalid;
                            while (0 < frameStack.Count)
                            {
                                var frameIdx = m_interner.FrameIntern(frameStack.Pop());
                                sample.StackIndex = m_interner.CallStackIntern(frameIdx, sample.StackIndex);
                            }

                            if (sample.TimeRelativeMSec > m_maxTime)
                            {
                                m_maxTime = sample.TimeRelativeMSec;
                            }

                            sample.SampleIndex = (StackSourceSampleIndex)m_curSample;
                            m_samples.Set(m_curSample++, sample);
                        }
                    }
                    break;

                case XmlNodeType.EndElement:
                    if (reader.Depth <= inputDepth)
                    {
                        reader.Read();
                        goto Done;
                    }
                    break;

                case XmlNodeType.Text:
                default:
                    break;
                }
            }
            Done :;
#if DEBUG
            for (int i = 0; i < m_samples.Count; i++)
            {
                Debug.Assert(m_samples[i] != null);
            }
            for (int i = 0; i < m_frames.Count; i++)
            {
                Debug.Assert(m_frames[i] != null);
            }
            for (int i = 0; i < m_stacks.Count; i++)
            {
                Debug.Assert(m_stacks[i].frameID >= 0);
                Debug.Assert(m_stacks[i].callerID >= -1);
            }
#endif
        }
Exemple #32
0
    internal unsafe void ConvertHeapDataToGraph()
    {
        if (m_converted)
        {
            return;
        }
        m_converted = true;

        if (!m_seenStart)
        {
            throw new ApplicationException("ETL file did not include a Start Heap Dump Event");
        }

        if (!m_ignoreEvents)
        {
            throw new ApplicationException("ETL file did not include a Stop Heap Dump Event");
        }

        // Since we may have multiple roots, I create a pseudo-node to act as its parent.
        var root = new MemoryNodeBuilder(m_graph, "[JS Roots]");

        var nodeNames = new GrowableArray <string>(1000);

        for (; ;)
        {
            BulkNodeValues node;
            if (!GetNextNode(out node))
            {
                break;
            }

            // Get the node index
            var nodeIdx = m_graph.GetNodeIndex(node.Address);
            m_children.Clear();

            // Get the basic type name
            var typeName = "?";
            if (0 <= node.TypeNameId)
            {
                typeName = m_stringTable[node.TypeNameId];
                if (typeName.Length > 6 && typeName.EndsWith("Object"))
                {
                    typeName = "JS" + typeName.Substring(0, typeName.Length - 6);
                }
            }
            var relationships = "";

            // Process the edges (which can add children)
            for (int i = 0; i < node.EdgeCount; i++)
            {
                BulkEdgeValues edge;
                if (!GetNextEdge(out edge))
                {
                    throw new ApplicationException("Missing Edge Nodes in ETW data");
                }

                // Is this an edge to another object?  (externals count)
                if (edge.TargetType == EdgeTargetType.Object || edge.TargetType == EdgeTargetType.External)
                {
                    var childIdx = m_graph.GetNodeIndex((Address)edge.Value);

                    // Get the property name if it has one
                    string childPropertyName = null;
                    if (edge.RelationshipType == EdgeRelationshipType.NamedProperty || edge.RelationshipType == EdgeRelationshipType.Event)
                    {
                        childPropertyName = m_stringTable[edge.NameId];
                    }
                    else if (edge.RelationshipType == EdgeRelationshipType.IndexedProperty)
                    {
                        // The edge is an element of an array and the NameID is the index in the array.
                        // We want to treat all index properties as a single field
                        childPropertyName = "[]";
                    }
                    else if (edge.RelationshipType == EdgeRelationshipType.InternalProperty)
                    {
                        childPropertyName = "InternalProperty";
                    }

                    if (childPropertyName != null)
                    {
                        // Remember the property so that when we display the target object, we show that too.
                        if ((int)childIdx >= nodeNames.Count)
                        {
                            nodeNames.Count = (int)childIdx + 100;   // expand by at least 100.
                        }
                        nodeNames[(int)childIdx] = childPropertyName;
                    }
                    m_children.Add(childIdx);
                }
                else if (edge.TargetType == EdgeTargetType.BSTR)
                {
                    if (edge.RelationshipType == EdgeRelationshipType.RelationShip)
                    {
                        // This is extra information (typically the tag or a class of a HTML DOM object).  Add it to the type name.
                        var relationshipName  = m_stringTable[edge.NameId];
                        var relationshipValue = m_stringTable[(int)edge.Value];
                        if (relationships.Length > 0)
                        {
                            relationships += " ";
                        }
                        relationships += relationshipName + ":" + relationshipValue;
                    }
                }
            }

            // Get the property name we saved from things that refer to this object.
            string propertyName = null;
            if ((int)nodeIdx < nodeNames.Count)
            {
                propertyName = nodeNames[(int)nodeIdx];
                if (propertyName != null)
                {
                    nodeNames[(int)nodeIdx] = null;
                }
            }

            // Process the attributes.  We can get a good function name as well as some more children from the attributes.
            int objSize = node.Size;
            for (int i = 0; i < node.AttributeCount; i++)
            {
                BulkAttributeValues attribute;
                if (!GetNextAttribute(out attribute))
                {
                    throw new ApplicationException("Missing Attribute Nodes in ETW data");
                }

                // TODO FIX NOW Currently I include the prototype link.  is this a good idea?
                if (attribute.Type == AttributeType.Prototype)
                {
                    m_children.Add(m_graph.GetNodeIndex(attribute.Value));
                }
                else if (attribute.Type == AttributeType.Scope)
                {
                    // TODO FIX NOW: it seems that Value is truncated to 32 bits and we have to restore it.
                    // Feels like a hack (and not clear if it is correct)
                    var target = attribute.Value;
                    if ((target >> 32) == 0 && (node.Address >> 32) != 0)
                    {
                        target += node.Address & 0xFFFFFFFF00000000;
                    }
                    m_children.Add(m_graph.GetNodeIndex(target));
                }
                // WPA does this, I don't really understand it.
                if (attribute.Type == AttributeType.TextChildrenSize)
                {
                    objSize += (int)attribute.Value;
                }
                else if (attribute.Type == AttributeType.FunctionName)
                {
                    propertyName = m_stringTable[(int)attribute.Value];
                }
            }


            if (relationships.Length > 0)
            {
                typeName += " <|" + relationships + "|>";
            }
            // Create the complete type name
            if ((node.Flags & ObjectFlags.WINRT) != 0)
            {
                typeName = "(WinRT " + " " + typeName + ")";
            }
            else
            {
                typeName = "(Type " + " " + typeName + ")";
            }
            if (propertyName != null)
            {
                typeName = propertyName + " " + typeName;
            }

            // typeName += " [0x" + node.Address.ToString("x") + "]";
            var typeIdx = GetTypeIndex(typeName, node.Size);

            if ((node.Flags & ObjectFlags.IS_ROOT) != 0)
            {
                root.AddChild(nodeIdx);
            }

            if (!m_graph.IsDefined(nodeIdx))
            {
                m_graph.SetNode(nodeIdx, typeIdx, objSize, m_children);
            }
            else
            {
                // Only external objects might be listed twice.
                Debug.Assert((node.Flags & (ObjectFlags.EXTERNAL | ObjectFlags.EXTERNAL_UNKNOWN | ObjectFlags.EXTERNAL_DISPATCH |
                                            ObjectFlags.WINRT_DELEGATE | ObjectFlags.WINRT_INSTANCE | ObjectFlags.WINRT_NAMESPACE |
                                            ObjectFlags.WINRT_RUNTIMECLASS)) != 0);
            }
        }

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