private unsafe void DispatchEventsToEventListeners() { // Struct to fill with the call to GetNextEvent. EventPipeEventInstanceData instanceData; while (!m_stopDispatchTask) { bool eventsReceived = false; // Get the next event. while (!m_stopDispatchTask && EventPipeInternal.GetNextEvent(m_sessionID, &instanceData)) { eventsReceived = true; // Filter based on provider. if (instanceData.ProviderID == m_RuntimeProviderID) { // Dispatch the event. ReadOnlySpan <byte> payload = new ReadOnlySpan <byte>((void *)instanceData.Payload, (int)instanceData.PayloadLength); DateTime dateTimeStamp = TimeStampToDateTime(instanceData.TimeStamp); NativeRuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload); } } // Wait for more events. if (!m_stopDispatchTask) { if (!eventsReceived) { EventPipeInternal.WaitForSessionSignal(m_sessionID, Timeout.Infinite); } Thread.Sleep(10); } } }
private unsafe void DispatchEventsToEventListeners() { // Struct to fill with the call to GetNextEvent. EventPipeEventInstanceData instanceData; while (!m_stopDispatchTask) { // Get the next event. while (!m_stopDispatchTask && EventPipeInternal.GetNextEvent(&instanceData)) { // Filter based on provider. if (instanceData.ProviderID == m_RuntimeProviderID) { // Dispatch the event. ReadOnlySpan <Byte> payload = new ReadOnlySpan <byte>((void *)instanceData.Payload, (int)instanceData.PayloadLength); DateTime dateTimeStamp = TimeStampToDateTime(instanceData.TimeStamp); RuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload); } } // Wait for more events. if (!m_stopDispatchTask) { Thread.Sleep(10); } } }
/// <summary> /// When a thread starts work that is on behalf of 'something else' (typically another /// thread or network request) it should mark the thread as working on that other work. /// This API marks the current thread as working on activity 'activityID'. It returns /// whatever activity the thread was previously marked with. There is a convention that /// callers can assume that callees restore this activity mark before the callee returns. /// To encourage this, this API returns the old activity, so that it can be restored later. /// /// All events created with the EventSource on this thread are also tagged with the /// activity ID of the thread. /// /// It is common, and good practice after setting the thread to an activity to log an event /// with a 'start' opcode to indicate that precise time/thread where the new activity /// started. /// </summary> /// <param name="activityId">A Guid that represents the new activity with which to mark /// the current thread</param> /// <param name="oldActivityThatWillContinue">The Guid that represents the current activity /// which will continue at some point in the future, on the current thread</param> public static void SetCurrentThreadActivityId(Guid activityId, out Guid oldActivityThatWillContinue) { oldActivityThatWillContinue = activityId; #if FEATURE_MANAGED_ETW // We ignore errors to keep with the convention that EventSources do not throw errors. // Note we can't access m_throwOnWrites because this is a static method. #if FEATURE_PERFTRACING && PLATFORM_WINDOWS EventPipeInternal.EventActivityIdControl( (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref oldActivityThatWillContinue); #elif FEATURE_PERFTRACING EventPipeInternal.EventActivityIdControl( (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, ref oldActivityThatWillContinue); #endif // FEATURE_PERFTRACING && PLATFORM_WINDOWS #if PLATFORM_WINDOWS UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, ref oldActivityThatWillContinue); #endif // PLATFORM_WINDOWS #endif // FEATURE_MANAGED_ETW // We don't call the activityDying callback here because the caller has declared that // it is not dying. if (TplEtwProvider.Log != null) { TplEtwProvider.Log.SetActivityId(activityId); } }
// Write an event. unsafe int IEventProvider.EventWriteTransferWrapper( long registrationHandle, ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid *activityId, Guid *relatedActivityId, int userDataCount, EventProvider.EventData *userData) { uint eventID = (uint)eventDescriptor.EventId; if (eventID != 0 && eventHandle != IntPtr.Zero) { if (userDataCount == 0) { EventPipeInternal.WriteEventData(eventHandle, eventID, null, 0, activityId, relatedActivityId); return(0); } // If Channel == 11, this is a TraceLogging event. // The first 3 descriptors contain event metadata that is emitted for ETW and should be discarded on EventPipe. // EventPipe metadata is provided via the EventPipeEventProvider.DefineEventHandle. if (eventDescriptor.Channel == 11) { userData = userData + 3; userDataCount = userDataCount - 3; Debug.Assert(userDataCount >= 0); } EventPipeInternal.WriteEventData(eventHandle, eventID, userData, (uint)userDataCount, activityId, relatedActivityId); } return(0); }
private void CommitDispatchConfiguration() { Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); // Ensure that the dispatch task is stopped. // This is a no-op if the task is already stopped. StopDispatchTask(); // Stop tracing. // This is a no-op if it's already disabled. EventPipeInternal.Disable(m_sessionID); // Check to see if tracing should be enabled. if (m_subscriptions.Count <= 0) { return; } // Determine the keywords and level that should be used based on the set of enabled EventListeners. EventKeywords aggregatedKeywords = EventKeywords.None; EventLevel highestLevel = EventLevel.LogAlways; foreach (EventListenerSubscription subscription in m_subscriptions.Values) { aggregatedKeywords |= subscription.MatchAnyKeywords; highestLevel = (subscription.Level > highestLevel) ? subscription.Level : highestLevel; } // Enable the EventPipe session. EventPipeProviderConfiguration[] providerConfiguration = new EventPipeProviderConfiguration[] { new EventPipeProviderConfiguration(RuntimeEventSource.EventSourceName, (ulong)aggregatedKeywords, (uint)highestLevel, null) }; m_sessionID = EventPipeInternal.Enable(null, 1024, 1, providerConfiguration, 1, 0); Debug.Assert(m_sessionID != 0); // Get the session information that is required to properly dispatch events. EventPipeSessionInfo sessionInfo; unsafe { if (!EventPipeInternal.GetSessionInfo(m_sessionID, &sessionInfo)) { Debug.Assert(false, "GetSessionInfo returned false."); } } m_syncTimeUtc = DateTime.FromFileTimeUtc(sessionInfo.StartTimeAsUTCFileTime); m_syncTimeQPC = sessionInfo.StartTimeStamp; m_timeQPCFrequency = sessionInfo.TimeStampFrequency; // Start the dispatch task. StartDispatchTask(); }
private void StopDispatchTask() { Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); if (m_dispatchTask != null) { m_stopDispatchTask = true; EventPipeInternal.SignalSession(m_sessionID); m_dispatchTask.Wait(); m_dispatchTask = null; } }
private void StartDispatchTask() { Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); if (m_dispatchTask == null) { m_stopDispatchTask = false; // Create a SafeWaitHandle that won't release the handle when done m_dispatchTaskWaitHandle.SafeWaitHandle = new SafeWaitHandle(EventPipeInternal.GetWaitHandle(m_sessionID), false); m_dispatchTask = Task.Factory.StartNew(DispatchEventsToEventListeners, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } }
// ActivityID support (see also WriteEventWithRelatedActivityIdCore) /// <summary> /// When a thread starts work that is on behalf of 'something else' (typically another /// thread or network request) it should mark the thread as working on that other work. /// This API marks the current thread as working on activity 'activityID'. This API /// should be used when the caller knows the thread's current activity (the one being /// overwritten) has completed. Otherwise, callers should prefer the overload that /// return the oldActivityThatWillContinue (below). /// /// All events created with the EventSource on this thread are also tagged with the /// activity ID of the thread. /// /// It is common, and good practice after setting the thread to an activity to log an event /// with a 'start' opcode to indicate that precise time/thread where the new activity /// started. /// </summary> /// <param name="activityId">A Guid that represents the new activity with which to mark /// the current thread</param> public static void SetCurrentThreadActivityId(Guid activityId) { if (TplEtwProvider.Log != null) { TplEtwProvider.Log.SetActivityId(activityId); } #if FEATURE_MANAGED_ETW #if FEATURE_ACTIVITYSAMPLING Guid newId = activityId; #endif // FEATURE_ACTIVITYSAMPLING // We ignore errors to keep with the convention that EventSources do not throw errors. // Note we can't access m_throwOnWrites because this is a static method. #if FEATURE_PERFTRACING && PLATFORM_WINDOWS // Set the activity id via EventPipe. EventPipeInternal.EventActivityIdControl( (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref activityId); // Set the activity id via ETW and fetch the previous id. if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, ref activityId) == 0) #elif FEATURE_PERFTRACING if (EventPipeInternal.EventActivityIdControl( (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, ref activityId) == 0) #elif PLATFORM_WINDOWS if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_GET_SET_ID, ref activityId) == 0) #endif // FEATURE_PERFTRACING && PLATFORM_WINDOWS { #if FEATURE_ACTIVITYSAMPLING var activityDying = s_activityDying; if (activityDying != null && newId != activityId) { if (activityId == Guid.Empty) { activityId = FallbackActivityId; } // OutputDebugString(string.Format("Activity dying: {0} -> {1}", activityId, newId)); activityDying(activityId); // This is actually the OLD activity ID. } #endif // FEATURE_ACTIVITYSAMPLING } #endif // FEATURE_MANAGED_ETW }
internal static void Enable(EventPipeConfiguration configuration) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } EventPipeProviderConfiguration[] providers = configuration.Providers; EventPipeInternal.Enable( configuration.OutputFile, configuration.CircularBufferSizeInMB, configuration.ProfilerSamplingRateInNanoseconds, providers, providers.Length); }
internal static void Enable(EventPipeConfiguration configuration) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } if (configuration.Providers == null) { throw new ArgumentNullException(nameof(configuration.Providers)); } EventPipeProviderConfiguration[] providers = configuration.Providers; s_sessionID = EventPipeInternal.Enable( configuration.OutputFile, configuration.Format, configuration.CircularBufferSizeInMB, providers); }
// Write an event. unsafe int IEventProvider.EventWriteTransferWrapper( long registrationHandle, ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid *activityId, Guid *relatedActivityId, int userDataCount, EventProvider.EventData *userData) { uint eventID = (uint)eventDescriptor.EventId; if (eventID != 0 && eventHandle != IntPtr.Zero) { if (userDataCount == 0) { EventPipeInternal.WriteEvent(eventHandle, eventID, null, 0, activityId, relatedActivityId); return(0); } uint length = 0; for (int i = 0; i < userDataCount; i++) { length += userData[i].Size; } byte[] data = new byte[length]; fixed(byte *pData = data) { uint offset = 0; for (int i = 0; i < userDataCount; i++) { byte *singleUserDataPtr = (byte *)(userData[i].Ptr); uint singleUserDataSize = userData[i].Size; WriteToBuffer(pData, length, ref offset, singleUserDataPtr, singleUserDataSize); } EventPipeInternal.WriteEvent(eventHandle, eventID, pData, length, activityId, relatedActivityId); } } return(0); }
internal static void Enable(EventPipeConfiguration configuration) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } if (configuration.Providers == null) { throw new ArgumentNullException(nameof(configuration.Providers)); } EventPipeProviderConfiguration[] providers = configuration.Providers; s_sessionID = EventPipeInternal.Enable( configuration.OutputFile, configuration.CircularBufferSizeInMB, (ulong)configuration.ProfilerSamplingRateInNanoseconds, providers, (uint)providers.Length, configuration.MultiFileTraceLengthInSeconds); }
// Write an event. unsafe int IEventProvider.EventWriteTransferWrapper( long registrationHandle, ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid *activityId, Guid *relatedActivityId, int userDataCount, EventProvider.EventData *userData) { uint eventID = (uint)eventDescriptor.EventId; if (eventID != 0 && eventHandle != IntPtr.Zero) { if (userDataCount == 0) { EventPipeInternal.WriteEventData(eventHandle, eventID, null, 0, activityId, relatedActivityId); return(0); } EventPipeInternal.WriteEventData(eventHandle, eventID, &userData, (uint)userDataCount, activityId, relatedActivityId); } return(0); }
// Register an event provider. unsafe uint IEventProvider.EventRegister( EventSource eventSource, UnsafeNativeMethods.ManifestEtw.EtwEnableCallback enableCallback, void *callbackContext, ref long registrationHandle) { uint returnStatus = 0; m_provHandle = EventPipeInternal.CreateProvider(eventSource.Name, enableCallback); if (m_provHandle != IntPtr.Zero) { // Fixed registration handle because a new EventPipeEventProvider // will be created for each new EventSource. registrationHandle = 1; } else { // Unable to create the provider. returnStatus = 1; } return(returnStatus); }
private unsafe void DispatchEventsToEventListeners() { // Struct to fill with the call to GetNextEvent. EventPipeEventInstanceData instanceData; while (!m_stopDispatchTask) { bool eventsReceived = false; // Get the next event. while (!m_stopDispatchTask && EventPipeInternal.GetNextEvent(m_sessionID, &instanceData)) { eventsReceived = true; // Filter based on provider. if (instanceData.ProviderID == m_RuntimeProviderID) { // Dispatch the event. ReadOnlySpan <Byte> payload = new ReadOnlySpan <byte>((void *)instanceData.Payload, (int)instanceData.PayloadLength); DateTime dateTimeStamp = TimeStampToDateTime(instanceData.TimeStamp); NativeRuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload); } } // Wait for more events. if (!m_stopDispatchTask) { if (!eventsReceived) { // Future TODO: this would make more sense to handle in EventPipeSession/EventPipe native code. Debug.Assert(!m_dispatchTaskWaitHandle.SafeWaitHandle.IsInvalid); m_dispatchTaskWaitHandle.WaitOne(); } Thread.Sleep(10); } } }
// ActivityID support (see also WriteEventWithRelatedActivityIdCore) /// <summary> /// When a thread starts work that is on behalf of 'something else' (typically another /// thread or network request) it should mark the thread as working on that other work. /// This API marks the current thread as working on activity 'activityID'. This API /// should be used when the caller knows the thread's current activity (the one being /// overwritten) has completed. Otherwise, callers should prefer the overload that /// return the oldActivityThatWillContinue (below). /// /// All events created with the EventSource on this thread are also tagged with the /// activity ID of the thread. /// /// It is common, and good practice after setting the thread to an activity to log an event /// with a 'start' opcode to indicate that precise time/thread where the new activity /// started. /// </summary> /// <param name="activityId">A Guid that represents the new activity with which to mark /// the current thread</param> public static void SetCurrentThreadActivityId(Guid activityId) { if (TplEventSource.Log != null) { TplEventSource.Log.SetActivityId(activityId); } // We ignore errors to keep with the convention that EventSources do not throw errors. // Note we can't access m_throwOnWrites because this is a static method. #if FEATURE_MANAGED_ETW #if FEATURE_PERFTRACING // Set the activity id via EventPipe. EventPipeInternal.EventActivityIdControl( (uint)UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref activityId); #endif // FEATURE_PERFTRACING #if PLATFORM_WINDOWS // Set the activity id via ETW. UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( UnsafeNativeMethods.ManifestEtw.ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref activityId); #endif // PLATFORM_WINDOWS #endif // FEATURE_MANAGED_ETW }
private void CommitDispatchConfiguration() { // Ensure that the dispatch task is stopped. // This is a no-op if the task is already stopped. StopDispatchTask(); // Stop tracing. // This is a no-op if it's already disabled. EventPipeInternal.Disable(); // Check to see if tracing should be enabled. if (m_subscriptions.Count <= 0) { return; } // Start collecting events. EventKeywords aggregatedKeywords = EventKeywords.None; EventLevel highestLevel = EventLevel.LogAlways; foreach (EventListenerSubscription subscription in m_subscriptions.Values) { aggregatedKeywords |= subscription.MatchAnyKeywords; highestLevel = (subscription.Level > highestLevel) ? subscription.Level : highestLevel; } EventPipeProviderConfiguration[] providerConfiguration = new EventPipeProviderConfiguration[] { new EventPipeProviderConfiguration(RuntimeEventSource.EventSourceName, (ulong)aggregatedKeywords, (uint)highestLevel) }; EventPipeInternal.Enable(null, 1024, 1, providerConfiguration, 1); // Start the dispatch task. StartDispatchTask(); }
// Unregister an event provider. uint IEventProvider.EventUnregister(long registrationHandle) { EventPipeInternal.DeleteProvider(m_provHandle); return(0); }
private EventPipeEventDispatcher() { // Get the ID of the runtime provider so that it can be used as a filter when processing events. m_RuntimeProviderID = EventPipeInternal.GetProvider(RuntimeEventSource.EventSourceName); }
private EventPipeEventDispatcher() { // Get the ID of the runtime provider so that it can be used as a filter when processing events. m_RuntimeProviderID = EventPipeInternal.GetProvider(NativeRuntimeEventSource.EventSourceName); m_dispatchTaskWaitHandle.SafeWaitHandle = new SafeWaitHandle(IntPtr.Zero, false); }
internal static void Disable() { EventPipeInternal.Disable(); }
// Get or set the per-thread activity ID. int IEventProvider.EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId) { return(EventPipeInternal.EventActivityIdControl((uint)ControlCode, ref ActivityId)); }
// Define an EventPipeEvent handle. unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength) { IntPtr eventHandlePtr = EventPipeInternal.DefineEvent(m_provHandle, eventID, keywords, eventVersion, level, pMetadata, metadataLength); return(eventHandlePtr); }
internal static void Disable() { EventPipeInternal.Disable(s_sessionID); }