Write EventSource events with metadata to EventPipe (dotnet/coreclr#11577)
authorXiangyang (Mark) Guo <xiangyang.guo@intel.com>
Mon, 15 May 2017 20:05:32 +0000 (13:05 -0700)
committerBrian Robbins <brianrob@microsoft.com>
Mon, 15 May 2017 20:05:32 +0000 (13:05 -0700)
* Fix EventPipe initialization.

* rebase code with master, add prototype of event source metadata

* fix define event

* add null ptr checking

* move WriteEvent metadata serialization to managed side

* Fix enabled keywords for COMPlus_PerformanceTracing=1.

* put parameter name into metadata, use WriteToBuffer

* Write event metadata to the file.

* allocate buffer in EventPipeEvent ctor

* prevent double free

* refactor code

* AddEvent params reorder

Commit migrated from https://github.com/dotnet/coreclr/commit/a7fae647fc09448cce04276a87a2873c09d31d42

16 files changed:
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
src/coreclr/src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs
src/coreclr/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs
src/coreclr/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs
src/coreclr/src/scripts/genEventPipe.py
src/coreclr/src/vm/ecalllist.h
src/coreclr/src/vm/eventpipe.cpp
src/coreclr/src/vm/eventpipe.h
src/coreclr/src/vm/eventpipeconfiguration.cpp
src/coreclr/src/vm/eventpipeconfiguration.h
src/coreclr/src/vm/eventpipeevent.cpp
src/coreclr/src/vm/eventpipeevent.h
src/coreclr/src/vm/eventpipeprovider.cpp
src/coreclr/src/vm/eventpipeprovider.h
src/coreclr/src/vm/sampleprofiler.cpp

index c8671db..5292551 100644 (file)
@@ -54,6 +54,7 @@ namespace System.Diagnostics.Tracing
         // subclasses of EventProvider use when creating efficient (but unsafe) version of
         // EventWrite.   We do make it a nested type because we really don't expect anyone to use 
         // it except subclasses (and then only rarely).  
+        [StructLayout(LayoutKind.Sequential)]
         public struct EventData
         {
             internal unsafe ulong Ptr;
@@ -78,7 +79,7 @@ namespace System.Diagnostics.Tracing
 
         private static bool m_setInformationMissing;
 
-        private IEventProvider m_eventProvider;          // The interface that implements the specific logging mechanism functions.
+        internal IEventProvider m_eventProvider;         // The interface that implements the specific logging mechanism functions.
         UnsafeNativeMethods.ManifestEtw.EtwEnableCallback m_etwCallback;     // Trace Callback function
         private long m_regHandle;                        // Trace Registration Handle
         private byte m_level;                            // Tracing Level
@@ -936,7 +937,7 @@ namespace System.Diagnostics.Tracing
         // </SecurityKernel>
         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Performance-critical code")]
         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
-        internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, params object[] eventPayload)
+        internal unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, params object[] eventPayload)
         {
             int status = 0;
 
@@ -1064,7 +1065,7 @@ namespace System.Diagnostics.Tracing
                                 userDataPtr[refObjPosition[7]].Ptr = (ulong)v7;
                             }
 
-                            status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData);
+                            status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData);
                         }
                     }
                     else
@@ -1090,7 +1091,7 @@ namespace System.Diagnostics.Tracing
                             }
                         }
 
-                        status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, argCount, userData);
+                        status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, argCount, userData);
 
                         for (int i = 0; i < refObjIndex; ++i)
                         {
@@ -1132,7 +1133,7 @@ namespace System.Diagnostics.Tracing
         // <CallsSuppressUnmanagedCode Name="UnsafeNativeMethods.ManifestEtw.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
         // </SecurityKernel>
         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
-        internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
+        internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
         {
             if (childActivityID != null)
             {
@@ -1143,7 +1144,7 @@ namespace System.Diagnostics.Tracing
                                 (EventOpcode)eventDescriptor.Opcode == EventOpcode.Stop);
             }
 
-            int status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, activityID, childActivityID, dataCount, (EventData*)data);
+            int status = m_eventProvider.EventWriteTransferWrapper(m_regHandle, ref eventDescriptor, eventHandle, activityID, childActivityID, dataCount, (EventData*)data);
 
             if (status != 0)
             {
@@ -1166,6 +1167,7 @@ namespace System.Diagnostics.Tracing
             status = m_eventProvider.EventWriteTransferWrapper(
                 m_regHandle,
                 ref eventDescriptor,
+                IntPtr.Zero,
                 activityID,
                 relatedActivityID,
                 dataCount,
@@ -1241,6 +1243,7 @@ namespace System.Diagnostics.Tracing
         unsafe int IEventProvider.EventWriteTransferWrapper(
             long registrationHandle,
             ref EventDescriptor eventDescriptor,
+            IntPtr eventHandle,
             Guid* activityId,
             Guid* relatedActivityId,
             int userDataCount,
@@ -1262,6 +1265,12 @@ namespace System.Diagnostics.Tracing
                 ControlCode,
                 ref ActivityId);
         }
+
+        // Define an EventPipeEvent handle.
+        unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength)
+        {
+            throw new System.NotSupportedException();
+        }
     }
 
 #elif !FEATURE_PERFTRACING
@@ -1285,6 +1294,7 @@ namespace System.Diagnostics.Tracing
         unsafe int IEventProvider.EventWriteTransferWrapper(
             long registrationHandle,
             ref EventDescriptor eventDescriptor,
+            IntPtr eventHandle,
             Guid* activityId,
             Guid* relatedActivityId,
             int userDataCount,
@@ -1297,6 +1307,12 @@ namespace System.Diagnostics.Tracing
         {
             return 0;
         }
+
+        // Define an EventPipeEvent handle.
+        unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength)
+        {
+            throw new System.NotSupportedException();
+        }
     }
 
 #endif
index 513366f..a0f0e1e 100644 (file)
@@ -686,6 +686,106 @@ namespace System.Diagnostics.Tracing
             Initialize(eventSourceGuid, eventSourceName, traits);
         }
 
+#if FEATURE_PERFTRACING
+        // Generate the serialized blobs that describe events for all strongly typed events (that is events that define strongly
+        // typed event methods. Dynamically defined events (that use Write) hare defined on the fly and are handled elsewhere.
+        private unsafe void DefineEventPipeEvents()
+        {
+            Debug.Assert(m_eventData != null);
+            Debug.Assert(m_provider != null);
+            int cnt = m_eventData.Length;
+            for (int i = 0; i < cnt; i++)
+            {
+                uint eventID = (uint)m_eventData[i].Descriptor.EventId;
+                if (eventID == 0)
+                    continue;
+
+                string eventName = m_eventData[i].Name;
+                Int64 keywords = m_eventData[i].Descriptor.Keywords;
+                uint eventVersion = m_eventData[i].Descriptor.Version;
+                uint level = m_eventData[i].Descriptor.Level;
+
+                // evnetID          : 4 bytes
+                // eventName        : (eventName.Length + 1) * 2 bytes
+                // keywords         : 8 bytes
+                // eventVersion     : 4 bytes
+                // level            : 4 bytes
+                // parameterCount   : 4 bytes
+                uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2;
+
+                // Increase the metadataLength for the types of all parameters.
+                metadataLength += (uint)m_eventData[i].Parameters.Length * 4;
+
+                // Increase the metadataLength for the names of all parameters.
+                foreach (var parameter in m_eventData[i].Parameters)
+                {
+                    string parameterName = parameter.Name;
+                    metadataLength = metadataLength + ((uint)parameterName.Length + 1) * 2;
+                }
+
+                byte[] metadata = new byte[metadataLength];
+
+                // Write metadata: evnetID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name...
+                fixed (byte *pMetadata = metadata)
+                {
+                    uint offset = 0;
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, eventID);
+                    fixed(char *pEventName = eventName)
+                    {
+                        WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pEventName, ((uint)eventName.Length + 1) * 2);
+                    }
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, keywords);
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, eventVersion);
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, level);
+                    WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)m_eventData[i].Parameters.Length);
+                    foreach (var parameter in m_eventData[i].Parameters)
+                    {
+                        // Write parameter type.
+                        WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)Type.GetTypeCode(parameter.ParameterType));
+                        
+                        // Write parameter name.
+                        string parameterName = parameter.Name;
+                        fixed (char *pParameterName = parameterName)
+                        {
+                            WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pParameterName, ((uint)parameterName.Length + 1) * 2);
+                        }
+                    }
+                    Debug.Assert(metadataLength == offset);
+                    IntPtr eventHandle = m_provider.m_eventProvider.DefineEventHandle(eventID, eventName, keywords, eventVersion, level, pMetadata, metadataLength);
+                    m_eventData[i].EventHandle = eventHandle; 
+                }
+            }
+        }
+
+        // Copy src to buffer and modify the offset.
+        // Note: We know the buffer size ahead of time to make sure no buffer overflow.
+        private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, byte *src, uint srcLength)
+        {
+            Debug.Assert(bufferLength >= (offset + srcLength));
+            for (int i = 0; i < srcLength; i++)
+            {
+                *(byte *)(buffer + offset + i) = *(byte *)(src + i);
+            }
+            offset += srcLength;
+        }
+
+        // Copy uint value to buffer.
+        private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, uint value)
+        {
+            Debug.Assert(bufferLength >= (offset + 4));
+            *(uint *)(buffer + offset) = value;
+            offset += 4;
+        }
+
+        // Copy long value to buffer.
+        private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, long value)
+        {
+            Debug.Assert(bufferLength >= (offset + 8));
+            *(long *)(buffer + offset) = value;
+            offset += 8;
+        }           
+#endif
+
         internal virtual void GetMetadata(out Guid eventSourceGuid, out string eventSourceName, out EventMetadata[] eventData, out byte[] manifestBytes)
         {
             //
@@ -1179,7 +1279,7 @@ namespace System.Diagnostics.Tracing
                                     // by default the Descriptor.Keyword will have the perEventSourceSessionId bit 
                                     // mask set to 0x0f so, when all ETW sessions want the event we don't need to 
                                     // synthesize a new one
-                                    if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+                                    if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
                                         ThrowEventSourceException(m_eventData[eventId].Name);
                                 }
                                 else
@@ -1199,7 +1299,7 @@ namespace System.Diagnostics.Tracing
                                         m_eventData[eventId].Descriptor.Task,
                                         unchecked((long)etwSessions.ToEventKeywords() | origKwd));
 
-                                    if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+                                    if (!m_provider.WriteEvent(ref desc, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
                                         ThrowEventSourceException(m_eventData[eventId].Name);
                                 }
                             }
@@ -1229,7 +1329,7 @@ namespace System.Diagnostics.Tracing
 #else
                         if (!SelfDescribingEvents)
                         {
-                            if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
+                            if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
                                 ThrowEventSourceException(m_eventData[eventId].Name);
                         }
                         else
@@ -1489,7 +1589,6 @@ namespace System.Diagnostics.Tracing
                 }
 #endif // PLATFORM_WINDOWS
 #endif // FEATURE_MANAGED_ETW
-
                 Debug.Assert(!m_eventSourceEnabled);     // We can't be enabled until we are completely initted.  
                 // We are logically completely initialized at this point.  
                 m_completelyInited = true;
@@ -1941,7 +2040,7 @@ namespace System.Diagnostics.Tracing
                                     // by default the Descriptor.Keyword will have the perEventSourceSessionId bit 
                                     // mask set to 0x0f so, when all ETW sessions want the event we don't need to 
                                     // synthesize a new one
-                                    if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
+                                    if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
                                         ThrowEventSourceException(m_eventData[eventId].Name);
                                 }
                                 else
@@ -1958,7 +2057,7 @@ namespace System.Diagnostics.Tracing
                                         m_eventData[eventId].Descriptor.Task,
                                         unchecked((long)etwSessions.ToEventKeywords() | origKwd));
 
-                                    if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args))
+                                    if (!m_provider.WriteEvent(ref desc, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
                                         ThrowEventSourceException(m_eventData[eventId].Name);
                                 }
                             }
@@ -1988,7 +2087,7 @@ namespace System.Diagnostics.Tracing
 #else
                         if (!SelfDescribingEvents)
                         {
-                            if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
+                            if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
                                 ThrowEventSourceException(m_eventData[eventId].Name);
                         }
                         else
@@ -2232,7 +2331,7 @@ namespace System.Diagnostics.Tracing
                         data.Ptr = (ulong)msgStringPtr;
                         data.Size = (uint)(2 * (msgString.Length + 1));
                         data.Reserved = 0;
-                        m_provider.WriteEvent(ref descr, null, null, 1, (IntPtr)((void*)&data));
+                        m_provider.WriteEvent(ref descr, m_eventData[0].EventHandle, null, null, 1, (IntPtr)((void*)&data));
                     }
                 }
             }
@@ -2517,6 +2616,7 @@ namespace System.Diagnostics.Tracing
         partial struct EventMetadata
         {
             public EventDescriptor Descriptor;
+            public IntPtr EventHandle;              // EventPipeEvent handle.
             public EventTags Tags;
             public bool EnabledForAnyListener;      // true if any dispatcher has this event turned on
             public bool EnabledForETW;              // is this event on for the OS ETW data dispatcher?
@@ -3065,6 +3165,10 @@ namespace System.Diagnostics.Tracing
                         dispatcher.m_EventEnabled = new bool[m_eventData.Length];
                     dispatcher = dispatcher.m_Next;
                 }
+#if FEATURE_PERFTRACING
+                // Initialize the EventPipe event handles.
+                DefineEventPipeEvents();
+#endif                
             }
             if (s_currentPid == 0)
             {
@@ -3119,7 +3223,7 @@ namespace System.Diagnostics.Tracing
                     dataDescrs[1].Size = (uint)Math.Min(dataLeft, chunkSize);
                     if (m_provider != null)
                     {
-                        if (!m_provider.WriteEvent(ref manifestDescr, null, null, 2, (IntPtr)dataDescrs))
+                        if (!m_provider.WriteEvent(ref manifestDescr, IntPtr.Zero, null, null, 2, (IntPtr)dataDescrs))
                         {
                             // Turns out that if users set the BufferSize to something less than 64K then WriteEvent
                             // can fail.   If we get this failure on the first chunk try again with something smaller
@@ -3597,7 +3701,11 @@ namespace System.Diagnostics.Tracing
                 throw new ArgumentException(msg, exception);
             }
 
+#if FEATURE_PERFTRACING
+            return null;
+#else
             return bNeedsManifest ? res : null;
+#endif
         }
 
         private static bool RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args)
@@ -3686,6 +3794,7 @@ namespace System.Diagnostics.Tracing
             eventData[eventAttribute.EventId].Message = eventAttribute.Message;
             eventData[eventAttribute.EventId].ActivityOptions = eventAttribute.ActivityOptions;
             eventData[eventAttribute.EventId].HasRelatedActivityID = hasRelatedActivityID;
+            eventData[eventAttribute.EventId].EventHandle = IntPtr.Zero;
         }
 
         // Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct
index 0b51e52..71a2fe4 100644 (file)
@@ -27,6 +27,7 @@ namespace System.Diagnostics.Tracing
         unsafe int EventWriteTransferWrapper(
             long registrationHandle,
             ref EventDescriptor eventDescriptor,
+            IntPtr eventHandle,
             Guid* activityId,
             Guid* relatedActivityId,
             int userDataCount,
@@ -34,5 +35,8 @@ namespace System.Diagnostics.Tracing
 
         // Get or set the per-thread activity ID.
         int EventActivityIdControl(UnsafeNativeMethods.ManifestEtw.ActivityControl ControlCode, ref Guid ActivityId);
+
+        // Define an EventPipeEvent handle.
+        unsafe IntPtr DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength);
     }
 }
index d962023..0d66c94 100644 (file)
@@ -162,7 +162,7 @@ namespace System.Diagnostics.Tracing
 
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         [SuppressUnmanagedCodeSecurity]
-        internal static extern IntPtr AddEvent(IntPtr provHandle, Int64 keywords, uint eventID, uint eventVersion, uint level, bool needStack);
+        internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, Int64 keywords, uint eventVersion, uint level, void *pMetadata, uint metadataLength);
 
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         [SuppressUnmanagedCodeSecurity]
@@ -170,6 +170,6 @@ namespace System.Diagnostics.Tracing
 
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         [SuppressUnmanagedCodeSecurity]
-        internal static extern unsafe void WriteEvent(IntPtr eventHandle, void* data, uint length);
+        internal static extern unsafe void WriteEvent(IntPtr eventHandle, uint eventID, void* pData, uint length);
     }
 }
index 42eb42a..cd9bd3c 100644 (file)
@@ -6,6 +6,8 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Security;
 using Microsoft.Win32;
+using System.Diagnostics;
+using System.Collections.Generic;
 
 namespace System.Diagnostics.Tracing
 {
@@ -49,11 +51,40 @@ namespace System.Diagnostics.Tracing
         unsafe int IEventProvider.EventWriteTransferWrapper(
             long registrationHandle,
             ref EventDescriptor eventDescriptor,
+            IntPtr eventHandle,
             Guid* activityId,
             Guid* relatedActivityId,
             int userDataCount,
             EventProvider.EventData* userData)
         {
+            uint eventID = (uint)eventDescriptor.EventId;
+            if(eventID != 0 && eventHandle != IntPtr.Zero)
+            {
+                if (userDataCount == 0)
+                {
+                    EventPipeInternal.WriteEvent(eventHandle, eventID, null, 0);
+                    return 0;
+                }
+
+                uint length = 0;
+                for (int i = 0; i < userDataCount; i++)
+                {
+                    length += userData[i].Size;
+                }
+
+                byte[] data = new byte[length];
+                fixed (byte *pData = data)
+                {
+                    uint offset = 0;
+                    for (int i = 0; i < userDataCount; i++)
+                    {
+                        byte * singleUserDataPtr = (byte *)(userData[i].Ptr);
+                        uint singleUserDataSize = userData[i].Size;
+                        WriteToBuffer(pData, length, ref offset, singleUserDataPtr, singleUserDataSize);
+                    }
+                    EventPipeInternal.WriteEvent(eventHandle, eventID, pData, length);
+                }
+            }
             return 0;
         }
 
@@ -62,5 +93,24 @@ namespace System.Diagnostics.Tracing
         {
             return 0;
         }
+
+        // Define an EventPipeEvent handle.
+        unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, Int64 keywords, uint eventVersion, uint level, byte *pMetadata, uint metadataLength)
+        {
+            IntPtr eventHandlePtr = EventPipeInternal.DefineEvent(m_provHandle, eventID, keywords, eventVersion, level, pMetadata, metadataLength);
+            return eventHandlePtr;
+        }
+
+        // Copy src to buffer and modify the offset.
+        // Note: We know the buffer size ahead of time to make sure no buffer overflow.
+        private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, byte *src, uint srcLength)
+        {
+            Debug.Assert(bufferLength >= (offset + srcLength));
+            for (int i = 0; i < srcLength; i++)
+            {
+                *(byte *)(buffer + offset + i) = *(byte *)(src + i);
+            }
+            offset += srcLength;
+        }
     }
 }
index 02634ad..7fd1a45 100644 (file)
@@ -138,7 +138,7 @@ def generateClrEventPipeWriteEventsImpl(
         taskName = eventNode.getAttribute('task')
 
         initEvent = """    EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s);
-""" % (eventName, providerPrettyName, eventKeywordsMask, eventValue, eventVersion, eventLevel)
+""" % (eventName, providerPrettyName, eventValue, eventKeywordsMask, eventVersion, eventLevel)
 
         WriteEventImpl.append(initEvent)
     WriteEventImpl.append("}")
index c51b4a8..39056a9 100644 (file)
@@ -1276,7 +1276,7 @@ FCFuncStart(gEventPipeInternalFuncs)
     QCFuncElement("Enable", EventPipeInternal::Enable)
     QCFuncElement("Disable", EventPipeInternal::Disable)
     QCFuncElement("CreateProvider", EventPipeInternal::CreateProvider)
-    QCFuncElement("AddEvent", EventPipeInternal::AddEvent)
+    QCFuncElement("DefineEvent", EventPipeInternal::DefineEvent)
     QCFuncElement("DeleteProvider", EventPipeInternal::DeleteProvider)
     QCFuncElement("WriteEvent", EventPipeInternal::WriteEvent)
 FCFuncEnd()
index 5805641..58f93ef 100644 (file)
@@ -484,22 +484,30 @@ INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
     return reinterpret_cast<INT_PTR>(pProvider);
 }
 
-INT_PTR QCALLTYPE EventPipeInternal::AddEvent(
+INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
     INT_PTR provHandle,
-    __int64 keywords,
     unsigned int eventID,
+    __int64 keywords,
     unsigned int eventVersion,
     unsigned int level,
-    bool needStack)
+    void *pMetadata,
+    unsigned int metadataLength)
 {
     QCALL_CONTRACT;
+
+    EventPipeEvent *pEvent = NULL;
+
     BEGIN_QCALL;
 
-    // TODO
+    _ASSERTE(provHandle != NULL);
+    _ASSERTE(pMetadata != NULL);
+    EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
+    pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
+    _ASSERTE(pEvent != NULL);
 
     END_QCALL;
 
-    return 0;
+    return reinterpret_cast<INT_PTR>(pEvent);
 }
 
 void QCALLTYPE EventPipeInternal::DeleteProvider(
@@ -519,13 +527,16 @@ void QCALLTYPE EventPipeInternal::DeleteProvider(
 
 void QCALLTYPE EventPipeInternal::WriteEvent(
     INT_PTR eventHandle,
+    unsigned int eventID,
     void *pData,
     unsigned int length)
 {
     QCALL_CONTRACT;
     BEGIN_QCALL;
 
-    // TODO
+    _ASSERTE(eventHandle != NULL);
+    EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
+    EventPipe::WriteEvent(*pEvent, (BYTE *)pData, length);
 
     END_QCALL;
 }
index 180a768..0aced25 100644 (file)
@@ -282,19 +282,21 @@ public:
         GUID providerID,
         EventPipeCallback pCallbackFunc);
 
-    static INT_PTR QCALLTYPE AddEvent(
+    static INT_PTR QCALLTYPE DefineEvent(
         INT_PTR provHandle,
-        __int64 keywords,
         unsigned int eventID,
+        __int64 keywords,
         unsigned int eventVersion,
         unsigned int level,
-        bool needStack);
+        void *pMetadata,
+        unsigned int metadataLength);
 
     static void QCALLTYPE DeleteProvider(
         INT_PTR provHandle);
 
     static void QCALLTYPE WriteEvent(
         INT_PTR eventHandle,
+        unsigned int eventID,
         void *pData,
         unsigned int length);
 };
index 7ce06ba..a227d9d 100644 (file)
@@ -63,8 +63,8 @@ void EventPipeConfiguration::Initialize()
 
     // Create the metadata event.
     m_pMetadataEvent = m_pConfigProvider->AddEvent(
-        0,      /* keywords */
         0,      /* eventID */
+        0,      /* keywords */
         0,      /* eventVersion */
         EventPipeEventLevel::LogAlways,
         false); /* needStack */
@@ -315,7 +315,7 @@ void EventPipeConfiguration::EnableRundown()
     Enable(1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
 }
 
-EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, BYTE *pPayloadData, unsigned int payloadLength)
+EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance)
 {
     CONTRACTL
     {
@@ -336,6 +336,8 @@ EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPip
     const GUID &providerID = sourceEvent.GetProvider()->GetProviderID();
     unsigned int eventID = sourceEvent.GetEventID();
     unsigned int eventVersion = sourceEvent.GetEventVersion();
+    BYTE *pPayloadData = sourceEvent.GetMetadata();
+    unsigned int payloadLength = sourceEvent.GetMetadataLength();
     unsigned int instancePayloadSize = sizeof(providerID) + sizeof(eventID) + sizeof(eventVersion) + sizeof(payloadLength) + payloadLength;
 
     // Allocate the payload.
@@ -398,7 +400,7 @@ EventPipeEnabledProviderList::EventPipeEnabledProviderList(
     if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
     {
         m_pCatchAllProvider = new EventPipeEnabledProvider();
-        m_pCatchAllProvider->Set(NULL, 0xFFFFFFFF, EventPipeEventLevel::Verbose);
+        m_pCatchAllProvider->Set(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose);
         return;
     }
 
index c579bee..44c4205 100644 (file)
@@ -69,7 +69,7 @@ public:
     void EnableRundown();
 
     // Get the event used to write metadata to the event stream.
-    EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, BYTE *pPayloadData = NULL, unsigned int payloadLength = 0);
+    EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance);
 
 private:
 
index 3b9f36b..abf942b 100644 (file)
@@ -8,7 +8,7 @@
 
 #ifdef FEATURE_PERFTRACING
 
-EventPipeEvent::EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack)
+EventPipeEvent::EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata, unsigned int metadataLength)
 {
     CONTRACTL
     {
@@ -25,6 +25,26 @@ EventPipeEvent::EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsi
     m_level = level;
     m_needStack = needStack;
     m_enabled = false;
+    if (pMetadata != NULL)
+    {
+        m_pMetadata = new BYTE[metadataLength];
+        memcpy(m_pMetadata, pMetadata, metadataLength);
+        m_metadataLength = metadataLength;
+    }
+    else
+    {
+        m_pMetadata = NULL;
+        m_metadataLength = 0;
+    }
+}
+
+EventPipeEvent::~EventPipeEvent()
+{
+    if (m_pMetadata != NULL)
+    {
+        delete[] m_pMetadata;
+        m_pMetadata = NULL;
+    }
 }
 
 EventPipeProvider* EventPipeEvent::GetProvider() const
@@ -76,6 +96,20 @@ bool EventPipeEvent::IsEnabled() const
     return m_enabled;
 }
 
+BYTE *EventPipeEvent::GetMetadata() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_pMetadata;
+}
+
+unsigned int EventPipeEvent::GetMetadataLength() const
+{
+    LIMITED_METHOD_CONTRACT;
+
+    return m_metadataLength;
+}
+
 void EventPipeEvent::RefreshState()
 {
     LIMITED_METHOD_CONTRACT;
index 3076617..c91c4ba 100644 (file)
@@ -37,15 +37,22 @@ private:
     // True if the event is current enabled.
     Volatile<bool> m_enabled;
 
+    // Metadata
+    BYTE *m_pMetadata;
+
+    // Metadata length;
+    unsigned int m_metadataLength;
+
     // Refreshes the runtime state for this event.
     // Called by EventPipeProvider when the provider configuration changes.
     void RefreshState();
 
     // Only EventPipeProvider can create events.
     // The provider is responsible for allocating and freeing events.
-    EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack);
+    EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
 
-public:
+  public:
+    ~EventPipeEvent();
 
     // Get the provider associated with this event.
     EventPipeProvider* GetProvider() const;
@@ -67,6 +74,12 @@ public:
 
     // True if the event is currently enabled.
     bool IsEnabled() const;
+
+    // Get metadata
+    BYTE *GetMetadata() const;
+
+    // Get metadata length
+    unsigned int GetMetadataLength() const;
 };
 
 #endif // FEATURE_PERFTRACING
index beee6fc..3c2d254 100644 (file)
@@ -128,7 +128,7 @@ void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, E
     InvokeCallback();
 }
 
-EventPipeEvent* EventPipeProvider::AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level)
+EventPipeEvent* EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, BYTE *pMetadata, unsigned int metadataLength)
 {
     CONTRACTL
     {
@@ -138,10 +138,10 @@ EventPipeEvent* EventPipeProvider::AddEvent(INT64 keywords, unsigned int eventID
     }
     CONTRACTL_END;
 
-    return AddEvent(keywords, eventID, eventVersion, level, true /* needStack */);
+    return AddEvent(eventID, keywords, eventVersion, level, true /* needStack */, pMetadata, metadataLength);
 }
 
-EventPipeEvent* EventPipeProvider::AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack)
+EventPipeEvent* EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata, unsigned int metadataLength)
 {
     CONTRACTL
     {
@@ -158,7 +158,9 @@ EventPipeEvent* EventPipeProvider::AddEvent(INT64 keywords, unsigned int eventID
         eventID,
         eventVersion,
         level,
-        needStack);
+        needStack,
+        pMetadata,
+        metadataLength);
 
     // Add it to the list of events.
     AddEvent(*pEvent);
index 771af21..605a82b 100644 (file)
@@ -73,16 +73,16 @@ public:
     bool EventEnabled(INT64 keywords, EventPipeEventLevel eventLevel) const;
 
     // Create a new event.
-    EventPipeEvent* AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level);
+    EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
 
-private:
+  private:
 
     // Create a new event, but allow needStack to be specified.
     // In general, we want stack walking to be controlled by the consumer and not the producer of events.
     // However, there are a couple of cases that we know we don't want to do a stackwalk that would affect performance significantly:
     // 1. Sample profiler events: The sample profiler already does a stack walk of the target thread.  Doing one of the sampler thread is a waste.
     // 2. Metadata events: These aren't as painful but because we have to keep this functionality around, might as well use it.
-    EventPipeEvent* AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack);
+    EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
 
     // Add an event to the provider.
     void AddEvent(EventPipeEvent &event);
index 3ed1a5b..c7373bc 100644 (file)
@@ -36,8 +36,8 @@ void SampleProfiler::Enable()
     {
         s_pEventPipeProvider = new EventPipeProvider(s_providerID);
         s_pThreadTimeEvent = s_pEventPipeProvider->AddEvent(
-            0, /* keywords */
             0, /* eventID */
+            0, /* keywords */
             0, /* eventVersion */
             EventPipeEventLevel::Informational,
             false /* NeedStack */);