From eb13fb092778db9fa8a0dea755393494959b71a6 Mon Sep 17 00:00:00 2001 From: Sung Yoon Whang Date: Tue, 2 Jul 2019 00:08:30 -0700 Subject: Add RundownRequested switch to EventPipe IPC protocol (#25495) * Add RundownRequested switch to EventPipe IPC protocol * Fix linux build * make the rundownRequested field a bool * some renaming * Make a new command that has an option for disabling rundown instead of breaking change * code review feedback --- src/vm/eventpipe.cpp | 35 +++++++++------- src/vm/eventpipe.h | 1 + src/vm/eventpipeinternal.cpp | 1 + src/vm/eventpipeprotocolhelper.cpp | 81 +++++++++++++++++++++++++++++++++++++- src/vm/eventpipeprotocolhelper.h | 25 +++++++++++- src/vm/eventpipesession.cpp | 4 +- src/vm/eventpipesession.h | 11 ++++++ 7 files changed, 140 insertions(+), 18 deletions(-) (limited to 'src/vm') diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp index 670c38692d..4ca57a274c 100644 --- a/src/vm/eventpipe.cpp +++ b/src/vm/eventpipe.cpp @@ -168,6 +168,7 @@ EventPipeSessionID EventPipe::Enable( uint32_t numProviders, EventPipeSessionType sessionType, EventPipeSerializationFormat format, + const bool rundownRequested, IpcStream *const pStream) { CONTRACTL @@ -202,6 +203,7 @@ EventPipeSessionID EventPipe::Enable( pStream, sessionType, format, + rundownRequested, circularBufferSizeInMB, pProviders, numProviders); @@ -344,26 +346,29 @@ void EventPipe::DisableInternal(EventPipeSessionID id, EventPipeProviderCallback pSession->Disable(); // Suspend EventPipeBufferManager, and remove providers. - // Do rundown before fully stopping the session. - pSession->EnableRundown(); // Set Rundown provider. - - EventPipeThread *const pEventPipeThread = EventPipeThread::GetOrCreate(); - if (pEventPipeThread != nullptr) + // Do rundown before fully stopping the session unless rundown wasn't requested + if (pSession->RundownRequested()) { - pEventPipeThread->SetAsRundownThread(pSession); + pSession->EnableRundown(); // Set Rundown provider. + + EventPipeThread *const pEventPipeThread = EventPipeThread::GetOrCreate(); + if (pEventPipeThread != nullptr) { - s_config.Enable(*pSession, pEventPipeProviderCallbackDataQueue); + pEventPipeThread->SetAsRundownThread(pSession); { - pSession->ExecuteRundown(); + s_config.Enable(*pSession, pEventPipeProviderCallbackDataQueue); + { + pSession->ExecuteRundown(); + } + s_config.Disable(*pSession, pEventPipeProviderCallbackDataQueue); } - s_config.Disable(*pSession, pEventPipeProviderCallbackDataQueue); + pEventPipeThread->SetAsRundownThread(nullptr); + } + else + { + _ASSERTE(!"Failed to get or create the EventPipeThread for rundown events."); + return; } - pEventPipeThread->SetAsRundownThread(nullptr); - } - else - { - _ASSERTE(!"Failed to get or create the EventPipeThread for rundown events."); - return; } --s_numberOfSessions; diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h index 9889abcb52..de2e72f4e8 100644 --- a/src/vm/eventpipe.h +++ b/src/vm/eventpipe.h @@ -51,6 +51,7 @@ public: uint32_t numProviders, EventPipeSessionType sessionType, EventPipeSerializationFormat format, + const bool rundownRequested, IpcStream *const pStream); // Disable tracing via the event pipe. diff --git a/src/vm/eventpipeinternal.cpp b/src/vm/eventpipeinternal.cpp index 90c51d46ab..e79005dd85 100644 --- a/src/vm/eventpipeinternal.cpp +++ b/src/vm/eventpipeinternal.cpp @@ -46,6 +46,7 @@ UINT64 QCALLTYPE EventPipeInternal::Enable( numProviders, outputFile != NULL ? EventPipeSessionType::File : EventPipeSessionType::Listener, format, + true, nullptr); } END_QCALL; diff --git a/src/vm/eventpipeprotocolhelper.cpp b/src/vm/eventpipeprotocolhelper.cpp index f928f326e6..e60e998469 100644 --- a/src/vm/eventpipeprotocolhelper.cpp +++ b/src/vm/eventpipeprotocolhelper.cpp @@ -38,6 +38,44 @@ static bool TryParseSerializationFormat(uint8_t*& bufferCursor, uint32_t& buffer return CanParse && (0 <= (int)serializationFormat) && ((int)serializationFormat < (int)EventPipeSerializationFormat::Count); } +static bool TryParseRundownRequested(uint8_t*& bufferCursor, uint32_t& bufferLen, bool& rundownRequested) +{ + return TryParse(bufferCursor, bufferLen, rundownRequested); +} + +const EventPipeCollectTracing2CommandPayload* EventPipeCollectTracing2CommandPayload::TryParse(BYTE* lpBuffer, uint16_t& BufferSize) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_PREEMPTIVE; + PRECONDITION(lpBuffer != nullptr); + } + CONTRACTL_END; + + EventPipeCollectTracing2CommandPayload *payload = new (nothrow) EventPipeCollectTracing2CommandPayload; + if (payload == nullptr) + { + // OOM + return nullptr; + } + + payload->incomingBuffer = lpBuffer; + uint8_t* pBufferCursor = payload->incomingBuffer; + uint32_t bufferLen = BufferSize; + if (!TryParseCircularBufferSize(pBufferCursor, bufferLen, payload->circularBufferSizeInMB) || + !TryParseSerializationFormat(pBufferCursor, bufferLen, payload->serializationFormat) || + !TryParseRundownRequested(pBufferCursor, bufferLen, payload->rundownRequested) || + !EventPipeProtocolHelper::TryParseProviderConfiguration(pBufferCursor, bufferLen, payload->providerConfigs)) + { + delete payload; + return nullptr; + } + + return payload; +} + const EventPipeCollectTracingCommandPayload* EventPipeCollectTracingCommandPayload::TryParse(BYTE* lpBuffer, uint16_t& BufferSize) { CONTRACTL @@ -86,7 +124,9 @@ void EventPipeProtocolHelper::HandleIpcMessage(DiagnosticsIpc::IpcMessage& messa case EventPipeCommandId::CollectTracing: EventPipeProtocolHelper::CollectTracing(message, pStream); break; - + case EventPipeCommandId::CollectTracing2: + EventPipeProtocolHelper::CollectTracing2(message, pStream); + break; case EventPipeCommandId::StopTracing: EventPipeProtocolHelper::StopTracing(message, pStream); break; @@ -200,6 +240,45 @@ void EventPipeProtocolHelper::CollectTracing(DiagnosticsIpc::IpcMessage& message static_cast(payload->providerConfigs.Size()), // numConfigs EventPipeSessionType::IpcStream, // EventPipeSessionType payload->serializationFormat, // EventPipeSerializationFormat + true, // rundownRequested + pStream); // IpcStream + + if (sessionId == 0) + { + DiagnosticsIpc::IpcMessage::SendErrorMessage(pStream, E_FAIL); + delete payload; + delete pStream; + } +} + +void EventPipeProtocolHelper::CollectTracing2(DiagnosticsIpc::IpcMessage& message, IpcStream *pStream) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + PRECONDITION(pStream != nullptr); + } + CONTRACTL_END; + + const EventPipeCollectTracing2CommandPayload* payload = message.TryParsePayload(); + if (payload == nullptr) + { + DiagnosticsIpc::IpcMessage::SendErrorMessage(pStream, CORDIAGIPC_E_BAD_ENCODING); + delete payload; + delete pStream; + return; + } + + auto sessionId = EventPipe::Enable( + nullptr, // strOutputPath (ignored in this scenario) + payload->circularBufferSizeInMB, // circularBufferSizeInMB + payload->providerConfigs.Ptr(), // pConfigs + static_cast(payload->providerConfigs.Size()), // numConfigs + EventPipeSessionType::IpcStream, // EventPipeSessionType + payload->serializationFormat, // EventPipeSerializationFormat + payload->rundownRequested, // rundownRequested pStream); // IpcStream if (sessionId == 0) diff --git a/src/vm/eventpipeprotocolhelper.h b/src/vm/eventpipeprotocolhelper.h index 5ae7abdc67..98d058b631 100644 --- a/src/vm/eventpipeprotocolhelper.h +++ b/src/vm/eventpipeprotocolhelper.h @@ -20,9 +20,32 @@ enum class EventPipeCommandId : uint8_t { StopTracing = 0x01, CollectTracing = 0x02, + CollectTracing2 = 0x03, // future }; + +// Command = 0x0203 +struct EventPipeCollectTracing2CommandPayload +{ + NewArrayHolder incomingBuffer; + + // 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, uint format, array providers + // uint = 4 little endian bytes + // wchar = 2 little endian bytes, UTF16 encoding + // array = uint length, length # of Ts + // string = (array 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; + bool rundownRequested; + CQuickArray providerConfigs; + static const EventPipeCollectTracing2CommandPayload* TryParse(BYTE* lpBuffer, uint16_t& BufferSize); +}; + + // Command = 0x0202 struct EventPipeCollectTracingCommandPayload { @@ -55,10 +78,10 @@ public: static void HandleIpcMessage(DiagnosticsIpc::IpcMessage& message, IpcStream *pStream); static void StopTracing(DiagnosticsIpc::IpcMessage& message, IpcStream *pStream); static void CollectTracing(DiagnosticsIpc::IpcMessage& message, IpcStream *pStream); // `dotnet-trace collect` + static void CollectTracing2(DiagnosticsIpc::IpcMessage& message, IpcStream *pStream); static bool TryParseProviderConfiguration(uint8_t *&bufferCursor, uint32_t &bufferLen, CQuickArray &result); private: - const static uint32_t DefaultCircularBufferMB = 1024; // 1 GB const static uint32_t IpcStreamReadBufferSize = 8192; }; diff --git a/src/vm/eventpipesession.cpp b/src/vm/eventpipesession.cpp index 8123c7e214..aa18df2dec 100644 --- a/src/vm/eventpipesession.cpp +++ b/src/vm/eventpipesession.cpp @@ -18,6 +18,7 @@ EventPipeSession::EventPipeSession( IpcStream *const pStream, EventPipeSessionType sessionType, EventPipeSerializationFormat format, + bool rundownSwitch, uint32_t circularBufferSizeInMB, const EventPipeProviderConfiguration *pProviders, uint32_t numProviders, @@ -25,7 +26,8 @@ EventPipeSession::EventPipeSession( m_pProviderList(new EventPipeSessionProviderList(pProviders, numProviders)), m_rundownEnabled(rundownEnabled), m_SessionType(sessionType), - m_format(format) + m_format(format), + m_rundownRequested(rundownSwitch) { CONTRACTL { diff --git a/src/vm/eventpipesession.h b/src/vm/eventpipesession.h index 277729354d..5e2f4b32c5 100644 --- a/src/vm/eventpipesession.h +++ b/src/vm/eventpipesession.h @@ -66,6 +66,9 @@ private: // irrelevant. EventPipeSerializationFormat m_format; + // For determininig if a particular session needs rundown events + const bool m_rundownRequested; + // Start date and time in UTC. FILETIME m_sessionStartTime; @@ -99,6 +102,7 @@ public: IpcStream *const pStream, EventPipeSessionType sessionType, EventPipeSerializationFormat format, + bool rundownRequested, uint32_t circularBufferSizeInMB, const EventPipeProviderConfiguration *pProviders, uint32_t numProviders, @@ -131,6 +135,13 @@ public: return m_format; } + // Get whether rundown was requested by the client. + bool RundownRequested() const + { + LIMITED_METHOD_CONTRACT; + return m_rundownRequested; + } + // Determine if rundown is enabled. bool RundownEnabled() const { -- cgit v1.2.3