From ba3681375cb978c5539815bc6b319b49899025e1 Mon Sep 17 00:00:00 2001 From: Sung Yoon Whang Date: Wed, 10 Feb 2021 16:21:39 -0800 Subject: [PATCH] Enable Portable ThreadPool events to be written using NativeRuntimeEventSource (#47829) * match up the GUID * why is this returning nothing * Make ThreadPool emit events via NativeRuntimeEventSource * found error... * hack around having duplicate events generated * make portable threadpool fire events through nativeruntimeeventsource * make the initializer live in correct namespace * EventListener tests are passing now * make native QCall endpoints that sink into LTTng * send events through XplatEventLogger sink * Fix merge error * double registration * fix callback not getting handled when lttng is enabled * cleanup 1 * rename file * remove stale comments * remove stale comment * undo useless change * fix broken EventListener * apply code review feedback * fix windows build * fix incorrect qcall * fix up ifdefs for Windows builds * fix ifdef * put back removed code * tests pass now * Fix NativeRuntimeEventSource not getting enabled for lttng * Add some more comments * Add comment in generated code * fix mono build * PR feedback * fix typo * code review feedback --- src/coreclr/scripts/genRuntimeEventSources.py | 40 ++--- src/coreclr/vm/corelib.cpp | 3 +- src/coreclr/vm/ecalllist.h | 19 ++- src/coreclr/vm/nativeeventsource.cpp | 103 ++++++++++++- src/coreclr/vm/nativeeventsource.h | 22 ++- .../src/System.Private.CoreLib.Shared.projitems | 2 +- .../src/System/Diagnostics/Tracing/EventSource.cs | 18 +-- .../Tracing/NativeRuntimeEventSource.cs | 116 +++++++++++++- .../Tracing/TraceLogging/XplatEventLogger.cs | 19 ++- ...NativeRuntimeEventSource.PortableThreadPool.cs} | 168 +++------------------ .../Threading/PortableThreadPool.GateThread.cs | 5 +- .../Threading/PortableThreadPool.HillClimbing.cs | 15 +- .../Threading/PortableThreadPool.WaitThread.cs | 9 +- .../Threading/PortableThreadPool.WorkerThread.cs | 14 +- src/native/eventpipe/ep-config.c | 13 -- 15 files changed, 333 insertions(+), 233 deletions(-) rename src/libraries/System.Private.CoreLib/src/System/Threading/{PortableThreadPoolEventSource.cs => NativeRuntimeEventSource.PortableThreadPool.cs} (55%) diff --git a/src/coreclr/scripts/genRuntimeEventSources.py b/src/coreclr/scripts/genRuntimeEventSources.py index 5eaf857..a220217 100644 --- a/src/coreclr/scripts/genRuntimeEventSources.py +++ b/src/coreclr/scripts/genRuntimeEventSources.py @@ -15,7 +15,7 @@ generatedCodeFileHeader="""// Licensed to the .NET Foundation under one or more /********************************************************************** DO NOT MODIFY. AUTOGENERATED FILE. -This file is generated by /src/scripts/genRuntimeEventSources.py +This file is generated by /src/coreclr/scripts/genRuntimeEventSources.py **********************************************************************/ """ @@ -73,22 +73,30 @@ def getCSharpTypeFromManifestType(manifestType): def generateEvent(eventNode, providerNode, outputFile, stringTable): + # ThreadPool events are defined manually in NativeRuntimeEventSource.PortableThreadPool.cs + symbol = eventNode.getAttribute("symbol") + if "ThreadPool" in symbol: + return + + evtLevel = eventNode.getAttribute("level")[4:] + evtKeywords = "" # Write the event attribute. - writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + eventNode.getAttribute("level")[4:]) + writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + evtLevel) # Not all events have keywords specified, and some have multiple keywords specified. keywords = eventNode.getAttribute("keywords") if keywords: if " " not in keywords: outputFile.write(", Keywords = Keywords." + keywords) + evtKeywords = "Keywords." + keywords else: keywords = keywords.split() outputFile.write(", Keywords = ") for keywordIndex in range(len(keywords)): - outputFile.write("Keywords." + keywords[keywordIndex]) + evtKeywords += "Keywords." + keywords[keywordIndex] if keywordIndex < (len(keywords) - 1): - outputFile.write(" | ") - + evtKeywords += " | " + outputFile.write(evtKeywords) outputFile.write(")]\n") # Get the template for the event. @@ -147,28 +155,10 @@ def generateEvent(eventNode, providerNode, outputFile, stringTable): outputFile.write(")\n") writeOutput(outputFile, "{\n") - # Write the call to WriteEvent. increaseTabLevel() - writeOutput(outputFile, "WriteEvent(" + eventNode.getAttribute("value")) - - # Add method parameters. - if argumentCount > 0: - # A ',' is needed after the event id. - outputFile.write(", ") - - # Write the parameter names to the method call. - argumentsProcessed = 0 - argumentNodes = templateNode.getElementsByTagName("data") - for argumentIndex in range(argumentCount): - argumentNode = argumentNodes[argumentIndex] - argumentName = argumentNode.getAttribute("name") - outputFile.write(argumentName) - if argumentIndex < (argumentCount - 1): - outputFile.write(", ") - - outputFile.write(");\n") + writeOutput(outputFile, "// To have this event be emitted from managed side, refer to NativeRuntimeEventSource.cs\n") + writeOutput(outputFile, "throw new NotImplementedException();\n") decreaseTabLevel() - writeOutput(outputFile, "}\n\n") diff --git a/src/coreclr/vm/corelib.cpp b/src/coreclr/vm/corelib.cpp index 0a983b5..8987aea 100644 --- a/src/coreclr/vm/corelib.cpp +++ b/src/coreclr/vm/corelib.cpp @@ -76,14 +76,15 @@ #endif #if defined(FEATURE_EVENTSOURCE_XPLAT) -#include "nativeeventsource.h" #include "eventpipeadapter.h" #include "eventpipeinternal.h" +#include "nativeeventsource.h" #endif //defined(FEATURE_EVENTSOURCE_XPLAT) #ifdef FEATURE_PERFTRACING #include "eventpipeadapter.h" #include "eventpipeinternal.h" +#include "nativeeventsource.h" #endif //FEATURE_PERFTRACING #include "tailcallhelp.h" diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 546fa2e..64d1b07 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -989,12 +989,25 @@ FCFuncStart(gStreamFuncs) FCFuncEnd() -#if defined(FEATURE_EVENTSOURCE_XPLAT) +#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING) FCFuncStart(gEventLogger) +#if defined(FEATURE_EVENTSOURCE_XPLAT) QCFuncElement("IsEventSourceLoggingEnabled", XplatEventSourceLogger::IsEventSourceLoggingEnabled) QCFuncElement("LogEventSource", XplatEventSourceLogger::LogEventSource) -FCFuncEnd() #endif // defined(FEATURE_EVENTSOURCE_XPLAT) +#if defined(FEATURE_PERFTRACING) + QCFuncElement("LogThreadPoolWorkerThreadStart", NativeEventLogger::LogThreadPoolWorkerThreadStart) + QCFuncElement("LogThreadPoolWorkerThreadStop", NativeEventLogger::LogThreadPoolWorkerThreadStop) + QCFuncElement("LogThreadPoolWorkerThreadWait", NativeEventLogger::LogThreadPoolWorkerThreadWait) + QCFuncElement("LogThreadPoolWorkerThreadAdjustmentSample", NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentSample) + QCFuncElement("LogThreadPoolWorkerThreadAdjustmentAdjustment", NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentAdjustment) + QCFuncElement("LogThreadPoolWorkerThreadAdjustmentStats", NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentStats) + QCFuncElement("LogThreadPoolIOEnqueue", NativeEventLogger::LogThreadPoolIOEnqueue) + QCFuncElement("LogThreadPoolIODequeue", NativeEventLogger::LogThreadPoolIODequeue) + QCFuncElement("LogThreadPoolWorkingThreadCount", NativeEventLogger::LogThreadPoolWorkingThreadCount) +#endif // defined(FEATURE_PERFTRACING) +FCFuncEnd() +#endif // defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING) #ifdef FEATURE_PERFTRACING FCFuncStart(gEventPipeInternalFuncs) @@ -1200,7 +1213,7 @@ FCClassElement("WeakReference`1", "System", gWeakReferenceOfTFuncs) FCClassElement("X86Base", "System.Runtime.Intrinsics.X86", gX86BaseFuncs) #endif // defined(TARGET_X86) || defined(TARGET_AMD64) -#if defined(FEATURE_EVENTSOURCE_XPLAT) +#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING) FCClassElement("XplatEventLogger", "System.Diagnostics.Tracing", gEventLogger) #endif //defined(FEATURE_EVENTSOURCE_XPLAT) diff --git a/src/coreclr/vm/nativeeventsource.cpp b/src/coreclr/vm/nativeeventsource.cpp index 753b74a..bdc6d97 100644 --- a/src/coreclr/vm/nativeeventsource.cpp +++ b/src/coreclr/vm/nativeeventsource.cpp @@ -9,9 +9,10 @@ // ============================================================================ #include "common.h" -#if defined(FEATURE_EVENTSOURCE_XPLAT) #include "nativeeventsource.h" +#if defined(FEATURE_EVENTSOURCE_XPLAT) + void QCALLTYPE XplatEventSourceLogger::LogEventSource(__in_z int eventID, __in_z LPCWSTR eventName, __in_z LPCWSTR eventSourceName, __in_z LPCWSTR payload) { QCALL_CONTRACT; @@ -31,7 +32,105 @@ BOOL QCALLTYPE XplatEventSourceLogger::IsEventSourceLoggingEnabled() END_QCALL; return retVal; - } #endif //defined(FEATURE_EVENTSOURCE_XPLAT) + +#ifdef FEATURE_PERFTRACING + +// These are native QCalls that call into corresponding FireEtw* events for events that want to be emitted from the managed +// side using NativeRuntimeEventSource. +// You need to add them to src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/XplatEventLogger.cs and +// change genRuntimeEventSources.py script to not emit the body that throws NotImplementedException for the event that +// want to be fired from managed code. +// See https://github.com/dotnet/runtime/pull/47829 for an example of how to do this. +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadStart(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkerThreadStart(activeWorkerThreadCount, retiredWorkerThreadCount, clrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadStop(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkerThreadStop(activeWorkerThreadCount, retiredWorkerThreadCount, clrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadWait(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkerThreadWait(activeWorkerThreadCount, retiredWorkerThreadCount, clrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentSample(__in_z double throughput, __in_z short clrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkerThreadAdjustmentSample(throughput, clrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentAdjustment(__in_z double averageThroughput, __in_z uint newWorkerThreadCount, __in_z uint reason, __in_z short clrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkerThreadAdjustmentAdjustment(averageThroughput, newWorkerThreadCount, reason, clrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentStats(__in_z double duration, __in_z double throughput, __in_z double threadWave, __in_z double throughputWave, __in_z double throughputErrorEstimate, __in_z double AverageThroughputErrorEstimate, __in_z double ThroughputRatio, __in_z double confidence, __in_z double newControlSetting, __in_z short newThreadWaveMagnitude, __in_z short ClrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkerThreadAdjustmentStats(duration, throughput, threadWave, throughputWave, throughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, confidence, newControlSetting, newThreadWaveMagnitude, ClrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolIOEnqueue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z bool multiDequeues, __in_z short ClrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolIOEnqueue(nativeOverlapped, overlapped, multiDequeues, ClrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolIODequeue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z short ClrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolIODequeue(nativeOverlapped, overlapped, ClrInstanceID); + + END_QCALL; +} + +void QCALLTYPE NativeEventLogger::LogThreadPoolWorkingThreadCount(__in_z uint count, __in_z short ClrInstanceID) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + FireEtwThreadPoolWorkingThreadCount(count, ClrInstanceID); + + END_QCALL; +} +#endif // FEATURE_PERFTRACING diff --git a/src/coreclr/vm/nativeeventsource.h b/src/coreclr/vm/nativeeventsource.h index f22d21d..7d1826b 100644 --- a/src/coreclr/vm/nativeeventsource.h +++ b/src/coreclr/vm/nativeeventsource.h @@ -12,13 +12,31 @@ #ifndef _NATIVEEVENTSOURCE_H_ #define _NATIVEEVENTSOURCE_H_ -#if defined(FEATURE_EVENTSOURCE_XPLAT) +#include "qcall.h" + +#if defined(FEATURE_PERFTRACING) class XplatEventSourceLogger { public: static void QCALLTYPE LogEventSource(__in_z int eventID, __in_z LPCWSTR eventName, __in_z LPCWSTR eventSourceName, __in_z LPCWSTR payload); static BOOL QCALLTYPE IsEventSourceLoggingEnabled(); }; +#endif //defined(FEATURE_PERFTRACING) + +#if defined(FEATURE_PERFTRACING) +class NativeEventLogger +{ +public: + static void QCALLTYPE LogThreadPoolWorkerThreadStart(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID); + static void QCALLTYPE LogThreadPoolWorkerThreadStop(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID); + static void QCALLTYPE LogThreadPoolWorkerThreadWait(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID); + static void QCALLTYPE LogThreadPoolWorkerThreadAdjustmentSample(__in_z double throughput, __in_z short clrInstanceID); + static void QCALLTYPE LogThreadPoolWorkerThreadAdjustmentAdjustment(__in_z double averageThroughput, __in_z uint newWorkerThreadCount, __in_z uint reason, __in_z short clrInstanceID); + static void QCALLTYPE LogThreadPoolWorkerThreadAdjustmentStats(__in_z double duration, __in_z double throughput, __in_z double threadWave, __in_z double throughputWave, __in_z double throughputErrorEstimate, __in_z double AverageThroughputErrorEstimate, __in_z double ThroughputRatio, __in_z double confidence, __in_z double newControlSetting, __in_z short newThreadWaveMagnitude, __in_z short ClrInstanceID); + static void QCALLTYPE LogThreadPoolIOEnqueue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z bool multiDequeues, __in_z short ClrInstanceID); + static void QCALLTYPE LogThreadPoolIODequeue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z short ClrInstanceID); + static void QCALLTYPE LogThreadPoolWorkingThreadCount(__in_z uint count, __in_z short ClrInstanceID); +}; +#endif // defined(FEATURE_PERFTRACING) -#endif //defined(FEATURE_EVENTSOURCE_XPLAT) #endif //_NATIVEEVENTSOURCE_H_ 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 a21bf72..8408056 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 @@ -1957,7 +1957,7 @@ - + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 327f6f8..020ca17 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -229,17 +229,18 @@ namespace System.Diagnostics.Tracing /// public partial class EventSource : IDisposable { -#if FEATURE_EVENTSOURCE_XPLAT -#pragma warning disable CA1823 // field is used to keep listener alive - private static readonly EventListener? persistent_Xplat_Listener = XplatEventLogger.InitializePersistentListener(); -#pragma warning restore CA1823 -#endif //FEATURE_EVENTSOURCE_XPLAT internal static bool IsSupported { get; } = InitializeIsSupported(); private static bool InitializeIsSupported() => AppContext.TryGetSwitch("System.Diagnostics.Tracing.EventSource.IsSupported", out bool isSupported) ? isSupported : true; +#if FEATURE_EVENTSOURCE_XPLAT +#pragma warning disable CA1823 // field is used to keep listener alive + private static readonly EventListener? persistent_Xplat_Listener = IsSupported ? XplatEventLogger.InitializePersistentListener() : null; +#pragma warning restore CA1823 +#endif //FEATURE_EVENTSOURCE_XPLAT + /// /// The human-friendly name of the eventSource. It defaults to the simple name of the class /// @@ -3804,11 +3805,10 @@ namespace System.Diagnostics.Tracing static EventListener() { #if FEATURE_PERFTRACING - // Ensure that NativeRuntimeEventSource is initialized so that EventListeners get an opportunity to subscribe to its events. - // This is required because NativeRuntimeEventSource never emit events on its own, and thus will never be initialized - // in the normal way that EventSources are initialized. + // This allows NativeRuntimeEventSource to get initialized so that EventListeners can subscribe to the runtime events emitted from + // native side. GC.KeepAlive(NativeRuntimeEventSource.Log); -#endif // FEATURE_PERFTRACING +#endif } /// 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 027e120..4147327 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 @@ -1,23 +1,76 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + namespace System.Diagnostics.Tracing { /// /// NativeRuntimeEventSource is an EventSource that represents the ETW/EventPipe events emitted by the native runtime. - /// Most of NativeRuntimeEventSource is auto-generated by scripts/genRuntimeEventSources.py based on the contents of the Microsoft-Windows-DotNETRuntime provider. + /// Most of NativeRuntimeEventSource is auto-generated by scripts/genRuntimeEventSources.py based on the contents of the + /// Microsoft-Windows-DotNETRuntime provider and will throw a NotImplementedException without hand-written overloads of the Events. + /// To have a runtime event be fired from the managed code, you need to add a managed definition for that event + /// and QCall into the native runtime that invoke the appropriate native sinks for the platform (i.e. ETW, EventPipe, LTTng). + /// To see some examples of this, refer to NativeRuntimeEventSource.PortableThreadPool.cs. + /// Then, modify genRuntimeEventSources.py to skip over the event so that it doesn't generate the dummy method. /// - [EventSource(Guid = "5E5BB766-BBFC-5662-0548-1D44FAD9BB56", Name = EventSourceName)] + [EventSource(Guid = "E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4", Name = EventSourceName)] [EventSourceAutoGenerate] internal sealed partial class NativeRuntimeEventSource : EventSource { internal const string EventSourceName = "Microsoft-Windows-DotNETRuntime"; - internal static NativeRuntimeEventSource Log = new NativeRuntimeEventSource(); + public static readonly NativeRuntimeEventSource Log = new NativeRuntimeEventSource(); // 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 _) { } + + // On Mono, we don't have these keywords defined from the genRuntimeEventSources.py, so we need to manually define them here. +#if MONO + public class Keywords + { + public const EventKeywords GCKeyword = (EventKeywords)0x1; + public const EventKeywords GCHandleKeyword = (EventKeywords)0x2; + public const EventKeywords AssemblyLoaderKeyword = (EventKeywords)0x4; + public const EventKeywords LoaderKeyword = (EventKeywords)0x8; + public const EventKeywords JitKeyword = (EventKeywords)0x10; + public const EventKeywords NGenKeyword = (EventKeywords)0x20; + public const EventKeywords StartEnumerationKeyword = (EventKeywords)0x40; + public const EventKeywords EndEnumerationKeyword = (EventKeywords)0x80; + public const EventKeywords SecurityKeyword = (EventKeywords)0x400; + public const EventKeywords AppDomainResourceManagementKeyword = (EventKeywords)0x800; + public const EventKeywords JitTracingKeyword = (EventKeywords)0x1000; + public const EventKeywords InteropKeyword = (EventKeywords)0x2000; + public const EventKeywords ContentionKeyword = (EventKeywords)0x4000; + public const EventKeywords ExceptionKeyword = (EventKeywords)0x8000; + public const EventKeywords ThreadingKeyword = (EventKeywords)0x10000; + public const EventKeywords JittedMethodILToNativeMapKeyword = (EventKeywords)0x20000; + public const EventKeywords OverrideAndSuppressNGenEventsKeyword = (EventKeywords)0x40000; + public const EventKeywords TypeKeyword = (EventKeywords)0x80000; + public const EventKeywords GCHeapDumpKeyword = (EventKeywords)0x100000; + public const EventKeywords GCSampledObjectAllocationHighKeyword = (EventKeywords)0x200000; + public const EventKeywords GCHeapSurvivalAndMovementKeyword = (EventKeywords)0x400000; + public const EventKeywords GCHeapCollectKeyword = (EventKeywords)0x800000; + public const EventKeywords GCHeapAndTypeNamesKeyword = (EventKeywords)0x1000000; + public const EventKeywords GCSampledObjectAllocationLowKeyword = (EventKeywords)0x2000000; + public const EventKeywords PerfTrackKeyword = (EventKeywords)0x20000000; + public const EventKeywords StackKeyword = (EventKeywords)0x40000000; + public const EventKeywords ThreadTransferKeyword = (EventKeywords)0x80000000; + public const EventKeywords DebuggerKeyword = (EventKeywords)0x100000000; + public const EventKeywords MonitoringKeyword = (EventKeywords)0x200000000; + public const EventKeywords CodeSymbolsKeyword = (EventKeywords)0x400000000; + public const EventKeywords EventSourceKeyword = (EventKeywords)0x800000000; + public const EventKeywords CompilationKeyword = (EventKeywords)0x1000000000; + public const EventKeywords CompilationDiagnosticKeyword = (EventKeywords)0x2000000000; + public const EventKeywords MethodDiagnosticKeyword = (EventKeywords)0x4000000000; + public const EventKeywords TypeDiagnosticKeyword = (EventKeywords)0x8000000000; + public const EventKeywords JitInstrumentationDataKeyword = (EventKeywords)0x10000000000; + } +#endif // MONO + /// /// Dispatch a single event with the specified event ID and payload. /// @@ -53,5 +106,62 @@ namespace System.Diagnostics.Tracing childActivityID: &childActivityId, args: decodedPayloadFields); } + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkerThreadStart(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkerThreadStop(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkerThreadWait(uint ActiveWorkerThreadCount, uint RetiredWorkerThreadCount, ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkerThreadAdjustmentSample(double Throughput, ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkerThreadAdjustmentAdjustment(double AverageThroughput, uint NewWorkerThreadCount, NativeRuntimeEventSource.ThreadAdjustmentReasonMap Reason, ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkerThreadAdjustmentStats( + double Duration, + double Throughput, + double ThreadPoolWorkerThreadWait, + double ThroughputWave, + double ThroughputErrorEstimate, + double AverageThroughputErrorEstimate, + double ThroughputRatio, + double Confidence, + double NewControlSetting, + ushort NewThreadWaveMagnitude, + ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolIOEnqueue( + IntPtr NativeOverlapped, + IntPtr Overlapped, + bool MultiDequeues, + ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolIODequeue( + IntPtr NativeOverlapped, + IntPtr Overlapped, + ushort ClrInstanceID); + + [NonEvent] + [DllImport(RuntimeHelpers.QCall)] + internal static extern void LogThreadPoolWorkingThreadCount( + uint Count, + ushort ClrInstanceID + ); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs index 3c11d5b..51ce2ce 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs @@ -16,11 +16,11 @@ namespace System.Diagnostics.Tracing { internal class XplatEventLogger : EventListener { + public XplatEventLogger() {} + private static readonly Lazy eventSourceNameFilter = new Lazy(() => CompatibilitySwitch.GetValueInternal("EventSourceFilter")); private static readonly Lazy eventSourceEventFilter = new Lazy(() => CompatibilitySwitch.GetValueInternal("EventNameFilter")); - public XplatEventLogger() {} - private static bool initializedPersistentListener; public static EventListener? InitializePersistentListener() @@ -160,11 +160,6 @@ namespace System.Diagnostics.Tracing protected internal override void OnEventSourceCreated(EventSource eventSource) { - // Don't enable forwarding of NativeRuntimeEventSource events.` - if (eventSource.GetType() == typeof(NativeRuntimeEventSource)) - { - return; - } string? eventSourceFilter = eventSourceNameFilter.Value; if (string.IsNullOrEmpty(eventSourceFilter) || (eventSource.Name.IndexOf(eventSourceFilter, StringComparison.OrdinalIgnoreCase) >= 0)) @@ -175,6 +170,16 @@ namespace System.Diagnostics.Tracing protected internal override void OnEventWritten(EventWrittenEventArgs eventData) { + // Don't enable forwarding of NativeRuntimeEventSource events. + // NativeRuntimeEventSource events are written to the native side via QCalls (see NativeRuntimeEventSource.cs/nativeeventsource.cpp) + // and is forwarded back to this EventListener via NativeRuntimeEventSource.ProcessEvent. We need to filter these events here + // because then these events can get logged back into the native runtime as EventSourceEvent events which we use to log + // managed events from other EventSources to LTTng. + if (eventData.EventSource.GetType() == typeof(NativeRuntimeEventSource)) + { + return; + } + string? eventFilter = eventSourceEventFilter.Value; if (string.IsNullOrEmpty(eventFilter) || (eventData.EventName!.IndexOf(eventFilter, StringComparison.OrdinalIgnoreCase) >= 0)) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs similarity index 55% rename from src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs rename to src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs index 784f64d..5884e3b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPoolEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.cs @@ -1,28 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Threading; using System.Diagnostics.Tracing; using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; -namespace System.Threading +namespace System.Diagnostics.Tracing { - // Currently with EventPipe there isn't a way to move events from the native side to the managed side and get the same - // experience. For now, the same provider name and guid are used as the native side and a temporary change has been made to - // EventPipe in CoreCLR to get thread pool events in performance profiles when the portable thread pool is enabled, as that - // seems to be the easiest way currently and the closest to the experience when the portable thread pool is disabled. - // TODO: Long-term options (also see https://github.com/dotnet/runtime/issues/38763): - // - Use NativeRuntimeEventSource instead, change its guid to match the provider guid from the native side, and fix the - // underlying issues such that duplicate events are not sent. This should get the same experience as sending events from - // the native side, and would allow easily moving other events from the native side to the managed side in the future if - // necessary. - // - Use a different provider name and guid (maybe "System.Threading.ThreadPool"), update PerfView and dotnet-trace to - // enable the provider by default when the Threading or other ThreadPool-related keywords are specified for the runtime - // provider, and update PerfView with a trace event parser for the new provider so that it knows about the events and may - // use them to identify thread pool threads. - [EventSource(Name = "Microsoft-Windows-DotNETRuntime", Guid = "e13c0d23-ccbc-4e12-931b-d9cc2eee27e4")] - [EventSourceAutoGenerate] - internal sealed partial class PortableThreadPoolEventSource : EventSource + // This is part of the NativeRuntimeEventsource, which is the managed version of the Microsoft-Windows-DotNETRuntime provider. + // It contains the handwritten implementation of the ThreadPool events. + // The events here do not call into the typical WriteEvent* APIs unlike most EventSources because that results in the + // events to be forwarded to EventListeners twice, once directly from the managed WriteEvent API, and another time + // from the mechanism in NativeRuntimeEventSource.ProcessEvents that forwards native runtime events to EventListeners. + // To prevent this, these events call directly into QCalls provided by the runtime (refer to NativeRuntimeEventSource.cs) which call + // FireEtw* methods auto-generated from ClrEtwAll.man. This ensures that corresponding event sinks are being used + // for the native platform. Refer to src/coreclr/vm/nativeruntimesource.cpp. + 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 @@ -59,12 +53,6 @@ namespace System.Threading public const EventOpcode Stats = (EventOpcode)102; } - public static class Keywords // this name and visibility is important for EventSource - { - public const EventKeywords ThreadingKeyword = (EventKeywords)0x10000; - public const EventKeywords ThreadTransferKeyword = (EventKeywords)0x80000000; - } - public enum ThreadAdjustmentReasonMap : uint { Warmup, @@ -77,29 +65,6 @@ namespace System.Threading ThreadTimedOut } - // Parameterized constructor to block initialization and ensure the EventSourceGenerator is creating the default constructor - // as you can't make a constructor partial. - private PortableThreadPoolEventSource(int _) { } - - [NonEvent] - private unsafe void WriteThreadEvent(int eventId, uint numExistingThreads) - { - uint retiredWorkerThreadCount = 0; - ushort clrInstanceId = DefaultClrInstanceId; - - EventData* data = stackalloc EventData[3]; - data[0].DataPointer = (IntPtr)(&numExistingThreads); - data[0].Size = sizeof(uint); - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&retiredWorkerThreadCount); - data[1].Size = sizeof(uint); - data[1].Reserved = 0; - data[2].DataPointer = (IntPtr)(&clrInstanceId); - data[2].Size = sizeof(ushort); - data[2].Reserved = 0; - WriteEventCore(eventId, 3, data); - } - [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, @@ -108,7 +73,7 @@ namespace System.Threading { if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword)) { - WriteThreadEvent(50, ActiveWorkerThreadCount); + LogThreadPoolWorkerThreadStart(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID); } } @@ -120,7 +85,7 @@ namespace System.Threading { if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword)) { - WriteThreadEvent(51, ActiveWorkerThreadCount); + LogThreadPoolWorkerThreadStop(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID); } } @@ -133,7 +98,7 @@ namespace System.Threading { if (IsEnabled(EventLevel.Informational, Keywords.ThreadingKeyword)) { - WriteThreadEvent(57, ActiveWorkerThreadCount); + LogThreadPoolWorkerThreadWait(ActiveWorkerThreadCount, RetiredWorkerThreadCount, ClrInstanceID); } } @@ -146,15 +111,7 @@ namespace System.Threading { return; } - - EventData* data = stackalloc EventData[2]; - data[0].DataPointer = (IntPtr)(&Throughput); - data[0].Size = sizeof(double); - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&ClrInstanceID); - data[1].Size = sizeof(ushort); - data[1].Reserved = 0; - WriteEventCore(54, 2, data); + LogThreadPoolWorkerThreadAdjustmentSample(Throughput, ClrInstanceID); } [Event(55, Level = EventLevel.Informational, Message = Messages.WorkerThreadAdjustmentAdjustment, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Adjustment, Version = 0, Keywords = Keywords.ThreadingKeyword)] @@ -168,21 +125,7 @@ namespace System.Threading { return; } - - EventData* data = stackalloc EventData[4]; - data[0].DataPointer = (IntPtr)(&AverageThroughput); - data[0].Size = sizeof(double); - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&NewWorkerThreadCount); - data[1].Size = sizeof(uint); - data[1].Reserved = 0; - data[2].DataPointer = (IntPtr)(&Reason); - data[2].Size = sizeof(ThreadAdjustmentReasonMap); - data[2].Reserved = 0; - data[3].DataPointer = (IntPtr)(&ClrInstanceID); - data[3].Size = sizeof(ushort); - data[3].Reserved = 0; - WriteEventCore(55, 4, data); + LogThreadPoolWorkerThreadAdjustmentAdjustment(AverageThroughput, NewWorkerThreadCount, Reason, ClrInstanceID); } [Event(56, Level = EventLevel.Verbose, Message = Messages.WorkerThreadAdjustmentStats, Task = Tasks.ThreadPoolWorkerThreadAdjustment, Opcode = Opcodes.Stats, Version = 0, Keywords = Keywords.ThreadingKeyword)] @@ -203,42 +146,7 @@ namespace System.Threading { return; } - - EventData* data = stackalloc EventData[11]; - data[0].DataPointer = (IntPtr)(&Duration); - data[0].Size = sizeof(double); - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&Throughput); - data[1].Size = sizeof(double); - data[1].Reserved = 0; - data[2].DataPointer = (IntPtr)(&ThreadWave); - data[2].Size = sizeof(double); - data[2].Reserved = 0; - data[3].DataPointer = (IntPtr)(&ThroughputWave); - data[3].Size = sizeof(double); - data[3].Reserved = 0; - data[4].DataPointer = (IntPtr)(&ThroughputErrorEstimate); - data[4].Size = sizeof(double); - data[4].Reserved = 0; - data[5].DataPointer = (IntPtr)(&AverageThroughputErrorEstimate); - data[5].Size = sizeof(double); - data[5].Reserved = 0; - data[6].DataPointer = (IntPtr)(&ThroughputRatio); - data[6].Size = sizeof(double); - data[6].Reserved = 0; - data[7].DataPointer = (IntPtr)(&Confidence); - data[7].Size = sizeof(double); - data[7].Reserved = 0; - data[8].DataPointer = (IntPtr)(&NewControlSetting); - data[8].Size = sizeof(double); - data[8].Reserved = 0; - data[9].DataPointer = (IntPtr)(&NewThreadWaveMagnitude); - data[9].Size = sizeof(ushort); - data[9].Reserved = 0; - data[10].DataPointer = (IntPtr)(&ClrInstanceID); - data[10].Size = sizeof(ushort); - data[10].Reserved = 0; - WriteEventCore(56, 11, data); + LogThreadPoolWorkerThreadAdjustmentStats(Duration, Throughput, ThreadWave, ThroughputWave, ThroughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, Confidence, NewControlSetting, NewThreadWaveMagnitude, ClrInstanceID); } [Event(63, Level = EventLevel.Verbose, Message = Messages.IOEnqueue, Task = Tasks.ThreadPool, Opcode = Opcodes.IOEnqueue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)] @@ -249,21 +157,7 @@ namespace System.Threading ushort ClrInstanceID = DefaultClrInstanceId) { int multiDequeuesInt = Convert.ToInt32(MultiDequeues); // bool maps to "win:Boolean", a 4-byte boolean - - EventData* data = stackalloc EventData[4]; - data[0].DataPointer = (IntPtr)(&NativeOverlapped); - data[0].Size = IntPtr.Size; - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&Overlapped); - data[1].Size = IntPtr.Size; - data[1].Reserved = 0; - data[2].DataPointer = (IntPtr)(&multiDequeuesInt); - data[2].Size = sizeof(int); - data[2].Reserved = 0; - data[3].DataPointer = (IntPtr)(&ClrInstanceID); - data[3].Size = sizeof(ushort); - data[3].Reserved = 0; - WriteEventCore(63, 4, data); + LogThreadPoolIOEnqueue(NativeOverlapped, Overlapped, MultiDequeues, ClrInstanceID); } // TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use @@ -284,17 +178,7 @@ namespace System.Threading IntPtr Overlapped, ushort ClrInstanceID = DefaultClrInstanceId) { - EventData* data = stackalloc EventData[3]; - data[0].DataPointer = (IntPtr)(&NativeOverlapped); - data[0].Size = IntPtr.Size; - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&Overlapped); - data[1].Size = IntPtr.Size; - data[1].Reserved = 0; - data[2].DataPointer = (IntPtr)(&ClrInstanceID); - data[2].Size = sizeof(ushort); - data[2].Reserved = 0; - WriteEventCore(64, 3, data); + LogThreadPoolIODequeue(NativeOverlapped, Overlapped, ClrInstanceID); } // TODO: This event is fired for minor compat with CoreCLR in this case. Consider removing this method and use @@ -316,19 +200,7 @@ namespace System.Threading { return; } - - EventData* data = stackalloc EventData[2]; - data[0].DataPointer = (IntPtr)(&Count); - data[0].Size = sizeof(uint); - data[0].Reserved = 0; - data[1].DataPointer = (IntPtr)(&ClrInstanceID); - data[1].Size = sizeof(ushort); - data[1].Reserved = 0; - WriteEventCore(60, 2, data); + LogThreadPoolWorkingThreadCount(Count, ClrInstanceID); } - -#pragma warning disable IDE1006 // Naming Styles - public static readonly PortableThreadPoolEventSource Log = new PortableThreadPoolEventSource(); -#pragma warning restore IDE1006 // Naming Styles } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs index c9f8075..99bad61 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.GateThread.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.Tracing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -43,9 +44,9 @@ namespace System.Threading { Thread.Sleep(GateThreadDelayMs); - if (ThreadPool.EnableWorkerTracking && PortableThreadPoolEventSource.Log.IsEnabled()) + if (ThreadPool.EnableWorkerTracking && NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkingThreadCount( + NativeRuntimeEventSource.Log.ThreadPoolWorkingThreadCount( (uint)threadPoolInstance.GetAndResetHighWatermarkCountOfThreadsProcessingUserCallbacks()); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs index c7ed0ee..d34c0da 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.Tracing; namespace System.Threading { @@ -169,9 +170,9 @@ namespace System.Threading // Add the current thread count and throughput sample to our history // double throughput = numCompletions / sampleDurationSeconds; - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkerThreadAdjustmentSample(throughput); + NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadAdjustmentSample(throughput); } int sampleIndex = (int)(_totalSamples % _samplesToMeasure); @@ -343,9 +344,9 @@ namespace System.Threading // Record these numbers for posterity // - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkerThreadAdjustmentStats(sampleDurationSeconds, throughput, threadWaveComponent.Real, throughputWaveComponent.Real, + NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadAdjustmentStats(sampleDurationSeconds, throughput, threadWaveComponent.Real, throughputWaveComponent.Real, throughputErrorEstimate, _averageThroughputNoise, ratio.Real, confidence, _currentControlSetting, (ushort)newThreadWaveMagnitude); } @@ -404,12 +405,12 @@ namespace System.Threading _logSize++; - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkerThreadAdjustmentAdjustment( + NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadAdjustmentAdjustment( throughput, (uint)newThreadCount, - (PortableThreadPoolEventSource.ThreadAdjustmentReasonMap)stateOrTransition); + (NativeRuntimeEventSource.ThreadAdjustmentReasonMap)stateOrTransition); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WaitThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WaitThread.cs index 4155506..59d5b52 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WaitThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WaitThread.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.Tracing; using Microsoft.Win32.SafeHandles; namespace System.Threading @@ -36,9 +37,9 @@ namespace System.Threading /// A description of the requested registration. internal void RegisterWaitHandle(RegisteredWaitHandle handle) { - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolIOEnqueue(handle); + NativeRuntimeEventSource.Log.ThreadPoolIOEnqueue(handle); } _waitThreadLock.Acquire(); @@ -75,9 +76,9 @@ namespace System.Threading internal static void CompleteWait(RegisteredWaitHandle handle, bool timedOut) { - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolIODequeue(handle); + NativeRuntimeEventSource.Log.ThreadPoolIODequeue(handle); } handle.PerformCallback(timedOut); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs index 18cc664..190a8ef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs @@ -1,6 +1,8 @@ // 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.Tracing; + namespace System.Threading { internal partial class PortableThreadPool @@ -20,9 +22,9 @@ namespace System.Threading AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.UnfairSemaphoreSpinLimit", 70, false), onWait: () => { - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkerThreadWait( + NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadWait( (uint)ThreadPoolInstance._separated.counts.VolatileRead().NumExistingThreads); } }); @@ -35,9 +37,9 @@ namespace System.Threading PortableThreadPool threadPoolInstance = ThreadPoolInstance; - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkerThreadStart( + NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadStart( (uint)threadPoolInstance._separated.counts.VolatileRead().NumExistingThreads); } @@ -125,9 +127,9 @@ namespace System.Threading { HillClimbing.ThreadPoolHillClimber.ForceChange(newNumThreadsGoal, HillClimbing.StateOrTransition.ThreadTimedOut); - if (PortableThreadPoolEventSource.Log.IsEnabled()) + if (NativeRuntimeEventSource.Log.IsEnabled()) { - PortableThreadPoolEventSource.Log.ThreadPoolWorkerThreadStop((uint)newNumExistingThreads); + NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadStop((uint)newNumExistingThreads); } return; } diff --git a/src/native/eventpipe/ep-config.c b/src/native/eventpipe/ep-config.c index 3840566..8b7b9a8 100644 --- a/src/native/eventpipe/ep-config.c +++ b/src/native/eventpipe/ep-config.c @@ -95,19 +95,6 @@ config_register_provider ( ep_requires_lock_held (); - // See if we've already registered this provider. When the portable thread pool is being used, allow there to be multiple - // DotNETRuntime providers, as the portable thread pool temporarily uses an event source on the managed side with the same - // provider name. - // TODO: This change to allow multiple DotNETRuntime providers is temporary to get EventPipe working for - // PortableThreadPoolEventSource. Once a long-term solution is figured out, this change should be reverted. See - // https://github.com/dotnet/runtime/issues/38763 for more information. - EventPipeProvider *existing_provider = NULL; - if (!ep_rt_config_value_get_use_portable_thread_pool () || ep_rt_utf8_string_compare (ep_config_get_public_provider_name_utf8 (), ep_provider_get_provider_name (provider)) != 0) - existing_provider = config_get_provider (config, ep_provider_get_provider_name (provider)); - - if (existing_provider) - return false; - // The provider has not been registered, so register it. if (!ep_rt_provider_list_append (&config->provider_list, provider)) return false; -- 2.7.4