Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 27 additions & 25 deletions src/inc/eventtracebase.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//

//
//
//
// #EventTracing
// Windows
// ETW (Event Tracing for Windows) is a high-performance, low overhead and highly scalable
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -242,13 +242,15 @@ class EventPipeHelper

#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(
Expand All @@ -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(
Expand All @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -332,7 +334,7 @@ extern "C" {

#include "clretwallmain.h"

#endif // FEATURE_EVENT_TRACE
#endif // FEATURE_EVENT_TRACE

/**************************/
/* CLR ETW infrastructure */
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -391,7 +393,7 @@ namespace ETW
HRESULT Register();

// Unregisters all the Event Tracing providers
HRESULT UnRegister();
HRESULT UnRegister();
#else
HRESULT Register()
{
Expand All @@ -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
{
Expand Down Expand Up @@ -447,7 +449,7 @@ namespace ETW
MethodDCEndILToNativeMap= 0x00020000,
JitMethodILToNativeMap= 0x00040000,
TypeUnload= 0x00080000,

// Helpers
ModuleRangeEnabledAny = ModuleRangeLoad | ModuleRangeDCStart | ModuleRangeDCEnd | ModuleRangeLoadPrivate,
JitMethodLoadOrDCStartAny = JitMethodLoad | JitMethodDCStart | MethodDCStartILToNativeMap,
Expand Down Expand Up @@ -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,
Expand All @@ -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
{
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
{
Expand All @@ -820,7 +822,7 @@ namespace ETW
class InfoLog
{
public:
typedef union _InfoStructs
typedef union _InfoStructs
{
typedef enum _StartupMode
{
Expand Down Expand Up @@ -961,7 +963,7 @@ class ETWTraceStartup {
// "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,
Expand Down Expand Up @@ -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,
Expand Down
13 changes: 13 additions & 0 deletions src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,19 @@ [In] void* callbackContext
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;
Expand Down
17 changes: 15 additions & 2 deletions src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@ internal struct EventPipeProviderConfiguration
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))
{
Expand All @@ -56,6 +60,7 @@ internal EventPipeProviderConfiguration(
m_providerName = providerName;
m_keywords = keywords;
m_loggingLevel = loggingLevel;
m_filterData = filterData;
}

internal string ProviderName
Expand All @@ -72,6 +77,8 @@ internal uint LoggingLevel
{
get { return m_loggingLevel; }
}

internal string FilterData => m_filterData;
}

internal sealed class EventPipeConfiguration
Expand Down Expand Up @@ -126,11 +133,17 @@ internal long ProfilerSamplingRateInNanoseconds
}

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)
Expand Down
58 changes: 37 additions & 21 deletions src/mscorlib/src/System/Diagnostics/Eventing/EventPipeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -54,9 +52,9 @@ internal sealed class EventPipeController
// 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.
Expand Down Expand Up @@ -168,8 +166,11 @@ private static EventPipeConfiguration BuildConfigFromFile(string configFilePath)
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))
Expand Down Expand Up @@ -225,7 +226,7 @@ private static EventPipeConfiguration BuildConfigFromFile(string configFilePath)

// Get the circular buffer size.
uint circularMB = DefaultCircularBufferMB;
if(!string.IsNullOrEmpty(strCircularMB))
if (!string.IsNullOrEmpty(strCircularMB))
{
circularMB = Convert.ToUInt32(strCircularMB);
}
Expand Down Expand Up @@ -313,33 +314,48 @@ private static void SetProviderConfiguration(string strConfig, EventPipeConfigur
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);
}
}

Expand Down
Loading