forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Dispatch Runtime Events to EventListener (dotnet/coreclr#18649)
Commit migrated from dotnet/coreclr@b3b9d08
- Loading branch information
Showing
23 changed files
with
907 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
...lr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/DotNETRuntimeEventSource.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
namespace System.Diagnostics.Tracing | ||
{ | ||
#if FEATURE_PERFTRACING | ||
/// <summary> | ||
/// RuntimeEventSource is an EventSource that represents the ETW/EventPipe events emitted by the native runtime. | ||
/// Most of RuntimeEventSource is auto-generated by scripts/genRuntimeEventSources.py based on the contents of the Microsoft-Windows-DotNETRuntime provider. | ||
/// </summary> | ||
internal sealed partial class RuntimeEventSource : EventSource | ||
{ | ||
/// <summary> | ||
/// Dispatch a single event with the specified event ID and payload. | ||
/// </summary> | ||
/// <param name="eventID">The eventID corresponding to the event as defined in the auto-generated portion of the RuntimeEventSource class.</param> | ||
/// <param name="payload">A span pointing to the data payload for the event.</param> | ||
[NonEvent] | ||
internal unsafe void ProcessEvent(uint eventID, ReadOnlySpan<Byte> payload) | ||
{ | ||
// Make sure the eventID is valid. | ||
if (eventID >= m_eventData.Length) | ||
{ | ||
return; | ||
} | ||
|
||
// Decode the payload. | ||
object[] decodedPayloadFields = EventPipePayloadDecoder.DecodePayload(ref m_eventData[eventID], payload); | ||
WriteToAllListeners((int)eventID, null, null, decodedPayloadFields); | ||
} | ||
} | ||
#endif // FEATURE_PERFTRACING | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
...lr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace System.Diagnostics.Tracing | ||
{ | ||
#if FEATURE_PERFTRACING | ||
internal sealed class EventPipeEventDispatcher | ||
{ | ||
internal sealed class EventListenerSubscription | ||
{ | ||
internal EventKeywords MatchAnyKeywords { get; private set; } | ||
internal EventLevel Level { get; private set; } | ||
|
||
internal EventListenerSubscription(EventKeywords matchAnyKeywords, EventLevel level) | ||
{ | ||
MatchAnyKeywords = matchAnyKeywords; | ||
Level = level; | ||
} | ||
} | ||
|
||
internal static readonly EventPipeEventDispatcher Instance = new EventPipeEventDispatcher(); | ||
|
||
private IntPtr m_RuntimeProviderID; | ||
|
||
private bool m_stopDispatchTask; | ||
private Task m_dispatchTask = null; | ||
private object m_dispatchControlLock = new object(); | ||
private Dictionary<EventListener, EventListenerSubscription> m_subscriptions = new Dictionary<EventListener, EventListenerSubscription>(); | ||
|
||
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); | ||
} | ||
|
||
internal void SendCommand(EventListener eventListener, EventCommand command, bool enable, EventLevel level, EventKeywords matchAnyKeywords) | ||
{ | ||
if (command == EventCommand.Update && enable) | ||
{ | ||
lock (m_dispatchControlLock) | ||
{ | ||
// Add the new subscription. This will overwrite an existing subscription for the listener if one exists. | ||
m_subscriptions[eventListener] = new EventListenerSubscription(matchAnyKeywords, level); | ||
|
||
// Commit the configuration change. | ||
CommitDispatchConfiguration(); | ||
} | ||
} | ||
else if (command == EventCommand.Update && !enable) | ||
{ | ||
RemoveEventListener(eventListener); | ||
} | ||
} | ||
|
||
internal void RemoveEventListener(EventListener listener) | ||
{ | ||
lock (m_dispatchControlLock) | ||
{ | ||
// Remove the event listener from the list of subscribers. | ||
if (m_subscriptions.ContainsKey(listener)) | ||
{ | ||
m_subscriptions.Remove(listener); | ||
} | ||
|
||
// Commit the configuration change. | ||
CommitDispatchConfiguration(); | ||
} | ||
} | ||
|
||
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(); | ||
} | ||
|
||
private void StartDispatchTask() | ||
{ | ||
Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); | ||
|
||
if (m_dispatchTask == null) | ||
{ | ||
m_stopDispatchTask = false; | ||
m_dispatchTask = Task.Factory.StartNew(DispatchEventsToEventListeners, TaskCreationOptions.LongRunning); | ||
} | ||
} | ||
|
||
private void StopDispatchTask() | ||
{ | ||
Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); | ||
|
||
if(m_dispatchTask != null) | ||
{ | ||
m_stopDispatchTask = true; | ||
m_dispatchTask.Wait(); | ||
m_dispatchTask = null; | ||
} | ||
} | ||
|
||
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); | ||
RuntimeEventSource.Log.ProcessEvent(instanceData.EventID, payload); | ||
} | ||
} | ||
|
||
// Wait for more events. | ||
if (!m_stopDispatchTask) | ||
{ | ||
Thread.Sleep(10); | ||
} | ||
} | ||
} | ||
} | ||
#endif // FEATURE_PERFTRACING | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.