Skip to content

Commit ba36813

Browse files
authored
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
1 parent 008de9a commit ba36813

15 files changed

+333
-233
lines changed

src/coreclr/scripts/genRuntimeEventSources.py

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/**********************************************************************
1616
1717
DO NOT MODIFY. AUTOGENERATED FILE.
18-
This file is generated by <root>/src/scripts/genRuntimeEventSources.py
18+
This file is generated by <root>/src/coreclr/scripts/genRuntimeEventSources.py
1919
2020
**********************************************************************/
2121
"""
@@ -73,22 +73,30 @@ def getCSharpTypeFromManifestType(manifestType):
7373

7474
def generateEvent(eventNode, providerNode, outputFile, stringTable):
7575

76+
# ThreadPool events are defined manually in NativeRuntimeEventSource.PortableThreadPool.cs
77+
symbol = eventNode.getAttribute("symbol")
78+
if "ThreadPool" in symbol:
79+
return
80+
81+
evtLevel = eventNode.getAttribute("level")[4:]
82+
evtKeywords = ""
7683
# Write the event attribute.
77-
writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + eventNode.getAttribute("level")[4:])
84+
writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + evtLevel)
7885

7986
# Not all events have keywords specified, and some have multiple keywords specified.
8087
keywords = eventNode.getAttribute("keywords")
8188
if keywords:
8289
if " " not in keywords:
8390
outputFile.write(", Keywords = Keywords." + keywords)
91+
evtKeywords = "Keywords." + keywords
8492
else:
8593
keywords = keywords.split()
8694
outputFile.write(", Keywords = ")
8795
for keywordIndex in range(len(keywords)):
88-
outputFile.write("Keywords." + keywords[keywordIndex])
96+
evtKeywords += "Keywords." + keywords[keywordIndex]
8997
if keywordIndex < (len(keywords) - 1):
90-
outputFile.write(" | ")
91-
98+
evtKeywords += " | "
99+
outputFile.write(evtKeywords)
92100
outputFile.write(")]\n")
93101

94102
# Get the template for the event.
@@ -147,28 +155,10 @@ def generateEvent(eventNode, providerNode, outputFile, stringTable):
147155
outputFile.write(")\n")
148156
writeOutput(outputFile, "{\n")
149157

150-
# Write the call to WriteEvent.
151158
increaseTabLevel()
152-
writeOutput(outputFile, "WriteEvent(" + eventNode.getAttribute("value"))
153-
154-
# Add method parameters.
155-
if argumentCount > 0:
156-
# A ',' is needed after the event id.
157-
outputFile.write(", ")
158-
159-
# Write the parameter names to the method call.
160-
argumentsProcessed = 0
161-
argumentNodes = templateNode.getElementsByTagName("data")
162-
for argumentIndex in range(argumentCount):
163-
argumentNode = argumentNodes[argumentIndex]
164-
argumentName = argumentNode.getAttribute("name")
165-
outputFile.write(argumentName)
166-
if argumentIndex < (argumentCount - 1):
167-
outputFile.write(", ")
168-
169-
outputFile.write(");\n")
159+
writeOutput(outputFile, "// To have this event be emitted from managed side, refer to NativeRuntimeEventSource.cs\n")
160+
writeOutput(outputFile, "throw new NotImplementedException();\n")
170161
decreaseTabLevel()
171-
172162
writeOutput(outputFile, "}\n\n")
173163

174164

src/coreclr/vm/corelib.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,15 @@
7676
#endif
7777

7878
#if defined(FEATURE_EVENTSOURCE_XPLAT)
79-
#include "nativeeventsource.h"
8079
#include "eventpipeadapter.h"
8180
#include "eventpipeinternal.h"
81+
#include "nativeeventsource.h"
8282
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)
8383

8484
#ifdef FEATURE_PERFTRACING
8585
#include "eventpipeadapter.h"
8686
#include "eventpipeinternal.h"
87+
#include "nativeeventsource.h"
8788
#endif //FEATURE_PERFTRACING
8889

8990
#include "tailcallhelp.h"

src/coreclr/vm/ecalllist.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -989,12 +989,25 @@ FCFuncStart(gStreamFuncs)
989989
FCFuncEnd()
990990

991991

992-
#if defined(FEATURE_EVENTSOURCE_XPLAT)
992+
#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
993993
FCFuncStart(gEventLogger)
994+
#if defined(FEATURE_EVENTSOURCE_XPLAT)
994995
QCFuncElement("IsEventSourceLoggingEnabled", XplatEventSourceLogger::IsEventSourceLoggingEnabled)
995996
QCFuncElement("LogEventSource", XplatEventSourceLogger::LogEventSource)
996-
FCFuncEnd()
997997
#endif // defined(FEATURE_EVENTSOURCE_XPLAT)
998+
#if defined(FEATURE_PERFTRACING)
999+
QCFuncElement("LogThreadPoolWorkerThreadStart", NativeEventLogger::LogThreadPoolWorkerThreadStart)
1000+
QCFuncElement("LogThreadPoolWorkerThreadStop", NativeEventLogger::LogThreadPoolWorkerThreadStop)
1001+
QCFuncElement("LogThreadPoolWorkerThreadWait", NativeEventLogger::LogThreadPoolWorkerThreadWait)
1002+
QCFuncElement("LogThreadPoolWorkerThreadAdjustmentSample", NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentSample)
1003+
QCFuncElement("LogThreadPoolWorkerThreadAdjustmentAdjustment", NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentAdjustment)
1004+
QCFuncElement("LogThreadPoolWorkerThreadAdjustmentStats", NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentStats)
1005+
QCFuncElement("LogThreadPoolIOEnqueue", NativeEventLogger::LogThreadPoolIOEnqueue)
1006+
QCFuncElement("LogThreadPoolIODequeue", NativeEventLogger::LogThreadPoolIODequeue)
1007+
QCFuncElement("LogThreadPoolWorkingThreadCount", NativeEventLogger::LogThreadPoolWorkingThreadCount)
1008+
#endif // defined(FEATURE_PERFTRACING)
1009+
FCFuncEnd()
1010+
#endif // defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
9981011

9991012
#ifdef FEATURE_PERFTRACING
10001013
FCFuncStart(gEventPipeInternalFuncs)
@@ -1200,7 +1213,7 @@ FCClassElement("WeakReference`1", "System", gWeakReferenceOfTFuncs)
12001213
FCClassElement("X86Base", "System.Runtime.Intrinsics.X86", gX86BaseFuncs)
12011214
#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
12021215

1203-
#if defined(FEATURE_EVENTSOURCE_XPLAT)
1216+
#if defined(FEATURE_EVENTSOURCE_XPLAT) || defined(FEATURE_PERFTRACING)
12041217
FCClassElement("XplatEventLogger", "System.Diagnostics.Tracing", gEventLogger)
12051218
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)
12061219

src/coreclr/vm/nativeeventsource.cpp

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
// ============================================================================
1010

1111
#include "common.h"
12-
#if defined(FEATURE_EVENTSOURCE_XPLAT)
1312
#include "nativeeventsource.h"
1413

14+
#if defined(FEATURE_EVENTSOURCE_XPLAT)
15+
1516
void QCALLTYPE XplatEventSourceLogger::LogEventSource(__in_z int eventID, __in_z LPCWSTR eventName, __in_z LPCWSTR eventSourceName, __in_z LPCWSTR payload)
1617
{
1718
QCALL_CONTRACT;
@@ -31,7 +32,105 @@ BOOL QCALLTYPE XplatEventSourceLogger::IsEventSourceLoggingEnabled()
3132
END_QCALL;
3233

3334
return retVal;
34-
3535
}
3636

3737
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)
38+
39+
#ifdef FEATURE_PERFTRACING
40+
41+
// These are native QCalls that call into corresponding FireEtw* events for events that want to be emitted from the managed
42+
// side using NativeRuntimeEventSource.
43+
// You need to add them to src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/XplatEventLogger.cs and
44+
// change genRuntimeEventSources.py script to not emit the body that throws NotImplementedException for the event that
45+
// want to be fired from managed code.
46+
// See https://github.com/dotnet/runtime/pull/47829 for an example of how to do this.
47+
void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadStart(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID)
48+
{
49+
QCALL_CONTRACT;
50+
BEGIN_QCALL;
51+
52+
FireEtwThreadPoolWorkerThreadStart(activeWorkerThreadCount, retiredWorkerThreadCount, clrInstanceID);
53+
54+
END_QCALL;
55+
}
56+
57+
void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadStop(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID)
58+
{
59+
QCALL_CONTRACT;
60+
BEGIN_QCALL;
61+
62+
FireEtwThreadPoolWorkerThreadStop(activeWorkerThreadCount, retiredWorkerThreadCount, clrInstanceID);
63+
64+
END_QCALL;
65+
}
66+
67+
void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadWait(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID)
68+
{
69+
QCALL_CONTRACT;
70+
BEGIN_QCALL;
71+
72+
FireEtwThreadPoolWorkerThreadWait(activeWorkerThreadCount, retiredWorkerThreadCount, clrInstanceID);
73+
74+
END_QCALL;
75+
}
76+
77+
void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentSample(__in_z double throughput, __in_z short clrInstanceID)
78+
{
79+
QCALL_CONTRACT;
80+
BEGIN_QCALL;
81+
82+
FireEtwThreadPoolWorkerThreadAdjustmentSample(throughput, clrInstanceID);
83+
84+
END_QCALL;
85+
}
86+
87+
void QCALLTYPE NativeEventLogger::LogThreadPoolWorkerThreadAdjustmentAdjustment(__in_z double averageThroughput, __in_z uint newWorkerThreadCount, __in_z uint reason, __in_z short clrInstanceID)
88+
{
89+
QCALL_CONTRACT;
90+
BEGIN_QCALL;
91+
92+
FireEtwThreadPoolWorkerThreadAdjustmentAdjustment(averageThroughput, newWorkerThreadCount, reason, clrInstanceID);
93+
94+
END_QCALL;
95+
}
96+
97+
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)
98+
{
99+
QCALL_CONTRACT;
100+
BEGIN_QCALL;
101+
102+
FireEtwThreadPoolWorkerThreadAdjustmentStats(duration, throughput, threadWave, throughputWave, throughputErrorEstimate, AverageThroughputErrorEstimate, ThroughputRatio, confidence, newControlSetting, newThreadWaveMagnitude, ClrInstanceID);
103+
104+
END_QCALL;
105+
}
106+
107+
void QCALLTYPE NativeEventLogger::LogThreadPoolIOEnqueue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z bool multiDequeues, __in_z short ClrInstanceID)
108+
{
109+
QCALL_CONTRACT;
110+
BEGIN_QCALL;
111+
112+
FireEtwThreadPoolIOEnqueue(nativeOverlapped, overlapped, multiDequeues, ClrInstanceID);
113+
114+
END_QCALL;
115+
}
116+
117+
void QCALLTYPE NativeEventLogger::LogThreadPoolIODequeue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z short ClrInstanceID)
118+
{
119+
QCALL_CONTRACT;
120+
BEGIN_QCALL;
121+
122+
FireEtwThreadPoolIODequeue(nativeOverlapped, overlapped, ClrInstanceID);
123+
124+
END_QCALL;
125+
}
126+
127+
void QCALLTYPE NativeEventLogger::LogThreadPoolWorkingThreadCount(__in_z uint count, __in_z short ClrInstanceID)
128+
{
129+
QCALL_CONTRACT;
130+
BEGIN_QCALL;
131+
132+
FireEtwThreadPoolWorkingThreadCount(count, ClrInstanceID);
133+
134+
END_QCALL;
135+
}
136+
#endif // FEATURE_PERFTRACING

src/coreclr/vm/nativeeventsource.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,31 @@
1212
#ifndef _NATIVEEVENTSOURCE_H_
1313
#define _NATIVEEVENTSOURCE_H_
1414

15-
#if defined(FEATURE_EVENTSOURCE_XPLAT)
15+
#include "qcall.h"
16+
17+
#if defined(FEATURE_PERFTRACING)
1618
class XplatEventSourceLogger
1719
{
1820
public:
1921
static void QCALLTYPE LogEventSource(__in_z int eventID, __in_z LPCWSTR eventName, __in_z LPCWSTR eventSourceName, __in_z LPCWSTR payload);
2022
static BOOL QCALLTYPE IsEventSourceLoggingEnabled();
2123
};
24+
#endif //defined(FEATURE_PERFTRACING)
25+
26+
#if defined(FEATURE_PERFTRACING)
27+
class NativeEventLogger
28+
{
29+
public:
30+
static void QCALLTYPE LogThreadPoolWorkerThreadStart(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID);
31+
static void QCALLTYPE LogThreadPoolWorkerThreadStop(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID);
32+
static void QCALLTYPE LogThreadPoolWorkerThreadWait(__in_z uint activeWorkerThreadCount, __in_z uint retiredWorkerThreadCount, __in_z short clrInstanceID);
33+
static void QCALLTYPE LogThreadPoolWorkerThreadAdjustmentSample(__in_z double throughput, __in_z short clrInstanceID);
34+
static void QCALLTYPE LogThreadPoolWorkerThreadAdjustmentAdjustment(__in_z double averageThroughput, __in_z uint newWorkerThreadCount, __in_z uint reason, __in_z short clrInstanceID);
35+
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);
36+
static void QCALLTYPE LogThreadPoolIOEnqueue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z bool multiDequeues, __in_z short ClrInstanceID);
37+
static void QCALLTYPE LogThreadPoolIODequeue(__in_z void* nativeOverlapped, __in_z void* overlapped, __in_z short ClrInstanceID);
38+
static void QCALLTYPE LogThreadPoolWorkingThreadCount(__in_z uint count, __in_z short ClrInstanceID);
39+
};
40+
#endif // defined(FEATURE_PERFTRACING)
2241

23-
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)
2442
#endif //_NATIVEEVENTSOURCE_H_

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,7 @@
19571957
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPool.Portable.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
19581958
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPoolBoundHandle.PlatformNotSupported.cs" Condition="'$(FeatureCoreCLR)' != 'true'" />
19591959
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.cs" />
1960-
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPoolEventSource.cs" />
1960+
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\NativeRuntimeEventSource.PortableThreadPool.cs" />
19611961
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.GateThread.cs" />
19621962
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.HillClimbing.cs" />
19631963
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\PortableThreadPool.HillClimbing.Complex.cs" />

src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,18 @@ internal sealed class EventSourceAutoGenerateAttribute : Attribute
229229
/// </remarks>
230230
public partial class EventSource : IDisposable
231231
{
232-
#if FEATURE_EVENTSOURCE_XPLAT
233-
#pragma warning disable CA1823 // field is used to keep listener alive
234-
private static readonly EventListener? persistent_Xplat_Listener = XplatEventLogger.InitializePersistentListener();
235-
#pragma warning restore CA1823
236-
#endif //FEATURE_EVENTSOURCE_XPLAT
237232

238233
internal static bool IsSupported { get; } = InitializeIsSupported();
239234

240235
private static bool InitializeIsSupported() =>
241236
AppContext.TryGetSwitch("System.Diagnostics.Tracing.EventSource.IsSupported", out bool isSupported) ? isSupported : true;
242237

238+
#if FEATURE_EVENTSOURCE_XPLAT
239+
#pragma warning disable CA1823 // field is used to keep listener alive
240+
private static readonly EventListener? persistent_Xplat_Listener = IsSupported ? XplatEventLogger.InitializePersistentListener() : null;
241+
#pragma warning restore CA1823
242+
#endif //FEATURE_EVENTSOURCE_XPLAT
243+
243244
/// <summary>
244245
/// The human-friendly name of the eventSource. It defaults to the simple name of the class
245246
/// </summary>
@@ -3804,11 +3805,10 @@ public event EventHandler<EventSourceCreatedEventArgs>? EventSourceCreated
38043805
static EventListener()
38053806
{
38063807
#if FEATURE_PERFTRACING
3807-
// Ensure that NativeRuntimeEventSource is initialized so that EventListeners get an opportunity to subscribe to its events.
3808-
// This is required because NativeRuntimeEventSource never emit events on its own, and thus will never be initialized
3809-
// in the normal way that EventSources are initialized.
3808+
// This allows NativeRuntimeEventSource to get initialized so that EventListeners can subscribe to the runtime events emitted from
3809+
// native side.
38103810
GC.KeepAlive(NativeRuntimeEventSource.Log);
3811-
#endif // FEATURE_PERFTRACING
3811+
#endif
38123812
}
38133813

38143814
/// <summary>

0 commit comments

Comments
 (0)