summaryrefslogtreecommitdiff
path: root/src/vm/eventtrace.cpp
diff options
context:
space:
mode:
authorSean Gillespie <segilles@microsoft.com>2018-01-23 18:53:30 -0800
committerGitHub <noreply@github.com>2018-01-23 18:53:30 -0800
commitfacdc8b97f73973fb416ed13e4b9dd9a255864bf (patch)
treec6be1ef07de8d324dcb121da524c13458d7f0f63 /src/vm/eventtrace.cpp
parent0bafdbc71e5a3efe6b6df0cbcf5aee5081a3e4c8 (diff)
downloadcoreclr-facdc8b97f73973fb416ed13e4b9dd9a255864bf.tar.gz
coreclr-facdc8b97f73973fb416ed13e4b9dd9a255864bf.tar.bz2
coreclr-facdc8b97f73973fb416ed13e4b9dd9a255864bf.zip
[Local GC] FEATURE_EVENT_TRACE 1/n: Tracking Event State (#15873)
* [Local GC] FEATURE_EVENT_TRACE 1/n: Add infrastructure for keeping event state within the GC and plumbing to communicate event state changes * Code review feedback: use a load without a barrier in IsEnabled and put debug-only code under TRACE_GC_EVENT_STATE * Address code review feedback: add EventPipe callback and comments * Fix the non-FEATURE_PAL build * Fix an issue where the GC fails to react to ETW callbacks to occur before the GC is initialized (e.g. on startup when an ETW session is already active) * Simplify callback locking scheme * Add a separate callback for each EventPipe provider and funnel them all through a common handler * Fix non-FEATURE_PAL build
Diffstat (limited to 'src/vm/eventtrace.cpp')
-rw-r--r--src/vm/eventtrace.cpp135
1 files changed, 128 insertions, 7 deletions
diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp
index f66c92e40e..533a3bc7fa 100644
--- a/src/vm/eventtrace.cpp
+++ b/src/vm/eventtrace.cpp
@@ -4313,6 +4313,110 @@ void InitializeEventTracing()
ETW::TypeSystemLog::PostRegistrationInit();
}
+// Plumbing to funnel event pipe callbacks and ETW callbacks together into a single common
+// handler, for the purposes of informing the GC of changes to the event state.
+//
+// There is one callback for every EventPipe provider and one for all of ETW. The reason
+// for this is that ETW passes the registration handle of the provider that was enabled
+// as a field on the "CallbackContext" field of the callback, while EventPipe passes null
+// unless another token is given to it when the provider is constructed. In the absence of
+// a suitable token, this implementation has a different callback for every EventPipe provider
+// that ultimately funnels them all into a common handler.
+
+// CallbackProviderIndex provides a quick identification of which provider triggered the
+// ETW callback.
+enum CallbackProviderIndex
+{
+ DotNETRuntime = 0,
+ DotNETRuntimeRundown = 1,
+ DotNETRuntimeStress = 2,
+ DotNETRuntimePrivate = 3
+};
+
+// Common handler for all ETW or EventPipe event notifications. Based on the provider that
+// was enabled/disabled, this implementation forwards the event state change onto GCHeapUtilities
+// which will inform the GC to update its local state about what events are enabled.
+VOID EtwCallbackCommon(
+ CallbackProviderIndex ProviderIndex,
+ ULONG ControlCode,
+ UCHAR Level,
+ ULONGLONG MatchAnyKeyword)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ bool bIsPublicTraceHandle = ProviderIndex == DotNETRuntime;
+#if !defined(FEATURE_PAL)
+ static_assert(GCEventLevel_None == TRACE_LEVEL_NONE, "GCEventLevel_None value mismatch");
+ static_assert(GCEventLevel_Fatal == TRACE_LEVEL_FATAL, "GCEventLevel_Fatal value mismatch");
+ static_assert(GCEventLevel_Error == TRACE_LEVEL_ERROR, "GCEventLevel_Error value mismatch");
+ static_assert(GCEventLevel_Warning == TRACE_LEVEL_WARNING, "GCEventLevel_Warning mismatch");
+ static_assert(GCEventLevel_Information == TRACE_LEVEL_INFORMATION, "GCEventLevel_Information mismatch");
+ static_assert(GCEventLevel_Verbose == TRACE_LEVEL_VERBOSE, "GCEventLevel_Verbose mismatch");
+#endif // !defined(FEATURE_PAL)
+ GCEventKeyword keywords = static_cast<GCEventKeyword>(MatchAnyKeyword);
+ GCEventLevel level = static_cast<GCEventLevel>(Level);
+ GCHeapUtilities::RecordEventStateChange(bIsPublicTraceHandle, keywords, level);
+}
+
+// Individual callbacks for each EventPipe provider.
+
+VOID EventPipeEtwCallbackDotNETRuntimeStress(
+ _In_ LPCGUID SourceId,
+ _In_ ULONG ControlCode,
+ _In_ UCHAR Level,
+ _In_ ULONGLONG MatchAnyKeyword,
+ _In_ ULONGLONG MatchAllKeyword,
+ _In_opt_ PVOID FilterData,
+ _Inout_opt_ PVOID CallbackContext)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ EtwCallbackCommon(DotNETRuntimeStress, ControlCode, Level, MatchAnyKeyword);
+}
+
+VOID EventPipeEtwCallbackDotNETRuntime(
+ _In_ LPCGUID SourceId,
+ _In_ ULONG ControlCode,
+ _In_ UCHAR Level,
+ _In_ ULONGLONG MatchAnyKeyword,
+ _In_ ULONGLONG MatchAllKeyword,
+ _In_opt_ PVOID FilterData,
+ _Inout_opt_ PVOID CallbackContext)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ EtwCallbackCommon(DotNETRuntime, ControlCode, Level, MatchAnyKeyword);
+}
+
+VOID EventPipeEtwCallbackDotNETRuntimeRundown(
+ _In_ LPCGUID SourceId,
+ _In_ ULONG ControlCode,
+ _In_ UCHAR Level,
+ _In_ ULONGLONG MatchAnyKeyword,
+ _In_ ULONGLONG MatchAllKeyword,
+ _In_opt_ PVOID FilterData,
+ _Inout_opt_ PVOID CallbackContext)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ EtwCallbackCommon(DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword);
+}
+
+VOID EventPipeEtwCallbackDotNETRuntimePrivate(
+ _In_ LPCGUID SourceId,
+ _In_ ULONG ControlCode,
+ _In_ UCHAR Level,
+ _In_ ULONGLONG MatchAnyKeyword,
+ _In_ ULONGLONG MatchAllKeyword,
+ _In_opt_ PVOID FilterData,
+ _Inout_opt_ PVOID CallbackContext)
+{
+ WRAPPER_NO_CONTRACT;
+
+ EtwCallbackCommon(DotNETRuntimePrivate, ControlCode, Level, MatchAnyKeyword);
+}
+
+
#if !defined(FEATURE_PAL)
HRESULT ETW::CEtwTracer::Register()
{
@@ -4397,7 +4501,6 @@ extern "C"
extern "C"
{
-
// #EtwCallback:
// During the build, MC generates the code to register our provider, and to register
// our ETW callback. (This is buried under Intermediates, in a path like
@@ -4446,12 +4549,30 @@ extern "C"
BOOLEAN bIsRundownTraceHandle = (context->RegistrationHandle==Microsoft_Windows_DotNETRuntimeRundownHandle);
- // TypeSystemLog needs a notification when certain keywords are modified, so
- // give it a hook here.
- if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle)
- {
- ETW::TypeSystemLog::OnKeywordsChanged();
- }
+ // EventPipeEtwCallback contains some GC eventing functionality shared between EventPipe and ETW.
+ // Eventually, we'll want to merge these two codepaths whenever we can.
+ CallbackProviderIndex providerIndex = DotNETRuntime;
+ if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeHandle) {
+ providerIndex = DotNETRuntime;
+ } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeRundownHandle) {
+ providerIndex = DotNETRuntimeRundown;
+ } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimeStressHandle) {
+ providerIndex = DotNETRuntimeStress;
+ } else if (context->RegistrationHandle == Microsoft_Windows_DotNETRuntimePrivateHandle) {
+ providerIndex = DotNETRuntimePrivate;
+ } else {
+ assert(!"unknown registration handle");
+ return;
+ }
+
+ EtwCallbackCommon(providerIndex, ControlCode, Level, MatchAnyKeyword);
+
+ // TypeSystemLog needs a notification when certain keywords are modified, so
+ // give it a hook here.
+ if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle)
+ {
+ ETW::TypeSystemLog::OnKeywordsChanged();
+ }
// A manifest based provider can be enabled to multiple event tracing sessions
// As long as there is atleast 1 enabled session, IsEnabled will be TRUE