Exemplo n.º 1
0
        public override void ForEach(Action <StackSourceSample> callback)
        {
            // Initialize the priority
            if (m_typePriorities == null)
            {
                PriorityRegExs = DefaultPriorities;
            }
            Debug.Assert(m_typePriorities != null);

            // Initialize the breadth-first work queue.
            var nodesToVisit = new PriorityQueue(1024);

            nodesToVisit.Enqueue(m_graph.RootIndex, 0.0F);

            // reset the visited information.
            for (int i = 0; i < m_parent.Length; i++)
            {
                m_parent[i] = NodeIndex.Invalid;
            }

            // We keep track of node depth so that we can limit it.
            ushort[]    nodeDepth      = new ushort[m_parent.Length];
            float[]     nodePriorities = new float[m_parent.Length];
            MemoryGraph asMemoryGraph  = m_graph as MemoryGraph;

            bool  scanedForOrphans = false;
            var   epsilon          = 1E-7F; // Something that is big enough not to bet lost in roundoff error.
            float order            = 0;

            for (int i = 0; ; i++)
            {
                if ((i & 0x1FFF) == 0)                // Every 8K
                {
                    System.Threading.Thread.Sleep(0); // Allow interruption.
                }
                NodeIndex nodeIndex;
                float     nodePriority;
                if (nodesToVisit.Count == 0)
                {
                    nodePriority = 0;
                    if (!scanedForOrphans)
                    {
                        scanedForOrphans = true;
                        AddOrphansToQueue(nodesToVisit);
                    }
                    if (nodesToVisit.Count == 0)
                    {
                        return;
                    }
                }
                nodeIndex = nodesToVisit.Dequeue(out nodePriority);

                // Insert any children that have not already been visited (had a parent assigned) into the work queue).
                Node node           = m_graph.GetNode(nodeIndex, m_nodeStorage);
                var  parentPriority = nodePriorities[(int)node.Index];
                for (var childIndex = node.GetFirstChildIndex(); childIndex != NodeIndex.Invalid; childIndex = node.GetNextChildIndex())
                {
                    if (m_parent[(int)childIndex] == NodeIndex.Invalid && childIndex != m_graph.RootIndex)
                    {
                        m_parent[(int)childIndex] = nodeIndex;
                        ushort parentDepth = nodeDepth[(int)nodeIndex];
                        if (parentDepth > MaxDepth)
                        {
                            m_log.WriteLine("WARNING: Orphaned node with index {0} because its depth from root exceeded {1}", childIndex, MaxDepth);
                            continue;                   // TODO today we just drop it, but we should add it to some special overflow node.
                        }
                        nodeDepth[(int)childIndex] = (ushort)(parentDepth + 1);

                        // the priority of the child is determined by its type and 1/10 by its parent.
                        var child         = m_graph.GetNode(childIndex, m_childStorage);
                        var childPriority = m_typePriorities[(int)child.TypeIndex] + parentPriority / 10;
                        nodePriorities[(int)childIndex] = childPriority;

                        // Subtract a small increasing value to keep the queue in order if the priorities are the same.
                        // This is a bit of a hack since it can get big and perturb the user-defined order.
                        order += epsilon;
                        nodesToVisit.Enqueue(childIndex, childPriority - order);
                    }
                }

                // Return the node.
                m_sampleStorage.Metric = node.Size;
                // We use the address as the timestamp.  This allows you to pick particular instances
                // and see where particular instances are in memory by looking at the 'time'.
                if (asMemoryGraph != null)
                {
                    m_sampleStorage.TimeRelativeMSec = asMemoryGraph.GetAddress(node.Index);
                }

                m_sampleStorage.SampleIndex = (StackSourceSampleIndex)node.Index;
                m_sampleStorage.StackIndex  = (StackSourceCallStackIndex)node.Index;
                if (m_countMultipliers != null)
                {
                    m_sampleStorage.Count  = m_countMultipliers[(int)node.TypeIndex];
                    m_sampleStorage.Metric = node.Size * m_sampleStorage.Count;
                }
                Debug.Assert(m_sampleStorage.Metric >= 0);
                Debug.Assert(m_sampleStorage.Count >= 0);
                Debug.Assert(0 < m_sampleStorage.Count && m_sampleStorage.Count <= float.MaxValue);
                Debug.Assert(0 <= m_sampleStorage.Metric && m_sampleStorage.Metric <= float.MaxValue);
                callback(m_sampleStorage);
            }
        }