Example #1
0
        public CSVStackSource(CSVReader reader, string eventName, double startRelativeMSec, double endRelativeMSec)
        {
            lock (reader)
            {
                reader.m_stackEventType = eventName;
                reader.T0 = (long)(startRelativeMSec * 1000);
                reader.T1 = long.MaxValue - 1000000;
                double endusec = endRelativeMSec * 1000;
                if (endusec < reader.T1)
                {
                    reader.T1 = (long)endusec;
                }

                reader.m_trace.Parameters.T0 = reader.T0;
                reader.m_trace.Parameters.T1 = reader.T1;

                var result = reader.m_trace.StackStream(delegate(ETLTrace.Frame frame, ETLTrace.TreeComputer treeComputer, long timeUsec, ulong weight)
                {
                    m_fullModulePaths        = treeComputer.fullModuleNames;
                    StackSourceSample sample = new StackSourceSample(this);
                    sample.TimeRelativeMSec  = timeUsec / 1000.0;
                    sample.Metric            = weight;

                    if (reader.m_stackEventType == "CSwitch")
                    {
                        sample.Metric = sample.Metric / 1000.0F;
                    }

                    if (sample.Metric == 0)
                    {
                        sample.Metric = 1;
                    }

                    // Get rid of quotes.
                    treeComputer.fullModuleNames["\"Unknown\""] = "UNKNOWN";

                    // We are traversing frames from the root (threadStart), to leaf (caller before callee).
                    StackSourceCallStackIndex stackIndex = StackSourceCallStackIndex.Invalid;
                    bool callerFrameIsThread             = false;
                    while (frame != null)
                    {
                        var fullFrameName = treeComputer.atomsNodeNames.MakeString(frame.id);
                        string moduleName = "";

                        // Parse it into module and function name
                        var frameName = fullFrameName;
                        var index     = fullFrameName.IndexOf('!');
                        if (index >= 0)
                        {
                            frameName  = fullFrameName.Substring(index + 1);
                            frameName  = frameName.Replace(';', ',');   // They use ';' for template separators for some reason, fix it.
                            moduleName = fullFrameName.Substring(0, index);
                            string fullModuleName;
                            if (treeComputer.fullModuleNames.TryGetValue(moduleName, out fullModuleName))
                            {
                                moduleName = fullModuleName;
                            }

                            if (moduleName.Length > 4 && moduleName[moduleName.Length - 4] == '.')
                            {
#if false // TODO decide if we want to ignore the .NI.DLL and if so do it uniformly.
                                if (moduleName.Length > 7 && moduleName[moduleName.Length - 7] == '.' &&
                                    moduleName[moduleName.Length - 6] == 'n' &&
                                    moduleName[moduleName.Length - 5] == 'i')
                                {
                                    moduleName = moduleName.Substring(0, moduleName.Length - 7);
                                }
                                else
#endif
                                moduleName = moduleName.Substring(0, moduleName.Length - 4);
                            }

                            // If the thread does not call into ntdll, we consider it broken
                            if (callerFrameIsThread && !moduleName.EndsWith("ntdll", StringComparison.Ordinal))
                            {
                                var brokenFrame = Interner.FrameIntern("BROKEN", Interner.ModuleIntern(""));
                                stackIndex      = Interner.CallStackIntern(brokenFrame, stackIndex);
                            }
                        }
                        else
                        {
                            Match m = Regex.Match(frameName, @"^tid *\( *(\d+)\)");
                            if (m.Success)
                            {
                                frameName = "Thread (" + m.Groups[1].Value + ")";
                            }
                            else
                            {
                                m = Regex.Match(frameName, @"^(.*?)(\.exe)? *\( *(\d+)\) *$");
                                if (m.Success)
                                {
                                    frameName = "Process " + m.Groups[1].Value + " (" + m.Groups[3].Value + ")";
                                }
                            }
                        }

                        var myModuleIndex   = Interner.ModuleIntern(moduleName);
                        var myFrameIndex    = Interner.FrameIntern(frameName, myModuleIndex);
                        stackIndex          = Interner.CallStackIntern(myFrameIndex, stackIndex);
                        callerFrameIsThread = frameName.StartsWith("tid ");
                        frame = frame.next;
                    }

                    sample.StackIndex = stackIndex;
                    AddSample(sample);
                });
                Interner.DoneInterning();
            }
        }
 public static StackSourceCallStackIndex IndexOf(this IndexMap map, int source, StackSourceCallStackIndex offset)
 {
     return((StackSourceCallStackIndex)map.IndexOf(source, (int)offset));
 }
Example #3
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
        }
        /// <summary>
        /// Generate the thread time stacks, outputting to 'stackSource'.
        /// </summary>
        /// <param name="outputStackSource"></param>
        /// <param name="traceEvents">Optional filtered trace events.</param>
        public void GenerateThreadTimeStacks(MutableTraceEventStackSource outputStackSource, TraceEvents traceEvents = null)
        {
            m_outputStackSource   = outputStackSource;
            m_sample              = new StackSourceSample(outputStackSource);
            m_nodeNameInternTable = new Dictionary <double, StackSourceFrameIndex>(10);
            m_ExternalFrameIndex  = outputStackSource.Interner.FrameIntern("UNMANAGED_CODE_TIME");
            m_cpuFrameIndex       = outputStackSource.Interner.FrameIntern("CPU_TIME");

            TraceLogEventSource eventSource = traceEvents == null?m_eventLog.Events.GetSource() :
                                                  traceEvents.GetSource();

            if (GroupByStartStopActivity)
            {
                UseTasks = true;
            }

            if (UseTasks)
            {
                m_activityComputer = new ActivityComputer(eventSource, m_symbolReader);
                m_activityComputer.AwaitUnblocks += delegate(TraceActivity activity, TraceEvent data)
                {
                    var sample = m_sample;
                    sample.Metric           = (float)(activity.StartTimeRelativeMSec - activity.CreationTimeRelativeMSec);
                    sample.TimeRelativeMSec = activity.CreationTimeRelativeMSec;

                    // The stack at the Unblock, is the stack at the time the task was created (when blocking started).
                    sample.StackIndex = m_activityComputer.GetCallStackForActivity(m_outputStackSource, activity, GetTopFramesForActivityComputerCase(data, data.Thread(), true));

                    StackSourceFrameIndex awaitFrame = m_outputStackSource.Interner.FrameIntern("AWAIT_TIME");
                    sample.StackIndex = m_outputStackSource.Interner.CallStackIntern(awaitFrame, sample.StackIndex);

                    m_outputStackSource.AddSample(sample);

                    if (m_threadToStartStopActivity != null)
                    {
                        UpdateStartStopActivityOnAwaitComplete(activity, data);
                    }
                };

                // We can provide a bit of extra value (and it is useful for debugging) if we immediately log a CPU
                // sample when we schedule or start a task.  That we we get the very instant it starts.
                var tplProvider = new TplEtwProviderTraceEventParser(eventSource);
                tplProvider.AwaitTaskContinuationScheduledSend += OnSampledProfile;
                tplProvider.TaskScheduledSend += OnSampledProfile;
                tplProvider.TaskExecuteStart  += OnSampledProfile;
                tplProvider.TaskWaitSend      += OnSampledProfile;
                tplProvider.TaskWaitStop      += OnTaskUnblock; // Log the activity stack even if you don't have a stack.
            }

            if (GroupByStartStopActivity)
            {
                m_startStopActivities = new StartStopActivityComputer(eventSource, m_activityComputer);

                // Maps thread Indexes to the start-stop activity that they are executing.
                m_threadToStartStopActivity = new StartStopActivity[m_eventLog.Threads.Count];

                /*********  Start Unknown Async State machine for StartStop activities ******/
                // The delegates below along with the AddUnkownAsyncDurationIfNeeded have one purpose:
                // To inject UNKNOWN_ASYNC stacks when there is an active start-stop activity that is
                // 'missing' time.   It has the effect of insuring that Start-Stop tasks always have
                // a metric that is not unrealistically small.
                m_activityComputer.Start += delegate(TraceActivity activity, TraceEvent data)
                {
                    StartStopActivity newStartStopActivityForThread = m_startStopActivities.GetCurrentStartStopActivity(activity.Thread, data);
                    UpdateThreadToWorkOnStartStopActivity(activity.Thread, newStartStopActivityForThread, data);
                };

                m_activityComputer.AfterStop += delegate(TraceActivity activity, TraceEvent data, TraceThread thread)
                {
                    StartStopActivity newStartStopActivityForThread = m_startStopActivities.GetCurrentStartStopActivity(thread, data);
                    UpdateThreadToWorkOnStartStopActivity(thread, newStartStopActivityForThread, data);
                };

                m_startStopActivities.Start += delegate(StartStopActivity startStopActivity, TraceEvent data)
                {
                    // We only care about the top-most activities since unknown async time is defined as time
                    // where a top  most activity is running but no thread (or await time) is associated with it
                    // fast out otherwise (we just insure that we mark the thread as doing this activity)
                    if (startStopActivity.Creator != null)
                    {
                        UpdateThreadToWorkOnStartStopActivity(data.Thread(), startStopActivity, data);
                        return;
                    }

                    // Then we have a refcount of exactly one
                    Debug.Assert(m_unknownTimeStartMsec.Get((int)startStopActivity.Index) >= 0); // There was nothing running before.

                    m_unknownTimeStartMsec.Set((int)startStopActivity.Index, -1);                // Set it so just we are running.
                    m_threadToStartStopActivity[(int)data.Thread().ThreadIndex] = startStopActivity;
                };

                m_startStopActivities.Stop += delegate(StartStopActivity startStopActivity, TraceEvent data)
                {
                    // We only care about the top-most activities since unknown async time is defined as time
                    // where a top  most activity is running but no thread (or await time) is associated with it
                    // fast out otherwise
                    if (startStopActivity.Creator != null)
                    {
                        return;
                    }

                    double unknownStartTime = m_unknownTimeStartMsec.Get((int)startStopActivity.Index);
                    if (0 < unknownStartTime)
                    {
                        AddUnkownAsyncDurationIfNeeded(startStopActivity, unknownStartTime, data);
                    }

                    // Actually emit all the async unknown events.
                    List <StackSourceSample> samples = m_startStopActivityToAsyncUnknownSamples.Get((int)startStopActivity.Index);
                    if (samples != null)
                    {
                        foreach (var sample in samples)
                        {
                            m_outputStackSource.AddSample(sample);  // Adding Unknown ASync
                        }

                        m_startStopActivityToAsyncUnknownSamples.Set((int)startStopActivity.Index, null);
                    }

                    m_unknownTimeStartMsec.Set((int)startStopActivity.Index, 0);
                    Debug.Assert(m_threadToStartStopActivity[(int)data.Thread().ThreadIndex] == startStopActivity ||
                                 m_threadToStartStopActivity[(int)data.Thread().ThreadIndex] == null);
                    m_threadToStartStopActivity[(int)data.Thread().ThreadIndex] = null;
                };
            }

            eventSource.Clr.GCAllocationTick          += OnSampledProfile;
            eventSource.Clr.GCSampledObjectAllocation += OnSampledProfile;

            var eventPipeTraceEventPraser = new SampleProfilerTraceEventParser(eventSource);

            eventPipeTraceEventPraser.ThreadSample += OnSampledProfile;

            if (IncludeEventSourceEvents)
            {
                eventSource.Dynamic.All += delegate(TraceEvent data)
                {
                    // TODO decide what the correct heuristic is.
                    // Currently I only do this for things that might be an EventSoruce (uses the name->Guid hashing)
                    // Most importantly, it excludes the high volume CLR providers.
                    if (!TraceEventProviders.MaybeAnEventSource(data.ProviderGuid))
                    {
                        return;
                    }

                    //  We don't want most of the FrameworkEventSource events either.
                    if (data.ProviderGuid == FrameworkEventSourceTraceEventParser.ProviderGuid)
                    {
                        if (!((TraceEventID)140 <= data.ID && data.ID <= (TraceEventID)143))    // These are the GetResponce and GetResestStream events
                        {
                            return;
                        }
                    }

                    // We don't care about EventPipe sample profiler events.
                    if (data.ProviderGuid == SampleProfilerTraceEventParser.ProviderGuid)
                    {
                        return;
                    }

                    // We don't care about the TPL provider.  Too many events.
                    if (data.ProviderGuid == TplEtwProviderTraceEventParser.ProviderGuid)
                    {
                        return;
                    }

                    // We don't care about ManifestData events.
                    if (data.ID == (TraceEventID)0xFFFE)
                    {
                        return;
                    }

                    TraceThread thread = data.Thread();
                    if (thread == null)
                    {
                        return;
                    }

                    StackSourceCallStackIndex stackIndex = GetCallStack(data, thread);

                    // Tack on additional info about the event.
                    var fieldNames = data.PayloadNames;
                    for (int i = 0; i < fieldNames.Length; i++)
                    {
                        var fieldName      = fieldNames[i];
                        var value          = data.PayloadString(i);
                        var fieldNodeName  = "EventData: " + fieldName + "=" + value;
                        var fieldNodeIndex = m_outputStackSource.Interner.FrameIntern(fieldNodeName);
                        stackIndex = m_outputStackSource.Interner.CallStackIntern(fieldNodeIndex, stackIndex);
                    }
                    stackIndex = m_outputStackSource.Interner.CallStackIntern(m_outputStackSource.Interner.FrameIntern("EventName: " + data.ProviderName + "/" + data.EventName), stackIndex);

                    m_threadState[(int)thread.ThreadIndex].LogThreadStack(data.TimeStampRelativeMSec, stackIndex, thread, this, false);
                };
            }

            eventSource.Process();

            m_outputStackSource.DoneAddingSamples();
            m_threadState = null;
        }
Example #5
0
 /// <summary>
 /// Get the frame index of a given call stack.
 /// </summary>
 /// <param name="callStackIndex">The call stack to look up.</param>
 /// <returns>The frame index of the call stack, if it exists, <see cref="StackSourceFrameIndex.Invalid"/> otherwise.</returns>
 public override StackSourceFrameIndex GetFrameIndex(StackSourceCallStackIndex callStackIndex)
 {
     return((callStackIndex - StackSourceCallStackIndex.Start) + StackSourceFrameIndex.Start);
 }
        private StackSourceCallStackIndex InternFrames(IEnumerator <Frame> frameIterator, StackSourceCallStackIndex stackIndex, int processID, int?threadid = null, BlockedTimeAnalyzer blockedTimeAnalyzer = null)
        {
            // We shouldn't advance the iterator if thread time is enabled because we need
            //   to add an extra frame to the caller stack that is not in the frameIterator.
            //   i.e. Short-circuiting prevents the frameIterator from doing MoveNext :)
            if (blockedTimeAnalyzer == null && !frameIterator.MoveNext())
            {
                return(StackSourceCallStackIndex.Invalid);
            }

            StackSourceFrameIndex frameIndex;
            string frameDisplayName;

            if (blockedTimeAnalyzer != null)
            {
                // If doThreadTime is true, then we need to make sure that threadid is not null
                Contract.Requires(threadid != null, nameof(threadid));

                if (blockedTimeAnalyzer.IsThreadBlocked((int)threadid))
                {
                    frameDisplayName = LinuxThreadState.BLOCKED_TIME.ToString();
                }
                else
                {
                    frameDisplayName = LinuxThreadState.CPU_TIME.ToString();
                }
            }
            else
            {
                frameDisplayName = frameIterator.Current.DisplayName;
            }

            frameIndex = this.InternFrame(frameDisplayName);

            stackIndex = this.InternCallerStack(frameIndex, this.InternFrames(frameIterator, stackIndex, processID));

            return(stackIndex);
        }
 public override StackSourceFrameIndex GetFrameIndex(StackSourceCallStackIndex callStackIndex)
 => samples.First(sample => sample.StackIndex == callStackIndex).FrameIndex;
Example #8
0
        public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
        {
            NodeIndex nodeIndex = (NodeIndex)callStackIndex;

            return((StackSourceCallStackIndex)m_parent[(int)nodeIndex]);
        }
Example #9
0
        /// <summary>
        /// Implementation of StackSource protocol.
        /// </summary>
        public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
        {
            Debug.Assert(callStackIndex >= 0);
            Debug.Assert(StackSourceCallStackIndex.Start == 0);         // If there are any cases before start, we need to handle them here.

            int curIndex  = (int)callStackIndex - (int)StackSourceCallStackIndex.Start;
            int nextIndex = (int)StackSourceCallStackIndex.Start;

            if (curIndex < m_log.CallStacks.Count)
            {
                var nextCallStackIndex = m_log.CallStacks.Caller((CallStackIndex)curIndex);
                if (nextCallStackIndex == CallStackIndex.Invalid)
                {
                    nextIndex += m_log.CallStacks.Count;    // Now points at the threads region.
                    var threadIndex = m_log.CallStacks.ThreadIndex((CallStackIndex)curIndex);
                    nextIndex += (int)threadIndex;

                    // Mark it as a broken stack, which come after all the indexes for normal threads and processes.
                    if (!ReasonableTopFrame(callStackIndex, threadIndex))
                    {
                        nextIndex += m_log.Threads.Count + m_log.Processes.Count;
                    }
                }
                else
                {
                    nextIndex += (int)nextCallStackIndex;
                }
                return((StackSourceCallStackIndex)nextIndex);
            }
            curIndex  -= m_log.CallStacks.Count;                                // Now is a thread index
            nextIndex += m_log.CallStacks.Count;                                // Output index points to the thread region.

            if (curIndex < m_log.Threads.Count)
            {
                nextIndex += m_log.Threads.Count;                                  // Output index point to process region.
                nextIndex += (int)m_log.Threads[(ThreadIndex)curIndex].Process.ProcessIndex;
                return((StackSourceCallStackIndex)nextIndex);
            }
            curIndex -= m_log.Threads.Count;                                      // Now is a broken thread index

            if (curIndex < m_log.Processes.Count)
            {
                return(StackSourceCallStackIndex.Invalid);                        // Process has no parent
            }
            curIndex -= m_log.Processes.Count;                                    // Now is a broken thread index

            if (curIndex < m_log.Threads.Count)                                   // It is a broken stack
            {
                nextIndex += curIndex;                                            // Indicate the real thread.
                return((StackSourceCallStackIndex)nextIndex);
            }
            curIndex -= m_log.Threads.Count;                                       // Now it points at the one-element stacks.

            if (curIndex < m_pseudoStacks.Count)
            {
                // Now points beginning of the broken stacks indexes.
                nextIndex += m_log.Threads.Count + m_log.Processes.Count;

                // Pick the broken stack for this thread.
                nextIndex += (int)m_pseudoStacks[curIndex].ThreadIndex;
                return((StackSourceCallStackIndex)nextIndex);
            }

            Debug.Assert(false, "Invalid CallStackIndex");
            return(StackSourceCallStackIndex.Invalid);
        }
        private void AddSamplesForDirectory(string directoryPath, StackSourceCallStackIndex directoryStack)
        {
            StackSourceSample sample = null;

            try
            {
                var directory = new FastDirectory(directoryPath);
                foreach (var member in directory.Members)
                {
                    if (member.IsDirectory)
                    {
                        var stack = Interner.CallStackIntern(Interner.FrameIntern("DIR: " + member.Name), directoryStack);
                        AddSamplesForDirectory(Path.Combine(directoryPath, member.Name), stack);
                    }
                    else
                    {
                        var stack = directoryStack;

                        // Allow easy grouping by extension.
                        var ext = Path.GetExtension(member.Name).ToLower();
                        // And whether the DLL/EXE is managed or not.
                        var suffix = "";
                        if (string.Compare(ext, ".dll", true) == 0 || string.Compare(ext, ".exe", true) == 0 || string.Compare(ext, ".winmd", true) == 0)
                        {
                            suffix = "";
                            string fileName = Path.Combine(directoryPath, member.Name);
                            try
                            {
                                using (var peFile = new PEFile.PEFile(fileName))
                                {
                                    suffix = peFile.Header.IsManaged ? " (MANAGED)" : " (UNMANAGED)";
                                    if (peFile.Header.IsPE64)
                                    {
                                        suffix += " (64Bit)";
                                    }
                                    if (peFile.HasPrecompiledManagedCode)
                                    {
                                        if (peFile.IsManagedReadyToRun)
                                        {
                                            short major, minor;
                                            peFile.ReadyToRunVersion(out major, out minor);
                                            suffix += " (ReadyToRun(" + major + "." + minor + "))";
                                        }
                                        else
                                        {
                                            suffix += " (NGEN)";
                                        }
                                    }
                                }
                            }
                            catch (Exception) {
                                m_log.WriteLine("Error: exception looking at file " + fileName);
                                m_log.Flush();
                            }
                        }
                        stack = Interner.CallStackIntern(Interner.FrameIntern("EXT: " + ext + suffix), stack);

                        // Finally the file name itself.
                        stack = Interner.CallStackIntern(Interner.FrameIntern("FILE: " + member.Name), stack);
                        if (sample == null)
                        {
                            sample = new StackSourceSample(this);
                        }

                        sample.Metric     = member.Size;
                        sample.StackIndex = stack;
                        if (m_useWriteTime)
                        {
                            sample.TimeRelativeMSec = (m_nowUtc - member.LastWriteTimeUtc).TotalDays;
                        }
                        else
                        {
                            sample.TimeRelativeMSec = (m_nowUtc - member.LastAccessTimeUtc).TotalDays;
                        }
                        AddSample(sample);

                        m_totalSize += member.Size;
                        int count = SampleIndexLimit;
                        if ((count % 1000) == 0)
                        {
                            m_log.WriteLine("[Processed " + count + " files, size " + (m_totalSize / 1000000).ToString("n0") + " MB in directory scan at " + Path.Combine(directoryPath, member.Name) + " ]");
                        }
                    }
                }
            }
            catch (Exception e)
            {
                m_log.WriteLine("Error processing directory " + directoryPath + ": " + e.Message);
            }
        }
 public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
 {
     return(StackSourceCallStackIndex.Invalid);
 }
Example #12
0
 public override StackSourceFrameIndex GetFrameIndex(StackSourceCallStackIndex callStackIndex)
 {
     return(this.inner.GetFrameIndex(callStackIndex));
 }
Example #13
0
 public override int GetNumberOfFoldedFrames(StackSourceCallStackIndex callStackIndex)
 {
     return(this.inner.GetNumberOfFoldedFrames(callStackIndex));
 }
        private 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();
        }
 protected override StackSourceCallStackIndex InternCallerStack(StackSourceFrameIndex frameIndex, StackSourceCallStackIndex stackIndex)
 {
     lock (internCallStackLock)
     {
         return(this.Interner.CallStackIntern(frameIndex, stackIndex));
     }
 }
Example #16
0
 public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
 {
     Debug.Assert(callStackIndex >= 0);
     // subtract 1 so 0 (clrprofiler Scentinal) becomes CallStackIndex Sentinal
     return((StackSourceCallStackIndex)(m_clrProfiler.NextFrame((ProfilerStackTraceID)(callStackIndex + 1)) - 1));
 }
 protected virtual StackSourceCallStackIndex InternCallerStack(StackSourceFrameIndex frameIndex, StackSourceCallStackIndex stackIndex)
 {
     return(this.Interner.CallStackIntern(frameIndex, stackIndex));
 }
        private static bool BuildInternalTempRepresentation(StackSource stackSource, string fileToWrite, string rootFunction)
        {
            StringBuilder flameChartStringBuilder = new StringBuilder();
            bool          enableRootingOnFunction = !string.IsNullOrWhiteSpace(rootFunction);

            // Write out the flame chart format, one line per stack
            // eg: corerun;foo;bar;baz 1
            stackSource.ForEach(sample =>
            {
                Stack <StackSourceCallStackIndex> callStackIndices = new Stack <StackSourceCallStackIndex>();

                callStackIndices.Push(sample.StackIndex);

                StackSourceCallStackIndex callerIdx = stackSource.GetCallerIndex(sample.StackIndex);
                while (callerIdx != StackSourceCallStackIndex.Invalid)
                {
                    callStackIndices.Push(callerIdx);
                    callerIdx = stackSource.GetCallerIndex(callerIdx);
                }

                bool firstOne          = true;
                bool foundRootFunction = false;
                while (callStackIndices.Count > 0)
                {
                    var currFrame = callStackIndices.Pop();
                    var frameIdx  = stackSource.GetFrameIndex(currFrame);

                    var frameName = stackSource.GetFrameName(frameIdx, false);

                    // If we're rooting on a function, skip the frames above it
                    if (enableRootingOnFunction && !foundRootFunction)
                    {
                        if (frameName.Contains(rootFunction))
                        {
                            foundRootFunction = true;
                        }
                        else
                        {
                            continue;
                        }
                    }

                    if (!firstOne)
                    {
                        flameChartStringBuilder.Append(";");
                    }

                    flameChartStringBuilder.Append(frameName);
                    firstOne = false;
                }

                flameChartStringBuilder.Append(" 1");
                flameChartStringBuilder.AppendLine();
            });

            using (TextWriter writer = File.CreateText(fileToWrite))
            {
                try
                {
                    writer.Write(flameChartStringBuilder.ToString());
                }
                catch (IOException)
                {
                    return(false);
                }
            }

            return(true);
        }
 public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
 => samples.First(sample => sample.StackIndex == callStackIndex).CallerIndex;
Example #20
0
        /// <summary>
        /// Generates a Stack Source from an XML file created with XmlStackSourceWriter.
        /// If 'readElement' is non-null Any XML Elements that are not recognised to it so
        /// that that information can be parsed by upper level logic.  When that routine
        /// returns it must have skipped past that element (so reader points at whatever
        /// is after the End element tag).
        ///
        /// If the filename ends in .zip, the file is assumed to be a ZIPPed XML file and
        /// it is first Unziped and then processed.
        ///
        /// If the file ends in .json or .json.zip it can also read that (using JsonReaderWriterFactory.CreateJsonReader)
        /// see https://msdn.microsoft.com/en-us/library/bb412170.aspx?f=255&amp;MSPPError=-2147217396 for
        /// more on this mapping.
        /// </summary>
        public XmlStackSource(string fileName, Action <XmlReader> readElement = null)
        {
            using (Stream dataStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
            {
                var    xmlStream    = dataStream;
                string unzippedName = fileName;
                if (fileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
                {
                    var zipArchive = new ZipArchive(dataStream);
                    var entries    = zipArchive.Entries;
                    if (entries.Count != 1)
                    {
                        throw new ApplicationException("The ZIP file does not have exactly 1 XML file in it,");
                    }
                    xmlStream    = entries[0].Open();
                    unzippedName = fileName.Substring(0, fileName.Length - 4);
                }

                XmlReader reader;
                if (unzippedName.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
                {
                    reader = GetJsonReader(dataStream);
                }
                else
                {
                    XmlReaderSettings settings = new XmlReaderSettings()
                    {
                        IgnoreWhitespace = true, IgnoreComments = true
                    };
                    reader = XmlTextReader.Create(xmlStream, settings);
                }

                reader.Read();      // Skip the StackWindow element.
                bool readStackSource = false;
                for (;;)
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        if (reader.Name == "StackSource")
                        {
                            if (!readStackSource)
                            {
                                Read(reader);
                                readStackSource = true;
                            }
                        }
                        else if (readElement != null)
                        {
                            readElement(reader);
                        }
                        else
                        {
                            reader.Read();
                        }
                    }
                    else if (!reader.Read())
                    {
                        break;
                    }
                }
                if (m_interner != null)
                {
                    // Transfer the interned names to the m_frames array.
                    // Go from high to low so at most one reallocation happens.
                    for (int i = m_interner.FrameCount - 1; 0 <= i; --i)
                    {
                        StackSourceFrameIndex frameIdx = m_interner.FrameStartIndex + i;
                        m_frames.Set((int)frameIdx, m_interner.GetFrameName(frameIdx, true));
                    }

                    for (int i = m_interner.CallStackCount - 1; 0 <= i; --i)
                    {
                        StackSourceCallStackIndex stackIdx = m_interner.CallStackStartIndex + i;
                        m_stacks.Set((int)stackIdx, new Frame(
                                         (int)m_interner.GetFrameIndex(stackIdx),
                                         (int)m_interner.GetCallerIndex(stackIdx)));
                    }

                    m_interner = null;  // we are done with it.
                }
            }
        }
Example #21
0
    /// <summary>
    /// If you place a file called PerfViewExtensions\PerfViewStartup next to the PerfView.exe it will
    /// run execute commands in that file.  If you put
    ///
    /// DeclareFileView .etl "Demo View In Etl File" DemoDeclareFileView
    ///
    /// It will create a child node for all .etl files called 'Demo View In Etl File'  If you click
    /// on this node it will execute this user command.  It is passed the name of the file that was
    /// opened and the name of the view that was opened (in this case 'Demo View In Etl File').
    /// </summary>
    public void DemoDeclareFileView(string fileName, string viewName)
    {
        // This demo creates a view that shows you all the START events in a stack view.
        LogFile.WriteLine("************ In DemoDeclareFileView file = {0} view = {1}", fileName, viewName);

        // This is an example of opening an ETL file.
        ETLDataFile etlFile = OpenETLFile(fileName);

        // An ETLData file is a high level construct that knows about high level 'views' of the data (CPU stacks, thread time Stacks ...)

        // However if you want to create a new view, you probably want a TraceLog which is the underlying ETW data.
        TraceLog traceLog = etlFile.TraceLog;

        // A tracelog represent the whole ETL file (which has process, images, threads etc), we want events, and we want callbacks
        // for each event which is what GetSource() does.   THus we get a source (which we can add callbacks to)
        var eventSource = traceLog.Events.GetSource();

        // At this point create the 'output' of our routine.  Our goal is to produce stacks that we will view in the
        // stack viewer.   Thus we create an 'empty' one fo these.
        var stackSource = new MutableTraceEventStackSource(traceLog);
        // A stack source is  list of samples.  We create a sample structure, mutate it and then call AddSample() repeatedly to add samples.
        var sample = new StackSourceSample(stackSource);

        // Setup the callbacks, In this case we are going to watch for stacks where GCs happen
        eventSource.Clr.GCStart += delegate(GCStartTraceData data)
        {
            // An TraceLog should have a callstack associated with this event;
            CallStackIndex callStackIdx = data.CallStackIndex();
            if (callStackIdx != CallStackIndex.Invalid)
            {
                // Convert the TraceLog call stack to a MutableTraceEventStackSource call stack
                StackSourceCallStackIndex stackCallStackIndex = stackSource.GetCallStack(callStackIdx, data);

                // Add a pseudo frame on the bottom of the stack
                StackSourceFrameIndex frameIdxForName = stackSource.Interner.FrameIntern("GC Gen " + data.Depth + "Reason " + data.Reason);
                stackCallStackIndex = stackSource.Interner.CallStackIntern(frameIdxForName, stackCallStackIndex);

                // create a sample with that stack and add it to the stack source (list of samples)
                sample.Metric           = 1;
                sample.TimeRelativeMSec = data.TimeStampRelativeMSec;
                sample.StackIndex       = stackCallStackIndex;
                stackSource.AddSample(sample);
            }
        };
        // You can set up other callback for other events.

        // This causes the TraceLog source to actually spin through all the events calling our callbacks as requested.
        eventSource.Process();

        // We are done adding sample to our stack Source, so we tell the MutableTraceEventStackSource that.
        // after that is becomes viewable (and read-only).
        stackSource.DoneAddingSamples();

        // Take the stack source (raw data) and make it into a 'Stacks' allows you to add filtering to and send to 'OpendStackViewer'
        Stacks stacksForViewer = new Stacks(stackSource, viewName, etlFile);

        // Set any filtering options here.

        // Now we can display the viewer.
        OpenStackViewer(stacksForViewer);
    }
Example #22
0
 public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
 {
     return((StackSourceCallStackIndex)m_stacks[(int)callStackIndex].callerID);
 }
Example #23
0
 /// <summary>
 /// Gets the index of the caller of a given call stack.
 /// </summary>
 /// <param name="callStackIndex">The call stack to look up.</param>
 /// <returns>The caller, if it exists, <see cref="StackSourceCallStackIndex.Invalid"/> otherwise.</returns>
 public override StackSourceCallStackIndex GetCallerIndex(StackSourceCallStackIndex callStackIndex)
 {
     // All pseudo-frames are top-level frames.
     Debug.Assert((int)callStackIndex >= 0 && (int)callStackIndex < names.Length);
     return(StackSourceCallStackIndex.Invalid);
 }
Example #24
0
 public override StackSourceFrameIndex GetFrameIndex(StackSourceCallStackIndex callStackIndex)
 {
     return((StackSourceFrameIndex)m_stacks[(int)callStackIndex].frameID);
 }
Example #25
0
 public static int SourceOf(this IndexMap map, StackSourceCallStackIndex aggregate)
 {
     return(map.SourceOf((int)aggregate));
 }
 public static StackSourceCallStackIndex OffsetOf(this IndexMap map, int source, StackSourceCallStackIndex aggregate)
 {
     return((StackSourceCallStackIndex)map.OffsetOf(source, (int)aggregate));
 }