Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 418e094

Browse files
authored
Merge pull request #20898 from jorive/dev/port-of-20796
Port to release/2.2 branch: EventPipe support for "Parameters" #20796
2 parents 1655a06 + 82558c9 commit 418e094

File tree

14 files changed

+216
-90
lines changed

14 files changed

+216
-90
lines changed

src/inc/eventtracebase.h

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//
1111

1212
//
13-
//
13+
//
1414
// #EventTracing
1515
// Windows
1616
// ETW (Event Tracing for Windows) is a high-performance, low overhead and highly scalable
@@ -35,7 +35,7 @@ void InitializeEventTracing();
3535
// The flags must match those in the ETW manifest exactly
3636
// !!!!!!! NOTE !!!!!!!!
3737

38-
// These flags need to be defined either when FEATURE_EVENT_TRACE is enabled or the
38+
// These flags need to be defined either when FEATURE_EVENT_TRACE is enabled or the
3939
// PROFILING_SUPPORTED is set, since they are used both by event tracing and profiling.
4040

4141
enum EtwTypeFlags
@@ -106,7 +106,7 @@ enum EtwThreadFlags
106106
#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
107107
#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
108108
#else //defined(FEATURE_PERFTRACING)
109-
#define ETW_INLINE
109+
#define ETW_INLINE
110110
#define ETWOnStartup(StartEventName, EndEventName)
111111
#define ETWFireEvent(EventName)
112112

@@ -242,13 +242,15 @@ class EventPipeHelper
242242

243243
#if defined(FEATURE_EVENT_TRACE)
244244

245+
struct EventFilterDescriptor;
246+
245247
VOID EventPipeEtwCallbackDotNETRuntimeStress(
246248
_In_ LPCGUID SourceId,
247249
_In_ ULONG ControlCode,
248250
_In_ UCHAR Level,
249251
_In_ ULONGLONG MatchAnyKeyword,
250252
_In_ ULONGLONG MatchAllKeyword,
251-
_In_opt_ PVOID FilterData,
253+
_In_opt_ EventFilterDescriptor* FilterData,
252254
_Inout_opt_ PVOID CallbackContext);
253255

254256
VOID EventPipeEtwCallbackDotNETRuntime(
@@ -257,7 +259,7 @@ VOID EventPipeEtwCallbackDotNETRuntime(
257259
_In_ UCHAR Level,
258260
_In_ ULONGLONG MatchAnyKeyword,
259261
_In_ ULONGLONG MatchAllKeyword,
260-
_In_opt_ PVOID FilterData,
262+
_In_opt_ EventFilterDescriptor* FilterData,
261263
_Inout_opt_ PVOID CallbackContext);
262264

263265
VOID EventPipeEtwCallbackDotNETRuntimeRundown(
@@ -266,7 +268,7 @@ VOID EventPipeEtwCallbackDotNETRuntimeRundown(
266268
_In_ UCHAR Level,
267269
_In_ ULONGLONG MatchAnyKeyword,
268270
_In_ ULONGLONG MatchAllKeyword,
269-
_In_opt_ PVOID FilterData,
271+
_In_opt_ EventFilterDescriptor* FilterData,
270272
_Inout_opt_ PVOID CallbackContext);
271273

272274
VOID EventPipeEtwCallbackDotNETRuntimePrivate(
@@ -275,7 +277,7 @@ VOID EventPipeEtwCallbackDotNETRuntimePrivate(
275277
_In_ UCHAR Level,
276278
_In_ ULONGLONG MatchAnyKeyword,
277279
_In_ ULONGLONG MatchAllKeyword,
278-
_In_opt_ PVOID FilterData,
280+
_In_opt_ EventFilterDescriptor* FilterData,
279281
_Inout_opt_ PVOID CallbackContext);
280282

281283
#ifndef FEATURE_PAL
@@ -332,7 +334,7 @@ extern "C" {
332334

333335
#include "clretwallmain.h"
334336

335-
#endif // FEATURE_EVENT_TRACE
337+
#endif // FEATURE_EVENT_TRACE
336338

337339
/**************************/
338340
/* CLR ETW infrastructure */
@@ -351,7 +353,7 @@ extern "C" {
351353
// has started, one may want to do something useful when that happens (e.g enumerate all the loaded modules
352354
// in the system). To enable this, we have to implement a callback routine.
353355
// file:../VM/eventtrace.cpp#EtwCallback is CLR's implementation of the callback.
354-
//
356+
//
355357

356358
#include "daccess.h"
357359
class Module;
@@ -379,7 +381,7 @@ namespace ETW
379381
{
380382
// Class to wrap the ETW infrastructure logic
381383
#if !defined(FEATURE_PAL)
382-
class CEtwTracer
384+
class CEtwTracer
383385
{
384386
#if defined(FEATURE_EVENT_TRACE)
385387
ULONG RegGuids(LPCGUID ProviderId, PENABLECALLBACK EnableCallback, PVOID CallbackContext, PREGHANDLE RegHandle);
@@ -391,7 +393,7 @@ namespace ETW
391393
HRESULT Register();
392394

393395
// Unregisters all the Event Tracing providers
394-
HRESULT UnRegister();
396+
HRESULT UnRegister();
395397
#else
396398
HRESULT Register()
397399
{
@@ -406,7 +408,7 @@ namespace ETW
406408
#endif // !defined(FEATURE_PAL)
407409

408410
class LoaderLog;
409-
class MethodLog;
411+
class MethodLog;
410412
// Class to wrap all the enumeration logic for ETW
411413
class EnumerationLog
412414
{
@@ -447,7 +449,7 @@ namespace ETW
447449
MethodDCEndILToNativeMap= 0x00020000,
448450
JitMethodILToNativeMap= 0x00040000,
449451
TypeUnload= 0x00080000,
450-
452+
451453
// Helpers
452454
ModuleRangeEnabledAny = ModuleRangeLoad | ModuleRangeDCStart | ModuleRangeDCEnd | ModuleRangeLoadPrivate,
453455
JitMethodLoadOrDCStartAny = JitMethodLoad | JitMethodDCStart | MethodDCStartILToNativeMap,
@@ -475,7 +477,7 @@ namespace ETW
475477
{
476478
#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
477479
public:
478-
typedef enum _EtwStackWalkStatus
480+
typedef enum _EtwStackWalkStatus
479481
{
480482
Completed = 0,
481483
UnInitialized = 1,
@@ -492,7 +494,7 @@ namespace ETW
492494
EtwStackWalkStatus GetCurrentThreadsCallStack(UINT32 *frameCount, PVOID **Stack);
493495
#endif // FEATURE_EVENT_TRACE && !defined(FEATURE_PAL)
494496
};
495-
497+
496498
// Class to wrap all Loader logic for ETW
497499
class LoaderLog
498500
{
@@ -537,9 +539,9 @@ namespace ETW
537539
}RangeFlags;
538540

539541
}LoaderStructs;
540-
542+
541543
static VOID DomainLoadReal(BaseDomain *pDomain, __in_opt LPWSTR wszFriendlyName=NULL);
542-
544+
543545
static VOID DomainLoad(BaseDomain *pDomain, __in_opt LPWSTR wszFriendlyName = NULL)
544546
{
545547
if (ETW_PROVIDER_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER))
@@ -733,7 +735,7 @@ namespace ETW
733735
{
734736
public:
735737
typedef union _BinderStructs {
736-
typedef enum _NGENBINDREJECT_REASON {
738+
typedef enum _NGENBINDREJECT_REASON {
737739
NGEN_BIND_START_BIND = 0,
738740
NGEN_BIND_NO_INDEX = 1,
739741
NGEN_BIND_SYSTEM_ASSEMBLY_NOT_AVAILABLE = 2,
@@ -797,19 +799,19 @@ namespace ETW
797799
IsCLSCompliant=0x10
798800
}ExceptionThrownFlags;
799801
}ExceptionStructs;
800-
};
802+
};
801803
// Class to wrap all Contention logic for ETW
802804
class ContentionLog
803805
{
804806
public:
805-
typedef union _ContentionStructs
807+
typedef union _ContentionStructs
806808
{
807-
typedef enum _ContentionFlags {
809+
typedef enum _ContentionFlags {
808810
ManagedContention=0,
809811
NativeContention=1
810812
} ContentionFlags;
811813
} ContentionStructs;
812-
};
814+
};
813815
// Class to wrap all Interop logic for ETW
814816
class InteropLog
815817
{
@@ -820,7 +822,7 @@ namespace ETW
820822
class InfoLog
821823
{
822824
public:
823-
typedef union _InfoStructs
825+
typedef union _InfoStructs
824826
{
825827
typedef enum _StartupMode
826828
{
@@ -961,7 +963,7 @@ class ETWTraceStartup {
961963
// "mc.exe -MOF" already generates this block for XP-suported builds inside ClrEtwAll.h;
962964
// on Vista+ builds, mc is run without -MOF, and we still have code that depends on it, so
963965
// we manually place it here.
964-
FORCEINLINE
966+
FORCEINLINE
965967
BOOLEAN __stdcall
966968
McGenEventTracingEnabled(
967969
__in PMCGEN_TRACE_CONTEXT EnableInfo,
@@ -1056,7 +1058,7 @@ struct CallStackFrame
10561058
#endif // FEATURE_EVENT_TRACE
10571059

10581060
#if defined(FEATURE_EVENT_TRACE) && !defined(FEATURE_PAL)
1059-
FORCEINLINE
1061+
FORCEINLINE
10601062
BOOLEAN __stdcall
10611063
McGenEventProviderEnabled(
10621064
__in PMCGEN_TRACE_CONTEXT Context,

src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,19 @@ [In] void* callbackContext
280280
m_allKeywordMask = allKeyword;
281281

282282
List<Tuple<SessionInfo, bool>> sessionsChanged = GetSessions();
283+
284+
// The GetSessions() logic was here to support the idea that different ETW sessions
285+
// could have different user-defined filters. (I believe it is currently broken but that is another matter.)
286+
// However in particular GetSessions() does not support EventPipe, only ETW, which is
287+
// the immediate problem. We work-around establishing the invariant that we always get a
288+
// OnControllerCallback under all circumstances, even if we can't find a delta in the
289+
// ETW logic. This fixes things for the EventPipe case.
290+
//
291+
// All this session based logic should be reviewed and likely removed, but that is a larger
292+
// change that needs more careful staging.
293+
if (sessionsChanged.Count == 0)
294+
sessionsChanged.Add(new Tuple<SessionInfo, bool>(new SessionInfo(0, 0), true));
295+
283296
foreach (var session in sessionsChanged)
284297
{
285298
int sessionChanged = session.Item1.sessionIdBit;

src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ internal struct EventPipeProviderConfiguration
4040
private ulong m_keywords;
4141
private uint m_loggingLevel;
4242

43+
[MarshalAs(UnmanagedType.LPWStr)]
44+
private readonly string m_filterData;
45+
4346
internal EventPipeProviderConfiguration(
4447
string providerName,
4548
ulong keywords,
46-
uint loggingLevel)
49+
uint loggingLevel,
50+
string filterData)
4751
{
4852
if(string.IsNullOrEmpty(providerName))
4953
{
@@ -56,6 +60,7 @@ internal EventPipeProviderConfiguration(
5660
m_providerName = providerName;
5761
m_keywords = keywords;
5862
m_loggingLevel = loggingLevel;
63+
m_filterData = filterData;
5964
}
6065

6166
internal string ProviderName
@@ -72,6 +77,8 @@ internal uint LoggingLevel
7277
{
7378
get { return m_loggingLevel; }
7479
}
80+
81+
internal string FilterData => m_filterData;
7582
}
7683

7784
internal sealed class EventPipeConfiguration
@@ -126,11 +133,17 @@ internal long ProfilerSamplingRateInNanoseconds
126133
}
127134

128135
internal void EnableProvider(string providerName, ulong keywords, uint loggingLevel)
136+
{
137+
EnableProviderWithFilter(providerName, keywords, loggingLevel, null);
138+
}
139+
140+
internal void EnableProviderWithFilter(string providerName, ulong keywords, uint loggingLevel, string filterData)
129141
{
130142
m_providers.Add(new EventPipeProviderConfiguration(
131143
providerName,
132144
keywords,
133-
loggingLevel));
145+
loggingLevel,
146+
filterData));
134147
}
135148

136149
private void EnableProviderConfiguration(EventPipeProviderConfiguration providerConfig)

src/mscorlib/src/System/Diagnostics/Eventing/EventPipeController.cs

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
using Internal.IO;
66
using Microsoft.Win32;
77
using System.IO;
8-
using System.Globalization;
98
using System.Reflection;
109
using System.Runtime.Versioning;
1110
using System.Text;
1211
using System.Threading;
13-
using System.Threading.Tasks;
1412

1513
namespace System.Diagnostics.Tracing
1614
{
@@ -54,9 +52,9 @@ internal sealed class EventPipeController
5452
// The default set of providers/keywords/levels. Used if an alternative configuration is not specified.
5553
private static readonly EventPipeProviderConfiguration[] DefaultProviderConfiguration = new EventPipeProviderConfiguration[]
5654
{
57-
new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntime", 0x4c14fccbd, 5),
58-
new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntimePrivate", 0x4002000b, 5),
59-
new EventPipeProviderConfiguration("Microsoft-DotNETCore-SampleProfiler", 0x0, 5)
55+
new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntime", 0x4c14fccbd, 5, null),
56+
new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntimePrivate", 0x4002000b, 5, null),
57+
new EventPipeProviderConfiguration("Microsoft-DotNETCore-SampleProfiler", 0x0, 5, null),
6058
};
6159

6260
// Singleton controller instance.
@@ -168,8 +166,11 @@ private static EventPipeConfiguration BuildConfigFromFile(string configFilePath)
168166
foreach (string configEntry in configEntries)
169167
{
170168
//`Split the key and value by '='.
171-
string[] entryComponents = configEntry.Split(ConfigEntryDelimiter);
172-
if(entryComponents.Length == 2)
169+
string[] entryComponents = configEntry.Split(
170+
ConfigEntryDelimiter,
171+
2, // Stop split on first occurrence of the separator.
172+
StringSplitOptions.RemoveEmptyEntries);
173+
if (entryComponents.Length == 2)
173174
{
174175
string key = entryComponents[0];
175176
if (key.Equals(ConfigKey_Providers))
@@ -225,7 +226,7 @@ private static EventPipeConfiguration BuildConfigFromFile(string configFilePath)
225226

226227
// Get the circular buffer size.
227228
uint circularMB = DefaultCircularBufferMB;
228-
if(!string.IsNullOrEmpty(strCircularMB))
229+
if (!string.IsNullOrEmpty(strCircularMB))
229230
{
230231
circularMB = Convert.ToUInt32(strCircularMB);
231232
}
@@ -313,33 +314,48 @@ private static void SetProviderConfiguration(string strConfig, EventPipeConfigur
313314
throw new ArgumentNullException(nameof(strConfig));
314315
}
315316

316-
// String must be of the form "providerName:keywords:level,providerName:keywords:level..."
317-
string[] providers = strConfig.Split(ProviderConfigDelimiter);
317+
// Provider format: "(GUID|KnownProviderName)[:Flags[:Level][:KeyValueArgs]]"
318+
// where KeyValueArgs are of the form: "[key1=value1][;key2=value2]"
319+
// `strConfig` must be of the form "Provider[,Provider]"
320+
string[] providers = strConfig.Split(
321+
ProviderConfigDelimiter,
322+
StringSplitOptions.RemoveEmptyEntries); // Remove "empty" providers.
318323
foreach (string provider in providers)
319324
{
320-
string[] components = provider.Split(ConfigComponentDelimiter);
321-
if (components.Length == 3)
325+
// Split expecting a maximum of four tokens.
326+
string[] components = provider.Split(
327+
ConfigComponentDelimiter,
328+
4, // if there is ':' in the parameters then anything after it will not be ignored.
329+
StringSplitOptions.None); // Keep empty tokens
330+
331+
string providerName = components.Length > 0 ? components[0] : null;
332+
if (string.IsNullOrEmpty(providerName))
333+
continue; // No provider name specified.
334+
335+
ulong keywords = ulong.MaxValue;
336+
if (components.Length > 1)
322337
{
323-
string providerName = components[0];
324-
325338
// We use a try/catch block here because ulong.TryParse won't accept 0x at the beginning
326339
// of a hex string. Thus, we either need to conditionally strip it or handle the exception.
327340
// Given that this is not a perf-critical path, catching the exception is the simpler code.
328-
ulong keywords = 0;
329341
try
330342
{
331343
keywords = Convert.ToUInt64(components[1], 16);
332344
}
333-
catch { }
334-
335-
uint level;
336-
if (!uint.TryParse(components[2], out level))
345+
catch
337346
{
338-
level = 0;
339347
}
348+
}
340349

341-
config.EnableProvider(providerName, keywords, level);
350+
uint level = 5; // Verbose
351+
if (components.Length > 2)
352+
{
353+
uint.TryParse(components[2], out level);
342354
}
355+
356+
string filterData = components.Length > 3 ? components[3] : null;
357+
358+
config.EnableProviderWithFilter(providerName, keywords, level, filterData);
343359
}
344360
}
345361

0 commit comments

Comments
 (0)