diff options
author | Victor "Nate" Graf <nategraf1@gmail.com> | 2017-08-24 15:13:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-24 15:13:49 -0700 |
commit | 421f9e7c64b05c71db6ef71791998c06249953f6 (patch) | |
tree | 3d416f3d85b892ff1b7c006de1453b1b5498bd2d /src | |
parent | 970c41b10cca6f0f4bc6c6524c6733ac2c5011ba (diff) | |
download | coreclr-421f9e7c64b05c71db6ef71791998c06249953f6.tar.gz coreclr-421f9e7c64b05c71db6ef71791998c06249953f6.tar.bz2 coreclr-421f9e7c64b05c71db6ef71791998c06249953f6.zip |
Remove unnecessary buffer copy from EventPipe::WriteEvent pipeline (#13347)
* [WIP] Eliminate extra buffer copy with new api path
* Copy blobs to a flat buffer is Rundown is on
* Refactor to use payload class and dedupe code
* Add contracts
* Fix many small errors
* Make names unambiguous
* Add EventPipe::WriteEventBlob to ecalllist.h
* Address code review
* Add test and fix a buffer copy bug
* Copy data instead of data pointer
* Add optional output file arg to tests
* Change failure return code
* Renamed variables for clarity
Diffstat (limited to 'src')
-rw-r--r-- | src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs | 4 | ||||
-rw-r--r-- | src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs | 21 | ||||
-rw-r--r-- | src/scripts/genEventPipe.py | 2 | ||||
-rw-r--r-- | src/vm/ecalllist.h | 1 | ||||
-rw-r--r-- | src/vm/eventpipe.cpp | 260 | ||||
-rw-r--r-- | src/vm/eventpipe.h | 81 | ||||
-rw-r--r-- | src/vm/eventpipebuffer.cpp | 11 | ||||
-rw-r--r-- | src/vm/eventpipebuffer.h | 3 | ||||
-rw-r--r-- | src/vm/eventpipebuffermanager.cpp | 9 | ||||
-rw-r--r-- | src/vm/eventpipebuffermanager.h | 3 |
10 files changed, 332 insertions, 63 deletions
diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs index 2f6fdf62ef..0d216c38ab 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs @@ -171,5 +171,9 @@ namespace System.Diagnostics.Tracing [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] [SuppressUnmanagedCodeSecurity] internal static extern unsafe void WriteEvent(IntPtr eventHandle, uint eventID, void* pData, uint length, Guid* activityId, Guid* relatedActivityId); + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + internal static extern unsafe void WriteEventData(IntPtr eventHandle, uint eventID, EventProvider.EventData** pEventData, uint dataCount, Guid* activityId, Guid* relatedActivityId); } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs index d5bc4c2889..1c521bbafc 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs @@ -62,28 +62,11 @@ namespace System.Diagnostics.Tracing { if (userDataCount == 0) { - EventPipeInternal.WriteEvent(eventHandle, eventID, null, 0, activityId, relatedActivityId); + EventPipeInternal.WriteEventData(eventHandle, eventID, null, 0, activityId, relatedActivityId); 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, activityId, relatedActivityId); - } + EventPipeInternal.WriteEventData(eventHandle, eventID, &userData, (uint) userDataCount, activityId, relatedActivityId); } return 0; } diff --git a/src/scripts/genEventPipe.py b/src/scripts/genEventPipe.py index 4c802acaf3..d5785d2799 100644 --- a/src/scripts/genEventPipe.py +++ b/src/scripts/genEventPipe.py @@ -110,7 +110,7 @@ def generateClrEventPipeWriteEventsImpl( WriteEventImpl.append( " EventPipe::WriteEvent(*EventPipeEvent" + eventName + - ", nullptr, 0);\n") + ", (BYTE*) nullptr, 0);\n") WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n") diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 114d2cf2fd..b76b81cb05 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -1245,6 +1245,7 @@ FCFuncStart(gEventPipeInternalFuncs) QCFuncElement("DefineEvent", EventPipeInternal::DefineEvent) QCFuncElement("DeleteProvider", EventPipeInternal::DeleteProvider) QCFuncElement("WriteEvent", EventPipeInternal::WriteEvent) + QCFuncElement("WriteEventData", EventPipeInternal::WriteEventData) FCFuncEnd() #endif // FEATURE_PERFTRACING diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp index 9a94923493..d8d3791d59 100644 --- a/src/vm/eventpipe.cpp +++ b/src/vm/eventpipe.cpp @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#include "clrtypes.h" +#include "safemath.h" #include "common.h" #include "eventpipe.h" #include "eventpipebuffermanager.h" @@ -38,6 +40,146 @@ extern "C" void InitProvidersAndEvents(); extern "C" void InitProvidersAndEvents(); #endif +EventPipeEventPayload::EventPipeEventPayload(BYTE *pData, unsigned int length) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_pData = pData; + m_pEventData = NULL; + m_eventDataCount = 0; + m_allocatedData = false; + + m_size = length; +} + +EventPipeEventPayload::EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_pData = NULL; + m_pEventData = pEventData; + m_eventDataCount = eventDataCount; + m_allocatedData = false; + + S_UINT32 tmp_size = S_UINT32(0); + for (unsigned int i=0; i<m_eventDataCount; i++) + { + tmp_size += S_UINT32(m_pEventData[i]->Size); + } + + if (tmp_size.IsOverflow()) + { + // If there is an overflow, drop the data and create an empty payload + m_pEventData = NULL; + m_eventDataCount = 0; + m_size = 0; + } + else + { + m_size = tmp_size.Value(); + } +} + +EventPipeEventPayload::~EventPipeEventPayload() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + if(m_allocatedData && m_pData != NULL) + { + delete[] m_pData; + m_pData = NULL; + } +} + +void EventPipeEventPayload::Flatten() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + if(m_size > 0) + { + if (!IsFlattened()) + { + BYTE* tmp_pData = new (nothrow) BYTE[m_size]; + if (tmp_pData != NULL) + { + m_allocatedData = true; + CopyData(tmp_pData); + m_pData = tmp_pData; + } + } + } +} + +void EventPipeEventPayload::CopyData(BYTE *pDst) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if(m_size > 0) + { + if(IsFlattened()) + { + memcpy(pDst, m_pData, m_size); + } + + else if(m_pEventData != NULL) + { + unsigned int offset = 0; + for(unsigned int i=0; i<m_eventDataCount; i++) + { + memcpy(pDst + offset, (BYTE*)m_pEventData[i]->Ptr, m_pEventData[i]->Size); + offset += m_pEventData[i]->Size; + } + } + } +} + +BYTE* EventPipeEventPayload::GetFlatData() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + if (!IsFlattened()) + { + Flatten(); + } + return m_pData; +} + void EventPipe::Initialize() { STANDARD_VM_CONTRACT; @@ -289,6 +431,34 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng NOTHROW; GC_NOTRIGGER; MODE_ANY; + } + CONTRACTL_END; + + EventPipeEventPayload payload(pData, length); + EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId); +} + +void EventPipe::WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + EventPipeEventPayload payload(pEventData, eventDataCount); + EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId); +} + +void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; PRECONDITION(s_pBufferManager != NULL); } CONTRACTL_END; @@ -309,7 +479,7 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL) { - if(!s_pBufferManager->WriteEvent(pThread, event, pData, length, pActivityId, pRelatedActivityId)) + if(!s_pBufferManager->WriteEvent(pThread, event, payload, pActivityId, pRelatedActivityId)) { // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer. return; @@ -317,19 +487,23 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng } else if(s_pConfig->RundownEnabled()) { - // Write synchronously to the file. - // We're under lock and blocking the disabling thread. - EventPipeEventInstance instance( - event, - pThread->GetOSThreadId(), - pData, - length, - pActivityId, - pRelatedActivityId); - - if(s_pFile != NULL) + BYTE *pData = payload.GetFlatData(); + if (pData != NULL) { - s_pFile->WriteEvent(instance); + // Write synchronously to the file. + // We're under lock and blocking the disabling thread. + EventPipeEventInstance instance( + event, + pThread->GetOSThreadId(), + pData, + payload.GetSize(), + pActivityId, + pRelatedActivityId); + + if(s_pFile != NULL) + { + s_pFile->WriteEvent(instance); + } } } @@ -337,25 +511,29 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng { GCX_PREEMP(); - // Create an instance of the event for the synchronous path. - EventPipeEventInstance instance( - event, - pThread->GetOSThreadId(), - pData, - length, - pActivityId, - pRelatedActivityId); - - // Write to the EventPipeFile if it exists. - if(s_pSyncFile != NULL) + BYTE *pData = payload.GetFlatData(); + if (pData != NULL) { - s_pSyncFile->WriteEvent(instance); - } + // Create an instance of the event for the synchronous path. + EventPipeEventInstance instance( + event, + pThread->GetOSThreadId(), + pData, + payload.GetSize(), + pActivityId, + pRelatedActivityId); + + // Write to the EventPipeFile if it exists. + if(s_pSyncFile != NULL) + { + s_pSyncFile->WriteEvent(instance); + } - // Write to the EventPipeJsonFile if it exists. - if(s_pJsonFile != NULL) - { - s_pJsonFile->WriteEvent(instance); + // Write to the EventPipeJsonFile if it exists. + if(s_pJsonFile != NULL) + { + s_pJsonFile->WriteEvent(instance); + } } } #endif // _DEBUG @@ -371,12 +549,14 @@ void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent } CONTRACTL_END; + EventPipeEventPayload payload(pData, length); + // Write the event to the thread's buffer. if(s_pBufferManager != NULL) { // Specify the sampling thread as the "current thread", so that we select the right buffer. // Specify the target thread so that the event gets properly attributed. - if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, pData, length, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents)) + if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, payload, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents)) { // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer. return; @@ -595,4 +775,22 @@ void QCALLTYPE EventPipeInternal::WriteEvent( END_QCALL; } +void QCALLTYPE EventPipeInternal::WriteEventData( + INT_PTR eventHandle, + unsigned int eventID, + EventData **pEventData, + unsigned int eventDataCount, + LPCGUID pActivityId, + LPCGUID pRelatedActivityId) +{ + QCALL_CONTRACT; + BEGIN_QCALL; + + _ASSERTE(eventHandle != NULL); + EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle); + EventPipe::WriteEvent(*pEvent, pEventData, eventDataCount, pActivityId, pRelatedActivityId); + + END_QCALL; +} + #endif // FEATURE_PERFTRACING diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h index fa7d734280..6ea29ac63b 100644 --- a/src/vm/eventpipe.h +++ b/src/vm/eventpipe.h @@ -29,6 +29,69 @@ typedef void (*EventPipeCallback)( void *FilterData, void *CallbackContext); +struct EventData +{ +public: + unsigned long Ptr; + unsigned int Size; + unsigned int Reserved; +}; + +class EventPipeEventPayload +{ +private: + BYTE *m_pData; + EventData **m_pEventData; + unsigned int m_eventDataCount; + unsigned int m_size; + bool m_allocatedData; + + // If the data is stored only as an array of EventData objects, create a flat buffer and copy into it + void Flatten(); + +public: + // Build this payload with a flat buffer inside + EventPipeEventPayload(BYTE *pData, unsigned int length); + + // Build this payload to contain an array of EventData objects + EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount); + + // If a buffer was allocated internally, delete it + ~EventPipeEventPayload(); + + // Copy the data (whether flat or array of objects) into a flat buffer at pDst + // Assumes that pDst points to an appropriatly sized buffer + void CopyData(BYTE *pDst); + + // Get the flat formatted data in this payload + // This method will allocate a buffer if it does not already contain flattened data + // This method will return NULL on OOM if a buffer needed to be allocated + BYTE* GetFlatData(); + + // Return true is the data is stored in a flat buffer + bool IsFlattened() const + { + LIMITED_METHOD_CONTRACT; + + return m_pData != NULL; + } + + // The the size of buffer needed to contain the stored data + unsigned int GetSize() const + { + LIMITED_METHOD_CONTRACT; + + return m_size; + } + + EventData** GetEventDataArray() const + { + LIMITED_METHOD_CONTRACT; + + return m_pEventData; + } +}; + class StackContents { private: @@ -186,10 +249,14 @@ class EventPipe // Delete a provider. static void DeleteProvider(EventPipeProvider *pProvider); - // Write out an event. + // Write out an event from a flat buffer. // Data is written as a serialized blob matching the ETW serialization conventions. static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL); + // Write out an event from an EventData array. + // Data is written as a serialized blob matching the ETW serialization conventions. + static void WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL); + // Write out a sample profile event. static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0); @@ -199,6 +266,11 @@ class EventPipe // Get the managed call stack for the specified thread. static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents); + protected: + + // The counterpart to WriteEvent which after the payload is constructed + static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL); + private: // Callback function for the stack walker. For each frame walked, this callback is invoked. @@ -307,6 +379,13 @@ public: void *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId); + + static void QCALLTYPE WriteEventData( + INT_PTR eventHandle, + unsigned int eventID, + EventData **pEventData, + unsigned int eventDataCount, + LPCGUID pActivityId, LPCGUID pRelatedActivityId); }; #endif // FEATURE_PERFTRACING diff --git a/src/vm/eventpipebuffer.cpp b/src/vm/eventpipebuffer.cpp index 00652c9fac..80b4a4f1b7 100644 --- a/src/vm/eventpipebuffer.cpp +++ b/src/vm/eventpipebuffer.cpp @@ -4,6 +4,7 @@ #include "common.h" +#include "eventpipe.h" #include "eventpipeeventinstance.h" #include "eventpipebuffer.h" @@ -46,7 +47,7 @@ EventPipeBuffer::~EventPipeBuffer() } } -bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int dataLength, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack) +bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack) { CONTRACTL { @@ -58,7 +59,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *p CONTRACTL_END; // Calculate the size of the event. - unsigned int eventSize = sizeof(EventPipeEventInstance) + dataLength; + unsigned int eventSize = sizeof(EventPipeEventInstance) + payload.GetSize(); // Make sure we have enough space to write the event. if(m_pCurrent + eventSize >= m_pLimit) @@ -77,7 +78,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *p event, pThread->GetOSThreadId(), pDataDest, - dataLength, + payload.GetSize(), pActivityId, pRelatedActivityId); @@ -89,9 +90,9 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *p } // Write the event payload data to the buffer. - if(dataLength > 0) + if(payload.GetSize() > 0) { - memcpy(pDataDest, pData, dataLength); + payload.CopyData(pDataDest); } // Save the most recent event timestamp. diff --git a/src/vm/eventpipebuffer.h b/src/vm/eventpipebuffer.h index f279a2865c..c96ad26609 100644 --- a/src/vm/eventpipebuffer.h +++ b/src/vm/eventpipebuffer.h @@ -7,6 +7,7 @@ #ifdef FEATURE_PERFTRACING +#include "eventpipe.h" #include "eventpipeevent.h" #include "eventpipeeventinstance.h" @@ -81,7 +82,7 @@ public: // Returns: // - true: The write succeeded. // - false: The write failed. In this case, the buffer should be considered full. - bool WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int dataLength, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack = NULL); + bool WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack = NULL); // Get the timestamp of the most recent event in the buffer. LARGE_INTEGER GetMostRecentTimeStamp() const; diff --git a/src/vm/eventpipebuffermanager.cpp b/src/vm/eventpipebuffermanager.cpp index 86a3e03c59..fa4c5e0b68 100644 --- a/src/vm/eventpipebuffermanager.cpp +++ b/src/vm/eventpipebuffermanager.cpp @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. #include "common.h" +#include "eventpipe.h" #include "eventpipeconfiguration.h" #include "eventpipebuffer.h" #include "eventpipebuffermanager.h" @@ -217,7 +218,7 @@ void EventPipeBufferManager::DeAllocateBuffer(EventPipeBuffer *pBuffer) } } -bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread, StackContents *pStack) +bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread, StackContents *pStack) { CONTRACTL { @@ -276,7 +277,7 @@ bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, else { // Attempt to write the event to the buffer. If this fails, we should allocate a new buffer. - allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, pData, length, pActivityId, pRelatedActivityId, pStack); + allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, payload, pActivityId, pRelatedActivityId, pStack); } } @@ -290,7 +291,7 @@ bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, // However, the GC is waiting on this call to return so that it can make forward progress. Thus it is not safe // to switch to preemptive mode here. - unsigned int requestSize = sizeof(EventPipeEventInstance) + length; + unsigned int requestSize = sizeof(EventPipeEventInstance) + payload.GetSize(); pBuffer = AllocateBufferForThread(pThread, requestSize); } @@ -299,7 +300,7 @@ bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, // This is the second time if this thread did have one or more buffers, but they were full. if(allocNewBuffer && pBuffer != NULL) { - allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, pData, length, pActivityId, pRelatedActivityId, pStack); + allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, payload, pActivityId, pRelatedActivityId, pStack); } // Mark that the thread is no longer writing an event. diff --git a/src/vm/eventpipebuffermanager.h b/src/vm/eventpipebuffermanager.h index a53721b7b8..23e4e7f3e9 100644 --- a/src/vm/eventpipebuffermanager.h +++ b/src/vm/eventpipebuffermanager.h @@ -7,6 +7,7 @@ #ifdef FEATURE_PERFTRACING +#include "eventpipe.h" #include "eventpipefile.h" #include "eventpipebuffer.h" #include "spinlock.h" @@ -67,7 +68,7 @@ public: // This is because the thread that writes the events is not the same as the "event thread". // An optional stack trace can be provided for sample profiler events. // Otherwise, if a stack trace is needed, one will be automatically collected. - bool WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread = NULL, StackContents *pStack = NULL); + bool WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread = NULL, StackContents *pStack = NULL); // Write the contents of the managed buffers to the specified file. // The stopTimeStamp is used to determine when tracing was stopped to ensure that we |