From 4302b80fa089ace2d6fd404af99efddd1f121871 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Thu, 15 Jun 2023 06:36:33 -0700 Subject: [PATCH] Add managed entry points for raising Contention events (#87087) * 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 --- .../System.Private.CoreLib.csproj | 2 +- ...meEventSource.Threading.NativeSinks.CoreCLR.cs} | 44 +++++-- src/coreclr/scripts/genRuntimeEventSources.py | 4 +- src/coreclr/vm/nativeeventsource.cpp | 36 ++++++ src/coreclr/vm/nativeeventsource.h | 3 + src/coreclr/vm/qcallentrypoints.cpp | 3 + .../src/System.Private.CoreLib.Shared.projitems | 4 +- ...iveRuntimeEventSource.Threading.NativeSinks.cs} | 64 ++++++++-- .../Tracing/NativeRuntimeEventSource.Threading.cs} | 134 ++++++++++++++++----- .../Tracing/NativeRuntimeEventSource.cs | 5 + .../System.Private.CoreLib.csproj | 2 +- ...ntimeEventSource.Threading.NativeSinks.Mono.cs} | 44 +++++-- .../System/Threading/ThreadPool.Browser.Mono.cs | 4 + src/mono/mono/component/event_pipe-stub.c | 54 ++++++++- src/mono/mono/component/event_pipe.c | 3 + src/mono/mono/component/event_pipe.h | 23 ++++ src/mono/mono/eventpipe/ep-rt-mono.c | 46 +++++++ src/mono/mono/eventpipe/ep-rt-mono.h | 20 +++ src/mono/mono/eventpipe/gen-eventing-event-inc.lst | 5 +- src/mono/mono/metadata/icall-decl.h | 3 + src/mono/mono/metadata/icall-def.h | 25 ++-- src/mono/mono/metadata/icall-eventpipe.c | 75 ++++++++++++ 22 files changed, 515 insertions(+), 88 deletions(-) rename src/coreclr/System.Private.CoreLib/src/System/Diagnostics/Eventing/{NativeRuntimeEventSource.PortableThreadPool.NativeSinks.CoreCLR.cs => NativeRuntimeEventSource.Threading.NativeSinks.CoreCLR.cs} (52%) rename src/libraries/System.Private.CoreLib/src/System/{Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs => Diagnostics/Tracing/NativeRuntimeEventSource.Threading.NativeSinks.cs} (81%) rename src/libraries/System.Private.CoreLib/src/System/{Threading/NativeRuntimeEventSource.PortableThreadPool.cs => Diagnostics/Tracing/NativeRuntimeEventSource.Threading.cs} (75%) rename src/mono/System.Private.CoreLib/src/System/Diagnostics/Tracing/{NativeRuntimeEventSource.PortableThreadPool.NativeSinks.Mono.cs => NativeRuntimeEventSource.Threading.NativeSinks.Mono.cs} (54%) diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index c9c6140..1dd3eb3 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 c618f1d..511476e 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 @@ 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); diff --git a/src/coreclr/scripts/genRuntimeEventSources.py b/src/coreclr/scripts/genRuntimeEventSources.py index fafa9a2..f47a30f 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 9ec8310..b4bca03 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 c649f7d9..a407c4b 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 352a85b..f45cd9a 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 33fc345..59ac572 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 28393f0..ad7ee54 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 @@ 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 } } 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 3c3fa3f..c7a6d96 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 @@ 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); } - } } 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 0d97fde..27bbd24 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 @@ 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 _) { } diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index a9b7ee6..de20a6f 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 6cf0ad3..20fc2b2 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 @@ 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); 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 67dc414..406c5ef 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 @@ 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(); diff --git a/src/mono/mono/component/event_pipe-stub.c b/src/mono/mono/component/event_pipe-stub.c index 3e465b2..a1769b9 100644 --- a/src/mono/mono/component/event_pipe-stub.c +++ b/src/mono/mono/component/event_pipe-stub.c @@ -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 */ diff --git a/src/mono/mono/component/event_pipe.c b/src/mono/mono/component/event_pipe.c index 4ba3489..398d463 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 3ba274e..bc1fe53 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 b68a71a..0fcfa9d 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 51c189d..7183393 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 3ed9522..4797935 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 2401075..c090abc 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 a2ed4f5..c467100 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 595d8a3..18b2805 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 */ -- 2.7.4