diff options
author | Noah Falk <noahfalk@users.noreply.github.com> | 2019-06-21 15:27:21 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-21 15:27:21 -0700 |
commit | 961e8d7bd1bdd058ee5f8f34937e9f3f9d80b65b (patch) | |
tree | 06c18fd142f826966f051c908252089e6e5ec55b /src/vm | |
parent | 205e01fc5020f597ee69643c24fd56268cdf1b50 (diff) | |
download | coreclr-961e8d7bd1bdd058ee5f8f34937e9f3f9d80b65b.tar.gz coreclr-961e8d7bd1bdd058ee5f8f34937e9f3f9d80b65b.tar.bz2 coreclr-961e8d7bd1bdd058ee5f8f34937e9f3f9d80b65b.zip |
Add EventPipe Processor Number support and make NetTrace the default … (#25276)
* 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
Diffstat (limited to 'src/vm')
-rw-r--r-- | src/vm/eventpipe.cpp | 24 | ||||
-rw-r--r-- | src/vm/eventpipe.h | 22 | ||||
-rw-r--r-- | src/vm/eventpipeblock.cpp | 9 | ||||
-rw-r--r-- | src/vm/eventpipeblock.h | 1 | ||||
-rw-r--r-- | src/vm/eventpipebuffer.cpp | 2 | ||||
-rw-r--r-- | src/vm/eventpipeconfiguration.cpp | 1 | ||||
-rw-r--r-- | src/vm/eventpipeeventinstance.cpp | 3 | ||||
-rw-r--r-- | src/vm/eventpipeeventinstance.h | 16 | ||||
-rw-r--r-- | src/vm/eventpipeinternal.cpp | 13 | ||||
-rw-r--r-- | src/vm/eventpipeinternal.h | 1 | ||||
-rw-r--r-- | src/vm/eventpipeprotocolhelper.cpp | 17 | ||||
-rw-r--r-- | src/vm/eventpipeprotocolhelper.h | 3 |
12 files changed, 89 insertions, 23 deletions
diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp index adec56bd16..81b588f485 100644 --- a/src/vm/eventpipe.cpp +++ b/src/vm/eventpipe.cpp @@ -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(), diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h index 20f6c1fc7f..7a8df26343 100644 --- a/src/vm/eventpipe.h +++ b/src/vm/eventpipe.h @@ -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."); diff --git a/src/vm/eventpipeblock.cpp b/src/vm/eventpipeblock.cpp index a2d561e1cd..fb9d6c721e 100644 --- a/src/vm/eventpipeblock.cpp +++ b/src/vm/eventpipeblock.cpp @@ -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)); diff --git a/src/vm/eventpipeblock.h b/src/vm/eventpipeblock.h index e7e9516fe5..1ce54dedb3 100644 --- a/src/vm/eventpipeblock.h +++ b/src/vm/eventpipeblock.h @@ -96,6 +96,7 @@ struct EventPipeEventHeader DWORD SequenceNumber; ULONGLONG ThreadId; ULONGLONG CaptureThreadId; + DWORD CaptureProcNumber; DWORD StackId; LARGE_INTEGER TimeStamp; GUID ActivityId; diff --git a/src/vm/eventpipebuffer.cpp b/src/vm/eventpipebuffer.cpp index 913fc57fcb..69eec1e268 100644 --- a/src/vm/eventpipebuffer.cpp +++ b/src/vm/eventpipebuffer.cpp @@ -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() diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp index 84512b50fd..b6c9f01df1 100644 --- a/src/vm/eventpipeconfiguration.cpp +++ b/src/vm/eventpipeconfiguration.cpp @@ -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 diff --git a/src/vm/eventpipeeventinstance.cpp b/src/vm/eventpipeeventinstance.cpp index 19ce26919b..5b214a13b3 100644 --- a/src/vm/eventpipeeventinstance.cpp +++ b/src/vm/eventpipeeventinstance.cpp @@ -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 diff --git a/src/vm/eventpipeeventinstance.h b/src/vm/eventpipeeventinstance.h index 2ecb1118b6..a7fd4975f8 100644 --- a/src/vm/eventpipeeventinstance.h +++ b/src/vm/eventpipeeventinstance.h @@ -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; diff --git a/src/vm/eventpipeinternal.cpp b/src/vm/eventpipeinternal.cpp index 093d1620c8..90c51d46ab 100644 --- a/src/vm/eventpipeinternal.cpp +++ b/src/vm/eventpipeinternal.cpp @@ -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, diff --git a/src/vm/eventpipeinternal.h b/src/vm/eventpipeinternal.h index 2e95657658..ab280c357d 100644 --- a/src/vm/eventpipeinternal.h +++ b/src/vm/eventpipeinternal.h @@ -46,6 +46,7 @@ public: //! static UINT64 QCALLTYPE Enable( __in_z LPCWSTR outputFile, + EventPipeSerializationFormat format, UINT32 circularBufferSizeInMB, EventPipeProviderConfiguration *pProviders, UINT32 numProviders); diff --git a/src/vm/eventpipeprotocolhelper.cpp b/src/vm/eventpipeprotocolhelper.cpp index 00de406dd4..de5d1df105 100644 --- a/src/vm/eventpipeprotocolhelper.cpp +++ b/src/vm/eventpipeprotocolhelper.cpp @@ -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) diff --git a/src/vm/eventpipeprotocolhelper.h b/src/vm/eventpipeprotocolhelper.h index 2961b41726..743df5e600 100644 --- a/src/vm/eventpipeprotocolhelper.h +++ b/src/vm/eventpipeprotocolhelper.h @@ -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); |