summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs13
-rw-r--r--src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs17
-rw-r--r--src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs58
-rw-r--r--src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs2
-rw-r--r--src/inc/eventtracebase.h52
-rw-r--r--src/vm/eventpipe.cpp8
-rw-r--r--src/vm/eventpipe.h37
-rw-r--r--src/vm/eventpipeconfiguration.cpp12
-rw-r--r--src/vm/eventpipeeventsource.cpp3
-rw-r--r--src/vm/eventpipeprovider.cpp37
-rw-r--r--src/vm/eventpipeprovider.h14
-rw-r--r--src/vm/eventpipesession.cpp35
-rw-r--r--src/vm/eventpipesession.h10
-rw-r--r--src/vm/eventtrace.cpp8
14 files changed, 216 insertions, 90 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
index c0838196d5..0624a178aa 100644
--- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
+++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs
@@ -283,6 +283,19 @@ namespace System.Diagnostics.Tracing
m_allKeywordMask = allKeyword;
List<Tuple<SessionInfo, bool>> sessionsChanged = GetSessions();
+
+ // The GetSessions() logic was here to support the idea that different ETW sessions
+ // could have different user-defined filters. (I believe it is currently broken but that is another matter.)
+ // However in particular GetSessions() does not support EventPipe, only ETW, which is
+ // the immediate problem. We work-around establishing the invariant that we always get a
+ // OnControllerCallback under all circumstances, even if we can't find a delta in the
+ // ETW logic. This fixes things for the EventPipe case.
+ //
+ // All this session based logic should be reviewed and likely removed, but that is a larger
+ // change that needs more careful staging.
+ if (sessionsChanged.Count == 0)
+ sessionsChanged.Add(new Tuple<SessionInfo, bool>(new SessionInfo(0, 0), true));
+
foreach (var session in sessionsChanged)
{
int sessionChanged = session.Item1.sessionIdBit;
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 456d301ed1..1a5de88bd1 100644
--- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs
+++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs
@@ -40,10 +40,14 @@ namespace System.Diagnostics.Tracing
private ulong m_keywords;
private uint m_loggingLevel;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ private readonly string m_filterData;
+
internal EventPipeProviderConfiguration(
string providerName,
ulong keywords,
- uint loggingLevel)
+ uint loggingLevel,
+ string filterData)
{
if(string.IsNullOrEmpty(providerName))
{
@@ -56,6 +60,7 @@ namespace System.Diagnostics.Tracing
m_providerName = providerName;
m_keywords = keywords;
m_loggingLevel = loggingLevel;
+ m_filterData = filterData;
}
internal string ProviderName
@@ -72,6 +77,8 @@ namespace System.Diagnostics.Tracing
{
get { return m_loggingLevel; }
}
+
+ internal string FilterData => m_filterData;
}
internal sealed class EventPipeConfiguration
@@ -127,10 +134,16 @@ namespace System.Diagnostics.Tracing
internal void EnableProvider(string providerName, ulong keywords, uint loggingLevel)
{
+ EnableProviderWithFilter(providerName, keywords, loggingLevel, null);
+ }
+
+ internal void EnableProviderWithFilter(string providerName, ulong keywords, uint loggingLevel, string filterData)
+ {
m_providers.Add(new EventPipeProviderConfiguration(
providerName,
keywords,
- loggingLevel));
+ loggingLevel,
+ filterData));
}
private void EnableProviderConfiguration(EventPipeProviderConfiguration providerConfig)
diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs
index 738cc02688..ef5f331e25 100644
--- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs
+++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs
@@ -5,12 +5,10 @@
using Internal.IO;
using Microsoft.Win32;
using System.IO;
-using System.Globalization;
using System.Reflection;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
-using System.Threading.Tasks;
namespace System.Diagnostics.Tracing
{
@@ -54,9 +52,9 @@ namespace System.Diagnostics.Tracing
// 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)
+ new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntime", 0x4c14fccbd, 5, null),
+ new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntimePrivate", 0x4002000b, 5, null),
+ new EventPipeProviderConfiguration("Microsoft-DotNETCore-SampleProfiler", 0x0, 5, null),
};
// Singleton controller instance.
@@ -169,8 +167,11 @@ namespace System.Diagnostics.Tracing
foreach (string configEntry in configEntries)
{
//`Split the key and value by '='.
- string[] entryComponents = configEntry.Split(ConfigEntryDelimiter);
- if(entryComponents.Length == 2)
+ string[] entryComponents = configEntry.Split(
+ ConfigEntryDelimiter,
+ 2, // Stop split on first occurrence of the separator.
+ StringSplitOptions.RemoveEmptyEntries);
+ if (entryComponents.Length == 2)
{
string key = entryComponents[0];
if (key.Equals(ConfigKey_Providers))
@@ -226,7 +227,7 @@ namespace System.Diagnostics.Tracing
// Get the circular buffer size.
uint circularMB = DefaultCircularBufferMB;
- if(!string.IsNullOrEmpty(strCircularMB))
+ if (!string.IsNullOrEmpty(strCircularMB))
{
circularMB = Convert.ToUInt32(strCircularMB);
}
@@ -314,33 +315,48 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(strConfig));
}
- // String must be of the form "providerName:keywords:level,providerName:keywords:level..."
- string[] providers = strConfig.Split(ProviderConfigDelimiter);
+ // Provider format: "(GUID|KnownProviderName)[:Flags[:Level][:KeyValueArgs]]"
+ // where KeyValueArgs are of the form: "[key1=value1][;key2=value2]"
+ // `strConfig` must be of the form "Provider[,Provider]"
+ string[] providers = strConfig.Split(
+ ProviderConfigDelimiter,
+ StringSplitOptions.RemoveEmptyEntries); // Remove "empty" providers.
foreach (string provider in providers)
{
- string[] components = provider.Split(ConfigComponentDelimiter);
- if (components.Length == 3)
+ // Split expecting a maximum of four tokens.
+ string[] components = provider.Split(
+ ConfigComponentDelimiter,
+ 4, // if there is ':' in the parameters then anything after it will not be ignored.
+ StringSplitOptions.None); // Keep empty tokens
+
+ string providerName = components.Length > 0 ? components[0] : null;
+ if (string.IsNullOrEmpty(providerName))
+ continue; // No provider name specified.
+
+ ulong keywords = ulong.MaxValue;
+ if (components.Length > 1)
{
- 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))
+ catch
{
- level = 0;
}
+ }
- config.EnableProvider(providerName, keywords, level);
+ uint level = 5; // Verbose
+ if (components.Length > 2)
+ {
+ uint.TryParse(components[2], out level);
}
+
+ string filterData = components.Length > 3 ? components[3] : null;
+
+ config.EnableProviderWithFilter(providerName, keywords, level, filterData);
}
}
diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs
index 5e6a5596e0..a5b5922932 100644
--- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs
+++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs
@@ -107,7 +107,7 @@ namespace System.Diagnostics.Tracing
// Enable the EventPipe session.
EventPipeProviderConfiguration[] providerConfiguration = new EventPipeProviderConfiguration[]
{
- new EventPipeProviderConfiguration(RuntimeEventSource.EventSourceName, (ulong) aggregatedKeywords, (uint) highestLevel)
+ new EventPipeProviderConfiguration(RuntimeEventSource.EventSourceName, (ulong) aggregatedKeywords, (uint) highestLevel, null)
};
m_sessionID = EventPipeInternal.Enable(null, 1024, 1, providerConfiguration, 1, 0);
diff --git a/src/inc/eventtracebase.h b/src/inc/eventtracebase.h
index 7c0ee78b87..26287ab54a 100644
--- a/src/inc/eventtracebase.h
+++ b/src/inc/eventtracebase.h
@@ -10,7 +10,7 @@
//
//
-//
+//
// #EventTracing
// Windows
// ETW (Event Tracing for Windows) is a high-performance, low overhead and highly scalable
@@ -35,7 +35,7 @@ void InitializeEventTracing();
// The flags must match those in the ETW manifest exactly
// !!!!!!! NOTE !!!!!!!!
-// These flags need to be defined either when FEATURE_EVENT_TRACE is enabled or the
+// These flags need to be defined either when FEATURE_EVENT_TRACE is enabled or the
// PROFILING_SUPPORTED is set, since they are used both by event tracing and profiling.
enum EtwTypeFlags
@@ -106,7 +106,7 @@ enum EtwThreadFlags
#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
#else //defined(FEATURE_PERFTRACING)
-#define ETW_INLINE
+#define ETW_INLINE
#define ETWOnStartup(StartEventName, EndEventName)
#define ETWFireEvent(EventName)
@@ -242,13 +242,15 @@ public:
#if defined(FEATURE_EVENT_TRACE)
+struct EventFilterDescriptor;
+
VOID EventPipeEtwCallbackDotNETRuntimeStress(
_In_ LPCGUID SourceId,
_In_ ULONG ControlCode,
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext);
VOID EventPipeEtwCallbackDotNETRuntime(
@@ -257,7 +259,7 @@ VOID EventPipeEtwCallbackDotNETRuntime(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext);
VOID EventPipeEtwCallbackDotNETRuntimeRundown(
@@ -266,7 +268,7 @@ VOID EventPipeEtwCallbackDotNETRuntimeRundown(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext);
VOID EventPipeEtwCallbackDotNETRuntimePrivate(
@@ -275,7 +277,7 @@ VOID EventPipeEtwCallbackDotNETRuntimePrivate(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext);
#ifndef FEATURE_PAL
@@ -332,7 +334,7 @@ extern "C" {
#include "clretwallmain.h"
-#endif // FEATURE_EVENT_TRACE
+#endif // FEATURE_EVENT_TRACE
/**************************/
/* CLR ETW infrastructure */
@@ -351,7 +353,7 @@ extern "C" {
// has started, one may want to do something useful when that happens (e.g enumerate all the loaded modules
// in the system). To enable this, we have to implement a callback routine.
// file:../VM/eventtrace.cpp#EtwCallback is CLR's implementation of the callback.
-//
+//
#include "daccess.h"
class Module;
@@ -379,7 +381,7 @@ namespace ETW
{
// Class to wrap the ETW infrastructure logic
#if !defined(FEATURE_PAL)
- class CEtwTracer
+ class CEtwTracer
{
#if defined(FEATURE_EVENT_TRACE)
ULONG RegGuids(LPCGUID ProviderId, PENABLECALLBACK EnableCallback, PVOID CallbackContext, PREGHANDLE RegHandle);
@@ -391,7 +393,7 @@ namespace ETW
HRESULT Register();
// Unregisters all the Event Tracing providers
- HRESULT UnRegister();
+ HRESULT UnRegister();
#else
HRESULT Register()
{
@@ -406,7 +408,7 @@ namespace ETW
#endif // !defined(FEATURE_PAL)
class LoaderLog;
- class MethodLog;
+ class MethodLog;
// Class to wrap all the enumeration logic for ETW
class EnumerationLog
{
@@ -447,7 +449,7 @@ namespace ETW
MethodDCEndILToNativeMap= 0x00020000,
JitMethodILToNativeMap= 0x00040000,
TypeUnload= 0x00080000,
-
+
// Helpers
ModuleRangeEnabledAny = ModuleRangeLoad | ModuleRangeDCStart | ModuleRangeDCEnd | ModuleRangeLoadPrivate,
JitMethodLoadOrDCStartAny = JitMethodLoad | JitMethodDCStart | MethodDCStartILToNativeMap,
@@ -475,7 +477,7 @@ namespace ETW
{
#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
public:
- typedef enum _EtwStackWalkStatus
+ typedef enum _EtwStackWalkStatus
{
Completed = 0,
UnInitialized = 1,
@@ -492,7 +494,7 @@ namespace ETW
EtwStackWalkStatus GetCurrentThreadsCallStack(UINT32 *frameCount, PVOID **Stack);
#endif // FEATURE_EVENT_TRACE && !defined(FEATURE_PAL)
};
-
+
// Class to wrap all Loader logic for ETW
class LoaderLog
{
@@ -537,9 +539,9 @@ namespace ETW
}RangeFlags;
}LoaderStructs;
-
+
static VOID DomainLoadReal(BaseDomain *pDomain, __in_opt LPWSTR wszFriendlyName=NULL);
-
+
static VOID DomainLoad(BaseDomain *pDomain, __in_opt LPWSTR wszFriendlyName = NULL)
{
if (ETW_PROVIDER_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER))
@@ -733,7 +735,7 @@ namespace ETW
{
public:
typedef union _BinderStructs {
- typedef enum _NGENBINDREJECT_REASON {
+ typedef enum _NGENBINDREJECT_REASON {
NGEN_BIND_START_BIND = 0,
NGEN_BIND_NO_INDEX = 1,
NGEN_BIND_SYSTEM_ASSEMBLY_NOT_AVAILABLE = 2,
@@ -797,19 +799,19 @@ namespace ETW
IsCLSCompliant=0x10
}ExceptionThrownFlags;
}ExceptionStructs;
- };
+ };
// Class to wrap all Contention logic for ETW
class ContentionLog
{
public:
- typedef union _ContentionStructs
+ typedef union _ContentionStructs
{
- typedef enum _ContentionFlags {
+ typedef enum _ContentionFlags {
ManagedContention=0,
NativeContention=1
} ContentionFlags;
} ContentionStructs;
- };
+ };
// Class to wrap all Interop logic for ETW
class InteropLog
{
@@ -820,7 +822,7 @@ namespace ETW
class InfoLog
{
public:
- typedef union _InfoStructs
+ typedef union _InfoStructs
{
typedef enum _StartupMode
{
@@ -961,7 +963,7 @@ public:
// "mc.exe -MOF" already generates this block for XP-suported builds inside ClrEtwAll.h;
// on Vista+ builds, mc is run without -MOF, and we still have code that depends on it, so
// we manually place it here.
-FORCEINLINE
+FORCEINLINE
BOOLEAN __stdcall
McGenEventTracingEnabled(
__in PMCGEN_TRACE_CONTEXT EnableInfo,
@@ -1056,7 +1058,7 @@ struct CallStackFrame
#endif // FEATURE_EVENT_TRACE
#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
-FORCEINLINE
+FORCEINLINE
BOOLEAN __stdcall
McGenEventProviderEnabled(
__in PMCGEN_TRACE_CONTEXT Context,
diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp
index 5ff8111414..66b7c8223c 100644
--- a/src/vm/eventpipe.cpp
+++ b/src/vm/eventpipe.cpp
@@ -411,8 +411,8 @@ void EventPipe::Disable(EventPipeSessionID id)
const unsigned int numRundownProviders = 2;
EventPipeProviderConfiguration rundownProviders[] =
{
- { W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose) }, // Public provider.
- { W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose) } // Rundown provider.
+ { W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL }, // Public provider.
+ { W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL } // Rundown provider.
};
// The circular buffer size doesn't matter because all events are written synchronously during rundown.
s_pSession = s_pConfig->CreateSession(EventPipeSessionType::File, 1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
@@ -1098,7 +1098,7 @@ INT_PTR QCALLTYPE EventPipeInternal::GetProvider(
EventPipeProvider *pProvider = NULL;
BEGIN_QCALL;
-
+
pProvider = EventPipe::GetProvider(providerName);
END_QCALL;
@@ -1243,6 +1243,6 @@ bool QCALLTYPE EventPipeInternal::GetNextEvent(
END_QCALL;
return pNextInstance != NULL;
-}
+}
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h
index b9d3fabf66..3f5919f13f 100644
--- a/src/vm/eventpipe.h
+++ b/src/vm/eventpipe.h
@@ -24,6 +24,27 @@ class SampleProfilerEventInstance;
struct EventPipeProviderConfiguration;
class EventPipeSession;
+// EVENT_FILTER_DESCRIPTOR (This type does not exist on non-Windows platforms.)
+// https://docs.microsoft.com/en-us/windows/desktop/api/evntprov/ns-evntprov-_event_filter_descriptor
+// The structure supplements the event provider, level, and keyword data that
+// determines which events are reported and traced. The structure gives the
+// event provider greater control over the selection of events for reporting
+// and tracing.
+struct EventFilterDescriptor
+{
+ // A pointer to the filter data.
+ ULONGLONG Ptr;
+
+ // The size of the filter data, in bytes. The maximum size is 1024 bytes.
+ ULONG Size;
+
+ // The type of filter data. The type is application-defined. An event
+ // controller that knows about the provider and knows details about the
+ // provider's events can use the Type field to send the provider an
+ // arbitrary set of data for use as enhancements to the filtering of events.
+ ULONG Type;
+};
+
// Define the event pipe callback to match the ETW callback signature.
typedef void (*EventPipeCallback)(
LPCGUID SourceID,
@@ -31,7 +52,7 @@ typedef void (*EventPipeCallback)(
UCHAR Level,
ULONGLONG MatchAnyKeywords,
ULONGLONG MatchAllKeywords,
- void *FilterData,
+ EventFilterDescriptor *FilterData,
void *CallbackContext);
struct EventData
@@ -342,6 +363,7 @@ private:
LPCWSTR m_pProviderName;
UINT64 m_keywords;
UINT32 m_loggingLevel;
+ LPCWSTR m_pFilterData;
public:
@@ -351,17 +373,20 @@ public:
m_pProviderName = NULL;
m_keywords = NULL;
m_loggingLevel = 0;
+ m_pFilterData = NULL;
}
EventPipeProviderConfiguration(
LPCWSTR pProviderName,
UINT64 keywords,
- UINT32 loggingLevel)
+ UINT32 loggingLevel,
+ LPCWSTR pFilterData)
{
LIMITED_METHOD_CONTRACT;
m_pProviderName = pProviderName;
m_keywords = keywords;
m_loggingLevel = loggingLevel;
+ m_pFilterData = pFilterData;
}
LPCWSTR GetProviderName() const
@@ -381,6 +406,12 @@ public:
LIMITED_METHOD_CONTRACT;
return m_loggingLevel;
}
+
+ LPCWSTR GetFilterData() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pFilterData;
+ }
};
class EventPipeInternal
@@ -469,7 +500,7 @@ public:
LPCGUID pActivityId, LPCGUID pRelatedActivityId);
static bool QCALLTYPE GetNextEvent(
- EventPipeEventInstanceData *pInstance);
+ EventPipeEventInstanceData *pInstance);
};
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp
index 6199748caf..d40f2b789e 100644
--- a/src/vm/eventpipeconfiguration.cpp
+++ b/src/vm/eventpipeconfiguration.cpp
@@ -182,7 +182,8 @@ bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
provider.SetConfiguration(
true /* providerEnabled */,
pSessionProvider->GetKeywords(),
- pSessionProvider->GetLevel());
+ pSessionProvider->GetLevel(),
+ pSessionProvider->GetFilterData());
}
}
@@ -372,7 +373,8 @@ void EventPipeConfiguration::Enable(EventPipeSession *pSession)
pProvider->SetConfiguration(
true /* providerEnabled */,
pSessionProvider->GetKeywords(),
- pSessionProvider->GetLevel());
+ pSessionProvider->GetLevel(),
+ pSessionProvider->GetFilterData());
}
pElem = m_pProviderList->GetNext(pElem);
@@ -402,7 +404,11 @@ void EventPipeConfiguration::Disable(EventPipeSession *pSession)
while(pElem != NULL)
{
EventPipeProvider *pProvider = pElem->GetValue();
- pProvider->SetConfiguration(false /* providerEnabled */, 0 /* keywords */, EventPipeEventLevel::Critical /* level */);
+ pProvider->SetConfiguration(
+ false /* providerEnabled */,
+ 0 /* keywords */,
+ EventPipeEventLevel::Critical /* level */,
+ NULL /* filterData */);
pElem = m_pProviderList->GetNext(pElem);
}
diff --git a/src/vm/eventpipeeventsource.cpp b/src/vm/eventpipeeventsource.cpp
index a115af7227..20dc5b2686 100644
--- a/src/vm/eventpipeeventsource.cpp
+++ b/src/vm/eventpipeeventsource.cpp
@@ -93,7 +93,8 @@ void EventPipeEventSource::Enable(EventPipeSession *pSession)
EventPipeSessionProvider *pSessionProvider = new EventPipeSessionProvider(
s_pProviderName,
-1,
- EventPipeEventLevel::LogAlways);
+ EventPipeEventLevel::LogAlways,
+ NULL);
pSession->AddSessionProvider(pSessionProvider);
}
diff --git a/src/vm/eventpipeprovider.cpp b/src/vm/eventpipeprovider.cpp
index c2a0169e7b..4630c93acd 100644
--- a/src/vm/eventpipeprovider.cpp
+++ b/src/vm/eventpipeprovider.cpp
@@ -111,7 +111,7 @@ bool EventPipeProvider::EventEnabled(INT64 keywords, EventPipeEventLevel eventLe
((eventLevel == EventPipeEventLevel::LogAlways) || (m_providerLevel >= eventLevel)));
}
-void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel)
+void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel, LPCWSTR pFilterData)
{
CONTRACTL
{
@@ -127,7 +127,7 @@ void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, E
m_providerLevel = providerLevel;
RefreshAllEvents();
- InvokeCallback();
+ InvokeCallback(pFilterData);
}
EventPipeEvent* EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, BYTE *pMetadata, unsigned int metadataLength)
@@ -186,7 +186,7 @@ void EventPipeProvider::AddEvent(EventPipeEvent &event)
event.RefreshState();
}
-void EventPipeProvider::InvokeCallback()
+void EventPipeProvider::InvokeCallback(LPCWSTR pFilterData)
{
CONTRACTL
{
@@ -197,6 +197,33 @@ void EventPipeProvider::InvokeCallback()
}
CONTRACTL_END;
+
+ bool isEventFilterDescriptorInitialized = false;
+ EventFilterDescriptor eventFilterDescriptor{};
+ CQuickArrayBase<char> buffer;
+ buffer.Init();
+
+ if (pFilterData != NULL)
+ {
+ // The callback is expecting that filter data to be a concatenated list
+ // of pairs of null terminated strings. The first member of the pair is
+ // the key and the second is the value.
+ // To convert to this format we need to convert all '=' and ';'
+ // characters to '\0'.
+ SString dstBuffer;
+ SString(pFilterData).ConvertToUTF8(dstBuffer);
+
+ const COUNT_T BUFFER_SIZE = dstBuffer.GetCount() + 1;
+ buffer.AllocThrows(BUFFER_SIZE);
+ for (COUNT_T i = 0; i < BUFFER_SIZE; ++i)
+ buffer[i] = (dstBuffer[i] == '=' || dstBuffer[i] == ';') ? '\0' : dstBuffer[i];
+
+ eventFilterDescriptor.Ptr = reinterpret_cast<ULONGLONG>(buffer.Ptr());
+ eventFilterDescriptor.Size = static_cast<ULONG>(BUFFER_SIZE);
+ eventFilterDescriptor.Type = 0; // EventProvider.cs: `internal enum ControllerCommand.Update`
+ isEventFilterDescriptorInitialized = true;
+ }
+
if(m_pCallbackFunction != NULL && !g_fEEShutDown)
{
(*m_pCallbackFunction)(
@@ -205,9 +232,11 @@ void EventPipeProvider::InvokeCallback()
(UCHAR) m_providerLevel,
m_keywords,
0 /* matchAllKeywords */,
- NULL /* FilterData */,
+ isEventFilterDescriptorInitialized ? &eventFilterDescriptor : NULL,
m_pCallbackData /* CallbackContext */);
}
+
+ buffer.Destroy();
}
bool EventPipeProvider::GetDeleteDeferred() const
diff --git a/src/vm/eventpipeprovider.h b/src/vm/eventpipeprovider.h
index 0ffe46f887..dffdc7e3db 100644
--- a/src/vm/eventpipeprovider.h
+++ b/src/vm/eventpipeprovider.h
@@ -13,16 +13,6 @@
class EventPipeEvent;
-// Define the event pipe callback to match the ETW callback signature.
-typedef void (*EventPipeCallback)(
- LPCGUID SourceID,
- ULONG IsEnabled,
- UCHAR Level,
- ULONGLONG MatchAnyKeywords,
- ULONGLONG MatchAllKeywords,
- void *FilterData,
- void *CallbackContext);
-
class EventPipeProvider
{
// Declare friends.
@@ -96,13 +86,13 @@ public:
// Set the provider configuration (enable and disable sets of events).
// This is called by EventPipeConfiguration.
- void SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel);
+ void SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel, LPCWSTR pFilterData);
// Refresh the runtime state of all events.
void RefreshAllEvents();
// Invoke the provider callback.
- void InvokeCallback();
+ void InvokeCallback(LPCWSTR pFilterData);
// Specifies whether or not the provider was deleted, but that deletion
// was deferred until after tracing is stopped.
diff --git a/src/vm/eventpipesession.cpp b/src/vm/eventpipesession.cpp
index de62f58ed9..7388472c7d 100644
--- a/src/vm/eventpipesession.cpp
+++ b/src/vm/eventpipesession.cpp
@@ -111,14 +111,15 @@ EventPipeSessionProviderList::EventPipeSessionProviderList(
// Enable all events if the provider name == '*', all keywords are on and the requested level == verbose.
if((wcscmp(W("*"), pConfig->GetProviderName()) == 0) && (pConfig->GetKeywords() == 0xFFFFFFFFFFFFFFFF) && ((EventPipeEventLevel)pConfig->GetLevel() == EventPipeEventLevel::Verbose) && (m_pCatchAllProvider == NULL))
{
- m_pCatchAllProvider = new EventPipeSessionProvider(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose);
+ m_pCatchAllProvider = new EventPipeSessionProvider(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose, NULL);
}
else
{
EventPipeSessionProvider *pProvider = new EventPipeSessionProvider(
pConfig->GetProviderName(),
pConfig->GetKeywords(),
- (EventPipeEventLevel)pConfig->GetLevel());
+ (EventPipeEventLevel)pConfig->GetLevel(),
+ pConfig->GetFilterData());
m_pProviders->InsertTail(new SListElem<EventPipeSessionProvider*>(pProvider));
}
@@ -225,7 +226,8 @@ bool EventPipeSessionProviderList::IsEmpty() const
EventPipeSessionProvider::EventPipeSessionProvider(
LPCWSTR providerName,
UINT64 keywords,
- EventPipeEventLevel loggingLevel)
+ EventPipeEventLevel loggingLevel,
+ LPCWSTR filterData)
{
CONTRACTL
{
@@ -248,6 +250,16 @@ EventPipeSessionProvider::EventPipeSessionProvider(
m_keywords = keywords;
m_loggingLevel = loggingLevel;
+ if(filterData != NULL)
+ {
+ size_t bufSize = wcslen(filterData) + 1;
+ m_pFilterData = new WCHAR[bufSize];
+ wcscpy_s(m_pFilterData, bufSize, filterData);
+ }
+ else
+ {
+ m_pFilterData = NULL;
+ }
}
EventPipeSessionProvider::~EventPipeSessionProvider()
@@ -260,11 +272,12 @@ EventPipeSessionProvider::~EventPipeSessionProvider()
}
CONTRACTL_END;
- if(m_pProviderName != NULL)
- {
- delete[] m_pProviderName;
- m_pProviderName = NULL;
- }
+ // C++ standard, $5.3.5/2: Deleting a NULL pointer is safe.
+ delete[] m_pProviderName;
+ m_pProviderName = NULL;
+
+ delete[] m_pFilterData;
+ m_pFilterData = NULL;
}
LPCWSTR EventPipeSessionProvider::GetProviderName() const
@@ -285,4 +298,10 @@ EventPipeEventLevel EventPipeSessionProvider::GetLevel() const
return m_loggingLevel;
}
+LPCWSTR EventPipeSessionProvider::GetFilterData() const
+{
+ LIMITED_METHOD_CONTRACT;
+ return m_pFilterData;
+}
+
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipesession.h b/src/vm/eventpipesession.h
index 01e83b25ed..3c4f293407 100644
--- a/src/vm/eventpipesession.h
+++ b/src/vm/eventpipesession.h
@@ -26,7 +26,7 @@ private:
// The configured size of the circular buffer.
size_t m_circularBufferSizeInBytes;
-
+
// True if rundown is enabled.
Volatile<bool> m_rundownEnabled;
@@ -154,12 +154,16 @@ private:
// The loging level.
EventPipeEventLevel m_loggingLevel;
+ // The filter data.
+ WCHAR *m_pFilterData;
+
public:
EventPipeSessionProvider(
LPCWSTR providerName,
UINT64 keywords,
- EventPipeEventLevel loggingLevel);
+ EventPipeEventLevel loggingLevel,
+ LPCWSTR filterData);
~EventPipeSessionProvider();
LPCWSTR GetProviderName() const;
@@ -167,6 +171,8 @@ public:
UINT64 GetKeywords() const;
EventPipeEventLevel GetLevel() const;
+
+ LPCWSTR GetFilterData() const;
};
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp
index 05fc63f098..59925f320c 100644
--- a/src/vm/eventtrace.cpp
+++ b/src/vm/eventtrace.cpp
@@ -4244,7 +4244,7 @@ VOID EventPipeEtwCallbackDotNETRuntimeStress(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext)
{
LIMITED_METHOD_CONTRACT;
@@ -4258,7 +4258,7 @@ VOID EventPipeEtwCallbackDotNETRuntime(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext)
{
LIMITED_METHOD_CONTRACT;
@@ -4272,7 +4272,7 @@ VOID EventPipeEtwCallbackDotNETRuntimeRundown(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext)
{
LIMITED_METHOD_CONTRACT;
@@ -4286,7 +4286,7 @@ VOID EventPipeEtwCallbackDotNETRuntimePrivate(
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
- _In_opt_ PVOID FilterData,
+ _In_opt_ EventFilterDescriptor* FilterData,
_Inout_opt_ PVOID CallbackContext)
{
WRAPPER_NO_CONTRACT;