Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Debugger.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\EditAndContinueHelper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\EventPipe.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\NativeRuntimeEventSource.PortableThreadPool.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\ICustomDebuggerNotification.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrame.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrameHelper.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading;
using System.Diagnostics.Tracing;
using System.Runtime.CompilerServices;
using Internal.Runtime.CompilerServices;

namespace System.Diagnostics.Tracing
{
// This is part of the NativeRuntimeEventsource, which is the managed version of the Microsoft-Windows-DotNETRuntime provider.
// It contains the handwritten implementation of the ThreadPool events.
// The events here do not call into the typical WriteEvent* APIs unlike most EventSources because that results in the
// events to be forwarded to EventListeners twice, once directly from the managed WriteEvent API, and another time
// from the mechanism in NativeRuntimeEventSource.ProcessEvents that forwards native runtime events to EventListeners.
// To prevent this, these events call directly into QCalls provided by the runtime (refer to NativeRuntimeEventSource.cs) which call
// FireEtw* methods auto-generated from ClrEtwAll.man. This ensures that corresponding event sinks are being used
// for the native platform. Refer to src/coreclr/vm/nativeruntimesource.cpp.
// For Mono implementation of these events, refer to NativeRuntimeEventSource.PortableThreadPool.cs.
internal sealed partial class NativeRuntimeEventSource : EventSource
{
// This value does not seem to be used, leaving it as zero for now. It may be useful for a scenario that may involve
// multiple instances of the runtime within the same process, but then it seems unlikely that both instances' thread
// pools would be in moderate use.
private const ushort DefaultClrInstanceId = 0;

private static class Messages
{
public const string WorkerThread = "ActiveWorkerThreadCount={0};\nRetiredWorkerThreadCount={1};\nClrInstanceID={2}";
public const string WorkerThreadAdjustmentSample = "Throughput={0};\nClrInstanceID={1}";
public const string WorkerThreadAdjustmentAdjustment = "AverageThroughput={0};\nNewWorkerThreadCount={1};\nReason={2};\nClrInstanceID={3}";
public const string WorkerThreadAdjustmentStats = "Duration={0};\nThroughput={1};\nThreadWave={2};\nThroughputWave={3};\nThroughputErrorEstimate={4};\nAverageThroughputErrorEstimate={5};\nThroughputRatio={6};\nConfidence={7};\nNewControlSetting={8};\nNewThreadWaveMagnitude={9};\nClrInstanceID={10}";
public const string IOEnqueue = "NativeOverlapped={0};\nOverlapped={1};\nMultiDequeues={2};\nClrInstanceID={3}";
public const string IO = "NativeOverlapped={0};\nOverlapped={1};\nClrInstanceID={2}";
public const string WorkingThreadCount = "Count={0};\nClrInstanceID={1}";
}

// The task definitions for the ETW manifest
public static class Tasks // this name and visibility is important for EventSource
{
public const EventTask ThreadPoolWorkerThread = (EventTask)16;
public const EventTask ThreadPoolWorkerThreadAdjustment = (EventTask)18;
public const EventTask ThreadPool = (EventTask)23;
public const EventTask ThreadPoolWorkingThreadCount = (EventTask)22;
}

public static class Opcodes // this name and visibility is important for EventSource
{
public const EventOpcode IOEnqueue = (EventOpcode)13;
public const EventOpcode IODequeue = (EventOpcode)14;
public const EventOpcode Wait = (EventOpcode)90;
public const EventOpcode Sample = (EventOpcode)100;
public const EventOpcode Adjustment = (EventOpcode)101;
public const EventOpcode Stats = (EventOpcode)102;
}

public enum ThreadAdjustmentReasonMap : uint
{
Warmup,
Initializing,
RandomMove,
ClimbingMove,
ChangePoint,
Stabilizing,
Starvation,
ThreadTimedOut
}

[Event(50, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = EventOpcode.Start, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadStart(
uint ActiveWorkerThreadCount,
uint RetiredWorkerThreadCount = 0,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadStart(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
}
}

[Event(51, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = EventOpcode.Stop, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public void ThreadPoolWorkerThreadStop(
uint ActiveWorkerThreadCount,
uint RetiredWorkerThreadCount = 0,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadStop(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
}
}

[Event(57, Level = EventLevel.Informational, Message = Messages.WorkerThread, Task = Tasks.ThreadPoolWorkerThread, Opcode = Opcodes.Wait, Version = 0, Keywords = Keywords.ThreadingKeyword)]
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThreadPoolWorkerThreadWait(
uint ActiveWorkerThreadCount,
uint RetiredWorkerThreadCount = 0,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
LogThreadPoolWorkerThreadWait(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID);
}
}

[Event(54, Level = EventLevel.Informational, Message = Messages.WorkerThreadAdjustmentSample, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Sample, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadAdjustmentSample(
double Throughput,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkerThreadAdjustmentSample(Throughput, ClrInstanceID);
}

[Event(55, Level = EventLevel.Informational, Message = Messages.WorkerThreadAdjustmentAdjustment, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Adjustment, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadAdjustmentAdjustment(
double AverageThroughput,
uint NewWorkerThreadCount,
ThreadAdjustmentReasonMap Reason,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkerThreadAdjustmentAdjustment(AverageThroughput, NewWorkerThreadCount, Reason, ClrInstanceID);
}

[Event(56, Level = EventLevel.Verbose, Message = Messages.WorkerThreadAdjustmentStats, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Stats, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkerThreadAdjustmentStats(
double Duration,
double Throughput,
double ThreadWave,
double ThroughputWave,
double ThroughputErrorEstimate,
double AverageThroughputErrorEstimate,
double ThroughputRatio,
double Confidence,
double NewControlSetting,
ushort NewThreadWaveMagnitude,
ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkerThreadAdjustmentStats(Duration, Throughput, ThreadWave, ThroughputWave, ThroughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, Confidence, NewControlSetting, NewThreadWaveMagnitude, ClrInstanceID);
}

[Event(63, Level = EventLevel.Verbose, Message = Messages.IOEnqueue, Task = Tasks.ThreadPool, Opcode = Opcodes.IOEnqueue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)]
private unsafe void ThreadPoolIOEnqueue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
bool MultiDequeues,
ushort ClrInstanceID = DefaultClrInstanceId)
{
int multiDequeuesInt = Convert.ToInt32(MultiDequeues); // bool maps to "win:Boolean", a 4-byte boolean
LogThreadPoolIOEnqueue(NativeOverlapped, Overlapped, MultiDequeues, ClrInstanceID);
}

// TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use
// FrameworkEventSource's thread transfer send/receive events instead at callers.
[NonEvent]
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThreadPoolIOEnqueue(RegisteredWaitHandle registeredWaitHandle)
{
if (IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword))
{
ThreadPoolIOEnqueue((IntPtr)registeredWaitHandle.GetHashCode(), IntPtr.Zero, registeredWaitHandle.Repeating);
}
}

[Event(64, Level = EventLevel.Verbose, Message = Messages.IO, Task = Tasks.ThreadPool, Opcode = Opcodes.IODequeue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)]
private unsafe void ThreadPoolIODequeue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
ushort ClrInstanceID = DefaultClrInstanceId)
{
LogThreadPoolIODequeue(NativeOverlapped, Overlapped, ClrInstanceID);
}

// TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use
// FrameworkEventSource's thread transfer send/receive events instead at callers.
[NonEvent]
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThreadPoolIODequeue(RegisteredWaitHandle registeredWaitHandle)
{
if (IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword))
{
ThreadPoolIODequeue((IntPtr)registeredWaitHandle.GetHashCode(), IntPtr.Zero);
}
}

[Event(60, Level = EventLevel.Verbose, Message = Messages.WorkingThreadCount, Task = Tasks.ThreadPoolWorkingThreadCount, Opcode = EventOpcode.Start, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolWorkingThreadCount(uint Count, ushort ClrInstanceID = DefaultClrInstanceId)
{
if (!IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword))
{
return;
}
LogThreadPoolWorkingThreadCount(Count, ClrInstanceID);
}
}
}
14 changes: 9 additions & 5 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -989,13 +989,15 @@ FCFuncStart(gStreamFuncs)
FCFuncEnd()


#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
FCFuncStart(gEventLogger)
#if defined(FEATURE_EVENTSOURCE_XPLAT)
FCFuncStart(gEventLogger)
QCFuncElement("IsEventSourceLoggingEnabled", XplatEventSourceLogger::IsEventSourceLoggingEnabled)
QCFuncElement("LogEventSource", XplatEventSourceLogger::LogEventSource)
FCFuncEnd()
#endif // defined(FEATURE_EVENTSOURCE_XPLAT)

#if defined(FEATURE_PERFTRACING)
FCFuncStart(gNativeEventLogger)
QCFuncElement("LogThreadPoolWorkerThreadStart", NativeEventLogger::LogThreadPoolWorkerThreadStart)
QCFuncElement("LogThreadPoolWorkerThreadStop", NativeEventLogger::LogThreadPoolWorkerThreadStop)
QCFuncElement("LogThreadPoolWorkerThreadWait", NativeEventLogger::LogThreadPoolWorkerThreadWait)
Expand All @@ -1005,9 +1007,8 @@ FCFuncStart(gEventLogger)
QCFuncElement("LogThreadPoolIOEnqueue", NativeEventLogger::LogThreadPoolIOEnqueue)
QCFuncElement("LogThreadPoolIODequeue", NativeEventLogger::LogThreadPoolIODequeue)
QCFuncElement("LogThreadPoolWorkingThreadCount", NativeEventLogger::LogThreadPoolWorkingThreadCount)
#endif // defined(FEATURE_PERFTRACING)
FCFuncEnd()
#endif // defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
#endif // defined(FEATURE_PERFTRACING)

#ifdef FEATURE_PERFTRACING
FCFuncStart(gEventPipeInternalFuncs)
Expand Down Expand Up @@ -1165,6 +1166,9 @@ FCClassElement("ModuleBuilder", "System.Reflection.Emit", gCOMModuleBuilderFuncs
FCClassElement("ModuleHandle", "System", gCOMModuleHandleFuncs)
FCClassElement("Monitor", "System.Threading", gMonitorFuncs)
FCClassElement("NativeLibrary", "System.Runtime.InteropServices", gInteropNativeLibraryFuncs)
#if defined(FEATURE_PERFTRACING)
FCClassElement("NativeRuntimeEventSource", "System.Diagnostics.Tracing", gNativeEventLogger)
#endif //defined(FEATURE_PERFTRACING)
#ifdef FEATURE_COMINTEROP
FCClassElement("OAVariantLib", "Microsoft.Win32", gOAVariantFuncs)
#endif
Expand Down Expand Up @@ -1213,7 +1217,7 @@ FCClassElement("WeakReference`1", "System", gWeakReferenceOfTFuncs)
FCClassElement("X86Base", "System.Runtime.Intrinsics.X86", gX86BaseFuncs)
#endif // defined(TARGET_X86) || defined(TARGET_AMD64)

#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
#if defined(FEATURE_EVENTSOURCE_XPLAT)
FCClassElement("XplatEventLogger", "System.Diagnostics.Tracing", gEventLogger)
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1960,7 +1960,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPool.Portable.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPoolBoundHandle.PlatformNotSupported.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.GateThread.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.HillClimbing.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.HillClimbing.Complex.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,15 @@ protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* rel
#endif // FEATURE_MANAGED_ETW

if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data);
{
#if MONO && !TARGET_BROWSER
// On Mono, managed events from NativeRuntimeEventSource are written using WriteEventCore which can be
// written doubly because EventPipe tries to pump it back up to EventListener via NativeRuntimeEventSource.ProcessEvents.
// So we need to prevent this from getting written directly to the Listeners.
if (this.GetType() != typeof(NativeRuntimeEventSource))
#endif // MONO && !TARGET_BROWSER
WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data);
}
}
catch (Exception ex)
{
Expand Down
Loading