summaryrefslogtreecommitdiff
path: root/src/vm
diff options
context:
space:
mode:
authorNoah Falk <noahfalk@users.noreply.github.com>2019-06-21 15:27:21 -0700
committerGitHub <noreply@github.com>2019-06-21 15:27:21 -0700
commit961e8d7bd1bdd058ee5f8f34937e9f3f9d80b65b (patch)
tree06c18fd142f826966f051c908252089e6e5ec55b /src/vm
parent205e01fc5020f597ee69643c24fd56268cdf1b50 (diff)
downloadcoreclr-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.cpp24
-rw-r--r--src/vm/eventpipe.h22
-rw-r--r--src/vm/eventpipeblock.cpp9
-rw-r--r--src/vm/eventpipeblock.h1
-rw-r--r--src/vm/eventpipebuffer.cpp2
-rw-r--r--src/vm/eventpipeconfiguration.cpp1
-rw-r--r--src/vm/eventpipeeventinstance.cpp3
-rw-r--r--src/vm/eventpipeeventinstance.h16
-rw-r--r--src/vm/eventpipeinternal.cpp13
-rw-r--r--src/vm/eventpipeinternal.h1
-rw-r--r--src/vm/eventpipeprotocolhelper.cpp17
-rw-r--r--src/vm/eventpipeprotocolhelper.h3
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);