コード例 #1
0
        private void OnThreadCSwitch(CSwitchTraceData data)
        {
            // Start blocking on the old thread.
            // Ignore the idle thread.
            if (data.OldThreadID != 0)
            {
                TraceThread oldThread = m_Configuration.TraceLog.Threads.GetThread(data.OldThreadID, data.TimeStampRelativeMSec);
                if (null != oldThread)
                {
                    ComputingResourceThreadState oldThreadState = m_ThreadState[(int)oldThread.ThreadIndex];
                    oldThreadState.LogBlockingStart(this, oldThread, data);
                }
            }

            // Stop blocking on the new thread.
            // Ignore the idle thread.
            if (data.ThreadID != 0)
            {
                TraceThread newThread = data.Thread();
                if (null != newThread)
                {
                    ComputingResourceThreadState newThreadState = m_ThreadState[(int)newThread.ThreadIndex];
                    newThreadState.LogBlockingStop(this, newThread, data);
                }
            }
        }
コード例 #2
0
        public StackSourceCallStackIndex GetCallStackForThread(TraceThread thread)
        {
            var processStack        = GetCallStackForProcess(thread.Process);
            var threadName          = "Thread (" + thread.ThreadID + ")";
            var internedThreadFrame = Interner.FrameIntern(threadName, m_emptyModuleIdx);
            var threadStack         = Interner.CallStackIntern(internedThreadFrame, processStack);

            return(threadStack);
        }
コード例 #3
0
        private void OnGCAllocationTick(GCAllocationTickTraceData data)
        {
            TraceThread thread = data.Thread();

            Debug.Assert(thread != null);
            if (null == thread)
            {
                return;
            }

            // Attempt to charge the allocation to a request.
            ScenarioThreadState scenarioThreadState = m_Configuration.ScenarioThreadState[(int)thread.ThreadIndex];

            CallStackIndex            traceLogCallStackIndex = data.CallStackIndex();
            StackSourceCallStackIndex callStackIndex         = scenarioThreadState.GetCallStackIndex(m_OutputStackSource, thread, data);

            // Add the thread.
            StackSourceFrameIndex threadFrameIndex = m_OutputStackSource.Interner.FrameIntern(thread.VerboseThreadName);

            callStackIndex = m_OutputStackSource.Interner.CallStackIntern(threadFrameIndex, callStackIndex);

            // Get the allocation call stack index.
            callStackIndex = m_OutputStackSource.GetCallStack(traceLogCallStackIndex, callStackIndex, null);

            // Add the type.
            string typeName = data.TypeName;

            if (typeName.Length > 0)
            {
                StackSourceFrameIndex nodeIndex = m_OutputStackSource.Interner.FrameIntern("Type " + data.TypeName);
                callStackIndex = m_OutputStackSource.Interner.CallStackIntern(nodeIndex, callStackIndex);
            }

            // Add a notification for large objects.
            if (data.AllocationKind == GCAllocationKind.Large)
            {
                StackSourceFrameIndex nodeIndex = m_OutputStackSource.Interner.FrameIntern("LargeObject");
                callStackIndex = m_OutputStackSource.Interner.CallStackIntern(nodeIndex, callStackIndex);
            }

            // Set the time.
            m_Sample.TimeRelativeMSec = data.TimeStampRelativeMSec;

            // Set the metric.
            bool seenBadAllocTick = false;

            m_Sample.Metric = data.GetAllocAmount(ref seenBadAllocTick);

            // Set the stack index.
            m_Sample.StackIndex = callStackIndex;

            // Add the sample.
            m_OutputStackSource.AddSample(m_Sample);
        }
コード例 #4
0
        /// <summary>
        /// Updates it so that 'thread' is now working on newStartStop, which can be null which means that it is not working on any
        /// start-stop task.
        /// </summary>
        private void UpdateThreadToWorkOnStartStopActivity(TraceThread thread, StartStopActivity newStartStop, TraceEvent data)
        {
            // Make the new-start stop activity be the top most one.   This is all we need and is more robust in the case
            // of unusual state transitions (e.g. lost events non-nested start-stops ...).  Ref-counting is very fragile
            // after all...
            if (newStartStop != null)
            {
                while (newStartStop.Creator != null)
                {
                    newStartStop = newStartStop.Creator;
                }
            }

            StartStopActivity oldStartStop = m_threadToStartStopActivity[(int)thread.ThreadIndex];

            Debug.Assert(oldStartStop == null || oldStartStop.Creator == null);
            if (oldStartStop == newStartStop)       // No change, nothing to do, quick exit.
            {
                return;
            }

            // Decrement the start-stop which lost its thread.
            if (oldStartStop != null)
            {
                double unknownStartTimeMSec = m_unknownTimeStartMsec.Get((int)oldStartStop.Index);
                Debug.Assert(unknownStartTimeMSec < 0);
                if (unknownStartTimeMSec < 0)
                {
                    unknownStartTimeMSec++;     //We represent the ref count as a negative number, here we are decrementing the ref count
                    if (unknownStartTimeMSec == 0)
                    {
                        unknownStartTimeMSec = data.TimeStampRelativeMSec;      // Remember when we dropped to zero.
                    }

                    m_unknownTimeStartMsec.Set((int)oldStartStop.Index, unknownStartTimeMSec);
                }
            }
            m_threadToStartStopActivity[(int)thread.ThreadIndex] = newStartStop;

            // Increment refcount on the new startStop activity
            if (newStartStop != null)
            {
                double unknownStartTimeMSec = m_unknownTimeStartMsec.Get((int)newStartStop.Index);
                // If we were off before (a positive number) then log the unknown time.
                if (0 < unknownStartTimeMSec)
                {
                    AddUnkownAsyncDurationIfNeeded(newStartStop, unknownStartTimeMSec, data);
                    unknownStartTimeMSec = 0;
                }
                --unknownStartTimeMSec;     //We represent the ref count as a negative number, here we are incrementing the ref count
                m_unknownTimeStartMsec.Set((int)newStartStop.Index, unknownStartTimeMSec);
            }
        }
コード例 #5
0
        // callbacks for pariticular ETW events
        private void OnCpuSample(SampledProfileTraceData data)
        {
            TraceThread thread = data.Thread();

            Debug.Assert(thread != null);
            if (null == thread)
            {
                return;
            }

            // Log the CPU sample.
            ComputingResourceThreadState threadState = m_ThreadState[(int)thread.ThreadIndex];

            threadState.LogCPUSample(this, thread, data);
        }
コード例 #6
0
            public void AddBlockTimeSample(double timeRelativeMSec, TraceThread thread, SampleProfilerThreadTimeComputer computer)
            {
                // Log the last sample if it was present
                if (LastBlockStackRelativeMSec > 0)
                {
                    var sample = computer.m_sample;
                    sample.Metric           = (float)(timeRelativeMSec - LastBlockStackRelativeMSec);
                    sample.TimeRelativeMSec = LastBlockStackRelativeMSec;

                    var nodeIndex = computer.m_ExternalFrameIndex;       // BLOCKED_TIME
                    sample.StackIndex = LastBlockCallStack;

                    sample.StackIndex = computer.m_outputStackSource.Interner.CallStackIntern(nodeIndex, sample.StackIndex);
                    computer.m_outputStackSource.AddSample(sample);
                }
            }
コード例 #7
0
        private void OnThreadEnd(ThreadTraceData data)
        {
            TraceThread thread = data.Thread();

            Debug.Assert(thread != null);
            if (null == thread)
            {
                return;
            }

            // Get the thread state.
            ComputingResourceThreadState threadState = m_ThreadState[(int)thread.ThreadIndex];

            // Mark the thread as dead.
            threadState.BlockTimeStartRelativeMSec = double.NegativeInfinity;
        }
コード例 #8
0
        private void OnThreadStart(ThreadTraceData data)
        {
            TraceThread thread = data.Thread();

            Debug.Assert(thread != null);
            if (null == thread)
            {
                return;
            }

            // Get the thread state.
            ComputingResourceThreadState threadState = m_ThreadState[(int)thread.ThreadIndex];

            // Mark that blocking has started.
            threadState.LogBlockingStart(this, thread, data);
        }
コード例 #9
0
        /// <summary>
        /// Get the call stack index for the current thread in its current state.
        /// </summary>
        /// <remarks>
        /// The return value will be used to append the actual call stack.  This is how real call stacks get stitched together with grouping mechanisms.
        /// </remarks>
        public virtual StackSourceCallStackIndex GetCallStackIndex(
            MutableTraceEventStackSource stackSource,
            TraceThread thread)
        {
            if (null == stackSource)
            {
                throw new ArgumentNullException("stackSource");
            }
            if (null == thread)
            {
                throw new ArgumentNullException("thread");
            }

            // By default, return the call stack for the process.
            return(stackSource.GetCallStackForProcess(thread.Process));
        }
コード例 #10
0
        /// <summary>
        /// Mark the thread as unblocked.
        /// </summary>
        public void LogBlockingStop(
            ComputingResourceStateMachine stateMachine,
            TraceThread thread,
            TraceEvent data)
        {
            if ((null == stateMachine) || (null == thread) || (null == data))
            {
                return;
            }

            // Only add a sample if the thread was blocked.
            if (ThreadBlocked)
            {
                StackSourceSample            sample      = stateMachine.Sample;
                MutableTraceEventStackSource stackSource = stateMachine.StackSource;

                // Set the time and metric.
                sample.TimeRelativeMSec = this.BlockTimeStartRelativeMSec;
                sample.Metric           = (float)(data.TimeStampRelativeMSec - this.BlockTimeStartRelativeMSec);

                /* Generate the stack trace. */

                CallStackIndex            traceLogCallStackIndex = data.CallStackIndex();
                ScenarioThreadState       scenarioThreadState    = stateMachine.Configuration.ScenarioThreadState[ThreadIndex];
                StackSourceCallStackIndex callStackIndex         = scenarioThreadState.GetCallStackIndex(stateMachine.StackSource, thread, data);

                // Add the thread.
                StackSourceFrameIndex threadFrameIndex = stackSource.Interner.FrameIntern(thread.VerboseThreadName);
                callStackIndex = stackSource.Interner.CallStackIntern(threadFrameIndex, callStackIndex);

                // Add the full call stack.
                callStackIndex = stackSource.GetCallStack(traceLogCallStackIndex, callStackIndex, null);

                // Add Pseud-frames representing the kind of resource.
                StackSourceFrameIndex frameIndex = stackSource.Interner.FrameIntern("BLOCKED TIME");
                callStackIndex = stackSource.Interner.CallStackIntern(frameIndex, callStackIndex);

                // Add the call stack to the sample.
                sample.StackIndex = callStackIndex;

                // Add the sample.
                stackSource.AddSample(sample);

                // Mark the thread as executing.
                BlockTimeStartRelativeMSec = -1;
            }
        }
コード例 #11
0
        /// <summary>
        /// This can actually be called with any event that has a stack.   Basically it will log a CPU sample whose
        /// size is the time between the last such call and the current one.
        /// </summary>
        private void OnSampledProfile(TraceEvent data)
        {
            TraceThread thread = data.Thread();

            if (thread != null)
            {
                StackSourceCallStackIndex stackIndex = GetCallStack(data, thread);

                bool onCPU = (data is ClrThreadSampleTraceData) ? ((ClrThreadSampleTraceData)data).Type == ClrThreadSampleType.Managed : true;

                m_threadState[(int)thread.ThreadIndex].LogThreadStack(data.TimeStampRelativeMSec, stackIndex, thread, this, onCPU);
            }
            else
            {
                Debug.WriteLine("Warning, no thread at " + data.TimeStampRelativeMSec.ToString("f3"));
            }
        }
コード例 #12
0
        /// <summary>
        /// Mark the thread as blocked.
        /// </summary>
        public void LogBlockingStart(
            TraceThread thread,
            TraceEvent data)
        {
            if ((null == thread) || (null == data))
            {
                return;
            }

            if (!ThreadDead)
            {
                // TODO: Fix (we'll need the last CPU stack as well).
                // AddCPUSample(timeRelMSec, thread, computer);

                BlockTimeStartRelMsec = data.TimeStampRelativeMSec;
            }
        }
コード例 #13
0
        // THis is for the TaskWaitEnd.  We want to have a stack event if 'data' does not have one, we lose the fact that
        // ANYTHING happened on this thread.   Thus we log the stack of the activity so that data does not need a stack.
        private void OnTaskUnblock(TraceEvent data)
        {
            if (m_activityComputer == null)
            {
                return;
            }

            TraceThread thread = data.Thread();

            if (thread != null)
            {
                TraceActivity activity = m_activityComputer.GetCurrentActivity(thread);

                StackSourceCallStackIndex stackIndex = m_activityComputer.GetCallStackForActivity(m_outputStackSource, activity, GetTopFramesForActivityComputerCase(data, data.Thread()));
                m_threadState[(int)thread.ThreadIndex].LogThreadStack(data.TimeStampRelativeMSec, stackIndex, thread, this, onCPU: true);
            }
            else
            {
                Debug.WriteLine("Warning, no thread at " + data.TimeStampRelativeMSec.ToString("f3"));
            }
        }
コード例 #14
0
        /// <summary>
        /// Log a CPU sample on this thread.
        /// </summary>
        public void LogCPUSample(
            ComputingResourceStateMachine stateMachine,
            TraceThread thread,
            TraceEvent data)
        {
            if ((null == stateMachine) || (null == thread) || (null == data))
            {
                return;
            }

            StackSourceSample sample = stateMachine.Sample;

            sample.Metric           = 1;
            sample.TimeRelativeMSec = data.TimeStampRelativeMSec;
            MutableTraceEventStackSource stackSource = stateMachine.StackSource;

            // Attempt to charge the CPU to a request.
            CallStackIndex traceLogCallStackIndex = data.CallStackIndex();

            ScenarioThreadState       scenarioThreadState = stateMachine.Configuration.ScenarioThreadState[ThreadIndex];
            StackSourceCallStackIndex callStackIndex      = scenarioThreadState.GetCallStackIndex(stackSource, thread, data);

            // Add the thread.
            StackSourceFrameIndex threadFrameIndex = stackSource.Interner.FrameIntern(thread.VerboseThreadName);

            callStackIndex = stackSource.Interner.CallStackIntern(threadFrameIndex, callStackIndex);

            // Rest of the stack.
            // NOTE: Do not pass a call stack map into this method, as it will skew results.
            callStackIndex = stackSource.GetCallStack(traceLogCallStackIndex, callStackIndex, null);

            // Add the CPU frame.
            StackSourceFrameIndex cpuFrameIndex = stackSource.Interner.FrameIntern("CPU");

            callStackIndex = stackSource.Interner.CallStackIntern(cpuFrameIndex, callStackIndex);

            // Add the sample.
            sample.StackIndex = callStackIndex;
            stackSource.AddSample(sample);
        }
コード例 #15
0
ファイル: EventThread.cs プロジェクト: chubbymaggie/harvester
        /// <summary>
        /// Constructs a new thread info from trace thread & monitored process.
        /// </summary>
        /// <param name="thread"></param>
        /// <param name="monitoredProcess"></param>
        /// <returns></returns>
        public static EventThread FromTrace(TraceThread thread, TraceProcess monitoredProcess)
        {
            // PID 0 is the Idle thread
            if (thread.Process.ProcessID == 0)
            {
                return(EventThread.Idle);
            }

            // Everything non-related we put to default
            if (thread.Process.ProcessID != monitoredProcess.ProcessID)
            {
                return(EventThread.System);
            }

            return(new EventThread()
            {
                Tid = thread.ThreadID,
                Pid = monitoredProcess.ProcessID,
                Uid = 1,
                Process = monitoredProcess.Name,
                User = "******"
            });
        }
コード例 #16
0
            public void LogThreadStack(double timeRelativeMSec, StackSourceCallStackIndex stackIndex, TraceThread thread, SampleProfilerThreadTimeComputer computer, bool onCPU)
            {
                if (onCPU)
                {
                    if (ThreadUninitialized) // First event is onCPU
                    {
                        AddCPUSample(timeRelativeMSec, thread, computer);
                        LastBlockStackRelativeMSec = -1; // make ThreadRunning true
                    }
                    else if (ThreadRunning)              // continue running
                    {
                        AddCPUSample(timeRelativeMSec, thread, computer);
                    }
                    else if (ThreadBlocked) // unblocked
                    {
                        AddBlockTimeSample(timeRelativeMSec, thread, computer);
                        LastBlockStackRelativeMSec = -timeRelativeMSec;
                    }

                    LastCPUStackRelativeMSec = timeRelativeMSec;
                    LastCPUCallStack         = stackIndex;
                }
                else
                {
                    if (ThreadBlocked || ThreadUninitialized) // continue blocking or assume we started blocked
                    {
                        AddBlockTimeSample(timeRelativeMSec, thread, computer);
                    }
                    else if (ThreadRunning) // blocked
                    {
                        AddCPUSample(timeRelativeMSec, thread, computer);
                    }

                    LastBlockStackRelativeMSec = timeRelativeMSec;
                    LastBlockCallStack         = stackIndex;
                }
            }
コード例 #17
0
 /// <summary>
 /// Returns a function that figures out the top (closest to stack root) frames for an event.  Often
 /// this returns null which means 'use the normal thread-process frames'.
 /// Normally this stack is for the current time, but if 'getAtCreationTime' is true, it will compute the
 /// stack at the time that the current activity was CREATED rather than the current time.  This works
 /// better for await time.
 /// </summary>
 private Func <TraceThread, StackSourceCallStackIndex> GetTopFramesForActivityComputerCase(TraceEvent data, TraceThread thread, bool getAtCreationTime = false)
 {
     Debug.Assert(m_activityComputer != null);
     return(topThread => m_startStopActivities.GetCurrentStartStopActivityStack(m_outputStackSource, thread, topThread, getAtCreationTime));
 }
コード例 #18
0
        /// <summary>
        /// Get the call stack for 'data'  Note that you thread must be data.Thread().   We pass it just to save the lookup.
        /// </summary>
        private StackSourceCallStackIndex GetCallStack(TraceEvent data, TraceThread thread)
        {
            Debug.Assert(data.Thread() == thread);

            return(m_activityComputer.GetCallStack(m_outputStackSource, data, GetTopFramesForActivityComputerCase(data, thread)));
        }
コード例 #19
0
ファイル: TraceBack.cs プロジェクト: techarch/ironruby
 private bool TracingThisFrame(TraceThread pyThread) {
     return pyThread != null &&  pyThread.Frames.Count != 0 && Type.ReferenceEquals(this, pyThread.Frames[pyThread.Frames.Count - 1]);
 }
コード例 #20
0
 /// <summary>
 /// The server request that we currently processing
 /// </summary>
 ServerRequest GetCurrentRequest(TraceThread thread)
 {
     return(null);
 }
コード例 #21
0
        /// <summary>
        /// Get the 'logcal' call stack from PROCESS ROOT (the root of all stacks) to (but not including) the frame for the
        /// thread.   By default (if you can't attribute it to anything else) it will just be attributed to the process, however
        /// it is likley that you want to insert pseudo-frames for the request and other logical groupings here.
        ///
        /// The actual method frames within a thread, as well as any resource specific pseduo-frames (e.g. BLOCKING, ...)
        /// are added by the ComputingResourceMachine itself.
        ///</summary>
        public virtual StackSourceCallStackIndex GetCallStackIndex(MutableTraceEventStackSource stackSource, TraceThread thread, TraceEvent data)
        {
            var callStackIndex = stackSource.GetCallStackForProcess(thread.Process);
            // There is no request, so add this stack as an unattributed sample.
            string frameName = "Unattributed";
            StackSourceFrameIndex requestsFrameIndex = stackSource.Interner.FrameIntern(frameName);

            callStackIndex = stackSource.Interner.CallStackIntern(requestsFrameIndex, callStackIndex);
            return(callStackIndex);
        }
コード例 #22
0
            public void LogThreadStack(double timeRelativeMSec, StackSourceCallStackIndex stackIndex, TraceThread thread, SampleProfilerThreadTimeComputer computer, bool onCPU)
            {
                if (onCPU)
                {
                    if (ThreadRunning) // continue running
                    {
                        AddCPUSample(timeRelativeMSec, thread, computer);
                    }
                    else if (ThreadBlocked) // unblocked
                    {
                        AddBlockTimeSample(timeRelativeMSec, thread, computer);
                        LastBlockStackRelativeMSec = -timeRelativeMSec;
                    }

                    LastCPUStackRelativeMSec = timeRelativeMSec;
                    LastCPUCallStack         = stackIndex;
                }
                else
                {
                    if (ThreadBlocked) // continue blocking
                    {
                        AddBlockTimeSample(timeRelativeMSec, thread, computer);
                    }
                    else if (ThreadRunning) // blocked
                    {
                        AddCPUSample(timeRelativeMSec, thread, computer);
                    }

                    LastBlockStackRelativeMSec = timeRelativeMSec;
                    LastBlockCallStack         = stackIndex;
                }
            }
コード例 #23
0
        /// <summary>
        /// Get the call stack representing a TraceEvent thread
        /// </summary>
        public StackSourceCallStackIndex GetCallStackForThread(TraceThread thread)
        {
            var idx = (int)StackSourceCallStackIndex.Start + m_log.CallStacks.MaxCallStackIndex + (int)thread.ThreadIndex;

            return((StackSourceCallStackIndex)idx);
        }
コード例 #24
0
        // Caller only need to provide TraceThread
        public StackSourceCallStackIndex GetCallStackThread(CallStackIndex callStackIndex, TraceThread thread)
        {
            if (callStackIndex == CallStackIndex.Invalid)
            {
                if (thread == null)
                {
                    return(StackSourceCallStackIndex.Invalid);
                }
                return(GetCallStackForThread(thread));
            }
            var idx = (int)StackSourceCallStackIndex.Start + (int)callStackIndex;

            return((StackSourceCallStackIndex)idx);
        }
コード例 #25
0
        /// <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, IgnoreApplicationInsightsRequestsWithRelatedActivityId);

                // 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;
        }
コード例 #26
0
ファイル: EtwEventSource.cs プロジェクト: ivberg/perfview
            internal ETWEventRecord(ETWEventSource source, TraceEvent data, Dictionary <string, int> columnOrder, int nonRestFields, double durationMSec)
                : base(nonRestFields)
            {
                m_source      = source;
                m_name        = data.ProviderName + "/" + data.EventName;
                m_processName = data.ProcessName;
                if (!m_processName.StartsWith("("))
                {
                    m_processName += " (" + data.ProcessID + ")";
                }

                m_timeStampRelativeMSec = data.TimeStampRelativeMSec;
                m_idx = data.EventIndex;

                // Compute the data column
                var restString = new StringBuilder();

                // Deal with the special HasStack, ThreadID and ActivityID, DataLength fields;
                var hasStack = data.CallStackIndex() != CallStackIndex.Invalid;

                if (hasStack)
                {
                    AddField("HasStack", hasStack.ToString(), columnOrder, restString);
                }

                var asCSwitch = data as CSwitchTraceData;

                if (asCSwitch != null)
                {
                    AddField("HasBlockingStack", (asCSwitch.BlockingStack() != CallStackIndex.Invalid).ToString(), columnOrder, restString);
                }

                AddField("ThreadID", data.ThreadID.ToString("n0"), columnOrder, restString);
                AddField("ProcessorNumber", data.ProcessorNumber.ToString(), columnOrder, restString);

                if (0 < durationMSec)
                {
                    AddField("DURATION_MSEC", durationMSec.ToString("n3"), columnOrder, restString);
                }

                var payloadNames = data.PayloadNames;

                if (payloadNames.Length == 0 && data.EventDataLength != 0)
                {
                    // WPP events look classic and use the EventID as their discriminator
                    if (data.IsClassicProvider && data.ID != 0)
                    {
                        AddField("EventID", ((int)data.ID).ToString(), columnOrder, restString);
                    }

                    AddField("DataLength", data.EventDataLength.ToString(), columnOrder, restString);
                }

                try
                {
                    for (int i = 0; i < payloadNames.Length; i++)
                    {
                        AddField(payloadNames[i], data.PayloadString(i), columnOrder, restString);
                    }
                }
                catch (Exception e)
                {
                    AddField("ErrorParsingFields", e.Message, columnOrder, restString);
                }

                var message = data.FormattedMessage;

                if (message != null)
                {
                    AddField("FormattedMessage", message, columnOrder, restString);
                }

                if (source.m_needsComputers)
                {
                    TraceThread thread = data.Thread();
                    if (thread != null)
                    {
                        TraceActivity activity = source.m_activityComputer.GetCurrentActivity(thread);
                        if (activity != null)
                        {
                            string id = activity.ID;
                            if (Math.Abs(activity.StartTimeRelativeMSec - m_timeStampRelativeMSec) < .0005)
                            {
                                id = "^" + id;              // Indicates it is at the start of the task.
                            }

                            AddField("ActivityInfo", id, columnOrder, restString);
                        }

                        var startStopActivity = source.m_startStopActivityComputer.GetCurrentStartStopActivity(thread, data);
                        if (startStopActivity != null)
                        {
                            string name       = startStopActivity.Name;
                            string parentName = "$";
                            if (startStopActivity.Creator != null)
                            {
                                parentName = startStopActivity.Creator.Name;
                            }

                            AddField("StartStopActivity", name + "/P=" + parentName, columnOrder, restString);
                        }
                    }
                }

                // We pass 0 as the process ID for creating the activityID because we want uniform syntax.
                if (data.ActivityID != Guid.Empty)
                {
                    AddField("ActivityID", StartStopActivityComputer.ActivityPathString(data.ActivityID), columnOrder, restString);
                }

                Guid relatedActivityID = data.RelatedActivityID;

                if (relatedActivityID != Guid.Empty)
                {
                    AddField("RelatedActivityID", StartStopActivityComputer.ActivityPathString(data.RelatedActivityID), columnOrder, restString);
                }

                if (data.ContainerID != null)
                {
                    AddField("ContainerID", data.ContainerID, columnOrder, restString);
                }

                m_asText = restString.ToString();
            }