Example #1
0
        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);
        }
Example #2
0
        /// <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));
        }
Example #3
0
        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);
        }
Example #4
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"));
            }
        }
Example #5
0
        // 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);
        }
Example #6
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"));
            }
        }
Example #7
0
        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);
            }
        }
Example #8
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)));
        }
Example #9
0
            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();
            }