Add EventPipe Processor Number support and make NetTrace the default … (#25276)
authorNoah Falk <noahfalk@users.noreply.github.com>
Fri, 21 Jun 2019 22:27:21 +0000 (15:27 -0700)
committerGitHub <noreply@github.com>
Fri, 21 Jun 2019 22:27:21 +0000 (15:27 -0700)
* Add EventPipe Processor Number support and make NetTrace the default format

The EventPipe header now has a Processor Number field. On windows we query the correct value, on other OSes we currently have a -1 placeholder, but the field is written to the format regardless.
NetTrace is now the default format when using the environment variable, and the format must be explicitly configured when using the IPC channel or managed API. A parallel change in the diagnostics repo is changing dotnet-trace and dotnet-counter to specify nettrace format which means .NET devs should see nettrace almost exclusively from now on. If for whatever reason it is needed, NetPerf remains available if a scenario explicitly requests to use it.

* PR feedback + attempting to fix broken tests

19 files changed:
dependencies.props
src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs
src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs
src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeEventDispatcher.cs
src/inc/clrconfigvalues.h
src/vm/eventpipe.cpp
src/vm/eventpipe.h
src/vm/eventpipeblock.cpp
src/vm/eventpipeblock.h
src/vm/eventpipebuffer.cpp
src/vm/eventpipeconfiguration.cpp
src/vm/eventpipeeventinstance.cpp
src/vm/eventpipeeventinstance.h
src/vm/eventpipeinternal.cpp
src/vm/eventpipeinternal.h
src/vm/eventpipeprotocolhelper.cpp
src/vm/eventpipeprotocolhelper.h
tests/src/tracing/common/TraceConfiguration.cs
tests/src/tracing/regress/GitHub_22247/GitHub_22247.cs

index a661e93..b04a885 100644 (file)
@@ -25,7 +25,7 @@
     <MicrosoftNETCoreRuntimeCoreCLRPackageVersion>3.0.0-preview6.19280.1</MicrosoftNETCoreRuntimeCoreCLRPackageVersion>
     <XunitPackageVersion>2.4.1-pre.build.4059</XunitPackageVersion>
     <XunitPerformanceApiPackageVersion>1.0.0-beta-build0015</XunitPerformanceApiPackageVersion>
-    <MicrosoftDiagnosticsTracingTraceEventPackageVersion>2.0.40</MicrosoftDiagnosticsTracingTraceEventPackageVersion>
+    <MicrosoftDiagnosticsTracingTraceEventPackageVersion>2.0.43</MicrosoftDiagnosticsTracingTraceEventPackageVersion>
     <CommandLineParserVersion>2.2.0</CommandLineParserVersion>
 
     <!-- Scenario tests install this version of Microsoft.NetCore.App, then patch coreclr binaries via xcopy. At the moment it is
index a7fb7cc..f3f48b4 100644 (file)
@@ -79,15 +79,23 @@ namespace System.Diagnostics.Tracing
         internal string? FilterData => m_filterData;
     }
 
+    internal enum EventPipeSerializationFormat
+    {
+        NetPerf,
+        NetTrace
+    }
+
     internal sealed class EventPipeConfiguration
     {
         private string m_outputFile;
+        private EventPipeSerializationFormat m_format;
         private uint m_circularBufferSizeInMB;
         private List<EventPipeProviderConfiguration> m_providers;
         private TimeSpan m_minTimeBetweenSamples = TimeSpan.FromMilliseconds(1);
 
         internal EventPipeConfiguration(
             string outputFile,
+            EventPipeSerializationFormat format,
             uint circularBufferSizeInMB)
         {
             if(string.IsNullOrEmpty(outputFile))
@@ -99,6 +107,7 @@ namespace System.Diagnostics.Tracing
                 throw new ArgumentOutOfRangeException(nameof(circularBufferSizeInMB));
             }
             m_outputFile = outputFile;
+            m_format = format;
             m_circularBufferSizeInMB = circularBufferSizeInMB;
             m_providers = new List<EventPipeProviderConfiguration>();
         }
@@ -108,6 +117,11 @@ namespace System.Diagnostics.Tracing
             get { return m_outputFile; }
         }
 
+        internal EventPipeSerializationFormat Format
+        {
+            get { return m_format; }
+        }
+
         internal uint CircularBufferSizeInMB
         {
             get { return m_circularBufferSizeInMB; }
@@ -176,6 +190,7 @@ namespace System.Diagnostics.Tracing
 
             s_sessionID = EventPipeInternal.Enable(
                 configuration.OutputFile,
+                configuration.Format,
                 configuration.CircularBufferSizeInMB,
                 providers,
                 (uint)providers.Length);
@@ -195,6 +210,7 @@ namespace System.Diagnostics.Tracing
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         internal static extern UInt64 Enable(
             string? outputFile,
+            EventPipeSerializationFormat format,
             uint circularBufferSizeInMB,
             EventPipeProviderConfiguration[] providers,
             uint numProviders);
index 8409078..af68aef 100644 (file)
@@ -68,6 +68,7 @@ namespace System.Diagnostics.Tracing
             // Create a new configuration object.
             EventPipeConfiguration config = new EventPipeConfiguration(
                 outputFilePath,
+                (Config_NetTraceFormat != 0) ? EventPipeSerializationFormat.NetTrace : EventPipeSerializationFormat.NetPerf,
                 Config_EventPipeCircularMB);
 
             // Get the configuration.
@@ -89,7 +90,7 @@ namespace System.Diagnostics.Tracing
         private static string BuildTraceFileName()
         {
             return GetAppName() + "." + Interop.GetCurrentProcessId().ToString() +
-              ((Config_NetTraceFormat > 0) ? NetTraceFileExtension : NetPerfFileExtension);
+              ((Config_NetTraceFormat != 0) ? NetTraceFileExtension : NetPerfFileExtension);
         }
 
         private static string GetAppName()
index 4ef9c51..a58d4eb 100644 (file)
@@ -110,7 +110,7 @@ namespace System.Diagnostics.Tracing
                 new EventPipeProviderConfiguration(NativeRuntimeEventSource.EventSourceName, (ulong) aggregatedKeywords, (uint) highestLevel, null)
             };
 
-            m_sessionID = EventPipeInternal.Enable(null, 1024, providerConfiguration, 1);
+            m_sessionID = EventPipeInternal.Enable(null, EventPipeSerializationFormat.NetTrace, 1024, providerConfiguration, 1);
             Debug.Assert(m_sessionID != 0);
 
             // Get the session information that is required to properly dispatch events.
index 7713af5..4343ef4 100644 (file)
@@ -719,11 +719,12 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_AllowDComReflection, W("AllowDComReflection"),
 // EventPipe
 //
 RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableEventPipe, W("EnableEventPipe"), 0, "Enable/disable event pipe.  Non-zero values enable tracing.")
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeNetTraceFormat, W("EventPipeNetTraceFormat"), 0, "Enable/disable using the newer nettrace file format.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeNetTraceFormat, W("EventPipeNetTraceFormat"), 1, "Enable/disable using the newer nettrace file format.")
 RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeOutputPath, W("EventPipeOutputPath"), "The full path excluding 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.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeProcNumbers, W("EventPipeProcNumbers"), 0, "Enable/disable capturing processor numbers in EventPipe event headers")
 
 #ifdef FEATURE_GDBJIT
 ///
index adec56b..81b588f 100644 (file)
@@ -33,6 +33,9 @@ Volatile<bool> EventPipe::s_tracingInitialized = false;
 EventPipeConfiguration EventPipe::s_config;
 EventPipeEventSource *EventPipe::s_pEventSource = nullptr;
 VolatilePtr<EventPipeSession> EventPipe::s_pSessions[MaxNumberOfSessions];
+#ifndef FEATURE_PAL
+unsigned int * EventPipe::s_pProcGroupOffsets = nullptr;
+#endif
 
 #ifdef FEATURE_PAL
 // This function is auto-generated from /src/scripts/genEventPipe.py
@@ -71,6 +74,26 @@ void EventPipe::Initialize()
     const unsigned long DefaultProfilerSamplingRateInNanoseconds = 1000000; // 1 msec.
     SampleProfiler::SetSamplingRate(DefaultProfilerSamplingRateInNanoseconds);
 
+
+    if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeProcNumbers) != 0)
+    {
+#ifndef FEATURE_PAL
+        // setup the windows processor group offset table
+        WORD numGroups = ::GetActiveProcessorGroupCount();
+        s_pProcGroupOffsets = new (nothrow) unsigned int[numGroups];
+        if (s_pProcGroupOffsets)
+        {
+            unsigned int countProcs = 0;
+            for (WORD i = 0; i < numGroups; i++)
+            {
+                s_pProcGroupOffsets[i] = countProcs;
+                countProcs += GetActiveProcessorCount(i);
+            }
+        }
+#endif
+    }
+
+
     {
         CrstHolder _crst(GetLock());
         s_tracingInitialized = tracingInitialized;
@@ -577,6 +600,7 @@ void EventPipe::WriteEventInternal(
             //    as opposed a a buffer copy here
             EventPipeEventInstance instance(
                 event,
+                GetCurrentProcessorNumber(),
                 pEventPipeThread->GetOSThreadId(),
                 pData,
                 payload.GetSize(),
index 20f6c1f..7a8df26 100644 (file)
@@ -114,6 +114,21 @@ public:
             InvokeCallback(eventPipeProviderCallbackData);
     }
 
+    // Returns the a number 0...N representing the processor number this thread is currently
+    // running on. If for any reason we can't tell then return 0xFFFFFFFF.
+    static unsigned int GetCurrentProcessorNumber()
+    {
+#ifndef FEATURE_PAL
+        if (s_pProcGroupOffsets)
+        {
+            PROCESSOR_NUMBER procNum;
+            GetCurrentProcessorNumberEx(&procNum);
+            return s_pProcGroupOffsets[procNum.Group] + procNum.Number;
+        }
+#endif
+        return 0xFFFFFFFF;
+    }
+
 private:
     static void InvokeCallback(EventPipeProviderCallbackData eventPipeProviderCallbackData);
 
@@ -174,6 +189,13 @@ private:
     static EventPipeConfiguration s_config;
     static VolatilePtr<EventPipeSession> s_pSessions[MaxNumberOfSessions];
     static EventPipeEventSource *s_pEventSource;
+
+    // A mapping from windows processor group index to the total number of processors
+    // in all groups preceding it. For example if there are three groups with sizes: 
+    // 1, 7, 6 the table would be 0, 1, 8
+#ifndef FEATURE_PAL
+    static unsigned int * s_pProcGroupOffsets;
+#endif
 };
 
 static_assert(EventPipe::MaxNumberOfSessions == 64, "Maximum number of EventPipe sessions is not 64.");
index a2d561e..fb9d6c7 100644 (file)
@@ -179,6 +179,7 @@ bool EventPipeEventBlockBase::WriteEvent(EventPipeEventInstance &instance,
 
     unsigned int dataLength = 0;
     BYTE* alignedEnd = NULL;
+    unsigned int captureProcNumber = instance.GetProcNumber();
 
     if (!m_fUseHeaderCompression)
     {
@@ -217,6 +218,9 @@ bool EventPipeEventBlockBase::WriteEvent(EventPipeEventInstance &instance,
             memcpy(m_pWritePointer, &captureThreadId, sizeof(captureThreadId));
             m_pWritePointer += sizeof(captureThreadId);
 
+            memcpy(m_pWritePointer, &captureProcNumber, sizeof(captureProcNumber));
+            m_pWritePointer += sizeof(captureProcNumber);
+
             memcpy(m_pWritePointer, &stackId, sizeof(stackId));
             m_pWritePointer += sizeof(stackId);
         }
@@ -253,10 +257,12 @@ bool EventPipeEventBlockBase::WriteEvent(EventPipeEventInstance &instance,
         }
         
         if (m_lastHeader.SequenceNumber + (instance.GetMetadataId() != 0 ? 1 : 0) != sequenceNumber ||
-            m_lastHeader.CaptureThreadId != captureThreadId)
+            m_lastHeader.CaptureThreadId != captureThreadId ||
+            m_lastHeader.CaptureProcNumber != captureProcNumber)
         {
             WriteVarUInt32(pWritePointer, sequenceNumber - m_lastHeader.SequenceNumber - 1);
             WriteVarUInt64(pWritePointer, captureThreadId);
+            WriteVarUInt32(pWritePointer, captureProcNumber);
             flags |= (1 << 1);
         }
 
@@ -307,6 +313,7 @@ bool EventPipeEventBlockBase::WriteEvent(EventPipeEventInstance &instance,
         m_lastHeader.SequenceNumber = sequenceNumber;
         m_lastHeader.ThreadId = instance.GetThreadId64();
         m_lastHeader.CaptureThreadId = captureThreadId;
+        m_lastHeader.CaptureProcNumber = captureProcNumber;
         m_lastHeader.StackId = stackId;
         m_lastHeader.TimeStamp.QuadPart = timeStamp->QuadPart;
         memcpy(&m_lastHeader.ActivityId, instance.GetActivityId(), sizeof(GUID));
index e7e9516..1ce54de 100644 (file)
@@ -96,6 +96,7 @@ struct EventPipeEventHeader
     DWORD SequenceNumber;
     ULONGLONG ThreadId;
     ULONGLONG CaptureThreadId;
+    DWORD CaptureProcNumber;
     DWORD StackId;
     LARGE_INTEGER TimeStamp;
     GUID ActivityId;
index 913fc57..69eec1e 100644 (file)
@@ -88,8 +88,10 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeSession &session, Eve
             pStack = &s;
         }
 
+        unsigned int procNumber = EventPipe::GetCurrentProcessorNumber();
         EventPipeEventInstance *pInstance = new (m_pCurrent) EventPipeEventInstance(
             event,
+            procNumber,
             (pThread == NULL) ?
 #ifdef FEATURE_PAL
                 ::PAL_GetCurrentOSThreadId()
index 84512b5..b6c9f01 100644 (file)
@@ -453,6 +453,7 @@ EventPipeEventInstance *EventPipeConfiguration::BuildEventMetadataEvent(EventPip
     // Construct the event instance.
     EventPipeEventInstance *pInstance = new EventPipeEventInstance(
         *m_pMetadataEvent,
+        EventPipe::GetCurrentProcessorNumber(),
 #ifdef FEATURE_PAL
         PAL_GetCurrentOSThreadId(),
 #else
index 19ce269..5b214a1 100644 (file)
@@ -13,6 +13,7 @@
 
 EventPipeEventInstance::EventPipeEventInstance(
     EventPipeEvent &event,
+    unsigned int procNumber,
     ULONGLONG threadId,
     BYTE *pData,
     unsigned int length,
@@ -32,6 +33,7 @@ EventPipeEventInstance::EventPipeEventInstance(
     m_debugEventEnd = 0xCAFEBABE;
 #endif // _DEBUG
     m_pEvent = &event;
+    m_procNumber = procNumber;
     m_threadId = threadId;
     if (pActivityId != NULL)
     {
@@ -101,6 +103,7 @@ unsigned int EventPipeEventInstance::GetAlignedTotalSize(EventPipeSerializationF
             sizeof(unsigned int) +          // Sequence number (implied by the buffer containing the event instance)
             sizeof(m_threadId) +            // Thread ID
             sizeof(ULONGLONG) +             // Capture Thread ID (implied by the buffer containing the event instance)
+            sizeof(m_procNumber) +          // ProcNumber
             sizeof(unsigned int) +          // Stack intern table id
             sizeof(m_timeStamp) +           // TimeStamp
             sizeof(m_activityId) +          // Activity ID
index 2ecb111..a7fd497 100644 (file)
@@ -24,7 +24,13 @@ class EventPipeEventInstance
 
 public:
 
-    EventPipeEventInstance(EventPipeEvent &event, ULONGLONG threadID, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId);
+    EventPipeEventInstance(EventPipeEvent &event, 
+                           unsigned int procNumber,
+                           ULONGLONG threadID,
+                           BYTE *pData,
+                           unsigned int length,
+                           LPCGUID pActivityId,
+                           LPCGUID pRelatedActivityId);
 
     void EnsureStack(const EventPipeSession &session);
 
@@ -63,6 +69,13 @@ public:
         m_metadataId = metadataId;
     }
 
+    unsigned int GetProcNumber() const
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        return m_procNumber;
+    }
+
     DWORD GetThreadId32() const
     {
         LIMITED_METHOD_CONTRACT;
@@ -129,6 +142,7 @@ protected:
 
     EventPipeEvent *m_pEvent;
     unsigned int m_metadataId;
+    unsigned int m_procNumber;
     ULONGLONG m_threadId;
     LARGE_INTEGER m_timeStamp;
     GUID m_activityId;
index 093d162..90c51d4 100644 (file)
@@ -19,6 +19,7 @@
 
 UINT64 QCALLTYPE EventPipeInternal::Enable(
     __in_z LPCWSTR outputFile,
+    EventPipeSerializationFormat format,
     UINT32 circularBufferSizeInMB,
     EventPipeProviderConfiguration *pProviders,
     UINT32 numProviders)
@@ -29,6 +30,7 @@ UINT64 QCALLTYPE EventPipeInternal::Enable(
 
     // Invalid input!
     if (circularBufferSizeInMB == 0 ||
+        format >= EventPipeSerializationFormat::Count ||
         numProviders == 0 ||
         pProviders == nullptr)
     {
@@ -37,17 +39,6 @@ UINT64 QCALLTYPE EventPipeInternal::Enable(
 
     BEGIN_QCALL;
     {
-        // This was a quick and dirty mechanism for testing but it may not be the final
-        // configuration scheme we want. This path handles both the AI profiler scenario
-        // doing private reflection and the EnableEventPipe env var. If we want to flip
-        // the default for one but not the other we'll have to hoist the configuration
-        // check into managed code.
-        EventPipeSerializationFormat format = EventPipeSerializationFormat::NetPerfV3;
-        if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeNetTraceFormat) > 0)
-        {
-            format = EventPipeSerializationFormat::NetTraceV4;
-        }
-
         sessionID = EventPipe::Enable(
             outputFile,
             circularBufferSizeInMB,
index 2e95657..ab280c3 100644 (file)
@@ -46,6 +46,7 @@ public:
     //!
     static UINT64 QCALLTYPE Enable(
         __in_z LPCWSTR outputFile,
+        EventPipeSerializationFormat format,
         UINT32 circularBufferSizeInMB,
         EventPipeProviderConfiguration *pProviders,
         UINT32 numProviders);
index 00de406..de5d1df 100644 (file)
@@ -32,6 +32,12 @@ static bool TryParseCircularBufferSize(uint8_t*& bufferCursor, uint32_t& bufferL
     return CanParse && (circularBufferSizeInMB > 0);
 }
 
+static bool TryParseSerializationFormat(uint8_t*& bufferCursor, uint32_t& bufferLen, EventPipeSerializationFormat& serializationFormat)
+{
+    const bool CanParse = TryParse(bufferCursor, bufferLen, (uint32_t&)serializationFormat);
+    return CanParse && (0 <= (int)serializationFormat) && ((int)serializationFormat < (int)EventPipeSerializationFormat::Count);
+}
+
 const EventPipeCollectTracingCommandPayload* EventPipeCollectTracingCommandPayload::TryParse(BYTE* lpBuffer, uint16_t& BufferSize)
 {
     CONTRACTL
@@ -54,6 +60,7 @@ const EventPipeCollectTracingCommandPayload* EventPipeCollectTracingCommandPaylo
     uint8_t* pBufferCursor = payload->incomingBuffer;
     uint32_t bufferLen = BufferSize;
     if (!TryParseCircularBufferSize(pBufferCursor, bufferLen, payload->circularBufferSizeInMB) ||
+        !TryParseSerializationFormat(pBufferCursor, bufferLen, payload->serializationFormat) ||
         !TryParseString(pBufferCursor, bufferLen, payload->outputPath) ||
         !EventPipeProtocolHelper::TryParseProviderConfiguration(pBufferCursor, bufferLen, payload->providerConfigs))
     {
@@ -187,21 +194,13 @@ void EventPipeProtocolHelper::CollectTracing(DiagnosticsIpc::IpcMessage& message
         return;
     }
 
-    // IPC should produce nettrace by default or be selectable via protocol
-    // but this is a simple starting point for testing
-    EventPipeSerializationFormat format = EventPipeSerializationFormat::NetPerfV3;
-    if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeNetTraceFormat) > 0)
-    {
-        format = EventPipeSerializationFormat::NetTraceV4;
-    }
-
     auto sessionId = EventPipe::Enable(
         nullptr,                                        // strOutputPath (ignored in this scenario)
         payload->circularBufferSizeInMB,                         // circularBufferSizeInMB
         payload->providerConfigs.Ptr(),                          // pConfigs
         static_cast<uint32_t>(payload->providerConfigs.Size()),  // numConfigs
         EventPipeSessionType::IpcStream,                // EventPipeSessionType
-        format,                                         // EventPipeSerializationFormat
+        payload->serializationFormat,                   // EventPipeSerializationFormat
         pStream);                                       // IpcStream
 
     if (sessionId == 0)
index 2961b41..743df5e 100644 (file)
@@ -30,13 +30,14 @@ struct EventPipeCollectTracingCommandPayload
 
     // The protocol buffer is defined as:
     // X, Y, Z means encode bytes for X followed by bytes for Y followed by bytes for Z
-    // message = uint circularBufferMB, string outputPath, array<provider_config> providers
+    // message = uint circularBufferMB, uint format, string outputPath, array<provider_config> providers
     // uint = 4 little endian bytes
     // wchar = 2 little endian bytes, UTF16 encoding
     // array<T> = uint length, length # of Ts
     // string = (array<char> where the last char must = 0) or (length = 0)
     // provider_config = ulong keywords, uint logLevel, string provider_name, string filter_data
     uint32_t circularBufferSizeInMB;
+    EventPipeSerializationFormat serializationFormat;
     LPCWSTR outputPath;
     CQuickArray<EventPipeProviderConfiguration> providerConfigs;
     static const EventPipeCollectTracingCommandPayload* TryParse(BYTE* lpBuffer, uint16_t& BufferSize);
index ad986c3..afb7db2 100644 (file)
@@ -7,6 +7,12 @@ using System.Reflection;
 
 namespace Tracing.Tests.Common
 {
+    public enum EventPipeSerializationFormat
+    {
+        NetPerf,
+        NetTrace
+    }
+
     public sealed class TraceConfiguration
     {
         private ConstructorInfo m_configurationCtor;
@@ -29,6 +35,7 @@ namespace Tracing.Tests.Common
                 new object[]
                 {
                     outputFile,
+                    EventPipeSerializationFormat.NetTrace,
                     circularBufferMB
                 });
         }
@@ -79,10 +86,17 @@ namespace Tracing.Tests.Common
                return false;
            }
 
-           m_configurationCtor = configurationType.GetConstructor(
+            Type formatType = SPC.GetType("System.Diagnostics.Tracing.EventPipeSerializationFormat");
+            if (formatType == null)
+            {
+                Console.WriteLine("formatType == null");
+                return false;
+            }
+
+            m_configurationCtor = configurationType.GetConstructor(
                BindingFlags.NonPublic | BindingFlags.Instance,
                null,
-               new Type[] { typeof(string), typeof(uint) },
+               new Type[] { typeof(string), formatType, typeof(uint) },
                null);
            if(m_configurationCtor == null)
            {
index a35c2b7..2e55544 100644 (file)
@@ -4,6 +4,12 @@ using System.Reflection;
 
 namespace EventPipe.Issue22247
 {
+    public enum EventPipeSerializationFormat
+    {
+        NetPerf,
+        NetTrace
+    }
+
     public sealed class TraceConfiguration
     {
         private ConstructorInfo m_configurationCtor;
@@ -26,6 +32,7 @@ namespace EventPipe.Issue22247
                 new object[]
                 {
                     outputFile,
+                    EventPipeSerializationFormat.NetTrace,
                     circularBufferMB
                 });
         }
@@ -75,11 +82,17 @@ namespace EventPipe.Issue22247
                 Console.WriteLine("configurationType == null");
                 return false;
             }
+            Type formatType = SPC.GetType("System.Diagnostics.Tracing.EventPipeSerializationFormat");
+            if (formatType == null)
+            {
+                Console.WriteLine("formatType == null");
+                return false;
+            }
 
             m_configurationCtor = configurationType.GetConstructor(
                 BindingFlags.NonPublic | BindingFlags.Instance,
                 null,
-                new Type[] { typeof(string), typeof(uint) },
+                new Type[] { typeof(string), formatType, typeof(uint) },
                 null);
             if (m_configurationCtor == null)
             {