From 7a231d1cecb9c2dad09e7d6c179af4b587d95687 Mon Sep 17 00:00:00 2001 From: Brian Robbins Date: Fri, 7 Sep 2018 13:48:21 -0700 Subject: [PATCH] Add Basic Out-of-Process EventPipe Control and Heap Snapshot Capture (#19720) --- .../System.Private.CoreLib.csproj | 5 +- src/System.Private.CoreLib/src/System/AppDomain.cs | 2 + .../src/System/Diagnostics/Eventing/EventPipe.cs | 13 + .../Diagnostics/Eventing/EventPipeController.cs | 300 +++++++++++++++++++++ src/inc/clrconfigvalues.h | 1 + src/vm/ceemain.cpp | 5 - src/vm/eventpipe.cpp | 31 --- src/vm/eventpipe.h | 3 - src/vm/eventtrace.cpp | 133 +++------ src/vm/eventtracepriv.h | 10 - 10 files changed, 354 insertions(+), 149 deletions(-) create mode 100644 src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index d50c66f..30b5b2b 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -435,6 +435,7 @@ + @@ -461,6 +462,9 @@ + + + @@ -488,7 +492,6 @@ - diff --git a/src/System.Private.CoreLib/src/System/AppDomain.cs b/src/System.Private.CoreLib/src/System/AppDomain.cs index be1330b..45ddeaa 100644 --- a/src/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/System.Private.CoreLib/src/System/AppDomain.cs @@ -656,6 +656,8 @@ namespace System SetupFusionStore(new AppDomainSetup(), null); } } + + System.Diagnostics.Tracing.EventPipeController.Initialize(); } [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs index 94ace3c..d83dff8 100644 --- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs @@ -127,6 +127,19 @@ namespace System.Diagnostics.Tracing loggingLevel)); } + private void EnableProviderConfiguration(EventPipeProviderConfiguration providerConfig) + { + m_providers.Add(providerConfig); + } + + internal void EnableProviderRange(EventPipeProviderConfiguration[] providerConfigs) + { + foreach(EventPipeProviderConfiguration config in providerConfigs) + { + EnableProviderConfiguration(config); + } + } + internal void SetProfilerSamplingRate(TimeSpan minTimeBetweenSamples) { if(minTimeBetweenSamples.Ticks <= 0) diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs new file mode 100644 index 0000000..8a9a54b --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#if FEATURE_PERFTRACING +using Internal.IO; +using Microsoft.Win32; +using System.IO; +using System.Globalization; +using System.Runtime.Versioning; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Diagnostics.Tracing +{ + /// + /// Simple out-of-process listener for controlling EventPipe. + /// The following environment variables are used to configure EventPipe: + /// - COMPlus_EnableEventPipe=1 : Enable EventPipe immediately for the life of the process. + /// - COMPlus_EnableEventPipe=4 : Enables this controller and creates a thread to listen for enable/disable events. + /// - COMPlus_EventPipeConfig : Provides the configuration in xperf string form for which providers/keywords/levels to be enabled. + /// If not specified, the default configuration is used. + /// - COMPlus_EventPipeOutputFile : The full path to the netperf file to be written. + /// - COMPlus_EventPipeCircularMB : The size in megabytes of the circular buffer. + /// Once the configuration is set and this controller is enabled, tracing is enabled by creating a marker file that this controller listens for. + /// Tracing is disabled by deleting the marker file. The marker file is the target trace file path with ".ctl" appended to it. For example, + /// if the trace file is /path/to/trace.netperf then the marker file is /path/to/trace.netperf.ctl. + /// This listener does not poll very often, and thus takes time to enable and disable tracing. This is by design to ensure that the listener does + /// not starve other threads on the system. + /// NOTE: If COMPlus_EnableEventPipe != 4 then this listener is not created and does not add any overhead to the process. + /// + internal sealed class EventPipeController + { + // Miscellaneous constants. + private const string NetPerfFileExtension = ".netperf"; + private const string MarkerFileExtension = ".ctl"; + private const int EnabledPollingIntervalMilliseconds = 1000; // 1 second + private const int DisabledPollingIntervalMilliseconds = 10000; // 10 seconds + private const uint DefaultCircularBufferMB = 1024; // 1 GB + private static readonly char[] ProviderConfigDelimiter = new char[] { ',' }; + private static readonly char[] ConfigComponentDelimiter = new char[] { ':' }; + + // The default set of providers/keywords/levels. Used if an alternative configuration is not specified. + private static readonly EventPipeProviderConfiguration[] DefaultProviderConfiguration = new EventPipeProviderConfiguration[] + { + new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntime", 0x4c14fccbd, 5), + new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntimePrivate", 0x4002000b, 5), + new EventPipeProviderConfiguration("Microsoft-DotNETCore-SampleProfiler", 0x0, 5) + }; + + // Cache for COMPlus configuration variables. + private static int s_Config_EnableEventPipe = -1; + private static string s_Config_EventPipeConfig = null; + private static uint s_Config_EventPipeCircularMB = 0; + private static string s_Config_EventPipeOutputFile = null; + + // Singleton controller instance. + private static EventPipeController s_controllerInstance = null; + + // Controller object state. + private Timer m_timer; + private string m_traceFilePath = null; + private string m_markerFilePath = null; + private bool m_markerFileExists = false; + + internal static void Initialize() + { + // Don't allow failures to propagate upstream. + // Instead, ensure program correctness without tracing. + try + { + if (s_controllerInstance == null) + { + if(Config_EnableEventPipe == 4) + { + // Create a new controller to listen for commands. + s_controllerInstance = new EventPipeController(); + } + else if (Config_EnableEventPipe > 0) + { + // Enable tracing immediately. + // It will be disabled automatically on shutdown. + EventPipe.Enable(GetConfiguration()); + } + } + } + catch { } + } + + private EventPipeController() + { + // Initialize the timer to run once. The timer will re-schedule itself after each poll operation. + // This is done to ensure that there aren't multiple concurrent polling operations when an operation + // takes longer than the polling interval (e.g. on disable/rundown). + m_timer = new Timer( + callback: new TimerCallback(PollForTracingCommand), + state: null, + dueTime: DisabledPollingIntervalMilliseconds, + period: Timeout.Infinite, + flowExecutionContext: false); + } + + private void PollForTracingCommand(object state) + { + // Make sure that any transient errors don't cause the listener thread to exit. + try + { + // Perform initialization when the timer fires for the first time. + if (m_traceFilePath == null) + { + // Set file paths. + m_traceFilePath = GetDisambiguatedTraceFilePath(Config_EventPipeOutputFile); + m_markerFilePath = MarkerFilePath; + + // Marker file is assumed to not exist. + // This will be updated when the monitoring thread starts. + m_markerFileExists = false; + } + + // Check for existence of the file. + // If the existence of the file has changed since the last time we checked + // this means that we need to act on that change. + bool fileExists = File.Exists(m_markerFilePath); + if (m_markerFileExists != fileExists) + { + // Save the result. + m_markerFileExists = fileExists; + + // Take the appropriate action. + if (fileExists) + { + // Enable tracing. + EventPipe.Enable(GetConfiguration()); + } + else + { + // Disable tracing. + EventPipe.Disable(); + } + } + + // Schedule the timer to run again. + m_timer.Change(fileExists ? EnabledPollingIntervalMilliseconds : DisabledPollingIntervalMilliseconds, Timeout.Infinite); + } + catch { } + } + + private static EventPipeConfiguration GetConfiguration() + { + // Create a new configuration object. + EventPipeConfiguration config = new EventPipeConfiguration( + GetDisambiguatedTraceFilePath(Config_EventPipeOutputFile), + Config_EventPipeCircularMB); + + // Get the configuration. + string strConfig = Config_EventPipeConfig; + if (!string.IsNullOrEmpty(strConfig)) + { + // String must be of the form "providerName:keywords:level,providerName:keywords:level..." + string[] providers = strConfig.Split(ProviderConfigDelimiter); + foreach (string provider in providers) + { + string[] components = provider.Split(ConfigComponentDelimiter); + if (components.Length == 3) + { + string providerName = components[0]; + + // We use a try/catch block here because ulong.TryParse won't accept 0x at the beginning + // of a hex string. Thus, we either need to conditionally strip it or handle the exception. + // Given that this is not a perf-critical path, catching the exception is the simpler code. + ulong keywords = 0; + try + { + keywords = Convert.ToUInt64(components[1], 16); + } + catch { } + + uint level; + if (!uint.TryParse(components[2], out level)) + { + level = 0; + } + + config.EnableProvider(providerName, keywords, level); + } + } + } + else + { + // Specify the default configuration. + config.EnableProviderRange(DefaultProviderConfiguration); + } + + return config; + } + + /// + /// Responsible for disambiguating the trace file path if the specified file already exists. + /// This can happen if there are multiple applications with tracing enabled concurrently and COMPlus_EventPipeOutputFile + /// is set to the same value for more than one concurrently running application. + /// + private static string GetDisambiguatedTraceFilePath(string inputPath) + { + if (string.IsNullOrEmpty(inputPath)) + { + throw new ArgumentNullException("inputPath"); + } + + string filePath = inputPath; + if (File.Exists(filePath)) + { + string directoryName = Path.GetDirectoryName(filePath); + string fileWithoutExtension = Path.GetFileName(filePath); + string extension = Path.GetExtension(filePath); + + string newFileWithExtension = fileWithoutExtension + "." + Win32Native.GetCurrentProcessId() + extension; + filePath = Path.Combine(directoryName, newFileWithExtension); + } + + return filePath; + } + + #region Configuration + + private static int Config_EnableEventPipe + { + get + { + if (s_Config_EnableEventPipe == -1) + { + string strEnabledValue = CompatibilitySwitch.GetValueInternal("EnableEventPipe"); + if ((strEnabledValue == null) || (!int.TryParse(strEnabledValue, out s_Config_EnableEventPipe))) + { + s_Config_EnableEventPipe = 0; + } + } + + return s_Config_EnableEventPipe; + } + } + + private static string Config_EventPipeConfig + { + get + { + if (s_Config_EventPipeConfig == null) + { + s_Config_EventPipeConfig = CompatibilitySwitch.GetValueInternal("EventPipeConfig"); + } + + return s_Config_EventPipeConfig; + } + } + + private static uint Config_EventPipeCircularMB + { + get + { + if (s_Config_EventPipeCircularMB == 0) + { + string strCircularMB = CompatibilitySwitch.GetValueInternal("EventPipeCircularMB"); + if ((strCircularMB == null) || (!uint.TryParse(strCircularMB, out s_Config_EventPipeCircularMB))) + { + s_Config_EventPipeCircularMB = DefaultCircularBufferMB; + } + } + + return s_Config_EventPipeCircularMB; + } + } + + private static string Config_EventPipeOutputFile + { + get + { + if (s_Config_EventPipeOutputFile == null) + { + s_Config_EventPipeOutputFile = CompatibilitySwitch.GetValueInternal("EventPipeOutputFile"); + if (s_Config_EventPipeOutputFile == null) + { + s_Config_EventPipeOutputFile = "Process-" + Win32Native.GetCurrentProcessId() + NetPerfFileExtension; + } + } + + return s_Config_EventPipeOutputFile; + } + } + + private static string MarkerFilePath + { + get + { + return Config_EventPipeOutputFile + MarkerFileExtension; + } + } + + #endregion Configuration + } +} + +#endif // FEATURE_PERFTRACING diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h index 0d843fb..a3b6515 100644 --- a/src/inc/clrconfigvalues.h +++ b/src/inc/clrconfigvalues.h @@ -741,6 +741,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableEventPipe, W("EnableEventPipe"), 0, "Ena RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeOutputFile, W("EventPipeOutputFile"), "The full path including file name for the trace file that will be written when COMPlus_EnableEventPipe&=1") RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeConfig, W("EventPipeConfig"), "Configuration for EventPipe.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeRundown, W("EventPipeRundown"), 1, "Enable/disable eventpipe rundown.") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeCircularMB, W("EventPipeCircularMB"), 1024, "The EventPipe circular buffer size in megabytes.") #ifdef FEATURE_GDBJIT /// diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp index 83f1b23..885a524 100644 --- a/src/vm/ceemain.cpp +++ b/src/vm/ceemain.cpp @@ -983,11 +983,6 @@ void EEStartupHelper(COINITIEE fFlags) SystemDomain::System()->PublishAppDomainAndInformDebugger(SystemDomain::System()->DefaultDomain()); #endif -#ifdef FEATURE_PERFTRACING - // Start the event pipe if requested. - EventPipe::EnableOnStartup(); -#endif // FEATURE_PERFTRACING - #endif // CROSSGEN_COMPILE SystemDomain::System()->Init(); diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp index 42eea42..df6728e 100644 --- a/src/vm/eventpipe.cpp +++ b/src/vm/eventpipe.cpp @@ -203,37 +203,6 @@ void EventPipe::Initialize() InitProvidersAndEvents(); } -void EventPipe::EnableOnStartup() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // Test COMPLUS variable to enable tracing at start-up. - if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableEventPipe) & 1) == 1) - { - SString outputPath; - outputPath.Printf("Process-%d.netperf", GetCurrentProcessId()); - - // Create a new session. - EventPipeSession *pSession = new EventPipeSession( - EventPipeSessionType::File, - 1024 /* 1 GB circular buffer */, - NULL, /* pProviders */ - 0 /* numProviders */); - - // Get the configuration from the environment. - GetConfigurationFromEnvironment(outputPath, pSession); - - // Enable the session. - Enable(outputPath, pSession); - } -} - void EventPipe::Shutdown() { CONTRACTL diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h index d5273c4..1982130 100644 --- a/src/vm/eventpipe.h +++ b/src/vm/eventpipe.h @@ -234,9 +234,6 @@ class EventPipe // Shutdown the event pipe. static void Shutdown(); - // Enable tracing from the start-up path based on COMPLUS variable. - static void EnableOnStartup(); - // Enable tracing via the event pipe. static EventPipeSessionID Enable( LPCWSTR strOutputPath, diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp index 3e11983..be83f1c 100644 --- a/src/vm/eventtrace.cpp +++ b/src/vm/eventtrace.cpp @@ -1642,81 +1642,6 @@ void BulkTypeEventLogger::FireBulkTypeEvent() } UINT16 nClrInstanceID = GetClrInstanceId(); -#if !defined(FEATURE_PAL) - // Normally, we'd use the MC-generated FireEtwBulkType for all this gunk, but - // it's insufficient as the bulk type event is too complex (arrays of structs of - // varying size). So we directly log the event via EventDataDescCreate and - // EventWrite - - // We use one descriptor for the count + one for the ClrInstanceID + 4 - // per batched type (to include fixed-size data + name + param count + param - // array). But the system limit of 128 descriptors per event kicks in way - // before the 64K event size limit, and we already limit our batch size - // (m_nBulkTypeValueCount) to stay within the 128 descriptor limit. - EVENT_DATA_DESCRIPTOR EventData[128]; - - UINT iDesc = 0; - - _ASSERTE(iDesc < _countof(EventData)); - EventDataDescCreate(&EventData[iDesc++], &m_nBulkTypeValueCount, sizeof(m_nBulkTypeValueCount)); - - _ASSERTE(iDesc < _countof(EventData)); - EventDataDescCreate(&EventData[iDesc++], &nClrInstanceID, sizeof(nClrInstanceID)); - - for (int iTypeData = 0; iTypeData < m_nBulkTypeValueCount; iTypeData++) - { - // Do fixed-size data as one bulk copy - _ASSERTE(iDesc < _countof(EventData)); - EventDataDescCreate( - &EventData[iDesc++], - &(m_rgBulkTypeValues[iTypeData].fixedSizedData), - sizeof(m_rgBulkTypeValues[iTypeData].fixedSizedData)); - - // Do var-sized data individually per field - - // Type name (nonexistent and thus empty on FEATURE_REDHAWK) - _ASSERTE(iDesc < _countof(EventData)); -#ifdef FEATURE_REDHAWK - EventDataDescCreate(&EventData[iDesc++], W(""), sizeof(WCHAR)); -#else // FEATURE_REDHAWK - LPCWSTR wszName = m_rgBulkTypeValues[iTypeData].sName.GetUnicode(); - EventDataDescCreate( - &EventData[iDesc++], - (wszName == NULL) ? W("") : wszName, - (wszName == NULL) ? sizeof(WCHAR) : (m_rgBulkTypeValues[iTypeData].sName.GetCount() + 1) * sizeof(WCHAR)); -#endif // FEATURE_REDHAWK - - // Type parameter count -#ifndef FEATURE_REDHAWK - m_rgBulkTypeValues[iTypeData].cTypeParameters = m_rgBulkTypeValues[iTypeData].rgTypeParameters.GetCount(); -#endif // FEATURE_REDHAWK - _ASSERTE(iDesc < _countof(EventData)); - EventDataDescCreate( - &EventData[iDesc++], - &(m_rgBulkTypeValues[iTypeData].cTypeParameters), - sizeof(m_rgBulkTypeValues[iTypeData].cTypeParameters)); - - // Type parameter array - if (m_rgBulkTypeValues[iTypeData].cTypeParameters > 0) - { - _ASSERTE(iDesc < _countof(EventData)); - EventDataDescCreate( - &EventData[iDesc++], -#ifdef FEATURE_REDHAWK - ((m_rgBulkTypeValues[iTypeData].cTypeParameters == 1) ? - &(m_rgBulkTypeValues[iTypeData].ullSingleTypeParameter) : - (ULONGLONG *) (m_rgBulkTypeValues[iTypeData].rgTypeParameters)), -#else - m_rgBulkTypeValues[iTypeData].rgTypeParameters.GetElements(), -#endif - sizeof(ULONGLONG) * m_rgBulkTypeValues[iTypeData].cTypeParameters); - } - } - - Win32EventWrite(Microsoft_Windows_DotNETRuntimeHandle, &BulkType, iDesc, EventData); - -#else // FEATURE_PAL - if(m_pBulkTypeEventBuffer == NULL) { // The buffer could not be allocated when this object was created, so bail. @@ -1770,7 +1695,6 @@ void BulkTypeEventLogger::FireBulkTypeEvent() FireEtwBulkType(m_nBulkTypeValueCount, GetClrInstanceId(), iSize, m_pBulkTypeEventBuffer); -#endif // FEATURE_PAL // Reset state m_nBulkTypeValueCount = 0; m_nBulkTypeValueByteCount = 0; @@ -4249,6 +4173,13 @@ void InitializeEventTracing() // a suitable token, this implementation has a different callback for every EventPipe provider // that ultimately funnels them all into a common handler. +#if defined(FEATURE_PAL) +// CLR_GCHEAPCOLLECT_KEYWORD is defined by the generated ETW manifest on Windows. +// On non-Windows, we need to make sure that this is defined. Given that we can't change +// the value due to compatibility, we specify it here rather than generating defines based on the manifest. +#define CLR_GCHEAPCOLLECT_KEYWORD 0x800000 +#endif // defined(FEATURE_PAL) + // CallbackProviderIndex provides a quick identification of which provider triggered the // ETW callback. enum CallbackProviderIndex @@ -4266,7 +4197,8 @@ VOID EtwCallbackCommon( CallbackProviderIndex ProviderIndex, ULONG ControlCode, UCHAR Level, - ULONGLONG MatchAnyKeyword) + ULONGLONG MatchAnyKeyword, + PVOID pFilterData) { LIMITED_METHOD_CONTRACT; @@ -4282,6 +4214,26 @@ VOID EtwCallbackCommon( GCEventKeyword keywords = static_cast(MatchAnyKeyword); GCEventLevel level = static_cast(Level); GCHeapUtilities::RecordEventStateChange(bIsPublicTraceHandle, keywords, level); + + // Special check for the runtime provider's GCHeapCollectKeyword. Profilers + // flick this to force a full GC. + if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle && + ((MatchAnyKeyword & CLR_GCHEAPCOLLECT_KEYWORD) != 0)) + { + // Profilers may (optionally) specify extra data in the filter parameter + // to log with the GCStart event. + LONGLONG l64ClientSequenceNumber = 0; +#if !defined(FEATURE_PAL) + PEVENT_FILTER_DESCRIPTOR FilterData = (PEVENT_FILTER_DESCRIPTOR)pFilterData; + if ((FilterData != NULL) && + (FilterData->Type == 1) && + (FilterData->Size == sizeof(l64ClientSequenceNumber))) + { + l64ClientSequenceNumber = *(LONGLONG *) (FilterData->Ptr); + } +#endif // !defined(FEATURE_PAL) + ETW::GCLog::ForceGC(l64ClientSequenceNumber); + } } // Individual callbacks for each EventPipe provider. @@ -4297,7 +4249,7 @@ VOID EventPipeEtwCallbackDotNETRuntimeStress( { LIMITED_METHOD_CONTRACT; - EtwCallbackCommon(DotNETRuntimeStress, ControlCode, Level, MatchAnyKeyword); + EtwCallbackCommon(DotNETRuntimeStress, ControlCode, Level, MatchAnyKeyword, FilterData); } VOID EventPipeEtwCallbackDotNETRuntime( @@ -4311,7 +4263,7 @@ VOID EventPipeEtwCallbackDotNETRuntime( { LIMITED_METHOD_CONTRACT; - EtwCallbackCommon(DotNETRuntime, ControlCode, Level, MatchAnyKeyword); + EtwCallbackCommon(DotNETRuntime, ControlCode, Level, MatchAnyKeyword, FilterData); } VOID EventPipeEtwCallbackDotNETRuntimeRundown( @@ -4325,7 +4277,7 @@ VOID EventPipeEtwCallbackDotNETRuntimeRundown( { LIMITED_METHOD_CONTRACT; - EtwCallbackCommon(DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword); + EtwCallbackCommon(DotNETRuntimeRundown, ControlCode, Level, MatchAnyKeyword, FilterData); } VOID EventPipeEtwCallbackDotNETRuntimePrivate( @@ -4339,7 +4291,7 @@ VOID EventPipeEtwCallbackDotNETRuntimePrivate( { WRAPPER_NO_CONTRACT; - EtwCallbackCommon(DotNETRuntimePrivate, ControlCode, Level, MatchAnyKeyword); + EtwCallbackCommon(DotNETRuntimePrivate, ControlCode, Level, MatchAnyKeyword, FilterData); } @@ -4491,7 +4443,7 @@ extern "C" return; } - EtwCallbackCommon(providerIndex, ControlCode, Level, MatchAnyKeyword); + EtwCallbackCommon(providerIndex, ControlCode, Level, MatchAnyKeyword, FilterData); // TypeSystemLog needs a notification when certain keywords are modified, so // give it a hook here. @@ -4551,23 +4503,6 @@ extern "C" { ETW::EnumerationLog::EnumerateForCaptureState(); } - - // Special check for the runtime provider's GCHeapCollectKeyword. Profilers - // flick this to force a full GC. - if (g_fEEStarted && !g_fEEShutDown && bIsPublicTraceHandle && - ((MatchAnyKeyword & CLR_GCHEAPCOLLECT_KEYWORD) != 0)) - { - // Profilers may (optionally) specify extra data in the filter parameter - // to log with the GCStart event. - LONGLONG l64ClientSequenceNumber = 0; - if ((FilterData != NULL) && - (FilterData->Type == 1) && - (FilterData->Size == sizeof(l64ClientSequenceNumber))) - { - l64ClientSequenceNumber = *(LONGLONG *) (FilterData->Ptr); - } - ETW::GCLog::ForceGC(l64ClientSequenceNumber); - } } #ifdef FEATURE_COMINTEROP if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, CCWRefCountChange)) diff --git a/src/vm/eventtracepriv.h b/src/vm/eventtracepriv.h index ae4f1c5..8e06daf 100644 --- a/src/vm/eventtracepriv.h +++ b/src/vm/eventtracepriv.h @@ -254,10 +254,8 @@ class BulkTypeEventLogger { private: -#ifdef FEATURE_PAL // The maximum event size, and the size of the buffer that we allocate to hold the event contents. static const size_t kSizeOfEventBuffer = 65536; -#endif // Estimate of how many bytes we can squeeze in the event data for the value struct // array. (Intentionally overestimate the size of the non-array parts to keep it safe.) @@ -299,9 +297,7 @@ private: // List of types we've batched. BulkTypeValue m_rgBulkTypeValues[kMaxCountTypeValues]; -#ifdef FEATURE_PAL BYTE *m_pBulkTypeEventBuffer; -#endif #ifdef FEATURE_REDHAWK int LogSingleType(EEType * pEEType); @@ -313,9 +309,7 @@ public: BulkTypeEventLogger() : m_nBulkTypeValueCount(0), m_nBulkTypeValueByteCount(0) -#ifdef FEATURE_PAL , m_pBulkTypeEventBuffer(NULL) -#endif { CONTRACTL { @@ -325,12 +319,9 @@ public: } CONTRACTL_END; -#ifdef FEATURE_PAL m_pBulkTypeEventBuffer = new (nothrow) BYTE[kSizeOfEventBuffer]; -#endif } -#ifdef FEATURE_PAL ~BulkTypeEventLogger() { CONTRACTL @@ -344,7 +335,6 @@ public: delete[] m_pBulkTypeEventBuffer; m_pBulkTypeEventBuffer = NULL; } -#endif void LogTypeAndParameters(ULONGLONG thAsAddr, ETW::TypeSystemLog::TypeLogBehavior typeLogBehavior); void FireBulkTypeEvent(); -- 2.7.4