Пример #1
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;
        }
Пример #2
0
        private static void ParseExtensionsLoggingEvent(TraceEvent data,
                                                        int minRequestDurationMilliseconds,
                                                        string eventArgs,
                                                        Dictionary <string, AspNetCoreRequest> aspnetCoreRequests,
                                                        Dictionary <AspNetCoreRequest, List <AspNetCoreTraceEvent> > failedRequests,
                                                        Dictionary <AspNetCoreRequestId, List <AspNetCoreTraceEvent> > requestsFullTrace,
                                                        AspNetCoreRequestEventType eventType)
        {
            var    loggerName = data.PayloadByName("LoggerName").ToString();
            string rawMessage = "";

            if (!string.IsNullOrWhiteSpace(eventArgs))
            {
                if (data.PayloadByName(eventArgs) != null)
                {
                    rawMessage = data.PayloadByName(eventArgs).ToString();
                    if (rawMessage.ToLower().Contains("StructValue[]".ToLower()))
                    {
                        rawMessage = "";
                        try
                        {
                            var args = (IDictionary <string, object>[])data.PayloadByName(eventArgs);
                            foreach (IDictionary <string, object> item in args.ToList())
                            {
                                var dict = item.ToDictionary(x => x.Key, x => x.Value);
                                rawMessage += $" {dict["Key"].ToString()}->[{dict["Value"].ToString()}]";
                            }
                        }
                        catch (Exception)
                        {
                        }
                    }
                    if (rawMessage.Length > 250)
                    {
                        rawMessage = rawMessage.Substring(0, 250) + "...[REMOVED_AS_MESSAGE_TOO_LARGE]";
                    }
                    rawMessage = eventType.ToString() + ":" + rawMessage;
                }
            }
            else
            {
                rawMessage = eventType.ToString();
            }

            var shortActivityId = StartStopActivityComputer.ActivityPathString(data.ActivityID);

            foreach (var key in requestsFullTrace.Keys.ToArray())
            {
                if (shortActivityId.StartsWith(key.ShortActivityId))
                {
                    AddRawAspNetTraceToDictionary(key, shortActivityId, loggerName, rawMessage, data, requestsFullTrace);
                    break;
                }
            }

            if (CheckAspNetLogger(loggerName) && eventType == AspNetCoreRequestEventType.Start)
            {
                if (data.ActivityID != Guid.Empty)
                {
                    if (!aspnetCoreRequests.ContainsKey(shortActivityId))
                    {
                        var coreRequest = new AspNetCoreRequest
                        {
                            ShortActivityId   = shortActivityId,
                            ProcessId         = data.ProcessID,
                            ActivityId        = data.ActivityID,
                            RelatedActivityId = StartStopActivityComputer.ActivityPathString(data.RelatedActivityID)
                        };
                        var arguments = (IDictionary <string, object>[])data.PayloadByName("Arguments");

                        GetAspnetCoreRequestDetailsFromArgs(arguments.ToList(), out coreRequest.Path, out coreRequest.RequestId);
                        coreRequest.StartTimeRelativeMSec = data.TimeStampRelativeMSec;

                        if (!string.IsNullOrWhiteSpace(coreRequest.Path) && !string.IsNullOrWhiteSpace(coreRequest.RequestId))
                        {
                            aspnetCoreRequests.Add(shortActivityId, coreRequest);
                        }
                    }

                    AspNetCoreRequestId requestId = new AspNetCoreRequestId
                    {
                        ShortActivityId = shortActivityId,
                        ActivityId      = data.ActivityID
                    };
                    AddRawAspNetTraceToDictionary(requestId, shortActivityId, loggerName, rawMessage, data, requestsFullTrace);
                }
            }
            if (CheckAspNetLogger(loggerName) && eventType == AspNetCoreRequestEventType.Stop)
            {
                if (data.ActivityID != Guid.Empty)
                {
                    if (aspnetCoreRequests.TryGetValue(shortActivityId, out AspNetCoreRequest coreRequest))
                    {
                        //
                        // We are setting EndTime in 'Request finished' as well. Not
                        // sure which is the correct one right now, so doing it both.
                        //
                        coreRequest.EndTimeRelativeMSec = data.TimeStampRelativeMSec;
                        if ((coreRequest.EndTimeRelativeMSec - coreRequest.StartTimeRelativeMSec) < minRequestDurationMilliseconds)
                        {
                            var keyToRemove = requestsFullTrace.Keys.Where(x => x.ShortActivityId == coreRequest.ShortActivityId).FirstOrDefault();
                            if (keyToRemove != null)
                            {
                                requestsFullTrace.Remove(keyToRemove);
                            }
                        }
                    }
                }
            }
            if (CheckAspNetLogger(loggerName) && eventType == AspNetCoreRequestEventType.Message)
            {
                string formattedMessage = string.Empty;
                if (data.PayloadByName("FormattedMessage") != null)
                {
                    formattedMessage = data.PayloadByName("FormattedMessage").ToString();
                }
                else if (data.PayloadByName("EventName") != null)
                {
                    formattedMessage = data.PayloadByName("EventName").ToString();
                }

                if (data.ActivityID != Guid.Empty)
                {
                    if (formattedMessage.StartsWith("Request finished", StringComparison.OrdinalIgnoreCase))
                    {
                        if (aspnetCoreRequests.TryGetValue(shortActivityId, out AspNetCoreRequest coreRequest))
                        {
                            int statusCode = GetStatusCodeFromRequestFinishedMessage(formattedMessage);
                            if (statusCode > 0)
                            {
                                coreRequest.StatusCode          = statusCode;
                                coreRequest.EndTimeRelativeMSec = data.TimeStampRelativeMSec;
                            }
                            if (statusCode >= 500)
                            {
                                AspNetCoreRequestId requestId = new AspNetCoreRequestId
                                {
                                    ShortActivityId = shortActivityId,
                                    ActivityId      = data.ActivityID
                                };

                                var requestFullTraceFailedRequest = requestsFullTrace.Where(x => x.Key.ShortActivityId == coreRequest.ShortActivityId).FirstOrDefault();
                                if (requestFullTraceFailedRequest.Value != null && failedRequests.Count() < MAX_FAILED_REQUESTS_TO_TRACE)
                                {
                                    failedRequests.Add(coreRequest.Clone(), requestFullTraceFailedRequest.Value.ToArray().ToList());
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #3
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();
            }
Пример #4
0
        public override void ForEach(Func <EventRecord, bool> callback)
        {
            int    cnt       = 0;
            double startTime = StartTimeRelativeMSec;
            double endTime   = EndTimeRelativeMSec;
            // TODO could be more efficient about process filtering by getting all the processes that match.
            Regex  procRegex             = null;
            string procNameMustStartWith = null;

            if (ProcessFilterRegex != null)
            {
                // As an optimization, find the part that is just alphaNumeric
                procNameMustStartWith = Regex.Match(ProcessFilterRegex, @"^(\w*)").Groups[1].Value;
                procRegex             = new Regex(ProcessFilterRegex, RegexOptions.IgnoreCase);
            }

            Predicate <ETWEventRecord> textFilter = null;

            if (!string.IsNullOrWhiteSpace(TextFilterRegex))
            {
                string pat    = TextFilterRegex;
                bool   negate = false;
                if (pat.StartsWith("!"))
                {
                    negate = true;
                    pat    = pat.Substring(1);
                }
                var textRegex = new Regex(pat, RegexOptions.IgnoreCase);
                textFilter = delegate(ETWEventRecord eventRecord)
                {
                    bool match = eventRecord.Matches(textRegex);
                    return(negate ? !match : match);
                };
            }

            Dictionary <string, int> columnOrder = null;

            ColumnSums = null;
            if (ColumnsToDisplay != null)
            {
                columnOrder = new Dictionary <string, int>();
                for (int i = 0; i < ColumnsToDisplay.Count;)
                {
                    // Discard duplicate columns
                    if (columnOrder.ContainsKey(ColumnsToDisplay[i]))
                    {
                        ColumnsToDisplay.RemoveAt(i);
                        continue;
                    }
                    columnOrder.Add(ColumnsToDisplay[i], i);
                    i++;
                }

                ColumnSums = new double[ColumnsToDisplay.Count];
            }

            if (m_selectedEvents != null)
            {
                ETWEventRecord emptyEventRecord = new ETWEventRecord(this);
                var            startStopRecords = new Dictionary <StartStopKey, double>(10);

                // Figure out if you need m_activityComputer or not
                // Because it is moderately expensive, and not typically used, we only include the activity stuff
                // when you explicitly ask for it
                m_needsComputers = false;
                if (ColumnsToDisplay != null)
                {
                    foreach (string column in ColumnsToDisplay)
                    {
                        if (column == "*" || column == "ActivityInfo" || column == "StartStopActivity")
                        {
                            m_needsComputers = true;
                            break;
                        }
                    }
                }

                /***********************************************************************/
                /*                        The main event loop                          */
                EventVisitedVersion.CurrentVersion++;
                var source = m_tracelog.Events.FilterByTime(m_needsComputers ? 0 : startTime, endTime).GetSource(); // If you need computers, you need the events from the start.
                if (m_needsComputers)
                {
                    m_activityComputer          = new ActivityComputer(source, App.GetSymbolReader());
                    m_startStopActivityComputer = new StartStopActivityComputer(source, m_activityComputer);
                }
                source.AllEvents += delegate(TraceEvent data)
                {
                    // FilterByTime would cover this, however for m_needsComputer == true we may not be able to do it that way.
                    if (data.TimeStampRelativeMSec < startTime)
                    {
                        return;
                    }

                    double durationMSec       = -1;
                    var    eventFilterVersion = data.EventTypeUserData as EventVisitedVersion;

                    if (eventFilterVersion == null || eventFilterVersion.Version != EventVisitedVersion.CurrentVersion)
                    {
                        var eventName = data.ProviderName + "/" + data.EventName;

                        bool processButDontShow = false;
                        var  shouldKeep         = m_selectedAllEvents;
                        if (!shouldKeep)
                        {
                            if (m_selectedEvents.TryGetValue(eventName, out processButDontShow))
                            {
                                shouldKeep = true;
                            }
                        }

                        eventFilterVersion = new EventVisitedVersion(shouldKeep, processButDontShow);
                        if (!(data is UnhandledTraceEvent))
                        {
                            data.EventTypeUserData = eventFilterVersion;
                        }
                    }
                    if (!eventFilterVersion.ShouldProcess)
                    {
                        return;
                    }

                    // If this is a StopEvent compute the DURATION_MSEC
                    var opcode = data.Opcode;
                    var task   = data.Task;
                    CorelationOptions corelationOptions = CorelationOptions.None;
                    if (data.ProviderGuid == ClrTraceEventParser.ProviderGuid)
                    {
                        // Fix Suspend and restart events to line up to make durations.
                        if ((int)data.ID == 9)          // SuspendEEStart
                        {
                            corelationOptions = CorelationOptions.UseThreadContext;
                            task   = (TraceEventTask)0xFFFE;    // unique task
                            opcode = TraceEventOpcode.Start;
                        }
                        else if ((int)data.ID == 8)     // SuspendEEStop
                        {
                            corelationOptions = CorelationOptions.UseThreadContext;
                            task   = (TraceEventTask)0xFFFE;    // unique task  (used for both suspend and Suspend-Restart.
                            opcode = TraceEventOpcode.Stop;
                        }
                        else if ((int)data.ID == 3)     // RestartEEStop
                        {
                            corelationOptions = CorelationOptions.UseThreadContext;
                            task   = (TraceEventTask)0xFFFE;    // unique task
                            opcode = TraceEventOpcode.Stop;
                        }
                    }

                    if (data.ProviderGuid == httpServiceProviderGuid)
                    {
                        corelationOptions = CorelationOptions.UseActivityID;
                        if (opcode == (TraceEventOpcode)13)    // HttpServiceDeliver
                        {
                            opcode = TraceEventOpcode.Start;
                        }
                        // HttpServiceSendComplete  ZeroSend FastSend
                        else if (opcode == (TraceEventOpcode)51 || opcode == (TraceEventOpcode)22 || opcode == (TraceEventOpcode)21)
                        {
                            opcode = TraceEventOpcode.Stop;
                        }
                    }

                    if (data.ProviderGuid == systemDataProviderGuid)
                    {
                        corelationOptions = CorelationOptions.UseActivityID;
                        if ((int)data.ID == 1)               // BeginExecute
                        {
                            task   = (TraceEventTask)0xFFFE; // unique task but used for both BeginExecute and EndExecute.
                            opcode = TraceEventOpcode.Start;
                        }
                        else if ((int)data.ID == 2)          // EndExecute
                        {
                            task   = (TraceEventTask)0xFFFE; // unique task but used for both BeginExecute and EndExecute.
                            opcode = TraceEventOpcode.Stop;
                        }
                    }

                    if (opcode == TraceEventOpcode.Start || opcode == TraceEventOpcode.Stop)
                    {
                        // Figure out what we use as a correlater between the start and stop.
                        Guid contextID = GetCoorelationIDForEvent(data, corelationOptions);
                        var  key       = new StartStopKey(data.ProviderGuid, task, contextID);
                        if (opcode == TraceEventOpcode.Start)
                        {
                            startStopRecords[key] = data.TimeStampRelativeMSec;
                        }
                        else
                        {
                            double startTimeStamp;
                            if (startStopRecords.TryGetValue(key, out startTimeStamp))
                            {
                                durationMSec = data.TimeStampRelativeMSec - startTimeStamp;

                                // A bit of a hack.  WE use the same start event (SuspenEEStart) for two durations.
                                // Thus don't remove it after SuspendEEStop because we also use it for RestartEEStop.
                                if (!(task == (TraceEventTask)0xFFFE && (int)data.ID == 8)) // Is this the SuspendEEStop event?
                                {
                                    startStopRecords.Remove(key);
                                }
                            }
                        }
                    }

                    if (!eventFilterVersion.ShouldShow)
                    {
                        return;
                    }

                    if (procRegex != null)
                    {
                        CSwitchTraceData cSwitch = data as CSwitchTraceData;
                        if (!data.ProcessName.StartsWith(procNameMustStartWith, StringComparison.OrdinalIgnoreCase))
                        {
                            if (cSwitch == null)
                            {
                                return;
                            }
                            // Special case.  Context switches will work for both the old and the new process
                            if (!cSwitch.OldProcessName.StartsWith(procNameMustStartWith, StringComparison.OrdinalIgnoreCase))
                            {
                                return;
                            }
                        }

                        var fullProcessName = data.ProcessName;
                        if (!fullProcessName.StartsWith("("))
                        {
                            fullProcessName += " (" + data.ProcessID + ")";
                        }

                        if (!procRegex.IsMatch(fullProcessName))
                        {
                            if (cSwitch == null)
                            {
                                return;
                            }
                            // Special case.  Context switches will work for both the old and the new process
                            var fullOldProcessName = cSwitch.OldProcessName;
                            if (!fullOldProcessName.StartsWith("("))
                            {
                                fullOldProcessName += " (" + cSwitch.OldProcessName + ")";
                            }

                            if (!procRegex.IsMatch(fullOldProcessName))
                            {
                                return;
                            }
                        }
                    }

                    ETWEventRecord eventRecord = null;
                    if (textFilter != null)
                    {
                        eventRecord = new ETWEventRecord(this, data, columnOrder, NonRestFields, durationMSec);
                        if (!textFilter(eventRecord))
                        {
                            return;
                        }
                    }

                    cnt++;
                    if (MaxRet < cnt)
                    {
                        // We have exceeded our MaxRet, return an empty record.
                        eventRecord = emptyEventRecord;
                        eventRecord.m_timeStampRelativeMSec = data.TimeStampRelativeMSec;
                    }

                    if (eventRecord == null)
                    {
                        eventRecord = new ETWEventRecord(this, data, columnOrder, NonRestFields, durationMSec);
                    }

                    if (ColumnSums != null)
                    {
                        var fields = eventRecord.DisplayFields;
                        var min    = Math.Min(ColumnSums.Length, fields.Length);
                        for (int i = 0; i < min; i++)
                        {
                            string value = fields[i];
                            double asDouble;
                            if (value != null && double.TryParse(value, out asDouble))
                            {
                                ColumnSums[i] += asDouble;
                            }
                        }
                    }
                    if (!callback(eventRecord))
                    {
                        source.StopProcessing();
                    }
                };
                source.Process();
            }
        }
Пример #5
0
        private unsafe Guid GetCoorelationIDForEvent(TraceEvent data, CorelationOptions options)
        {
            int?intContextID = null;       // When the obvious ID is an integer

            if ((options & CorelationOptions.UseThreadContext) == 0)
            {
                if ((options & CorelationOptions.UseActivityID) == 0)
                {
                    // If the payloads have parameters that indicate it is a correlation event, use that.
                    var names = data.PayloadNames;
                    if (names != null && names.Length > 0)
                    {
                        int fieldNum = -1;    // First try to use a field as the correlater
                        if (0 < names.Length)
                        {
                            if (names[0].EndsWith("id", StringComparison.OrdinalIgnoreCase) ||
                                string.Compare("Name", names[0], StringComparison.OrdinalIgnoreCase) == 0 || // Used for simple generic taskss
                                names[0] == "Count")                                                         // Hack for GC/Start
                            {
                                fieldNum = 0;
                            }
                            else if (1 < names.Length && names[1] == "ContextId")       // This is for ASP.NET events
                            {
                                fieldNum = 1;
                            }
                        }

                        if (0 <= fieldNum)
                        {
                            var value = data.PayloadValue(fieldNum);
                            if (value is Guid)
                            {
                                return((Guid)value);
                            }
                            else
                            {
                                if (value != null)
                                {
                                    intContextID = value.GetHashCode();                 // Use the hash if it is not a GUID
                                }
                            }
                        }
                    }
                }
                // If we have not found a context field, and there is an activity ID use that.
                if (data.ActivityID != Guid.Empty)
                {
                    if (!intContextID.HasValue)
                    {
                        return(data.ActivityID);
                    }

                    //TODO Currently, people may have recursive tasks that are not marked (because they can't if they want it to work before V4.6)
                    // For now we don't try to correlate with activity IDS.
                    if (false && StartStopActivityComputer.IsActivityPath(data.ActivityID, data.ProcessID))
                    {
                        int guidHash = data.ActivityID.GetHashCode();
                        // Make up a correlater that is the combination of both the value and the Activity ID, the tail is arbitrary
                        // TODO this is causing unnecessary collisions.
                        return(new Guid(intContextID.Value, (short)guidHash, (short)(guidHash >> 16), 45, 34, 34, 67, 4, 4, 5, 5));
                    }
                }
            }

            // If we have not found a context, use the thread as a context.
            if (!intContextID.HasValue)
            {
                intContextID = data.ThreadID;                  // By default use the thread as the correlation ID
            }

            return(new Guid(intContextID.Value, 1, 5, 45, 23, 23, 3, 5, 5, 4, 5));
        }