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); } } }
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); }
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); }
/// <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); } }
// 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); }
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); } }
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; }
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); }
/// <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)); }
/// <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; } }
/// <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")); } }
/// <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; } }
// 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")); } }
/// <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); }
/// <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 = "******" }); }
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; } }
/// <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)); }
/// <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))); }
private bool TracingThisFrame(TraceThread pyThread) { return pyThread != null && pyThread.Frames.Count != 0 && Type.ReferenceEquals(this, pyThread.Frames[pyThread.Frames.Count - 1]); }
/// <summary> /// The server request that we currently processing /// </summary> ServerRequest GetCurrentRequest(TraceThread thread) { return(null); }
/// <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); }
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; } }
/// <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); }
// 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); }
/// <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; }
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(); }