Add managed entry points for raising Contention events (#87087)
authorKoundinya Veluri <kouvel@users.noreply.github.com>
Thu, 15 Jun 2023 13:36:33 +0000 (06:36 -0700)
committerGitHub <noreply@github.com>
Thu, 15 Jun 2023 13:36:33 +0000 (06:36 -0700)
* Add managed entry points for raising Contention events

- Added the events similarly to how the PortableThreadPool events are currently set up. They may need further tweaking to make them work from NativeAOT.
- The events are not raised anywhere from the managed side yet, it's expected that they will eventually be raised by a new Lock type and at least by NativeAOT's Lock

22 files changed:
src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.Threading.NativeSinks.CoreCLR.cs [moved from src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.CoreCLR.cs with 52% similarity]
src/coreclr/scripts/genRuntimeEventSources.py
src/coreclr/vm/nativeeventsource.cpp
src/coreclr/vm/nativeeventsource.h
src/coreclr/vm/qcallentrypoints.cpp
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.cs [moved from src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs with 81% similarity]
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.cs [moved from src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs with 75% similarity]
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs
src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.Mono.cs [moved from src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.Mono.cs with 54% similarity]
src/mono/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs
src/mono/mono/component/event_pipe-stub.c
src/mono/mono/component/event_pipe.c
src/mono/mono/component/event_pipe.h
src/mono/mono/eventpipe/ep-rt-mono.c
src/mono/mono/eventpipe/ep-rt-mono.h
src/mono/mono/eventpipe/gen-eventing-event-inc.lst
src/mono/mono/metadata/icall-decl.h
src/mono/mono/metadata/icall-def.h
src/mono/mono/metadata/icall-eventpipe.c

index c9c6140..1dd3eb3 100644 (file)
     <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.NativeSinks.CoreCLR.cs" Condition="'$(FeaturePortableThreadPool)' == 'true'" />
+    <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\NativeRuntimeEventSource.Threading.NativeSinks.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\ICustomDebuggerNotification.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrame.CoreCLR.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrameHelper.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 @@ namespace System.Diagnostics.Tracing
     {
         [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 @@ namespace System.Diagnostics.Tracing
 
         [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 @@ namespace System.Diagnostics.Tracing
 
         [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);
index fafa9a2..f47a30f 100644 (file)
@@ -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 = ""
index 9ec8310..b4bca03 100644 (file)
@@ -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
index c649f7d..a407c4b 100644 (file)
@@ -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_
index 352a85b..f45cd9a 100644 (file)
@@ -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)
index 33fc345..59ac572 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\IncrementingEventCounter.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\IncrementingPollingCounter.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\NativeRuntimeEventSource.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\NativeRuntimeEventSource.Threading.cs" Condition="'$(FeaturePerfTracing)' != 'true' or '$(FeatureNativeAot)' == 'true'" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\NativeRuntimeEventSource.Threading.NativeSinks.cs" Condition="'$(FeaturePerfTracing)' == 'true' and '$(FeatureNativeAot)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\PollingCounter.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSource.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\Winmeta.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\CompleteWaitThreadPoolWorkItem.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPool.Portable.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPool.Unix.cs" Condition="'$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true'" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.cs" Condition="'$(FeatureCoreCLR)' != 'true' and '$(FeatureMono)' != 'true'" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs" Condition="'$(FeatureCoreCLR)' == 'true' or '$(FeatureMono)' == 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.Blocking.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.GateThread.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 @@ namespace System.Diagnostics.Tracing
         }
 
         // 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 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
             public const EventOpcode Stats = (EventOpcode)102;
         }
 
+        public enum ContentionFlagsMap : byte
+        {
+            Managed,
+            Native,
+        }
+
         public enum ThreadAdjustmentReasonMap : uint
         {
             Warmup,
@@ -66,9 +72,41 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
         {
             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
             }
         }
 
@@ -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 @@ namespace System.Diagnostics.Tracing
         }
 
         // 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 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
             public const EventOpcode Stats = (EventOpcode)102;
         }
 
+        public enum ContentionFlagsMap : byte
+        {
+            Managed,
+            Native,
+        }
+
         public enum ThreadAdjustmentReasonMap : uint
         {
             Warmup,
@@ -71,8 +76,80 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
         }
 #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 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
             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 @@ namespace System.Diagnostics.Tracing
         {
             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 @@ namespace System.Diagnostics.Tracing
             }
         }
 
-        [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 @@ namespace System.Diagnostics.Tracing
             }
         }
 
-        [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 @@ namespace System.Diagnostics.Tracing
         }
 
 
-        [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 @@ namespace System.Diagnostics.Tracing
             data[4].Reserved = 0;
             WriteEventCore(59, 5, data);
         }
-
     }
 }
index 0d97fde..27bbd24 100644 (file)
@@ -21,6 +21,11 @@ namespace System.Diagnostics.Tracing
         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 _) { }
index a9b7ee6..de20a6f 100644 (file)
       <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackFrame.Mono.cs" />
       <Compile Include="$(BclSourcesRoot)\System\Diagnostics\StackTrace.Mono.cs" />
       <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Tracing\EventPipe.Mono.cs" />
-      <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Tracing\NativeRuntimeEventSource.PortableThreadPool.NativeSinks.Mono.cs" Condition="'$(FeaturePortableThreadPool)' == 'true'" />
+      <Compile Include="$(BclSourcesRoot)\System\Diagnostics\Tracing\NativeRuntimeEventSource.Threading.NativeSinks.Mono.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
       <Compile Include="$(BclSourcesRoot)\System\IO\FileLoadException.Mono.cs" />
       <Compile Include="$(BclSourcesRoot)\System\Reflection\Assembly.Mono.cs" />
       <Compile Include="$(BclSourcesRoot)\System\Reflection\AssemblyName.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 @@ namespace System.Diagnostics.Tracing
     {
         [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 @@ namespace System.Diagnostics.Tracing
 
         [NonEvent]
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern void LogThreadPoolIOEnqueue(
+        private static extern void LogThreadPoolIOEnqueue(
             IntPtr NativeOverlapped,
             IntPtr Overlapped,
             bool MultiDequeues,
@@ -61,21 +79,21 @@ namespace System.Diagnostics.Tracing
 
         [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);
index 67dc414..406c5ef 100644 (file)
@@ -23,6 +23,10 @@ namespace System.Threading
         {
         }
 
+#pragma warning disable CA1822 // Mark members as static
+        internal bool Repeating => false;
+#pragma warning restore CA1822
+
         public bool Unregister(WaitHandle? waitObject)
         {
             throw new PlatformNotSupportedException();
index 3e465b2..a1769b9 100644 (file)
@@ -186,6 +186,26 @@ event_pipe_stub_write_event_threadpool_io_pack (
        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);
 
 static bool
@@ -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
 };
@@ -489,6 +512,35 @@ event_pipe_stub_write_event_threadpool_io_pack (
 }
 
 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)
 {
        return true;
@@ -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 */
index 4ba3489..398d463 100644 (file)
@@ -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
 };
index 3ba274e..bc1fe53 100644 (file)
@@ -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;
index b68a71a..0fcfa9d 100644 (file)
@@ -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 (
index 51c189d..7183393 100644 (file)
@@ -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.
 */
index 3ed9522..4797935 100644 (file)
@@ -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:*
index 2401075..c090abc 100644 (file)
@@ -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);
index a2ed4f5..c467100 100644 (file)
@@ -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))
index 595d8a3..18b2805 100644 (file)
@@ -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 */