Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Add support for the NetTrace EventPipe file format
Browse files Browse the repository at this point in the history
Right now the new format is not on by default, but it can be enabled using COMPlus_EventPipeNetTraceFormat = 1 for testing purposes. The plan to have a follow up PR that will add shipping configuration mechanisms and change the default setting.

See the documentation in the PerfView repo for more details about the format. At a glance the goal is to create a format that is more efficient to produce, has a smaller on disk size, and offers enhanced functionality in a few areas:
a) 64 bit thread id support
b) Detection of dropped events via sequence numbers
c) Better support for extracting subsets of the file

Together with the change there was also some refactoring of the EventPipeBufferManager and EventPipeThread.

This change addresses (at least in part) the following issues:
#19688, #23414, #24188, #20751, #20555, #21827, #24852, #25046
  • Loading branch information
noahfalk committed Jun 10, 2019
1 parent 7a44fb1 commit 835836c
Show file tree
Hide file tree
Showing 34 changed files with 2,577 additions and 848 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal static class EventPipeController
// Miscellaneous constants.
private const string DefaultAppName = "app";
private const string NetPerfFileExtension = ".netperf";
private const string NetTraceFileExtension = ".nettrace";
private const uint DefaultCircularBufferMB = 256; // MB (PerfView and dotnet-trace default)
private const char ProviderConfigDelimiter = ',';
private const char ConfigComponentDelimiter = ':';
Expand Down Expand Up @@ -87,7 +88,8 @@ private static EventPipeConfiguration BuildConfigFromEnvironment()

private static string BuildTraceFileName()
{
return GetAppName() + "." + Interop.GetCurrentProcessId().ToString() + NetPerfFileExtension;
return GetAppName() + "." + Interop.GetCurrentProcessId().ToString() +
((Config_NetTraceFormat > 0) ? NetTraceFileExtension : NetPerfFileExtension);
}

private static string GetAppName()
Expand Down Expand Up @@ -180,6 +182,20 @@ private static int Config_EnableEventPipe
}
}

private static int Config_NetTraceFormat
{
get
{
string? stringValue = CompatibilitySwitch.GetValueInternal("EventPipeNetTraceFormat");
if ((stringValue == null) || (!int.TryParse(stringValue, out int value)))
{
value = -1; // Indicates no value (or is illegal)
}

return value;
}
}

private static string? Config_EventPipeConfig => CompatibilitySwitch.GetValueInternal("EventPipeConfig");

private static uint Config_EventPipeCircularMB
Expand Down
2 changes: 1 addition & 1 deletion src/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *
// initialize our local copy from the marshaled target Thread instance
ZeroMemory (threadData, sizeof(DacpThreadData));
threadData->corThreadId = thread->m_ThreadId;
threadData->osThreadId = thread->m_OSThreadId;
threadData->osThreadId = (DWORD)thread->m_OSThreadId;
threadData->state = thread->m_State;
threadData->preemptiveGCDisabled = thread->m_fPreemptiveGCDisabled;
threadData->allocContextPtr = TO_CDADDR(thread->m_alloc_context.alloc_ptr);
Expand Down
1 change: 1 addition & 0 deletions src/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_AllowDComReflection, W("AllowDComReflection"),
// EventPipe
//
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableEventPipe, W("EnableEventPipe"), 0, "Enable/disable event pipe. Non-zero values enable tracing.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeNetTraceFormat, W("EventPipeNetTraceFormat"), 0, "Enable/disable using the newer nettrace file format.")
RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeOutputPath, W("EventPipeOutputPath"), "The full path excluding file name for the trace file that will be written when COMPlus_EnableEventPipe=1")
RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeConfig, W("EventPipeConfig"), "Configuration for EventPipe.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeRundown, W("EventPipeRundown"), 1, "Enable/disable eventpipe rundown.")
Expand Down
11 changes: 11 additions & 0 deletions src/pal/inc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,17 @@ CreateThread(
IN DWORD dwCreationFlags,
OUT LPDWORD lpThreadId);

PALIMPORT
HANDLE
PALAPI
PAL_CreateThread64(
IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
IN DWORD dwStackSize,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN DWORD dwCreationFlags,
OUT SIZE_T* pThreadId);

PALIMPORT
PAL_NORETURN
VOID
Expand Down
4 changes: 2 additions & 2 deletions src/pal/src/include/pal/thread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace CorUnix
LPVOID lpParameter,
DWORD dwCreationFlags,
PalThreadType eThreadType,
LPDWORD lpThreadId,
SIZE_T* pThreadId,
HANDLE *phThread
);

Expand Down Expand Up @@ -215,7 +215,7 @@ namespace CorUnix
LPVOID,
DWORD,
PalThreadType,
LPDWORD,
SIZE_T*,
HANDLE*
);

Expand Down
4 changes: 3 additions & 1 deletion src/pal/src/synchmgr/synchmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1486,18 +1486,20 @@ namespace CorUnix
}

HANDLE hWorkerThread = NULL;
SIZE_T osThreadId = 0;
palErr = InternalCreateThread(pthrCurrent,
NULL,
0,
&WorkerThread,
(PVOID)pSynchManager,
0,
PalWorkerThread,
&pSynchManager->m_dwWorkerThreadTid,
&osThreadId,
&hWorkerThread);

if (NO_ERROR == palErr)
{
pSynchManager->m_dwWorkerThreadTid = (DWORD)osThreadId;
palErr = InternalGetThreadDataFromHandle(pthrCurrent,
hWorkerThread,
0,
Expand Down
6 changes: 3 additions & 3 deletions src/pal/src/thread/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,7 @@ class PAL_RuntimeStartupHelper
PAL_ERROR pe = NO_ERROR;
BOOL ret;
UnambiguousProcessDescriptor unambiguousProcessDescriptor;
SIZE_T osThreadId = 0;

#ifdef __APPLE__
if (lpApplicationGroupId != NULL)
Expand Down Expand Up @@ -1734,7 +1735,6 @@ class PAL_RuntimeStartupHelper

// Add a reference for the thread handler
AddRef();

pe = InternalCreateThread(
pThread,
NULL,
Expand All @@ -1743,7 +1743,7 @@ class PAL_RuntimeStartupHelper
this,
0,
UserCreatedThread,
&m_threadId,
&osThreadId,
&m_threadHandle);

if (NO_ERROR != pe)
Expand All @@ -1752,7 +1752,7 @@ class PAL_RuntimeStartupHelper
Release();
goto exit;
}

m_threadId = (DWORD)osThreadId;
exit:
return pe;
}
Expand Down
70 changes: 64 additions & 6 deletions src/pal/src/thread/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ CreateThread(
dwCreationFlags, lpThreadId);

pThread = InternalGetCurrentThread();

SIZE_T osThreadId = 0;
palError = InternalCreateThread(
pThread,
lpThreadAttributes,
Expand All @@ -519,21 +519,79 @@ CreateThread(
lpParameter,
dwCreationFlags,
UserCreatedThread,
lpThreadId,
&osThreadId,
&hNewThread
);

if (NO_ERROR != palError)
{
pThread->SetLastError(palError);
}

if(lpThreadId != nullptr)
{
*lpThreadId = (DWORD)osThreadId;
}
LOGEXIT("CreateThread returns HANDLE %p\n", hNewThread);
PERF_EXIT(CreateThread);

return hNewThread;
}

/*++
Function:
PAL_CreateThread64
Similar to CreateThread but passes out a 64 bit thread id on platforms which use one.
Note:
lpThreadAttributes could be ignored.
See MSDN doc.
--*/
HANDLE
PALAPI
PAL_CreateThread64(
IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
IN DWORD dwStackSize,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN DWORD dwCreationFlags,
OUT SIZE_T* pThreadId)
{
PAL_ERROR palError;
CPalThread *pThread;
HANDLE hNewThread = NULL;

PERF_ENTRY(PAL_CreateThread64);
ENTRY("PAL_CreateThread64(lpThreadAttr=%p, dwStackSize=%u, lpStartAddress=%p, "
"lpParameter=%p, dwFlags=%#x, pThreadId=%p)\n",
lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter,
dwCreationFlags, pThreadId);

pThread = InternalGetCurrentThread();
palError = InternalCreateThread(
pThread,
lpThreadAttributes,
dwStackSize,
lpStartAddress,
lpParameter,
dwCreationFlags,
UserCreatedThread,
pThreadId,
&hNewThread
);

if (NO_ERROR != palError)
{
pThread->SetLastError(palError);
}

LOGEXIT("PAL_CreateThread64 returns HANDLE %p\n", hNewThread);
PERF_EXIT(PAL_CreateThread64);

return hNewThread;
}

PAL_ERROR
CorUnix::InternalCreateThread(
CPalThread *pThread,
Expand All @@ -543,7 +601,7 @@ CorUnix::InternalCreateThread(
LPVOID lpParameter,
DWORD dwCreationFlags,
PalThreadType eThreadType,
LPDWORD lpThreadId,
SIZE_T* pThreadId,
HANDLE *phThread
)
{
Expand Down Expand Up @@ -825,9 +883,9 @@ CorUnix::InternalCreateThread(
//
*phThread = hNewThread;

if (NULL != lpThreadId)
if (NULL != pThreadId)
{
*lpThreadId = pNewThread->GetThreadId();
*pThreadId = pNewThread->GetThreadId();
}
}
else
Expand Down
1 change: 1 addition & 0 deletions src/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ set(VM_SOURCES_WKS
eventpipemetadatagenerator.cpp
eventpipeprotocolhelper.cpp
eventpipeprovider.cpp
eventpipethread.cpp
eventpipebuffer.cpp
eventpipebuffermanager.cpp
eventpipesession.cpp
Expand Down
13 changes: 10 additions & 3 deletions src/vm/eventpipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,15 @@ EventPipeSessionID EventPipe::Enable(
const EventPipeProviderConfiguration *pProviders,
uint32_t numProviders,
EventPipeSessionType sessionType,
EventPipeSerializationFormat format,
IpcStream *const pStream)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_PREEMPTIVE;
PRECONDITION(format < EventPipeSerializationFormat::Count);
PRECONDITION(circularBufferSizeInMB > 0);
PRECONDITION(numProviders > 0 && pProviders != nullptr);
}
Expand All @@ -295,6 +297,7 @@ EventPipeSessionID EventPipe::Enable(
strOutputPath,
pStream,
sessionType,
format,
circularBufferSizeInMB,
pProviders,
numProviders);
Expand Down Expand Up @@ -478,6 +481,10 @@ void EventPipe::DisableInternal(EventPipeSessionID id, EventPipeProviderCallback
return;
}

// Write a final sequence point to the file now that all events have
// been emitted
pSession->WriteSequencePointUnbuffered();

// Remove the session.
s_config.DeleteSession(pSession);

Expand Down Expand Up @@ -699,7 +706,7 @@ void EventPipe::WriteEventInternal(
// as opposed a a buffer copy here
EventPipeEventInstance instance(
event,
pThread->GetOSThreadId(),
pEventPipeThread->GetOSThreadId(),
pData,
payload.GetSize(),
pActivityId,
Expand All @@ -713,7 +720,7 @@ void EventPipe::WriteEventInternal(
{
_ASSERTE(pRundownSession != nullptr);
if (pRundownSession != nullptr)
pRundownSession->WriteEvent(instance);
pRundownSession->WriteEventUnbuffered(instance, pEventPipeThread);
}
EX_CATCH {}
EX_END_CATCH(SwallowAllExceptions);
Expand Down Expand Up @@ -742,7 +749,7 @@ void EventPipe::WriteEventInternal(
// allowed to set s_pSessions[i] = NULL at any time and that may have occured in between
// the check and the load
if (pSession != nullptr)
pSession->WriteEvent(
pSession->WriteEventBuffered(
pThread,
event,
payload,
Expand Down
5 changes: 4 additions & 1 deletion src/vm/eventpipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct EventPipeProviderConfiguration;
class EventPipeSession;
class IpcStream;
enum class EventPipeSessionType;
enum class EventPipeSerializationFormat;

enum class EventPipeEventLevel
{
Expand Down Expand Up @@ -272,6 +273,8 @@ class EventPipe
friend class EventPipeProvider;

public:
static const uint32_t MaxNumberOfSessions = 64;

// Initialize the event pipe.
static void Initialize();

Expand All @@ -285,6 +288,7 @@ class EventPipe
const EventPipeProviderConfiguration *pProviders,
uint32_t numProviders,
EventPipeSessionType sessionType,
EventPipeSerializationFormat format,
IpcStream *const pStream);

// Disable tracing via the event pipe.
Expand Down Expand Up @@ -406,7 +410,6 @@ class EventPipe
static CrstStatic s_configCrst;
static Volatile<bool> s_tracingInitialized;
static EventPipeConfiguration s_config;
static const uint32_t MaxNumberOfSessions = 64;
static VolatilePtr<EventPipeSession> s_pSessions[MaxNumberOfSessions];
static EventPipeEventSource *s_pEventSource;
static HANDLE s_fileSwitchTimerHandle;
Expand Down
Loading

0 comments on commit 835836c

Please sign in to comment.