示例#1
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");
        }
示例#2
0
    public static MemoryGraph ReadMemoryGraphFromXml(XmlReader reader)
    {
        if (reader.NodeType != XmlNodeType.Element)
        {
            throw new InvalidOperationException("Must advance to MemoryGraph element (e.g. call ReadToDescendant)");
        }

        var expectedSize = 1000;
        var nodeCount    = reader.GetAttribute("NodeCount");

        if (nodeCount != null)
        {
            expectedSize = int.Parse(nodeCount) + 1;        // 1 for undefined
        }

        MemoryGraph graph = new MemoryGraph(10);

        Debug.Assert((int)graph.NodeTypeIndexLimit == 1);
        var firstNode = graph.CreateNode();                             // Use one up

        Debug.Assert(firstNode == 0);
        Debug.Assert((int)graph.NodeIndexLimit == 1);

        var inputDepth = reader.Depth;

        reader.Read();      // Advance to children
        while (inputDepth < reader.Depth)
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.Name)
                {
                case "NodeTypes":
                    ReadNodeTypesFromXml(reader, graph);
                    break;

                case "Nodes":
                    ReadNodesFromXml(reader, graph);
                    break;

                case "RootIndex":
                    graph.RootIndex = (NodeIndex)reader.ReadElementContentAsInt();
                    break;

                default:
                    Debug.WriteLine("Skipping unknown element {0}", reader.Name);
                    reader.Skip();
                    break;
                }
            }
            else if (!reader.Read())
            {
                break;
            }
        }

        graph.AllowReading();
        return(graph);
    }
示例#3
0
    /// <summary>
    /// Read in the memory dump from javaScriptEtlName.   Since there can be more than one, choose the first one
    /// after double startTimeRelativeMSec.  If processId is non-zero only that process is considered, otherwise it considered
    /// the first heap dump regardless of process.
    /// </summary>
    public MemoryGraph Read(string javaScriptEtlName, int processId = 0, double startTimeRelativeMSec = 0)
    {
        var ret = new MemoryGraph(10000);

        Append(ret, javaScriptEtlName, processId, startTimeRelativeMSec);
        ret.AllowReading();
        return(ret);
    }
    public MemoryGraph Read(TraceEventDispatcher source, string processNameOrId = null, double startTimeRelativeMSec = 0)
    {
        var ret = new MemoryGraph(10000);

        Append(ret, source, processNameOrId, startTimeRelativeMSec);
        ret.AllowReading();
        return(ret);
    }
    /// <summary>
    /// Read in the memory dump from javaScriptEtlName.   Since there can be more than one, choose the first one
    /// after double startTimeRelativeMSec.  If processId is non-zero only that process is considered, otherwise it considered
    /// the first heap dump regardless of process.
    /// </summary>
    public MemoryGraph Read(string etlFilePath, string processNameOrId = null, double startTimeRelativeMSec = 0)
    {
        m_etlFilePath = etlFilePath;
        var ret = new MemoryGraph(10000);

        Append(ret, etlFilePath, processNameOrId, startTimeRelativeMSec);
        ret.AllowReading();
        return(ret);
    }
示例#6
0
    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);
    }
示例#7
0
        internal static bool TryCollectMemoryGraph(CancellationToken ct, int processId, int timeout, bool verbose,
                                                   out MemoryGraph memoryGraph)
        {
            var heapInfo = new DotNetHeapInfo();
            var log      = verbose ? Console.Out : TextWriter.Null;

            memoryGraph = new MemoryGraph(50_000);

            if (!EventPipeDotNetHeapDumper.DumpFromEventPipe(ct, processId, memoryGraph, log, timeout, heapInfo))
            {
                return(false);
            }

            memoryGraph.AllowReading();
            return(true);
        }
示例#8
0
    public MemoryGraph Read(string projectNMetaDataLog)
    {
        m_graph      = new MemoryGraph(1000);
        m_knownTypes = new Dictionary <string, NodeTypeIndex>(1000);

        using (TextReader reader = File.OpenText(projectNMetaDataLog))
        {
            int    lineNum = 0;
            string line;
            try
            {
                // Skip headers line
                line = reader.ReadLine();
                lineNum++;
                if (line == null)
                {
                    return(null);
                }

                LineData lineData = new LineData();
                for (; ;)
                {
                    line = reader.ReadLine();
                    if (line == null)
                    {
                        break;
                    }
                    lineNum++;

                    Match m = Regex.Match(line, "^(\\S+), +(\\S+), +\"(.*)\", +\"(.*?)\"$");
                    if (m.Success)
                    {
                        uint newOffset = uint.Parse(m.Groups[1].Value, NumberStyles.HexNumber) & 0xFFFFFF;
                        lineData.Size = (int)(newOffset - lineData.Offset);
                        if (lineNum > 2)
                        {
                            NodeIndex nodeIndex = AddLineData(ref lineData);
                            if (lineNum == 3)
                            {
                                m_graph.RootIndex = nodeIndex;
                            }
                        }

                        lineData.Offset = newOffset;
                        lineData.Kind   = m.Groups[2].Value.Replace("\\\"", "\"").Replace("\\\\", "\\");
                        lineData.Name   = m.Groups[3].Value.Replace("\\\"", "\"").Replace("\\\\", "\\");
                        lineData.Children.Clear();
                        if (m.Groups[4].Length > 0)
                        {
                            string[] handleStrs = m.Groups[4].Value.Split(' ');
                            foreach (var handleStr in handleStrs)
                            {
                                lineData.Children.Add(m_graph.GetNodeIndex(uint.Parse(handleStr, NumberStyles.HexNumber) & 0xFFFFFF));
                            }
                        }
                    }
                    else
                    {
                        throw new FileFormatException();
                    }
                }
                if (lineNum > 1)
                {
                    lineData.Size = 16;  // TODO Better estimate.
                    AddLineData(ref lineData);
                }
            }
            catch (Exception e)
            {
                throw new FileFormatException("Error on line number " + lineNum + "  " + e.Message);
            }
        }
        m_graph.AllowReading();
        return(m_graph);
    }
示例#9
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);
    }
        protected override async Task OnEventSourceAvailable(EventPipeEventSource eventSource, Func <Task> stopSessionAsync, CancellationToken token)
        {
            int gcNum = -1;

            Action <GCStartTraceData, Action> gcStartHandler = (GCStartTraceData data, Action taskComplete) =>
            {
                taskComplete();

                if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC)
                {
                    gcNum = data.Count;
                }
            };

            Action <GCBulkNodeTraceData, Action> gcBulkNodeHandler = (GCBulkNodeTraceData data, Action taskComplete) =>
            {
                taskComplete();
            };

            Action <GCEndTraceData, Action> gcEndHandler = (GCEndTraceData data, Action taskComplete) =>
            {
                if (data.Count == gcNum)
                {
                    taskComplete();
                }
            };

            // Register event handlers on the event source and represent their completion as tasks
            using var gcStartTaskSource = new EventTaskSource <Action <GCStartTraceData> >(
                      taskComplete => data => gcStartHandler(data, taskComplete),
                      handler => eventSource.Clr.GCStart += handler,
                      handler => eventSource.Clr.GCStart -= handler,
                      token);
            using var gcBulkNodeTaskSource = new EventTaskSource <Action <GCBulkNodeTraceData> >(
                      taskComplete => data => gcBulkNodeHandler(data, taskComplete),
                      handler => eventSource.Clr.GCBulkNode += handler,
                      handler => eventSource.Clr.GCBulkNode -= handler,
                      token);
            using var gcStopTaskSource = new EventTaskSource <Action <GCEndTraceData> >(
                      taskComplete => data => gcEndHandler(data, taskComplete),
                      handler => eventSource.Clr.GCStop += handler,
                      handler => eventSource.Clr.GCStop -= handler,
                      token);
            using var sourceCompletedTaskSource = new EventTaskSource <Action>(
                      taskComplete => taskComplete,
                      handler => eventSource.Completed += handler,
                      handler => eventSource.Completed -= handler,
                      token);

            // A task that is completed whenever GC data is received
            Task gcDataTask = Task.WhenAny(gcStartTaskSource.Task, gcBulkNodeTaskSource.Task);
            Task gcStopTask = gcStopTaskSource.Task;

            DotNetHeapDumpGraphReader dumper = new DotNetHeapDumpGraphReader(TextWriter.Null)
            {
                DotNetHeapInfo = new DotNetHeapInfo()
            };

            dumper.SetupCallbacks(_gcGraph, eventSource);

            // The event source will not always provide the GC events when it starts listening. However,
            // they will be provided when the event source is told to stop processing events. Give the
            // event source some time to produce the events, but if it doesn't start producing them within
            // a short amount of time (5 seconds), then stop processing events to allow them to be flushed.
            Task eventsTimeoutTask = Task.Delay(TimeSpan.FromSeconds(5), token);
            Task completedTask     = await Task.WhenAny(gcDataTask, eventsTimeoutTask);

            token.ThrowIfCancellationRequested();

            // If started receiving GC events, wait for the GC Stop event.
            if (completedTask == gcDataTask)
            {
                await gcStopTask;
            }

            // Stop receiving events; if haven't received events yet, this will force flushing of events.
            await stopSessionAsync();

            // Wait for all received events to be processed.
            await sourceCompletedTaskSource.Task;

            // Check that GC data and stop events were received. This is done by checking that the
            // associated tasks have ran to completion. If one of them has not reached the completion state, then
            // fail the GC dump operation.
            if (gcDataTask.Status != TaskStatus.RanToCompletion ||
                gcStopTask.Status != TaskStatus.RanToCompletion)
            {
                throw new InvalidOperationException("Unable to create GC dump due to incomplete GC data.");
            }

            dumper.ConvertHeapDataToGraph();

            _gcGraph.AllowReading();
        }