diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index c9c6140ea56ded..1dd3eb3291ca9a 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -138,7 +138,7 @@
-
+
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.Threading.NativeSinks.CoreCLR.cs
similarity index 52%
rename from src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.CoreCLR.cs
rename to src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.Threading.NativeSinks.CoreCLR.cs
index c618f1d5203e4e..511476e789fe2a 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.Threading.NativeSinks.CoreCLR.cs
@@ -1,8 +1,6 @@
// 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 System.Runtime.InteropServices;
@@ -14,31 +12,51 @@ internal sealed partial class NativeRuntimeEventSource : EventSource
{
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkerThreadStart(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
+ private static partial void LogContentionLockCreated(nint LockID, nint AssociatedObjectID, ushort ClrInstanceID);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkerThreadStop(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
+ private static partial void LogContentionStart(
+ ContentionFlagsMap ContentionFlags,
+ ushort ClrInstanceID,
+ nint LockID,
+ nint AssociatedObjectID,
+ ulong LockOwnerThreadID);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkerThreadWait(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
+ private static partial void LogContentionStop(
+ ContentionFlagsMap ContentionFlags,
+ ushort ClrInstanceID,
+ double DurationNs);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolMinMaxThreads(ushort MinWorkerThreads, ushort MaxWorkerThreads, ushort MinIOCompletionThreads, ushort MaxIOCompletionThreads, ushort ClrInstanceID);
+ private static partial void LogThreadPoolWorkerThreadStart(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkerThreadAdjustmentSample(double Throughput, ushort ClrInstanceID);
+ private static partial void LogThreadPoolWorkerThreadStop(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkerThreadAdjustmentAdjustment(double AverageThroughput, uint NewWorkerThreadCount, ThreadAdjustmentReasonMap Reason, ushort ClrInstanceID);
+ private static partial void LogThreadPoolWorkerThreadWait(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkerThreadAdjustmentStats(
+ private static partial void LogThreadPoolMinMaxThreads(ushort MinWorkerThreads, ushort MaxWorkerThreads, ushort MinIOCompletionThreads, ushort MaxIOCompletionThreads, ushort ClrInstanceID);
+
+ [NonEvent]
+ [LibraryImport(RuntimeHelpers.QCall)]
+ private static partial void LogThreadPoolWorkerThreadAdjustmentSample(double Throughput, ushort ClrInstanceID);
+
+ [NonEvent]
+ [LibraryImport(RuntimeHelpers.QCall)]
+ private static partial void LogThreadPoolWorkerThreadAdjustmentAdjustment(double AverageThroughput, uint NewWorkerThreadCount, ThreadAdjustmentReasonMap Reason, ushort ClrInstanceID);
+
+ [NonEvent]
+ [LibraryImport(RuntimeHelpers.QCall)]
+ private static partial void LogThreadPoolWorkerThreadAdjustmentStats(
double Duration,
double Throughput,
double ThreadPoolWorkerThreadWait,
@@ -53,7 +71,7 @@ internal static partial void LogThreadPoolWorkerThreadAdjustmentStats(
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolIOEnqueue(
+ private static partial void LogThreadPoolIOEnqueue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
[MarshalAs(UnmanagedType.Bool)] bool MultiDequeues,
@@ -61,21 +79,21 @@ internal static partial void LogThreadPoolIOEnqueue(
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolIODequeue(
+ private static partial void LogThreadPoolIODequeue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
ushort ClrInstanceID);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolWorkingThreadCount(
+ private static partial void LogThreadPoolWorkingThreadCount(
uint Count,
ushort ClrInstanceID
);
[NonEvent]
[LibraryImport(RuntimeHelpers.QCall)]
- internal static partial void LogThreadPoolIOPack(
+ private static partial void LogThreadPoolIOPack(
IntPtr NativeOverlapped,
IntPtr Overlapped,
ushort ClrInstanceID);
diff --git a/src/coreclr/scripts/genRuntimeEventSources.py b/src/coreclr/scripts/genRuntimeEventSources.py
index fafa9a223a7218..f47a30f284519f 100644
--- a/src/coreclr/scripts/genRuntimeEventSources.py
+++ b/src/coreclr/scripts/genRuntimeEventSources.py
@@ -85,10 +85,12 @@ def getManifestsToGenerate(runtimeFlavor):
def generateEvent(eventNode, providerNode, outputFile, stringTable):
- # ThreadPool events are defined manually in NativeRuntimeEventSource.PortableThreadPool.cs
+ # ThreadPool and Contention events are defined manually in NativeRuntimeEventSource.Threading.cs
symbol = eventNode.getAttribute("symbol")
if "ThreadPool" in symbol:
return
+ if "Contention" in symbol:
+ return
evtLevel = eventNode.getAttribute("level")[4:]
evtKeywords = ""
diff --git a/src/coreclr/vm/nativeeventsource.cpp b/src/coreclr/vm/nativeeventsource.cpp
index 9ec83103ca505a..b4bca0355e6c7a 100644
--- a/src/coreclr/vm/nativeeventsource.cpp
+++ b/src/coreclr/vm/nativeeventsource.cpp
@@ -153,4 +153,40 @@ extern "C" void QCALLTYPE LogThreadPoolIOPack(_In_z_ void* nativeOverlapped, _In
END_QCALL;
}
+
+extern "C" void QCALLTYPE LogContentionLockCreated(void* LockID, void* AssociatedObjectID, uint16_t ClrInstanceID)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
+
+ FireEtwContentionLockCreated(LockID, AssociatedObjectID, ClrInstanceID);
+
+ END_QCALL;
+}
+
+extern "C" void QCALLTYPE LogContentionStart(
+ uint8_t ContentionFlags,
+ uint16_t ClrInstanceID,
+ void* LockID,
+ void* AssociatedObjectID,
+ uint64_t LockOwnerThreadID)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
+
+ FireEtwContentionStart_V2(ContentionFlags, ClrInstanceID, LockID, AssociatedObjectID, LockOwnerThreadID);
+
+ END_QCALL;
+}
+
+extern "C" void QCALLTYPE LogContentionStop(uint8_t ContentionFlags, uint16_t ClrInstanceID, double DurationNs)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
+
+ FireEtwContentionStop_V1(ContentionFlags, ClrInstanceID, DurationNs);
+
+ END_QCALL;
+}
+
#endif // FEATURE_PERFTRACING
diff --git a/src/coreclr/vm/nativeeventsource.h b/src/coreclr/vm/nativeeventsource.h
index c649f7d9d0c37b..a407c4b5ebb10b 100644
--- a/src/coreclr/vm/nativeeventsource.h
+++ b/src/coreclr/vm/nativeeventsource.h
@@ -28,6 +28,9 @@ extern "C" void QCALLTYPE LogThreadPoolIOEnqueue(_In_z_ void* nativeOverlapped,
extern "C" void QCALLTYPE LogThreadPoolIODequeue(_In_z_ void* nativeOverlapped, _In_z_ void* overlapped, _In_z_ short ClrInstanceID);
extern "C" void QCALLTYPE LogThreadPoolWorkingThreadCount(_In_z_ uint count, _In_z_ short ClrInstanceID);
extern "C" void QCALLTYPE LogThreadPoolIOPack(_In_z_ void* nativeOverlapped, _In_z_ void* overlapped, _In_z_ short ClrInstanceID);
+extern "C" void QCALLTYPE LogContentionLockCreated(void* LockID, void* AssociatedObjectID, uint16_t ClrInstanceID);
+extern "C" void QCALLTYPE LogContentionStart(uint8_t ContentionFlags, uint16_t ClrInstanceID, void* LockID, void* AssociatedObjectID, uint64_t LockOwnerThreadID);
+extern "C" void QCALLTYPE LogContentionStop(uint8_t ContentionFlags, uint16_t ClrInstanceID, double DurationNs);
#endif // defined(FEATURE_PERFTRACING)
#endif //_NATIVEEVENTSOURCE_H_
diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp
index 352a85b5e809f8..f45cd9a25c47ec 100644
--- a/src/coreclr/vm/qcallentrypoints.cpp
+++ b/src/coreclr/vm/qcallentrypoints.cpp
@@ -275,6 +275,9 @@ static const Entry s_QCall[] =
DllImportEntry(LogThreadPoolIODequeue)
DllImportEntry(LogThreadPoolIOPack)
DllImportEntry(LogThreadPoolWorkingThreadCount)
+ DllImportEntry(LogContentionLockCreated)
+ DllImportEntry(LogContentionStart)
+ DllImportEntry(LogContentionStop)
DllImportEntry(EventPipeInternal_Enable)
DllImportEntry(EventPipeInternal_Disable)
DllImportEntry(EventPipeInternal_GetSessionInfo)
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 33fc345a995020..59ac5722225a26 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1444,6 +1444,8 @@
+
+
@@ -2549,8 +2551,6 @@
-
-
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.cs
similarity index 81%
rename from src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs
rename to src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.cs
index 28393f05627fef..ad7ee54ae227a4 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.cs
@@ -1,31 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Runtime.CompilerServices;
-using System.Diagnostics.CodeAnalysis;
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.
+ // It contains the handwritten implementation of threading 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.
- // For implementation of these events not supporting native sinks, refer to NativeRuntimeEventSource.PortableThreadPool.cs.
+ // For implementation of these events not supporting native sinks, refer to NativeRuntimeEventSource.Threading.cs.
[SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "NativeRuntimeEventSource is a special case where event methods don't use WriteEvent/WriteEventCore but still need to be instance methods.")]
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
+ private static partial class Messages
{
+ public const string ContentionLockCreated = "LockID={0};\nAssociatedObjectID={1};\nClrInstanceID={2}";
+ public const string ContentionStart = "ContentionFlags={0};\nClrInstanceID={1};\nLockID={2};\nAssociatedObjectID={3}\nLockOwnerThreadID={4}";
+ public const string ContentionStop = "ContentionFlags={0};\nClrInstanceID={1};\nDurationNs={2}";
public const string WorkerThread = "ActiveWorkerThreadCount={0};\nRetiredWorkerThreadCount={1};\nClrInstanceID={2}";
public const string MinMaxThreads = "MinWorkerThreads={0};\nMaxWorkerThreads={1};\nMinIOCompletionThreads={2};\nMaxIOCompletionThreads={3};\nClrInstanceID={4}";
public const string WorkerThreadAdjustmentSample = "Throughput={0};\nClrInstanceID={1}";
@@ -37,8 +35,9 @@ private static class Messages
}
// The task definitions for the ETW manifest
- public static class Tasks // this name and visibility is important for EventSource
+ public static partial class Tasks // this name and visibility is important for EventSource
{
+ public const EventTask Contention = (EventTask)8;
public const EventTask ThreadPoolWorkerThread = (EventTask)16;
public const EventTask ThreadPoolWorkerThreadAdjustment = (EventTask)18;
public const EventTask ThreadPool = (EventTask)23;
@@ -46,8 +45,9 @@ private static class Messages
public const EventTask ThreadPoolMinMaxThreads = (EventTask)38;
}
- public static class Opcodes // this name and visibility is important for EventSource
+ public static partial class Opcodes // this name and visibility is important for EventSource
{
+ public const EventOpcode LockCreated = (EventOpcode)11;
public const EventOpcode IOEnqueue = (EventOpcode)13;
public const EventOpcode IODequeue = (EventOpcode)14;
public const EventOpcode IOPack = (EventOpcode)15;
@@ -57,6 +57,12 @@ private static class Messages
public const EventOpcode Stats = (EventOpcode)102;
}
+ public enum ContentionFlagsMap : byte
+ {
+ Managed,
+ Native,
+ }
+
public enum ThreadAdjustmentReasonMap : uint
{
Warmup,
@@ -66,9 +72,41 @@ public enum ThreadAdjustmentReasonMap : uint
ChangePoint,
Stabilizing,
Starvation,
- ThreadTimedOut
+ ThreadTimedOut,
+ CooperativeBlocking,
+ }
+
+ [Event(90, Level = EventLevel.Informational, Message = Messages.ContentionLockCreated, Task = Tasks.Contention, Opcode = EventOpcode.Info, Version = 0, Keywords = Keywords.ContentionKeyword)]
+ private void ContentionLockCreated(nint LockID, nint AssociatedObjectID, ushort ClrInstanceID = DefaultClrInstanceId)
+ {
+ Debug.Assert(IsEnabled(EventLevel.Informational, Keywords.ContentionKeyword));
+ LogContentionLockCreated(LockID, AssociatedObjectID, ClrInstanceID);
}
+ [Event(81, Level = EventLevel.Informational, Message = Messages.ContentionStart, Task = Tasks.Contention, Opcode = EventOpcode.Start, Version = 2, Keywords = Keywords.ContentionKeyword)]
+ private void ContentionStart(
+ ContentionFlagsMap ContentionFlags,
+ ushort ClrInstanceID,
+ nint LockID,
+ nint AssociatedObjectID,
+ ulong LockOwnerThreadID)
+ {
+ Debug.Assert(IsEnabled(EventLevel.Informational, Keywords.ContentionKeyword));
+ LogContentionStart(ContentionFlags, ClrInstanceID, LockID, AssociatedObjectID, LockOwnerThreadID);
+ }
+
+ [Event(91, Level = EventLevel.Informational, Message = Messages.ContentionStop, Task = Tasks.Contention, Opcode = EventOpcode.Stop, Version = 1, Keywords = Keywords.ContentionKeyword)]
+ private void ContentionStop(ContentionFlagsMap ContentionFlags, ushort ClrInstanceID, double DurationNs)
+ {
+ Debug.Assert(IsEnabled(EventLevel.Informational, Keywords.ContentionKeyword));
+ LogContentionStop(ContentionFlags, ClrInstanceID, DurationNs);
+ }
+
+ [NonEvent]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void ContentionStop(double durationNs) =>
+ ContentionStop(ContentionFlagsMap.Managed, DefaultClrInstanceId, durationNs);
+
[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,
@@ -184,7 +222,9 @@ public void ThreadPoolIOEnqueue(RegisteredWaitHandle registeredWaitHandle)
{
if (IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword))
{
+#pragma warning disable CA1416 // 'RegisteredWaitHandle.Repeating' is unsupported on: 'browser'
ThreadPoolIOEnqueue((IntPtr)registeredWaitHandle.GetHashCode(), IntPtr.Zero, registeredWaitHandle.Repeating);
+#pragma warning restore CA1416
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.cs
similarity index 75%
rename from src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs
rename to src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.cs
index 3c3fa3fc700c32..c7a6d96aab2ba2 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.cs
@@ -1,32 +1,29 @@
// 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.CodeAnalysis;
-using System.Diagnostics.Tracing;
+using System.Threading;
using System.Runtime.CompilerServices;
namespace System.Diagnostics.Tracing
{
// This is part of the NativeRuntimeEventsource, which is the managed version of the Microsoft-Windows-DotNETRuntime provider.
- // Contains the implementation of ThreadPool events. This implementation is used by runtime not supporting NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs.
+ // Contains the implementation of threading events. This implementation is used by runtime not supporting NativeRuntimeEventSource.Threading.NativeSinks.cs.
internal sealed partial class NativeRuntimeEventSource : EventSource
{
// We don't have these keywords defined from the genRuntimeEventSources.py, so we need to manually define them here.
- public static class Keywords
+ public static partial class Keywords
{
+ public const EventKeywords ContentionKeyword = (EventKeywords)0x4000;
public const EventKeywords ThreadingKeyword = (EventKeywords)0x10000;
public const EventKeywords ThreadTransferKeyword = (EventKeywords)0x80000000;
}
- private const string EventSourceSuppressMessage = "Parameters to this method are primitive and are trimmer safe";
- // 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
+ private static partial class Messages
{
+ public const string ContentionLockCreated = "LockID={0};\nAssociatedObjectID={1};\nClrInstanceID={2}";
+ public const string ContentionStart = "ContentionFlags={0};\nClrInstanceID={1};\nLockID={2};\nAssociatedObjectID={3}\nLockOwnerThreadID={4}";
+ public const string ContentionStop = "ContentionFlags={0};\nClrInstanceID={1};\nDurationNs={2}";
public const string WorkerThread = "ActiveWorkerThreadCount={0};\nRetiredWorkerThreadCount={1};\nClrInstanceID={2}";
public const string MinMaxThreads = "MinWorkerThreads={0};\nMaxWorkerThreads={1};\nMinIOCompletionThreads={2};\nMaxIOCompletionThreads={3};\nClrInstanceID={4}";
public const string WorkerThreadAdjustmentSample = "Throughput={0};\nClrInstanceID={1}";
@@ -38,8 +35,9 @@ private static class Messages
}
// The task definitions for the ETW manifest
- public static class Tasks // this name and visibility is important for EventSource
+ public static partial class Tasks // this name and visibility is important for EventSource
{
+ public const EventTask Contention = (EventTask)8;
public const EventTask ThreadPoolWorkerThread = (EventTask)16;
public const EventTask ThreadPoolWorkerThreadAdjustment = (EventTask)18;
public const EventTask ThreadPool = (EventTask)23;
@@ -47,8 +45,9 @@ private static class Messages
public const EventTask ThreadPoolMinMaxThreads = (EventTask)38;
}
- public static class Opcodes // this name and visibility is important for EventSource
+ public static partial class Opcodes // this name and visibility is important for EventSource
{
+ public const EventOpcode LockCreated = (EventOpcode)11;
public const EventOpcode IOEnqueue = (EventOpcode)13;
public const EventOpcode IODequeue = (EventOpcode)14;
public const EventOpcode IOPack = (EventOpcode)15;
@@ -58,6 +57,12 @@ private static class Messages
public const EventOpcode Stats = (EventOpcode)102;
}
+ public enum ContentionFlagsMap : byte
+ {
+ Managed,
+ Native,
+ }
+
public enum ThreadAdjustmentReasonMap : uint
{
Warmup,
@@ -71,8 +76,80 @@ public enum ThreadAdjustmentReasonMap : uint
CooperativeBlocking,
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
+ [Event(90, Level = EventLevel.Informational, Message = Messages.ContentionLockCreated, Task = Tasks.Contention, Opcode = EventOpcode.Info, Version = 0, Keywords = Keywords.ContentionKeyword)]
+ private unsafe void ContentionLockCreated(nint LockID, nint AssociatedObjectID, ushort ClrInstanceID = DefaultClrInstanceId)
+ {
+ Debug.Assert(IsEnabled(EventLevel.Informational, Keywords.ContentionKeyword));
+
+ EventData* data = stackalloc EventData[3];
+ data[0].DataPointer = (nint)(&LockID);
+ data[0].Size = nint.Size;
+ data[0].Reserved = 0;
+ data[1].DataPointer = (nint)(&AssociatedObjectID);
+ data[1].Size = nint.Size;
+ data[1].Reserved = 0;
+ data[2].DataPointer = (nint)(&ClrInstanceID);
+ data[2].Size = sizeof(ushort);
+ data[2].Reserved = 0;
+ WriteEventCore(90, 3, data);
+ }
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
+ [Event(81, Level = EventLevel.Informational, Message = Messages.ContentionStart, Task = Tasks.Contention, Opcode = EventOpcode.Start, Version = 2, Keywords = Keywords.ContentionKeyword)]
+ private unsafe void ContentionStart(
+ ContentionFlagsMap ContentionFlags,
+ ushort ClrInstanceID,
+ nint LockID,
+ nint AssociatedObjectID,
+ ulong LockOwnerThreadID)
+ {
+ Debug.Assert(IsEnabled(EventLevel.Informational, Keywords.ContentionKeyword));
+
+ EventData* data = stackalloc EventData[5];
+ data[0].DataPointer = (nint)(&ContentionFlags);
+ data[0].Size = sizeof(ContentionFlagsMap);
+ data[0].Reserved = 0;
+ data[1].DataPointer = (nint)(&ClrInstanceID);
+ data[1].Size = sizeof(ushort);
+ data[1].Reserved = 0;
+ data[2].DataPointer = (nint)(&LockID);
+ data[2].Size = nint.Size;
+ data[2].Reserved = 0;
+ data[3].DataPointer = (nint)(&AssociatedObjectID);
+ data[3].Size = nint.Size;
+ data[3].Reserved = 0;
+ data[4].DataPointer = (nint)(&LockOwnerThreadID);
+ data[4].Size = sizeof(ulong);
+ data[4].Reserved = 0;
+ WriteEventCore(81, 3, data);
+ }
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
+ [Event(91, Level = EventLevel.Informational, Message = Messages.ContentionStop, Task = Tasks.Contention, Opcode = EventOpcode.Stop, Version = 1, Keywords = Keywords.ContentionKeyword)]
+ private unsafe void ContentionStop(ContentionFlagsMap ContentionFlags, ushort ClrInstanceID, double DurationNs)
+ {
+ Debug.Assert(IsEnabled(EventLevel.Informational, Keywords.ContentionKeyword));
+
+ EventData* data = stackalloc EventData[3];
+ data[0].DataPointer = (nint)(&ContentionFlags);
+ data[0].Size = sizeof(ContentionFlagsMap);
+ data[0].Reserved = 0;
+ data[1].DataPointer = (nint)(&ClrInstanceID);
+ data[1].Size = sizeof(ushort);
+ data[1].Reserved = 0;
+ data[2].DataPointer = (nint)(&DurationNs);
+ data[2].Size = sizeof(double);
+ data[2].Reserved = 0;
+ WriteEventCore(91, 3, data);
+ }
+
+ [NonEvent]
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void ContentionStop(double durationNs) =>
+ ContentionStop(ContentionFlagsMap.Managed, DefaultClrInstanceId, durationNs);
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[NonEvent]
private unsafe void WriteThreadEvent(int eventId, uint numExistingThreads)
{
@@ -131,8 +208,7 @@ public void ThreadPoolWorkerThreadWait(
}
#pragma warning restore IDE0060
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[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,
@@ -152,8 +228,7 @@ public unsafe void ThreadPoolWorkerThreadAdjustmentSample(
WriteEventCore(54, 2, data);
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[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,
@@ -181,8 +256,7 @@ public unsafe void ThreadPoolWorkerThreadAdjustmentAdjustment(
WriteEventCore(55, 4, data);
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[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,
@@ -238,8 +312,7 @@ public unsafe void ThreadPoolWorkerThreadAdjustmentStats(
WriteEventCore(56, 11, data);
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[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,
@@ -285,12 +358,13 @@ public void ThreadPoolIOEnqueue(RegisteredWaitHandle registeredWaitHandle)
{
if (IsEnabled(EventLevel.Verbose, Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword))
{
+#pragma warning disable CA1416 // 'RegisteredWaitHandle.Repeating' is unsupported on: 'browser'
ThreadPoolIOEnqueue((IntPtr)registeredWaitHandle.GetHashCode(), IntPtr.Zero, registeredWaitHandle.Repeating);
+#pragma warning restore CA1416
}
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[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,
@@ -334,8 +408,7 @@ public void ThreadPoolIODequeue(RegisteredWaitHandle registeredWaitHandle)
}
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[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)
{
@@ -365,8 +438,7 @@ public unsafe void ThreadPoolIOPack(NativeOverlapped* nativeOverlapped)
}
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[Event(65, Level = EventLevel.Verbose, Message = Messages.IO, Task = Tasks.ThreadPool, Opcode = Opcodes.IOPack, Version = 0, Keywords = Keywords.ThreadingKeyword)]
private unsafe void ThreadPoolIOPack(
IntPtr NativeOverlapped,
@@ -387,8 +459,7 @@ private unsafe void ThreadPoolIOPack(
}
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
- Justification = EventSourceSuppressMessage)]
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern", Justification = "Parameters to this method are primitive and are trimmer safe")]
[Event(59, Level = EventLevel.Informational, Message = Messages.MinMaxThreads, Task = Tasks.ThreadPoolMinMaxThreads, Opcode = EventOpcode.Info, Version = 0, Keywords = Keywords.ThreadingKeyword)]
public unsafe void ThreadPoolMinMaxThreads(
ushort MinWorkerThreads,
@@ -419,6 +490,5 @@ public unsafe void ThreadPoolMinMaxThreads(
data[4].Reserved = 0;
WriteEventCore(59, 5, data);
}
-
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
index 0d97fdedaa2287..27bbd24a048379 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
@@ -21,6 +21,11 @@ internal sealed partial class NativeRuntimeEventSource : EventSource
internal const string EventSourceName = "Microsoft-Windows-DotNETRuntime";
public static readonly NativeRuntimeEventSource Log = new NativeRuntimeEventSource();
+ // 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;
+
// Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor
// as you can't make a constructor partial.
private NativeRuntimeEventSource(int _) { }
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index a9b7ee6424b202..de20a6fe30e693 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -195,7 +195,7 @@
-
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.Mono.cs
similarity index 54%
rename from src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.Mono.cs
rename to src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.Mono.cs
index 6cf0ad3df38904..20fc2b2c72da88 100644
--- a/src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.Mono.cs
@@ -1,8 +1,6 @@
// 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 System.Runtime.InteropServices;
@@ -14,31 +12,51 @@ internal sealed partial class NativeRuntimeEventSource : EventSource
{
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkerThreadStart(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
+ private static extern void LogContentionLockCreated(nint LockID, nint AssociatedObjectID, ushort ClrInstanceID);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkerThreadStop(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
+ private static extern void LogContentionStart(
+ ContentionFlagsMap ContentionFlags,
+ ushort ClrInstanceID,
+ nint LockID,
+ nint AssociatedObjectID,
+ ulong LockOwnerThreadID);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkerThreadWait(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
+ private static extern void LogContentionStop(
+ ContentionFlagsMap ContentionFlags,
+ ushort ClrInstanceID,
+ double DurationNs);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolMinMaxThreads(ushort MinWorkerThreads, ushort MaxWorkerThreads, ushort MinIOCompletionThreads, ushort MaxIOCompletionThreads, ushort ClrInstanceID);
+ private static extern void LogThreadPoolWorkerThreadStart(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkerThreadAdjustmentSample(double Throughput, ushort ClrInstanceID);
+ private static extern void LogThreadPoolWorkerThreadStop(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkerThreadAdjustmentAdjustment(double AverageThroughput, uint NewWorkerThreadCount, NativeRuntimeEventSource.ThreadAdjustmentReasonMap Reason, ushort ClrInstanceID);
+ private static extern void LogThreadPoolWorkerThreadWait(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkerThreadAdjustmentStats(
+ private static extern void LogThreadPoolMinMaxThreads(ushort MinWorkerThreads, ushort MaxWorkerThreads, ushort MinIOCompletionThreads, ushort MaxIOCompletionThreads, ushort ClrInstanceID);
+
+ [NonEvent]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void LogThreadPoolWorkerThreadAdjustmentSample(double Throughput, ushort ClrInstanceID);
+
+ [NonEvent]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void LogThreadPoolWorkerThreadAdjustmentAdjustment(double AverageThroughput, uint NewWorkerThreadCount, NativeRuntimeEventSource.ThreadAdjustmentReasonMap Reason, ushort ClrInstanceID);
+
+ [NonEvent]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void LogThreadPoolWorkerThreadAdjustmentStats(
double Duration,
double Throughput,
double ThreadPoolWorkerThreadWait,
@@ -53,7 +71,7 @@ internal static extern void LogThreadPoolWorkerThreadAdjustmentStats(
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolIOEnqueue(
+ private static extern void LogThreadPoolIOEnqueue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
bool MultiDequeues,
@@ -61,21 +79,21 @@ internal static extern void LogThreadPoolIOEnqueue(
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolIODequeue(
+ private static extern void LogThreadPoolIODequeue(
IntPtr NativeOverlapped,
IntPtr Overlapped,
ushort ClrInstanceID);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolWorkingThreadCount(
+ private static extern void LogThreadPoolWorkingThreadCount(
uint Count,
ushort ClrInstanceID
);
[NonEvent]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void LogThreadPoolIOPack(
+ private static extern void LogThreadPoolIOPack(
IntPtr NativeOverlapped,
IntPtr Overlapped,
ushort ClrInstanceID);
diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs
index 67dc4147f7e48b..406c5efcba46ec 100644
--- a/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs
@@ -23,6 +23,10 @@ internal RegisteredWaitHandle()
{
}
+#pragma warning disable CA1822 // Mark members as static
+ internal bool Repeating => false;
+#pragma warning restore CA1822
+
public bool Unregister(WaitHandle? waitObject)
{
throw new PlatformNotSupportedException();
diff --git a/src/mono/mono/component/event_pipe-stub.c b/src/mono/mono/component/event_pipe-stub.c
index 3e465b20fb14dc..a1769b9454af51 100644
--- a/src/mono/mono/component/event_pipe-stub.c
+++ b/src/mono/mono/component/event_pipe-stub.c
@@ -185,6 +185,26 @@ event_pipe_stub_write_event_threadpool_io_pack (
intptr_t overlapped,
uint16_t clr_instance_id);
+static bool
+event_pipe_stub_write_event_contention_lock_created (
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id);
+
+static bool
+event_pipe_stub_write_event_contention_start (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id);
+
+static bool
+event_pipe_stub_write_event_contention_stop (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns);
+
static bool
event_pipe_stub_signal_session (EventPipeSessionID session_id);
@@ -228,6 +248,9 @@ static MonoComponentEventPipe fn_table = {
&event_pipe_stub_write_event_threadpool_io_dequeue,
&event_pipe_stub_write_event_threadpool_working_thread_count,
&event_pipe_stub_write_event_threadpool_io_pack,
+ &event_pipe_stub_write_event_contention_lock_created,
+ &event_pipe_stub_write_event_contention_start,
+ &event_pipe_stub_write_event_contention_stop,
&event_pipe_stub_signal_session,
&event_pipe_stub_wait_for_session_signal
};
@@ -488,6 +511,35 @@ event_pipe_stub_write_event_threadpool_io_pack (
return true;
}
+static bool
+event_pipe_stub_write_event_contention_lock_created (
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id)
+{
+ return true;
+}
+
+static bool
+event_pipe_stub_write_event_contention_start (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id)
+{
+ return true;
+}
+
+static bool
+event_pipe_stub_write_event_contention_stop (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns)
+{
+ return true;
+}
+
static bool
event_pipe_stub_signal_session (EventPipeSessionID session_id)
{
@@ -546,4 +598,4 @@ mono_wasm_event_pipe_session_disable (MonoWasmEventPipeSessionID session_id)
{
g_assert_not_reached ();
}
-#endif /* HOST_WASM && !HOST_WASI */
\ No newline at end of file
+#endif /* HOST_WASM && !HOST_WASI */
diff --git a/src/mono/mono/component/event_pipe.c b/src/mono/mono/component/event_pipe.c
index 4ba3489101263b..398d463d19eaae 100644
--- a/src/mono/mono/component/event_pipe.c
+++ b/src/mono/mono/component/event_pipe.c
@@ -139,6 +139,9 @@ static MonoComponentEventPipe fn_table = {
&ep_rt_write_event_threadpool_io_dequeue,
&ep_rt_write_event_threadpool_working_thread_count,
&ep_rt_write_event_threadpool_io_pack,
+ &ep_rt_write_event_contention_lock_created,
+ &ep_rt_write_event_contention_start,
+ &ep_rt_write_event_contention_stop,
&event_pipe_signal_session,
&event_pipe_wait_for_session_signal
};
diff --git a/src/mono/mono/component/event_pipe.h b/src/mono/mono/component/event_pipe.h
index 3ba274e9f43483..bc1fe532dbd25c 100644
--- a/src/mono/mono/component/event_pipe.h
+++ b/src/mono/mono/component/event_pipe.h
@@ -222,6 +222,26 @@ typedef bool
intptr_t overlapped,
uint16_t clr_instance_id);
+typedef bool
+(*event_pipe_component_write_event_contention_lock_created_func)(
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id);
+
+typedef bool
+(*event_pipe_component_write_event_contention_start_func)(
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id);
+
+typedef bool
+(*event_pipe_component_write_event_contention_stop_func)(
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns);
+
/*
* MonoComponentEventPipe function table.
*/
@@ -258,6 +278,9 @@ typedef struct _MonoComponentEventPipe {
event_pipe_component_write_event_threadpool_io_dequeue_func write_event_threadpool_io_dequeue;
event_pipe_component_write_event_threadpool_working_thread_count_func write_event_threadpool_working_thread_count;
event_pipe_component_write_event_threadpool_io_pack_func write_event_threadpool_io_pack;
+ event_pipe_component_write_event_contention_lock_created_func write_event_contention_lock_created;
+ event_pipe_component_write_event_contention_start_func write_event_contention_start;
+ event_pipe_component_write_event_contention_stop_func write_event_contention_stop;
event_pipe_component_signal_session signal_session;
event_pipe_component_wait_for_session_signal wait_for_session_signal;
} MonoComponentEventPipe;
diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c
index b68a71af08bdcb..0fcfa9dba87251 100644
--- a/src/mono/mono/eventpipe/ep-rt-mono.c
+++ b/src/mono/mono/eventpipe/ep-rt-mono.c
@@ -4493,6 +4493,52 @@ ep_rt_write_event_threadpool_io_pack (
NULL) == 0 ? true : false;
}
+bool
+ep_rt_write_event_contention_lock_created (
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id)
+{
+ return FireEtwContentionLockCreated (
+ (const void *)lock_id,
+ (const void *)associated_object_id,
+ clr_instance_id,
+ NULL,
+ NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_contention_start (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id)
+{
+ return FireEtwContentionStart_V2 (
+ contention_flags,
+ clr_instance_id,
+ (const void *)lock_id,
+ (const void *)associated_object_id,
+ lock_owner_thread_id,
+ NULL,
+ NULL) == 0 ? true : false;
+}
+
+bool
+ep_rt_write_event_contention_stop (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns)
+{
+ return FireEtwContentionStop_V1 (
+ contention_flags,
+ clr_instance_id,
+ duration_ns,
+ NULL,
+ NULL) == 0 ? true : false;
+}
+
static
void
runtime_profiler_jit_begin (
diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h
index 51c189d60ae6ed..7183393a698a42 100644
--- a/src/mono/mono/eventpipe/ep-rt-mono.h
+++ b/src/mono/mono/eventpipe/ep-rt-mono.h
@@ -1979,6 +1979,26 @@ ep_rt_write_event_threadpool_io_pack (
intptr_t overlapped,
uint16_t clr_instance_id);
+bool
+ep_rt_write_event_contention_lock_created (
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id);
+
+bool
+ep_rt_write_event_contention_start (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id);
+
+bool
+ep_rt_write_event_contention_stop (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns);
+
/*
* EventPipe provider callbacks.
*/
diff --git a/src/mono/mono/eventpipe/gen-eventing-event-inc.lst b/src/mono/mono/eventpipe/gen-eventing-event-inc.lst
index 3ed9522cee188f..47979354dc6ff7 100644
--- a/src/mono/mono/eventpipe/gen-eventing-event-inc.lst
+++ b/src/mono/mono/eventpipe/gen-eventing-event-inc.lst
@@ -5,8 +5,11 @@ AssemblyDCEnd_V1
AssemblyLoad_V1
AssemblyUnload_V1
BulkType
+ContentionLockCreated
ContentionStart_V1
+ContentionStart_V2
ContentionStop
+ContentionStop_V1
DCEndComplete_V1
DCEndInit_V1
DomainModuleDCEnd_V1
@@ -49,4 +52,4 @@ ThreadPoolIOPack
ThreadTerminated
TypeLoadStart
TypeLoadStop
-Microsoft-DotNETRuntimeMonoProfiler:*
\ No newline at end of file
+Microsoft-DotNETRuntimeMonoProfiler:*
diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h
index 2401075a6758fd..c090abcbfbddd2 100644
--- a/src/mono/mono/metadata/icall-decl.h
+++ b/src/mono/mono/metadata/icall-decl.h
@@ -173,6 +173,9 @@ ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_
ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolMinMaxThreads (uint16_t min_worker_threads, uint16_t max_worker_threads, uint16_t min_io_completion_threads, uint16_t max_io_completion_threads, uint16_t clr_instance_id);
ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkingThreadCount (uint16_t count, uint16_t clr_instance_id);
ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOPack (intptr_t native_overlapped, intptr_t overlapped, uint16_t clr_instance_id);
+ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionLockCreated (intptr_t lock_id, intptr_t associated_object_id, uint16_t clr_instance_id);
+ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStart (uint8_t contention_flags, uint16_t clr_instance_id, intptr_t lock_id, intptr_t associated_object_id, uint64_t lock_owner_thread_id);
+ICALL_EXPORT void ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStop (uint8_t contention_flags, uint16_t clr_instance_id, double duration_ns);
ICALL_EXPORT void ves_icall_Mono_RuntimeGPtrArrayHandle_GPtrArrayFree (GPtrArray *ptr_array);
ICALL_EXPORT void ves_icall_Mono_SafeStringMarshal_GFree (void *c_str);
diff --git a/src/mono/mono/metadata/icall-def.h b/src/mono/mono/metadata/icall-def.h
index a2ed4f55f80891..c467100c4691ae 100644
--- a/src/mono/mono/metadata/icall-def.h
+++ b/src/mono/mono/metadata/icall-def.h
@@ -175,17 +175,20 @@ NOHANDLES(ICALL(EVENTPIPE_14, "WaitForSessionSignal", ves_icall_System_Diagnosti
NOHANDLES(ICALL(EVENTPIPE_13, "WriteEventData", ves_icall_System_Diagnostics_Tracing_EventPipeInternal_WriteEventData))
ICALL_TYPE(NATIVE_RUNTIME_EVENT_SOURCE, "System.Diagnostics.Tracing.NativeRuntimeEventSource", NATIVE_RUNTIME_EVENT_SOURCE_1)
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_1, "LogThreadPoolIODequeue", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIODequeue))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_2, "LogThreadPoolIOEnqueue", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOEnqueue))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_10, "LogThreadPoolIOPack", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOPack))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_11, "LogThreadPoolMinMaxThreads", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolMinMaxThreads))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_3, "LogThreadPoolWorkerThreadAdjustmentAdjustment", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadAdjustmentAdjustment))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_4, "LogThreadPoolWorkerThreadAdjustmentSample", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadAdjustmentSample))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_5, "LogThreadPoolWorkerThreadAdjustmentStats", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadAdjustmentStats))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_6, "LogThreadPoolWorkerThreadStart", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadStart))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_7, "LogThreadPoolWorkerThreadStop", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadStop))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_8, "LogThreadPoolWorkerThreadWait", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadWait))
-NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_9, "LogThreadPoolWorkingThreadCount", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkingThreadCount))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_1, "LogContentionLockCreated", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionLockCreated))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_2, "LogContentionStart", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStart))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_3, "LogContentionStop", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStop))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_4, "LogThreadPoolIODequeue", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIODequeue))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_5, "LogThreadPoolIOEnqueue", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOEnqueue))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_6, "LogThreadPoolIOPack", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOPack))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_7, "LogThreadPoolMinMaxThreads", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolMinMaxThreads))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_8, "LogThreadPoolWorkerThreadAdjustmentAdjustment", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadAdjustmentAdjustment))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_9, "LogThreadPoolWorkerThreadAdjustmentSample", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadAdjustmentSample))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_10, "LogThreadPoolWorkerThreadAdjustmentStats", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadAdjustmentStats))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_11, "LogThreadPoolWorkerThreadStart", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadStart))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_12, "LogThreadPoolWorkerThreadStop", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadStop))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_13, "LogThreadPoolWorkerThreadWait", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkerThreadWait))
+NOHANDLES(ICALL(NATIVE_RUNTIME_EVENT_SOURCE_14, "LogThreadPoolWorkingThreadCount", ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolWorkingThreadCount))
ICALL_TYPE(ENUM, "System.Enum", ENUM_1)
HANDLES(ENUM_1, "GetEnumValuesAndNames", ves_icall_System_Enum_GetEnumValuesAndNames, void, 3, (MonoQCallTypeHandle, MonoArrayOut, MonoArrayOut))
diff --git a/src/mono/mono/metadata/icall-eventpipe.c b/src/mono/mono/metadata/icall-eventpipe.c
index 595d8a343f8282..18b28050dc8b26 100644
--- a/src/mono/mono/metadata/icall-eventpipe.c
+++ b/src/mono/mono/metadata/icall-eventpipe.c
@@ -429,6 +429,46 @@ ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOPac
clr_instance_id);
}
+void
+ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionLockCreated (
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id)
+{
+ mono_component_event_pipe ()->write_event_contention_lock_created (
+ lock_id,
+ associated_object_id,
+ clr_instance_id);
+}
+
+void
+ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStart (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id)
+{
+ mono_component_event_pipe ()->write_event_contention_start (
+ contention_flags,
+ clr_instance_id,
+ lock_id,
+ associated_object_id,
+ lock_owner_thread_id);
+}
+
+void
+ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStop (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns)
+{
+ mono_component_event_pipe ()->write_event_contention_stop (
+ contention_flags,
+ clr_instance_id,
+ duration_ns);
+}
+
#else /* ENABLE_PERFTRACING */
gconstpointer
@@ -703,4 +743,39 @@ ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogThreadPoolIOPac
mono_error_set_pending_exception (error);
}
+void
+ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionLockCreated (
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint16_t clr_instance_id)
+{
+ ERROR_DECL (error);
+ mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.NativeRuntimeEventSource.LogContentionLockCreated");
+ mono_error_set_pending_exception (error);
+}
+
+void
+ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStart (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ intptr_t lock_id,
+ intptr_t associated_object_id,
+ uint64_t lock_owner_thread_id)
+{
+ ERROR_DECL (error);
+ mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.NativeRuntimeEventSource.LogContentionStart");
+ mono_error_set_pending_exception (error);
+}
+
+void
+ves_icall_System_Diagnostics_Tracing_NativeRuntimeEventSource_LogContentionStop (
+ uint8_t contention_flags,
+ uint16_t clr_instance_id,
+ double duration_ns)
+{
+ ERROR_DECL (error);
+ mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.NativeRuntimeEventSource.LogContentionStop");
+ mono_error_set_pending_exception (error);
+}
+
#endif /* ENABLE_PERFTRACING */