private StackSourceCallStackIndex GetStack(TraceEvent event_) { // Console.WriteLine("Getting Stack for sample at {0:f4}", sample.TimeStampRelativeMSec); int ret = (int)event_.CallStackIndex(); if (ret == (int)CallStackIndex.Invalid) { var thread = event_.Thread(); if (thread == null) { return(StackSourceCallStackIndex.Invalid); } // If the event is a sample profile, or page fault we can make a one element stack with the EIP in the event CodeAddressIndex codeAddrIdx = CodeAddressIndex.Invalid; var asSampleProfile = event_ as SampledProfileTraceData; if (asSampleProfile != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } else { var asPageFault = event_ as MemoryHardFaultTraceData; if (asPageFault != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } } if (codeAddrIdx != CodeAddressIndex.Invalid) { // Encode the code address for the given thread. int pseudoStackIndex = GetPseudoStack(thread.ThreadIndex, codeAddrIdx); // Psuedostacks happen after all the others. if (0 <= pseudoStackIndex) { ret = m_log.CallStacks.Count + 2 * m_log.Threads.Count + m_log.Processes.Count + pseudoStackIndex; } } // If we have run out of pseudo-stacks, we encode the stack as being at the thread. if (ret == (int)CallStackIndex.Invalid) { ret = m_log.CallStacks.Count + (int)thread.ThreadIndex; } } else { // We expect the thread we get when looking at the CallStack to match the thread of the event. Debug.Assert(m_log.CallStacks.Thread((CallStackIndex)ret).ThreadID == event_.ThreadID); Debug.Assert(event_.Thread().Process.ProcessID == event_.ProcessID); } ret = ret + (int)StackSourceCallStackIndex.Start; return((StackSourceCallStackIndex)ret); }
/// <summary> /// Convert the TraceEvent callStack 'callStackIdx' into a StackSourceCallStack. 'callStackIdx is /// assumed to be related to the traceEvent 'data'. 'data' is used to determine the process and thread /// of the stack. (TODO data may not be needed anymore as callStackIndexes do encode their thread (and thus process)). /// </summary> public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, TraceEvent data) { // This only happens if only have ONLY the thread and process (no addressses) // TODO do we care about this case? Should we remove? var thread = data.Thread(); StackSourceCallStackIndex topOfStack; if (thread == null) { var process = data.Process(); if (process != null) { topOfStack = GetCallStackForProcess(process); } else { topOfStack = StackSourceCallStackIndex.Invalid; } } else { topOfStack = GetCallStackForThread(thread); } return(GetCallStack(callStackIndex, topOfStack, m_callStackMap)); }
private StackSourceCallStackIndex GetStack(TraceEvent event_) { // Console.WriteLine("Getting Stack for sample at {0:f4}", sample.TimeStampRelativeMSec); var ret = (int)event_.CallStackIndex(); if (ret == (int)CallStackIndex.Invalid) { var thread = event_.Thread(); if (thread == null) { return(StackSourceCallStackIndex.Invalid); } // If the event is a sample profile, or page fault we can make a one element stack with the EIP in the event CodeAddressIndex codeAddrIdx = CodeAddressIndex.Invalid; var asSampleProfile = event_ as SampledProfileTraceData; if (asSampleProfile != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } else { var asPageFault = event_ as PageFaultHardFaultTraceData; if (asPageFault != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } } if (codeAddrIdx != CodeAddressIndex.Invalid) { // Encode the code address for the given thread. int pseudoStackIndex = GetPseudoStack(thread.ThreadIndex, codeAddrIdx); if (pseudoStackIndex < 0) { return(StackSourceCallStackIndex.Start); } // Psuedostacks happen after all the others. ret = m_log.CallStacks.MaxCallStackIndex + 2 * m_log.Threads.MaxThreadIndex + m_log.Processes.MaxProcessIndex + pseudoStackIndex; } else { // Otherwise we encode the stack as being at the thread. ret = m_log.CallStacks.MaxCallStackIndex + (int)thread.ThreadIndex; } } ret = ret + (int)StackSourceCallStackIndex.Start; return((StackSourceCallStackIndex)ret); }
/// <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")); } }
// Note that this always returns a stack, since we know the thread and process. public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, TraceEvent data) { if (callStackIndex == CallStackIndex.Invalid) { if (data == null) { return(StackSourceCallStackIndex.Invalid); } var thread = data.Thread(); if (thread == null) { return(StackSourceCallStackIndex.Invalid); } return(GetCallStackForThread(thread)); } var idx = (int)StackSourceCallStackIndex.Start + (int)callStackIndex; return((StackSourceCallStackIndex)idx); }
// 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")); } }
internal void OnClrEvent(TraceEvent data) { TraceEventID eventID = data.ID; HeapEvents heapEvent = HeapEvents.Unknown; // TODO don't use IDs but use individual callbacks. const TraceEventID GCStartEventID = (TraceEventID)1; const TraceEventID GCStopEventID = (TraceEventID)2; const TraceEventID GCRestartEEStopEventID = (TraceEventID)3; const TraceEventID GCHeapStatsEventID = (TraceEventID)4; const TraceEventID GCCreateSegmentEventID = (TraceEventID)5; const TraceEventID GCFreeSegmentEventID = (TraceEventID)6; const TraceEventID GCRestartEEStartEventID = (TraceEventID)7; const TraceEventID GCSuspendEEStopEventID = (TraceEventID)8; const TraceEventID GCSuspendEEStartEventID = (TraceEventID)9; const TraceEventID GCAllocationTickEventID = (TraceEventID)10; const TraceEventID GCCreateConcurrentThreadEventID = (TraceEventID)11; const TraceEventID GCTerminateConcurrentThreadEventID = (TraceEventID)12; const TraceEventID GCFinalizersStopEventID = (TraceEventID)13; const TraceEventID GCFinalizersStartEventID = (TraceEventID)14; const TraceEventID ContentionStartEventID = (TraceEventID)81; const TraceEventID ContentionStopEventID = (TraceEventID)91; switch (eventID) { case GCStartEventID: { var mdata = data as Microsoft.Diagnostics.Tracing.Parsers.Clr.GCStartTraceData; if (mdata != null) { GcEventExtra extra = GetGcEventExtra(mdata.Count); extra.GCStartIndex = data.EventIndex; extra.GCStartThread = data.Thread(); } } heapEvent = HeapEvents.GCStart; break; case GCStopEventID: heapEvent = HeapEvents.GCEnd; break; case GCRestartEEStartEventID: heapEvent = HeapEvents.GCRestartEEBegin; break; case GCRestartEEStopEventID: heapEvent = HeapEvents.GCRestartEEEnd; break; case GCHeapStatsEventID: heapEvent = HeapEvents.GCHeapStats; break; case GCCreateSegmentEventID: heapEvent = HeapEvents.GCCreateSegment; break; case GCFreeSegmentEventID: heapEvent = HeapEvents.GCFreeSegment; break; case GCSuspendEEStartEventID: heapEvent = HeapEvents.GCSuspendEEBegin; break; case GCSuspendEEStopEventID: heapEvent = HeapEvents.GCSuspendEEEnd; break; case GCAllocationTickEventID: heapEvent = HeapEvents.GCAllocationTick; { GCAllocationTickTraceData mdata = data as GCAllocationTickTraceData; AllocationTick(mdata, mdata.AllocationKind == GCAllocationKind.Large, mdata.GetAllocAmount(ref seenBadAlloc) / OneMBD); } break; case GCCreateConcurrentThreadEventID: heapEvent = HeapEvents.GCCreateConcurrentThread; break; case GCTerminateConcurrentThreadEventID: heapEvent = HeapEvents.GCTerminateConcurrentThread; break; case GCFinalizersStartEventID: heapEvent = HeapEvents.GCFinalizersBegin; break; case GCFinalizersStopEventID: heapEvent = HeapEvents.GCFinalizersEnd; break; case ContentionStartEventID: heapEvent = HeapEvents.ContentionStart; break; case ContentionStopEventID: heapEvent = HeapEvents.ContentionStop; break; default: break; } if (heapEvent != HeapEvents.Unknown) { ThreadMemoryInfo thread = GetThread(data.ThreadID); thread.AddEvent(heapEvent, data.TimeStampRelativeMSec); } }
/// <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))); }
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(); }