summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs12
-rw-r--r--src/debug/debug-pal/CMakeLists.txt2
-rw-r--r--src/debug/debug-pal/unix/diagnosticsipc.cpp142
-rw-r--r--src/debug/debug-pal/win/diagnosticsipc.cpp142
-rw-r--r--src/debug/inc/diagnosticsipc.h68
-rw-r--r--src/inc/stresslog.h2
-rw-r--r--src/pal/inc/pal.h11
-rw-r--r--src/pal/src/thread/process.cpp54
-rw-r--r--src/vm/CMakeLists.txt9
-rw-r--r--src/vm/ceemain.cpp3
-rw-r--r--src/vm/common.h1
-rw-r--r--src/vm/diagnosticserver.cpp171
-rw-r--r--src/vm/diagnosticserver.h58
-rw-r--r--src/vm/diagnosticsprotocol.h54
-rw-r--r--src/vm/eventpipe.cpp428
-rw-r--r--src/vm/eventpipe.h326
-rw-r--r--src/vm/eventpipeconfiguration.cpp120
-rw-r--r--src/vm/eventpipeconfiguration.h25
-rw-r--r--src/vm/eventpipeeventinstance.h2
-rw-r--r--src/vm/eventpipeeventsource.cpp1
-rw-r--r--src/vm/eventpipefile.cpp9
-rw-r--r--src/vm/eventpipeinternal.cpp270
-rw-r--r--src/vm/eventpipeinternal.h107
-rw-r--r--src/vm/eventpipeprotocolhelper.cpp156
-rw-r--r--src/vm/eventpipeprotocolhelper.h35
-rw-r--r--src/vm/eventpipeprovider.h2
-rw-r--r--src/vm/eventpipesession.cpp226
-rw-r--r--src/vm/eventpipesession.h74
-rw-r--r--src/vm/eventpipesessionprovider.cpp195
-rw-r--r--src/vm/eventpipesessionprovider.h81
-rw-r--r--src/vm/fastserializer.cpp125
-rw-r--r--src/vm/fastserializer.h71
-rw-r--r--src/vm/mscorlib.cpp2
33 files changed, 1996 insertions, 988 deletions
diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs
index 1a5de88bd1..9f05540610 100644
--- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs
+++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.cs
@@ -196,9 +196,9 @@ namespace System.Diagnostics.Tracing
s_sessionID = EventPipeInternal.Enable(
configuration.OutputFile,
configuration.CircularBufferSizeInMB,
- configuration.ProfilerSamplingRateInNanoseconds,
+ (ulong)configuration.ProfilerSamplingRateInNanoseconds,
providers,
- providers.Length,
+ (uint)providers.Length,
configuration.MultiFileTraceLengthInSeconds);
}
@@ -214,7 +214,13 @@ namespace System.Diagnostics.Tracing
// These PInvokes are used by the configuration APIs to interact with EventPipe.
//
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- internal static extern UInt64 Enable(string outputFile, uint circularBufferSizeInMB, long profilerSamplingRateInNanoseconds, EventPipeProviderConfiguration[] providers, int numProviders, ulong multiFileTraceLengthInSeconds);
+ internal static extern UInt64 Enable(
+ string outputFile,
+ uint circularBufferSizeInMB,
+ ulong profilerSamplingRateInNanoseconds,
+ EventPipeProviderConfiguration[] providers,
+ uint numProviders,
+ ulong multiFileTraceLengthInSeconds);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
internal static extern void Disable(UInt64 sessionID);
diff --git a/src/debug/debug-pal/CMakeLists.txt b/src/debug/debug-pal/CMakeLists.txt
index 83e400c28f..c1b5b443a9 100644
--- a/src/debug/debug-pal/CMakeLists.txt
+++ b/src/debug/debug-pal/CMakeLists.txt
@@ -11,6 +11,7 @@ if(WIN32)
include_directories(../../inc) #needed for warning control
set(TWO_WAY_PIPE_SOURCES
+ win/diagnosticsipc.cpp
win/twowaypipe.cpp
win/processdescriptor.cpp
)
@@ -24,6 +25,7 @@ if(CLR_CMAKE_PLATFORM_UNIX)
add_definitions(-D_POSIX_C_SOURCE=200809L)
set(TWO_WAY_PIPE_SOURCES
+ unix/diagnosticsipc.cpp
unix/twowaypipe.cpp
unix/processdescriptor.cpp
)
diff --git a/src/debug/debug-pal/unix/diagnosticsipc.cpp b/src/debug/debug-pal/unix/diagnosticsipc.cpp
new file mode 100644
index 0000000000..182dff01be
--- /dev/null
+++ b/src/debug/debug-pal/unix/diagnosticsipc.cpp
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <pal.h>
+#include <pal_assert.h>
+#include <new>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "diagnosticsipc.h"
+#include "processdescriptor.h"
+
+IpcStream::DiagnosticsIpc::DiagnosticsIpc(const int serverSocket, sockaddr_un *const pServerAddress) :
+ _serverSocket(serverSocket),
+ _pServerAddress(new (std::nothrow) sockaddr_un)
+{
+ _ASSERTE(_pServerAddress != nullptr);
+ _ASSERTE(_serverSocket != -1);
+ _ASSERTE(pServerAddress != nullptr);
+
+ if (_pServerAddress == nullptr || pServerAddress == nullptr)
+ return;
+ memcpy(_pServerAddress, pServerAddress, sizeof(sockaddr_un));
+}
+
+IpcStream::DiagnosticsIpc::~DiagnosticsIpc()
+{
+ if (_serverSocket != -1)
+ {
+ const int fSuccessClose = ::close(_serverSocket);
+ _ASSERTE(fSuccessClose != -1); // TODO: Add error handling?
+
+ const int fSuccessUnlink = ::unlink(_pServerAddress->sun_path);
+ _ASSERTE(fSuccessUnlink != -1); // TODO: Add error handling?
+
+ delete _pServerAddress;
+ }
+}
+
+IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const pIpcName, ErrorCallback callback)
+{
+ const int serverSocket = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (serverSocket == -1)
+ {
+ if (callback != nullptr)
+ callback(strerror(errno), errno);
+ _ASSERTE(serverSocket != -1);
+ return nullptr;
+ }
+
+ sockaddr_un serverAddress{};
+ serverAddress.sun_family = AF_UNIX;
+ const ProcessDescriptor pd = ProcessDescriptor::FromCurrentProcess();
+ PAL_GetTransportName(
+ sizeof(serverAddress.sun_path),
+ serverAddress.sun_path,
+ pIpcName,
+ pd.m_Pid,
+ pd.m_ApplicationGroupId,
+ "socket");
+
+ const int fSuccessBind = ::bind(serverSocket, (sockaddr *)&serverAddress, sizeof(serverAddress));
+ if (fSuccessBind == -1)
+ {
+ if (callback != nullptr)
+ callback(strerror(errno), errno);
+ _ASSERTE(fSuccessBind != -1);
+ return nullptr;
+ }
+
+ return new IpcStream::DiagnosticsIpc(serverSocket, &serverAddress);
+}
+
+IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const
+{
+ if (::listen(_serverSocket, /* backlog */ 255) == -1)
+ return nullptr;
+ sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ const int clientSocket = ::accept(_serverSocket, (sockaddr *)&from, &fromlen);
+ if (clientSocket == -1)
+ {
+ if (callback != nullptr)
+ callback(strerror(errno), errno);
+ return nullptr;
+ }
+
+ auto pIpcStream = new (std::nothrow) IpcStream(clientSocket);
+ if (pIpcStream == nullptr && callback != nullptr)
+ callback("Failed to allocate an IpcStream object.", 1);
+ return pIpcStream;
+}
+
+IpcStream::~IpcStream()
+{
+ if (_clientSocket != -1)
+ {
+ const int fSuccessClose = ::close(_clientSocket);
+ _ASSERTE(fSuccessClose != -1);
+ }
+}
+
+bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead) const
+{
+ _ASSERTE(lpBuffer != nullptr);
+
+ const ssize_t ssize = ::recv(_clientSocket, lpBuffer, nBytesToRead, 0);
+ const bool fSuccess = ssize != -1;
+
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ }
+
+ nBytesRead = static_cast<uint32_t>(ssize);
+ return fSuccess;
+}
+
+bool IpcStream::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const
+{
+ _ASSERTE(lpBuffer != nullptr);
+
+ const ssize_t ssize = ::send(_clientSocket, lpBuffer, nBytesToWrite, 0);
+ const bool fSuccess = ssize != -1;
+
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ }
+
+ nBytesWritten = static_cast<uint32_t>(ssize);
+ return fSuccess;
+}
+
+bool IpcStream::Flush() const
+{
+ // fsync - http://man7.org/linux/man-pages/man2/fsync.2.html ???
+ return true;
+}
diff --git a/src/debug/debug-pal/win/diagnosticsipc.cpp b/src/debug/debug-pal/win/diagnosticsipc.cpp
new file mode 100644
index 0000000000..7d9f84e7e5
--- /dev/null
+++ b/src/debug/debug-pal/win/diagnosticsipc.cpp
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <assert.h>
+#include <new>
+#include <stdio.h>
+#include "diagnosticsipc.h"
+
+IpcStream::DiagnosticsIpc::DiagnosticsIpc(const char(&namedPipeName)[MaxNamedPipeNameLength])
+{
+ memcpy(_pNamedPipeName, namedPipeName, sizeof(_pNamedPipeName));
+}
+
+IpcStream::DiagnosticsIpc::~DiagnosticsIpc()
+{
+}
+
+IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const pIpcName, ErrorCallback callback)
+{
+ assert(pIpcName != nullptr);
+ if (pIpcName == nullptr)
+ return nullptr;
+
+ char namedPipeName[MaxNamedPipeNameLength]{};
+ const int nCharactersWritten = sprintf_s(
+ namedPipeName,
+ sizeof(namedPipeName),
+ "\\\\.\\pipe\\%s-%d",
+ pIpcName,
+ ::GetCurrentProcessId());
+
+ if (nCharactersWritten == -1)
+ {
+ if (callback != nullptr)
+ callback("Failed to generate the named pipe name", nCharactersWritten);
+ assert(nCharactersWritten != -1);
+ return nullptr;
+ }
+
+ return new IpcStream::DiagnosticsIpc(namedPipeName);
+}
+
+IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const
+{
+ const uint32_t nInBufferSize = 16 * 1024;
+ const uint32_t nOutBufferSize = 16 * 1024;
+ HANDLE hPipe = ::CreateNamedPipeA(
+ _pNamedPipeName, // pipe name
+ PIPE_ACCESS_DUPLEX/* | FILE_FLAG_OVERLAPPED*/, // read/write access
+ PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, // message type pipe, message-read and blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ nOutBufferSize, // output buffer size
+ nInBufferSize, // input buffer size
+ 0, // default client time-out
+ NULL); // default security attribute
+
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ if (callback != nullptr)
+ callback("Failed to create an instance of a named pipe.", ::GetLastError());
+ return nullptr;
+ }
+
+ const BOOL fSuccess = ::ConnectNamedPipe(hPipe, NULL) != 0;
+ const DWORD errorCode = ::GetLastError();
+ if (!fSuccess && (errorCode != ERROR_PIPE_CONNECTED))
+ {
+ if (callback != nullptr)
+ callback("Failed to wait for a client process to connect.", errorCode);
+ return nullptr;
+ }
+
+ auto pIpcStream = new (std::nothrow) IpcStream(hPipe);
+ if (pIpcStream == nullptr && callback != nullptr)
+ callback("Failed to allocate an IpcStream object.", 1);
+ return pIpcStream;
+}
+
+IpcStream::~IpcStream()
+{
+ if (_hPipe != INVALID_HANDLE_VALUE)
+ {
+ const BOOL fSuccessDisconnectNamedPipe = ::DisconnectNamedPipe(_hPipe);
+ assert(fSuccessDisconnectNamedPipe != 0);
+
+ const BOOL fSuccessCloseHandle = ::CloseHandle(_hPipe);
+ assert(CloseHandle != 0);
+ }
+}
+
+bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead) const
+{
+ assert(lpBuffer != nullptr);
+
+ DWORD nNumberOfBytesRead = 0;
+ const bool fSuccess = ::ReadFile(
+ _hPipe, // handle to pipe
+ lpBuffer, // buffer to receive data
+ nBytesToRead, // size of buffer
+ &nNumberOfBytesRead, // number of bytes read
+ NULL) != 0; // not overlapped I/O
+
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ }
+
+ nBytesRead = static_cast<uint32_t>(nNumberOfBytesRead);
+ return fSuccess;
+}
+
+bool IpcStream::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const
+{
+ assert(lpBuffer != nullptr);
+
+ DWORD nNumberOfBytesWritten = 0;
+ const bool fSuccess = ::WriteFile(
+ _hPipe, // handle to pipe
+ lpBuffer, // buffer to write from
+ nBytesToWrite, // number of bytes to write
+ &nNumberOfBytesWritten, // number of bytes written
+ NULL) != 0; // not overlapped I/O
+
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ }
+
+ nBytesWritten = static_cast<uint32_t>(nNumberOfBytesWritten);
+ return fSuccess;
+}
+
+bool IpcStream::Flush() const
+{
+ const bool fSuccess = ::FlushFileBuffers(_hPipe) != 0;
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ }
+ return fSuccess;
+}
diff --git a/src/debug/inc/diagnosticsipc.h b/src/debug/inc/diagnosticsipc.h
new file mode 100644
index 0000000000..81789f0803
--- /dev/null
+++ b/src/debug/inc/diagnosticsipc.h
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __DIAGNOSTICS_IPC_H__
+#define __DIAGNOSTICS_IPC_H__
+
+#include <stdint.h>
+
+#ifdef FEATURE_PAL
+ struct sockaddr_un;
+#else
+ #include <Windows.h>
+#endif /* FEATURE_PAL */
+
+typedef void (*ErrorCallback)(const char *szMessage, uint32_t code);
+
+class IpcStream final
+{
+public:
+ ~IpcStream();
+ bool Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead) const;
+ bool Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const;
+ bool Flush() const;
+
+ class DiagnosticsIpc final
+ {
+ public:
+ static DiagnosticsIpc *Create(const char *const pIpcName, ErrorCallback callback = nullptr);
+ ~DiagnosticsIpc();
+ IpcStream *Accept(ErrorCallback callback = nullptr) const;
+
+ private:
+
+#ifdef FEATURE_PAL
+ DiagnosticsIpc(const int serverSocket, sockaddr_un *const pServerAddress);
+ const int _serverSocket = -1;
+ sockaddr_un *const _pServerAddress;
+#else
+ static const uint32_t MaxNamedPipeNameLength = 256;
+ DiagnosticsIpc(const char(&namedPipeName)[MaxNamedPipeNameLength]);
+ char _pNamedPipeName[MaxNamedPipeNameLength]; // https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createnamedpipea
+#endif /* FEATURE_PAL */
+
+ DiagnosticsIpc() = delete;
+ DiagnosticsIpc(const DiagnosticsIpc &src) = delete;
+ DiagnosticsIpc(DiagnosticsIpc &&src) = delete;
+ DiagnosticsIpc &operator=(const DiagnosticsIpc &rhs) = delete;
+ DiagnosticsIpc &&operator=(DiagnosticsIpc &&rhs) = delete;
+ };
+
+private:
+#ifdef FEATURE_PAL
+ int _clientSocket = -1;
+ IpcStream(int clientSocket) : _clientSocket(clientSocket) {}
+#else
+ HANDLE _hPipe = INVALID_HANDLE_VALUE;
+ IpcStream(HANDLE hPipe) : _hPipe(hPipe) {}
+#endif /* FEATURE_PAL */
+
+ IpcStream() = delete;
+ IpcStream(const IpcStream &src) = delete;
+ IpcStream(IpcStream &&src) = delete;
+ IpcStream &operator=(const IpcStream &rhs) = delete;
+ IpcStream &&operator=(IpcStream &&rhs) = delete;
+};
+
+#endif // __DIAGNOSTICS_IPC_H__
diff --git a/src/inc/stresslog.h b/src/inc/stresslog.h
index dd8c029b0a..8f98f9a7b2 100644
--- a/src/inc/stresslog.h
+++ b/src/inc/stresslog.h
@@ -127,7 +127,7 @@
LOG((facility, level, msg, data1, data2, data3, data4, data5, data6, data7)); \
} while(0)
-#define STRESS_LOG_COND0(facility, level, msg) do { \
+#define STRESS_LOG_COND0(facility, level, cond, msg) do { \
if (StressLog::LogOn(facility, level) && (cond)) \
StressLog::LogMsg(level, facility, 0, msg); \
LOG((facility, level, msg)); \
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
index 26c9e3f6d8..1be000ce8a 100644
--- a/src/pal/inc/pal.h
+++ b/src/pal/inc/pal.h
@@ -480,6 +480,17 @@ static const int MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH = MAX_PATH;
PALIMPORT
VOID
PALAPI
+PAL_GetTransportName(
+ const int MAX_TRANSPORT_NAME_LENGTH,
+ OUT char *name,
+ IN const char *prefix,
+ IN DWORD id,
+ IN const char *applicationGroupId,
+ IN const char *suffix);
+
+PALIMPORT
+VOID
+PALAPI
PAL_GetTransportPipeName(
OUT char *name,
IN DWORD id,
diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp
index 5615036806..f7618cbdb9 100644
--- a/src/pal/src/thread/process.cpp
+++ b/src/pal/src/thread/process.cpp
@@ -1549,7 +1549,8 @@ static uint64_t HashSemaphoreName(uint64_t a, uint64_t b)
#define HashSemaphoreName(a,b) a,b
#endif
-static const char* PipeNameFormat = "clr-debug-pipe-%d-%llu-%s";
+static const char *const TwoWayNamedPipePrefix = "clr-debug-pipe";
+static const char* IpcNameFormat = "%s-%d-%llu-%s";
class PAL_RuntimeStartupHelper
{
@@ -2288,14 +2289,16 @@ GetProcessIdDisambiguationKey(DWORD processId, UINT64 *disambiguationKey)
/*++
Function:
- PAL_GetTransportPipeName
+ PAL_GetTransportName
- Builds the transport pipe names from the process id.
+ Builds the transport IPC names from the process id.
--*/
VOID
PALAPI
-PAL_GetTransportPipeName(
+PAL_GetTransportName(
+ const int MAX_TRANSPORT_NAME_LENGTH,
OUT char *name,
+ IN const char *prefix,
IN DWORD id,
IN const char *applicationGroupId,
IN const char *suffix)
@@ -2305,7 +2308,7 @@ PAL_GetTransportPipeName(
UINT64 disambiguationKey = 0;
PathCharString formatBufferString;
BOOL ret = GetProcessIdDisambiguationKey(id, &disambiguationKey);
- char *formatBuffer = formatBufferString.OpenStringBuffer(MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH-1);
+ char *formatBuffer = formatBufferString.OpenStringBuffer(MAX_TRANSPORT_NAME_LENGTH-1);
if (formatBuffer == nullptr)
{
ERROR("Out Of Memory");
@@ -2337,9 +2340,9 @@ PAL_GetTransportPipeName(
}
// Verify the size of the path won't exceed maximum allowed size
- if (formatBufferString.GetCount() >= MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH)
+ if (formatBufferString.GetCount() >= MAX_TRANSPORT_NAME_LENGTH)
{
- ERROR("GetApplicationContainerFolder returned a path that was larger than MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH");
+ ERROR("GetApplicationContainerFolder returned a path that was larger than MAX_TRANSPORT_NAME_LENGTH");
return;
}
}
@@ -2347,27 +2350,50 @@ PAL_GetTransportPipeName(
#endif // __APPLE__
{
// Get a temp file location
- dwRetVal = ::GetTempPathA(MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH, formatBuffer);
+ dwRetVal = ::GetTempPathA(MAX_TRANSPORT_NAME_LENGTH, formatBuffer);
if (dwRetVal == 0)
{
ERROR("GetTempPath failed (0x%08x)", ::GetLastError());
return;
}
- if (dwRetVal > MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH)
+ if (dwRetVal > MAX_TRANSPORT_NAME_LENGTH)
{
- ERROR("GetTempPath returned a path that was larger than MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH");
+ ERROR("GetTempPath returned a path that was larger than MAX_TRANSPORT_NAME_LENGTH");
return;
}
}
- if (strncat_s(formatBuffer, MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH, PipeNameFormat, strlen(PipeNameFormat)) == STRUNCATE)
+ if (strncat_s(formatBuffer, MAX_TRANSPORT_NAME_LENGTH, IpcNameFormat, strlen(IpcNameFormat)) == STRUNCATE)
{
- ERROR("TransportPipeName was larger than MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH");
+ ERROR("TransportPipeName was larger than MAX_TRANSPORT_NAME_LENGTH");
return;
}
- int chars = snprintf(name, MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH, formatBuffer, id, disambiguationKey, suffix);
- _ASSERTE(chars > 0 && chars < MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH);
+ int chars = snprintf(name, MAX_TRANSPORT_NAME_LENGTH, formatBuffer, prefix, id, disambiguationKey, suffix);
+ _ASSERTE(chars > 0 && chars < MAX_TRANSPORT_NAME_LENGTH);
+}
+
+/*++
+ Function:
+ PAL_GetTransportPipeName
+
+ Builds the transport pipe names from the process id.
+--*/
+VOID
+PALAPI
+PAL_GetTransportPipeName(
+ OUT char *name,
+ IN DWORD id,
+ IN const char *applicationGroupId,
+ IN const char *suffix)
+{
+ PAL_GetTransportName(
+ MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH,
+ name,
+ TwoWayNamedPipePrefix,
+ id,
+ applicationGroupId,
+ suffix);
}
/*++
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index 397f4e2ea5..b7ae17a156 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -306,6 +306,7 @@ set(VM_SOURCES_WKS
comwaithandle.cpp
customattribute.cpp
custommarshalerinfo.cpp
+ diagnosticserver.cpp
dllimportcallback.cpp
eeconfig.cpp
eecontract.cpp
@@ -319,12 +320,15 @@ set(VM_SOURCES_WKS
eventpipeeventsource.cpp
eventpipeblock.cpp
eventpipefile.cpp
+ eventpipeinternal.cpp
eventpipejsonfile.cpp
eventpipemetadatagenerator.cpp
+ eventpipeprotocolhelper.cpp
eventpipeprovider.cpp
eventpipebuffer.cpp
eventpipebuffermanager.cpp
eventpipesession.cpp
+ eventpipesessionprovider.cpp
eventstore.cpp
fastserializer.cpp
fcall.cpp
@@ -421,6 +425,8 @@ set(VM_HEADERS_WKS
comwaithandle.h
customattribute.h
custommarshalerinfo.h
+ diagnosticserver.h
+ diagnosticsprotocol.h
dllimportcallback.h
eeconfig.h
eecontract.h
@@ -439,10 +445,13 @@ set(VM_HEADERS_WKS
eventpipeeventinstance.h
eventpipeeventsource.h
eventpipefile.h
+ eventpipeinternal.h
eventpipejsonfile.h
eventpipemetadatagenerator.h
+ eventpipeprotocolhelper.h
eventpipeprovider.h
eventpipesession.h
+ eventpipesessionprovider.h
eventstore.hpp
fastserializer.h
fcall.h
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp
index e5267cf131..1b85649d67 100644
--- a/src/vm/ceemain.cpp
+++ b/src/vm/ceemain.cpp
@@ -215,6 +215,7 @@
#include "perfmap.h"
#endif
+#include "diagnosticserver.h"
#include "eventpipe.h"
#ifndef FEATURE_PAL
@@ -667,6 +668,7 @@ void EEStartupHelper(COINITIEE fFlags)
#ifdef FEATURE_PERFTRACING
// Initialize the event pipe.
+ DiagnosticServer::Initialize();
EventPipe::Initialize();
#endif // FEATURE_PERFTRACING
@@ -1462,6 +1464,7 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
#ifdef FEATURE_PERFTRACING
// Shutdown the event pipe.
EventPipe::Shutdown();
+ DiagnosticServer::Shutdown();
#endif // FEATURE_PERFTRACING
#if defined(FEATURE_COMINTEROP)
diff --git a/src/vm/common.h b/src/vm/common.h
index 9050ae7c63..2a91e77220 100644
--- a/src/vm/common.h
+++ b/src/vm/common.h
@@ -75,7 +75,6 @@
#include <stdlib.h>
#include <wchar.h>
#include <objbase.h>
-#include <stddef.h>
#include <float.h>
#include <math.h>
#include <time.h>
diff --git a/src/vm/diagnosticserver.cpp b/src/vm/diagnosticserver.cpp
new file mode 100644
index 0000000000..c0e11d100f
--- /dev/null
+++ b/src/vm/diagnosticserver.cpp
@@ -0,0 +1,171 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "diagnosticserver.h"
+#include "diagnosticsipc.h"
+#include "eventpipeprotocolhelper.h"
+
+#ifdef FEATURE_PAL
+#include "pal.h"
+#endif // FEATURE_PAL
+
+#ifdef FEATURE_PERFTRACING
+
+static DWORD WINAPI DiagnosticsServerThread(LPVOID lpThreadParameter)
+{
+ CONTRACTL
+ {
+ // TODO: Maybe this should not throw.
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(lpThreadParameter != nullptr);
+ }
+ CONTRACTL_END;
+
+ auto pIpc = reinterpret_cast<IpcStream::DiagnosticsIpc *>(lpThreadParameter);
+ if (pIpc == nullptr)
+ {
+ STRESS_LOG0(LF_STARTUP, LL_ERROR,"Diagnostics IPC listener was undefined\n");
+ return 1;
+ }
+
+#ifdef _DEBUG
+ ErrorCallback LoggingCallback = [](const char *szMessage, uint32_t code) {
+ LOG((LF_REMOTING, LL_WARNING, "warning (%d): %s.\n", code, szMessage));
+ };
+#else
+ ErrorCallback LoggingCallback = nullptr;
+#endif
+
+ while (true)
+ {
+ // FIXME: Ideally this would be something like a std::shared_ptr
+ IpcStream *pStream = pIpc->Accept(LoggingCallback);
+ if (pStream == nullptr)
+ continue;
+
+ // TODO: Read operation should happen in a loop.
+ uint32_t nNumberOfBytesRead = 0;
+ MessageHeader header;
+ bool fSuccess = pStream->Read(&header, sizeof(header), nNumberOfBytesRead);
+ if (!fSuccess || nNumberOfBytesRead != sizeof(header))
+ {
+ delete pStream;
+ continue;
+ }
+
+ // TODO: Dispatch thread worker.
+ switch (header.RequestType)
+ {
+ case DiagnosticMessageType::EnableEventPipe:
+ EventPipeProtocolHelper::EnableFileTracingEventHandler(pStream);
+ break;
+
+ case DiagnosticMessageType::DisableEventPipe:
+ EventPipeProtocolHelper::DisableTracingEventHandler(pStream);
+ break;
+
+ default:
+ LOG((LF_REMOTING, LL_WARNING, "Received unknow request type (%d)\n", header.RequestType));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+bool DiagnosticServer::Initialize()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ bool fSuccess = false;
+
+ EX_TRY
+ {
+ auto ErrorCallback = [](const char *szMessage, uint32_t code) {
+ STRESS_LOG2(
+ LF_STARTUP, // facility
+ LL_ERROR, // level
+ "Failed to create diagnostic IPC: error (%d): %s.\n", // msg
+ code, // data1
+ szMessage); // data2
+ };
+ IpcStream::DiagnosticsIpc *pIpc = IpcStream::DiagnosticsIpc::Create(
+ "dotnetcore-diagnostic", ErrorCallback);
+
+ if (pIpc != nullptr)
+ {
+ DWORD dwThreadId = 0;
+ HANDLE hThread = ::CreateThread( // TODO: Is it correct to have this "lower" level call here?
+ nullptr, // no security attribute
+ 0, // default stack size
+ DiagnosticsServerThread, // thread proc
+ (LPVOID)pIpc, // thread parameter
+ 0, // not suspended
+ &dwThreadId); // returns thread ID
+
+ if (hThread == nullptr)
+ {
+ // Failed to create IPC thread.
+ STRESS_LOG1(
+ LF_STARTUP, // facility
+ LL_ERROR, // level
+ "Failed to create diagnostic server thread (%d).\n", // msg
+ ::GetLastError()); // data1
+ }
+ else
+ {
+ // FIXME: Maybe hold on to the thread to abort/cleanup at exit?
+ ::CloseHandle(hThread);
+
+ // TODO: Add error handling?
+ fSuccess = true;
+ }
+ }
+ }
+ EX_CATCH
+ {
+ // TODO: Should we log anything here?
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return fSuccess;
+}
+
+bool DiagnosticServer::Shutdown()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ bool fSuccess = false;
+
+ EX_TRY
+ {
+ // FIXME: Stop IPC server thread?
+ fSuccess = true;
+ }
+ EX_CATCH
+ {
+ fSuccess = false;
+ // TODO: Should we log anything here?
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return fSuccess;
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/diagnosticserver.h b/src/vm/diagnosticserver.h
new file mode 100644
index 0000000000..95399a2ef8
--- /dev/null
+++ b/src/vm/diagnosticserver.h
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __DIAGNOSTIC_SERVER_H__
+#define __DIAGNOSTIC_SERVER_H__
+
+#include <stdint.h>
+
+#ifdef FEATURE_PERFTRACING // This macro should change to something more generic than performance.
+
+//! TODO: Temp class.
+enum class DiagnosticMessageType : uint32_t
+{
+ ///////////////////////////////////////////////////////////////////////////
+ // Debug = 0
+
+ ///////////////////////////////////////////////////////////////////////////
+ // EventPipe
+ EnableEventPipe = 1024,
+ DisableEventPipe,
+
+ // TODO: Define what else is available on the out-of-proc interface?
+ // GetSessionInfo,
+ // CreateProvider,
+ // DefineEvent,
+ // GetProvider,
+ // DeleteProvider,
+ // EventActivityIdControl,
+ // WriteEvent,
+ // WriteEventData,
+ // GetNextEvent,
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Profiler = 2048
+};
+
+//! TODO: Temp class.
+struct MessageHeader
+{
+ DiagnosticMessageType RequestType;
+ uint32_t Pid;
+};
+
+//! Defines an implementation of a IPC handler that dispatches messages to the runtime.
+class DiagnosticServer final
+{
+public:
+ //! Initialize the event pipe (Creates the EventPipe IPC server).
+ static bool Initialize();
+
+ //! Shutdown the event pipe.
+ static bool Shutdown();
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __DIAGNOSTIC_SERVER_H__
diff --git a/src/vm/diagnosticsprotocol.h b/src/vm/diagnosticsprotocol.h
new file mode 100644
index 0000000000..765977f02a
--- /dev/null
+++ b/src/vm/diagnosticsprotocol.h
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __DIAGNOSTICS_PROTOCOL_H__
+#define __DIAGNOSTICS_PROTOCOL_H__
+
+#ifdef FEATURE_PERFTRACING
+
+template <typename T>
+bool TryParse(uint8_t *&bufferCursor, uint32_t &bufferLen, T &result)
+{
+ static_assert(
+ std::is_integral<T>::value || std::is_same<T, float>::value || std::is_same<T, double>::value,
+ "Can only be instantiated with integral and floating point types.");
+
+ if (bufferLen < sizeof(T))
+ return false;
+ result = *(reinterpret_cast<T *>(bufferCursor));
+ bufferCursor += sizeof(T);
+ bufferLen -= sizeof(T);
+ return true;
+}
+
+template <typename T>
+bool TryParseString(uint8_t *&bufferCursor, uint32_t &bufferLen, const T *&result)
+{
+ static_assert(
+ std::is_same<T, char>::value || std::is_same<T, wchar_t>::value,
+ "Can only be instantiated with char and wchar_t types.");
+
+ uint32_t stringLen = 0;
+ if (!TryParse(bufferCursor, bufferLen, stringLen))
+ return false;
+ if (stringLen == 0)
+ {
+ result = nullptr;
+ return true;
+ }
+ if (stringLen > (bufferLen / sizeof(T)))
+ return false;
+ if ((reinterpret_cast<const T *>(bufferCursor))[stringLen - 1] != 0)
+ return false;
+ result = reinterpret_cast<const T *>(bufferCursor);
+
+ const uint32_t TotalStringLength = stringLen * sizeof(T);
+ bufferCursor += TotalStringLength;
+ bufferLen -= TotalStringLength;
+ return true;
+}
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __DIAGNOSTICS_PROTOCOL_H__
diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp
index 4de0b3c943..634f1d0d69 100644
--- a/src/vm/eventpipe.cpp
+++ b/src/vm/eventpipe.cpp
@@ -8,6 +8,7 @@
#include "eventpipe.h"
#include "eventpipebuffermanager.h"
#include "eventpipeconfiguration.h"
+#include "eventpipesessionprovider.h"
#include "eventpipeevent.h"
#include "eventpipeeventsource.h"
#include "eventpipefile.h"
@@ -26,12 +27,12 @@
CrstStatic EventPipe::s_configCrst;
bool EventPipe::s_tracingInitialized = false;
-EventPipeConfiguration* EventPipe::s_pConfig = NULL;
-EventPipeSession* EventPipe::s_pSession = NULL;
-EventPipeBufferManager* EventPipe::s_pBufferManager = NULL;
+EventPipeConfiguration *EventPipe::s_pConfig = NULL;
+EventPipeSession *EventPipe::s_pSession = NULL;
+EventPipeBufferManager *EventPipe::s_pBufferManager = NULL;
LPCWSTR EventPipe::s_pOutputPath = NULL;
-EventPipeFile* EventPipe::s_pFile = NULL;
-EventPipeEventSource* EventPipe::s_pEventSource = NULL;
+EventPipeFile *EventPipe::s_pFile = NULL;
+EventPipeEventSource *EventPipe::s_pEventSource = NULL;
LPCWSTR EventPipe::s_pCommandLine = NULL;
unsigned long EventPipe::s_nextFileIndex;
HANDLE EventPipe::s_fileSwitchTimerHandle = NULL;
@@ -78,7 +79,7 @@ EventPipeEventPayload::EventPipeEventPayload(EventData *pEventData, unsigned int
m_allocatedData = false;
S_UINT32 tmp_size = S_UINT32(0);
- for (unsigned int i=0; i<m_eventDataCount; i++)
+ for (unsigned int i = 0; i < m_eventDataCount; i++)
{
tmp_size += S_UINT32(m_pEventData[i].Size);
}
@@ -106,7 +107,7 @@ EventPipeEventPayload::~EventPipeEventPayload()
}
CONTRACTL_END;
- if(m_allocatedData && m_pData != NULL)
+ if (m_allocatedData && m_pData != NULL)
{
delete[] m_pData;
m_pData = NULL;
@@ -123,11 +124,11 @@ void EventPipeEventPayload::Flatten()
}
CONTRACTL_END;
- if(m_size > 0)
+ if (m_size > 0)
{
if (!IsFlattened())
{
- BYTE* tmp_pData = new (nothrow) BYTE[m_size];
+ BYTE *tmp_pData = new (nothrow) BYTE[m_size];
if (tmp_pData != NULL)
{
m_allocatedData = true;
@@ -148,26 +149,26 @@ void EventPipeEventPayload::CopyData(BYTE *pDst)
}
CONTRACTL_END;
- if(m_size > 0)
+ if (m_size > 0)
{
- if(IsFlattened())
+ if (IsFlattened())
{
memcpy(pDst, m_pData, m_size);
}
- else if(m_pEventData != NULL)
+ else if (m_pEventData != NULL)
{
unsigned int offset = 0;
- for(unsigned int i=0; i<m_eventDataCount; i++)
+ for (unsigned int i = 0; i < m_eventDataCount; i++)
{
- memcpy(pDst + offset, (BYTE*) m_pEventData[i].Ptr, m_pEventData[i].Size);
+ memcpy(pDst + offset, (BYTE *)m_pEventData[i].Ptr, m_pEventData[i].Size);
offset += m_pEventData[i].Size;
}
}
}
}
-BYTE* EventPipeEventPayload::GetFlatData()
+BYTE *EventPipeEventPayload::GetFlatData()
{
CONTRACTL
{
@@ -222,7 +223,7 @@ void EventPipe::Shutdown()
{
Disable((EventPipeSessionID)s_pSession);
}
- EX_CATCH { }
+ EX_CATCH {}
EX_END_CATCH(SwallowAllExceptions);
// Save pointers to the configuration and buffer manager.
@@ -236,42 +237,48 @@ void EventPipe::Shutdown()
FlushProcessWriteBuffers();
// Free resources.
- delete(pConfig);
- delete(pBufferManager);
- delete(s_pEventSource);
+ delete pConfig;
+ delete pBufferManager;
+ delete s_pEventSource;
s_pEventSource = NULL;
- delete(s_pOutputPath);
+ delete[] s_pOutputPath;
s_pOutputPath = NULL;
// On Windows, this is just a pointer to the return value from
// GetCommandLineW(), so don't attempt to free it.
#ifdef FEATURE_PAL
- delete[](s_pCommandLine);
+ delete[] s_pCommandLine;
s_pCommandLine = NULL;
#endif
}
EventPipeSessionID EventPipe::Enable(
LPCWSTR strOutputPath,
- unsigned int circularBufferSizeInMB,
- EventPipeProviderConfiguration *pProviders,
- int numProviders,
- UINT64 multiFileTraceLengthInSeconds)
+ uint32_t circularBufferSizeInMB,
+ uint64_t profilerSamplingRateInNanoseconds,
+ const EventPipeProviderConfiguration *pProviders,
+ uint32_t numProviders,
+ uint64_t multiFileTraceLengthInSeconds)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
+ PRECONDITION((numProviders == 0) || (numProviders > 0 && pProviders != nullptr));
}
CONTRACTL_END;
+ // Take the lock before enabling tracing.
+ CrstHolder _crst(GetLock());
+
// Create a new session.
+ SampleProfiler::SetSamplingRate((unsigned long)profilerSamplingRateInNanoseconds);
EventPipeSession *pSession = s_pConfig->CreateSession(
(strOutputPath != NULL) ? EventPipeSessionType::File : EventPipeSessionType::Streaming,
circularBufferSizeInMB,
pProviders,
- static_cast<unsigned int>(numProviders),
+ numProviders,
multiFileTraceLengthInSeconds);
// Enable the session.
@@ -286,27 +293,21 @@ EventPipeSessionID EventPipe::Enable(LPCWSTR strOutputPath, EventPipeSession *pS
GC_TRIGGERS;
MODE_ANY;
PRECONDITION(pSession != NULL);
+ PRECONDITION(GetLock()->OwnedByCurrentThread());
}
CONTRACTL_END;
// If tracing is not initialized or is already enabled, bail here.
- if(!s_tracingInitialized || s_pConfig == NULL || s_pConfig->Enabled())
- {
+ if (!s_tracingInitialized || s_pConfig == NULL || s_pConfig->Enabled())
return 0;
- }
// If the state or arguments are invalid, bail here.
- if(pSession == NULL || !pSession->IsValid())
- {
+ if (pSession == NULL || !pSession->IsValid())
return 0;
- }
// Enable the EventPipe EventSource.
s_pEventSource->Enable(pSession);
- // Take the lock before enabling tracing.
- CrstHolder _crst(GetLock());
-
// Initialize the next file index.
s_nextFileIndex = 1;
@@ -342,7 +343,7 @@ EventPipeSessionID EventPipe::Enable(LPCWSTR strOutputPath, EventPipeSession *pS
SampleProfiler::Enable();
// Enable the file switch timer if needed.
- if(s_pSession->GetMultiFileTraceLengthInSeconds() > 0)
+ if (s_pSession->GetMultiFileTraceLengthInSeconds() > 0)
{
CreateFileSwitchTimer();
}
@@ -363,7 +364,7 @@ void EventPipe::Disable(EventPipeSessionID id)
// Only perform the disable operation if the session ID
// matches the current active session.
- if(id != (EventPipeSessionID)s_pSession)
+ if (id != (EventPipeSessionID)s_pSession)
{
return;
}
@@ -374,7 +375,7 @@ void EventPipe::Disable(EventPipeSessionID id)
// Take the lock before disabling tracing.
CrstHolder _crst(GetLock());
- if(s_pConfig != NULL && s_pConfig->Enabled())
+ if (s_pConfig != NULL && s_pConfig->Enabled())
{
// Disable the profiler.
SampleProfiler::Disable();
@@ -399,30 +400,31 @@ void EventPipe::Disable(EventPipeSessionID id)
FlushProcessWriteBuffers();
// Write to the file.
- if(s_pFile != NULL)
+ if (s_pFile != NULL)
{
LARGE_INTEGER disableTimeStamp;
QueryPerformanceCounter(&disableTimeStamp);
s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
- if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeRundown) > 0)
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeRundown) > 0)
{
// Before closing the file, do rundown.
- const unsigned int numRundownProviders = 2;
- EventPipeProviderConfiguration rundownProviders[] =
- {
- { W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL }, // Public provider.
- { W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL } // Rundown provider.
+ const EventPipeProviderConfiguration RundownProviders[] = {
+ {W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL}, // Public provider.
+ {W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose), NULL} // Rundown provider.
};
+
// The circular buffer size doesn't matter because all events are written synchronously during rundown.
- s_pSession = s_pConfig->CreateSession(EventPipeSessionType::File, 1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
+ s_pSession = s_pConfig->CreateSession(
+ EventPipeSessionType::File,
+ 1 /* circularBufferSizeInMB */,
+ RundownProviders,
+ sizeof(RundownProviders) / sizeof(EventPipeProviderConfiguration));
s_pConfig->EnableRundown(s_pSession);
// Ask the runtime to emit rundown events.
- if(g_fEEStarted && !g_fEEShutDown)
- {
+ if (g_fEEStarted && !g_fEEShutDown)
ETW::EnumerationLog::EndRundown();
- }
// Disable the event pipe now that rundown is complete.
s_pConfig->Disable(s_pSession);
@@ -432,7 +434,7 @@ void EventPipe::Disable(EventPipeSessionID id)
s_pSession = NULL;
}
- delete(s_pFile);
+ delete s_pFile;
s_pFile = NULL;
}
@@ -456,7 +458,7 @@ void EventPipe::CreateFileSwitchTimer()
}
CONTRACTL_END
- NewHolder<ThreadpoolMgr::TimerInfoContext> timerContextHolder = new(nothrow) ThreadpoolMgr::TimerInfoContext();
+ NewHolder<ThreadpoolMgr::TimerInfoContext> timerContextHolder = new (nothrow) ThreadpoolMgr::TimerInfoContext();
if (timerContextHolder == NULL)
{
return;
@@ -503,7 +505,7 @@ void EventPipe::DeleteFileSwitchTimer()
}
CONTRACTL_END
- if((s_fileSwitchTimerHandle != NULL) && (ThreadpoolMgr::DeleteTimerQueueTimer(s_fileSwitchTimerHandle, NULL)))
+ if ((s_fileSwitchTimerHandle != NULL) && (ThreadpoolMgr::DeleteTimerQueueTimer(s_fileSwitchTimerHandle, NULL)))
{
s_fileSwitchTimerHandle = NULL;
}
@@ -520,25 +522,23 @@ void WINAPI EventPipe::SwitchToNextFileTimerCallback(PVOID parameter, BOOLEAN ti
}
CONTRACTL_END;
-
// Take the lock control lock to make sure that tracing isn't disabled during this operation.
CrstHolder _crst(GetLock());
// Make sure that we should actually switch files.
UINT64 multiFileTraceLengthInSeconds = s_pSession->GetMultiFileTraceLengthInSeconds();
- if(!Enabled() || s_pSession->GetSessionType() != EventPipeSessionType::File || multiFileTraceLengthInSeconds == 0)
+ if (!Enabled() || s_pSession->GetSessionType() != EventPipeSessionType::File || multiFileTraceLengthInSeconds == 0)
{
return;
}
GCX_PREEMP();
- if(CLRGetTickCount64() > (s_lastFileSwitchTime + (multiFileTraceLengthInSeconds * 1000)))
+ if (CLRGetTickCount64() > (s_lastFileSwitchTime + (multiFileTraceLengthInSeconds * 1000)))
{
SwitchToNextFile();
s_lastFileSwitchTime = CLRGetTickCount64();
}
-
}
void EventPipe::SwitchToNextFile()
@@ -562,14 +562,15 @@ void EventPipe::SwitchToNextFile()
// Open the new file.
SString nextTraceFilePath;
GetNextFilePath(s_pSession, nextTraceFilePath);
- EventPipeFile* pFile = new (nothrow) EventPipeFile(nextTraceFilePath);
- if(pFile == NULL)
+ EventPipeFile *pFile = new (nothrow) EventPipeFile(nextTraceFilePath);
+ if (pFile == NULL)
{
+ // TODO: Add error handling.
return;
}
// Close the previous file.
- delete(s_pFile);
+ delete s_pFile;
// Swap in the new file.
s_pFile = pFile;
@@ -592,11 +593,11 @@ void EventPipe::GetNextFilePath(EventPipeSession *pSession, SString &nextTraceFi
// If multiple files have been requested, then add a sequence number to the trace file name.
UINT64 multiFileTraceLengthInSeconds = pSession->GetMultiFileTraceLengthInSeconds();
- if(multiFileTraceLengthInSeconds > 0)
+ if (multiFileTraceLengthInSeconds > 0)
{
// Remove the ".netperf" file extension if it exists.
SString::Iterator netPerfExtension = nextTraceFilePath.End();
- if(nextTraceFilePath.FindBack(netPerfExtension, W(".netperf")))
+ if (nextTraceFilePath.FindBack(netPerfExtension, W(".netperf")))
{
nextTraceFilePath.Truncate(netPerfExtension);
}
@@ -608,12 +609,12 @@ void EventPipe::GetNextFilePath(EventPipeSession *pSession, SString &nextTraceFi
}
}
-EventPipeSession* EventPipe::GetSession(EventPipeSessionID id)
+EventPipeSession *EventPipe::GetSession(EventPipeSessionID id)
{
LIMITED_METHOD_CONTRACT;
EventPipeSession *pSession = NULL;
- if((EventPipeSessionID)s_pSession == id)
+ if ((EventPipeSessionID)s_pSession == id)
{
pSession = s_pSession;
}
@@ -625,7 +626,7 @@ bool EventPipe::Enabled()
LIMITED_METHOD_CONTRACT;
bool enabled = false;
- if(s_pConfig != NULL)
+ if (s_pConfig != NULL)
{
enabled = s_pConfig->Enabled();
}
@@ -633,7 +634,7 @@ bool EventPipe::Enabled()
return enabled;
}
-EventPipeProvider* EventPipe::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
+EventPipeProvider *EventPipe::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
{
CONTRACTL
{
@@ -650,10 +651,9 @@ EventPipeProvider* EventPipe::CreateProvider(const SString &providerName, EventP
}
return pProvider;
-
}
-EventPipeProvider* EventPipe::GetProvider(const SString &providerName)
+EventPipeProvider *EventPipe::GetProvider(const SString &providerName)
{
CONTRACTL
{
@@ -687,9 +687,9 @@ void EventPipe::DeleteProvider(EventPipeProvider *pProvider)
// where we hold a provider after tracing has been disabled.
CrstHolder _crst(GetLock());
- if(pProvider != NULL)
+ if (pProvider != NULL)
{
- if(Enabled())
+ if (Enabled())
{
// Save the provider until the end of the tracing session.
pProvider->SetDeleteDeferred();
@@ -744,7 +744,7 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload
CONTRACTL_END;
// Exit early if the event is not enabled.
- if(!event.IsEnabled())
+ if (!event.IsEnabled())
{
return;
}
@@ -752,7 +752,7 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload
// Get the current thread;
Thread *pThread = GetThread();
- if(s_pConfig == NULL)
+ if (s_pConfig == NULL)
{
// We can't procede without a configuration
return;
@@ -760,23 +760,23 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload
_ASSERTE(s_pSession != NULL);
// If the activity id isn't specified AND we are in a managed thread, pull it from the current thread.
- // If pThread is NULL (we aren't in writing from a managed thread) then pActivityId can be NULL
- if(pActivityId == NULL && pThread != NULL)
+ // If pThread is NULL (we aren't in writing from a managed thread) then pActivityId can be NULL
+ if (pActivityId == NULL && pThread != NULL)
{
pActivityId = pThread->GetActivityId();
}
- if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
+ if (!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
{
s_pBufferManager->WriteEvent(pThread, *s_pSession, event, payload, pActivityId, pRelatedActivityId);
}
- else if(s_pConfig->RundownEnabled())
+ else if (s_pConfig->RundownEnabled())
{
// It is possible that some events that are enabled on rundown can be emitted from other threads.
// We're not interested in these events and they can cause corrupted trace files because rundown
// events are written synchronously and not under lock.
// If we encounter an event that did not originate on the thread that is doing rundown, ignore it.
- if(pThread == NULL || !s_pConfig->IsRundownThread(pThread))
+ if (pThread == NULL || !s_pConfig->IsRundownThread(pThread))
{
return;
}
@@ -800,7 +800,7 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload
pRelatedActivityId);
instance.EnsureStack(*s_pSession);
- if(s_pFile != NULL)
+ if (s_pFile != NULL)
{
// EventPipeFile::WriteEvent needs to allocate a metadata event
// and can therefore throw. In this context we will silently
@@ -809,7 +809,7 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload
{
s_pFile->WriteEvent(instance);
}
- EX_CATCH { }
+ EX_CATCH {}
EX_END_CATCH(SwallowAllExceptions);
}
}
@@ -829,7 +829,7 @@ void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent
EventPipeEventPayload payload(pData, length);
// Write the event to the thread's buffer.
- if(s_pBufferManager != NULL)
+ 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.
@@ -848,7 +848,7 @@ bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
CONTRACTL_END;
Thread *pThread = GetThread();
- if(pThread != NULL)
+ if (pThread != NULL)
{
return WalkManagedStackForThread(pThread, stackContents);
}
@@ -869,12 +869,12 @@ bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackC
// Calling into StackWalkFrames in preemptive mode violates the host contract,
// but this contract is not used on CoreCLR.
- CONTRACT_VIOLATION( HostViolation );
+ CONTRACT_VIOLATION(HostViolation);
stackContents.Reset();
StackWalkAction swaRet = pThread->StackWalkFrames(
- (PSTACKWALKFRAMESCALLBACK) &StackWalkCallback,
+ (PSTACKWALKFRAMESCALLBACK)&StackWalkCallback,
&stackContents,
ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES | ALLOW_INVALID_OBJECTS);
@@ -895,9 +895,9 @@ StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pDa
// Get the IP.
UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
- if(controlPC == 0)
+ if (controlPC == 0)
{
- if(pData->GetLength() == 0)
+ if (pData->GetLength() == 0)
{
// This happens for pinvoke stubs on the top of the stack.
return SWA_CONTINUE;
@@ -909,21 +909,20 @@ StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pDa
// Add the IP to the captured stack.
pData->Append(
controlPC,
- pCf->GetFunction()
- );
+ pCf->GetFunction());
// Continue the stack walk.
return SWA_CONTINUE;
}
-EventPipeConfiguration* EventPipe::GetConfiguration()
+EventPipeConfiguration *EventPipe::GetConfiguration()
{
LIMITED_METHOD_CONTRACT;
return s_pConfig;
}
-CrstStatic* EventPipe::GetLock()
+CrstStatic *EventPipe::GetLock()
{
LIMITED_METHOD_CONTRACT;
@@ -955,7 +954,7 @@ void EventPipe::SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv
commandLine.Append((WCHAR)' ');
commandLine.Append(pwzAssemblyPath);
- for(int i=0; i<argc; i++)
+ for (int i = 0; i < argc; i++)
{
commandLine.Append((WCHAR)' ');
commandLine.Append(argv[i]);
@@ -971,7 +970,7 @@ void EventPipe::SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv
#endif
}
-EventPipeEventInstance* EventPipe::GetNextEvent()
+EventPipeEventInstance *EventPipe::GetNextEvent()
{
CONTRACTL
{
@@ -993,253 +992,4 @@ EventPipeEventInstance* EventPipe::GetNextEvent()
return pInstance;
}
-UINT64 QCALLTYPE EventPipeInternal::Enable(
- __in_z LPCWSTR outputFile,
- UINT32 circularBufferSizeInMB,
- INT64 profilerSamplingRateInNanoseconds,
- EventPipeProviderConfiguration *pProviders,
- INT32 numProviders,
- UINT64 multiFileTraceLengthInSeconds)
-{
- QCALL_CONTRACT;
-
- UINT64 sessionID = 0;
-
- BEGIN_QCALL;
- SampleProfiler::SetSamplingRate((unsigned long)profilerSamplingRateInNanoseconds);
- sessionID = EventPipe::Enable(outputFile, circularBufferSizeInMB, pProviders, numProviders, multiFileTraceLengthInSeconds);
- END_QCALL;
-
- return sessionID;
-}
-
-void QCALLTYPE EventPipeInternal::Disable(UINT64 sessionID)
-{
- QCALL_CONTRACT;
-
- BEGIN_QCALL;
- EventPipe::Disable(sessionID);
- END_QCALL;
-}
-
-bool QCALLTYPE EventPipeInternal::GetSessionInfo(UINT64 sessionID, EventPipeSessionInfo *pSessionInfo)
-{
- QCALL_CONTRACT;
-
- bool retVal = false;
- BEGIN_QCALL;
-
- if(pSessionInfo != NULL)
- {
- EventPipeSession *pSession = EventPipe::GetSession(sessionID);
- if(pSession != NULL)
- {
- pSessionInfo->StartTimeAsUTCFileTime = pSession->GetStartTime();
- pSessionInfo->StartTimeStamp.QuadPart = pSession->GetStartTimeStamp().QuadPart;
- QueryPerformanceFrequency(&pSessionInfo->TimeStampFrequency);
- retVal = true;
- }
- }
-
- END_QCALL;
- return retVal;
-}
-
-INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
- __in_z LPCWSTR providerName,
- EventPipeCallback pCallbackFunc)
-{
- QCALL_CONTRACT;
-
- EventPipeProvider *pProvider = NULL;
-
- BEGIN_QCALL;
-
- pProvider = EventPipe::CreateProvider(providerName, pCallbackFunc, NULL);
-
- END_QCALL;
-
- return reinterpret_cast<INT_PTR>(pProvider);
-}
-
-INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
- INT_PTR provHandle,
- UINT32 eventID,
- __int64 keywords,
- UINT32 eventVersion,
- UINT32 level,
- void *pMetadata,
- UINT32 metadataLength)
-{
- QCALL_CONTRACT;
-
- EventPipeEvent *pEvent = NULL;
-
- BEGIN_QCALL;
-
- _ASSERTE(provHandle != NULL);
- EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
- pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
- _ASSERTE(pEvent != NULL);
-
- END_QCALL;
-
- return reinterpret_cast<INT_PTR>(pEvent);
-}
-
-INT_PTR QCALLTYPE EventPipeInternal::GetProvider(
- __in_z LPCWSTR providerName)
-{
- QCALL_CONTRACT;
-
- EventPipeProvider *pProvider = NULL;
-
- BEGIN_QCALL;
-
- pProvider = EventPipe::GetProvider(providerName);
-
- END_QCALL;
-
- return reinterpret_cast<INT_PTR>(pProvider);
-}
-
-void QCALLTYPE EventPipeInternal::DeleteProvider(
- INT_PTR provHandle)
-{
- QCALL_CONTRACT;
- BEGIN_QCALL;
-
- if(provHandle != NULL)
- {
- EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider*>(provHandle);
- EventPipe::DeleteProvider(pProvider);
- }
-
- END_QCALL;
-}
-
-int QCALLTYPE EventPipeInternal::EventActivityIdControl(
- uint controlCode,
- GUID *pActivityId)
-{
-
- QCALL_CONTRACT;
-
- int retVal = 0;
-
- BEGIN_QCALL;
-
- Thread *pThread = GetThread();
- if(pThread == NULL || pActivityId == NULL)
- {
- retVal = 1;
- }
- else
- {
- ActivityControlCode activityControlCode = (ActivityControlCode)controlCode;
- GUID currentActivityId;
- switch(activityControlCode)
- {
- case ActivityControlCode::EVENT_ACTIVITY_CONTROL_GET_ID:
-
- *pActivityId = *pThread->GetActivityId();
- break;
-
- case ActivityControlCode::EVENT_ACTIVITY_CONTROL_SET_ID:
-
- pThread->SetActivityId(pActivityId);
- break;
-
- case ActivityControlCode::EVENT_ACTIVITY_CONTROL_CREATE_ID:
-
- CoCreateGuid(pActivityId);
- break;
-
- case ActivityControlCode::EVENT_ACTIVITY_CONTROL_GET_SET_ID:
-
- currentActivityId = *pThread->GetActivityId();
- pThread->SetActivityId(pActivityId);
- *pActivityId = currentActivityId;
-
- break;
-
- case ActivityControlCode::EVENT_ACTIVITY_CONTROL_CREATE_SET_ID:
-
- *pActivityId = *pThread->GetActivityId();
- CoCreateGuid(&currentActivityId);
- pThread->SetActivityId(&currentActivityId);
- break;
-
- default:
- retVal = 1;
- };
- }
-
- END_QCALL;
- return retVal;
-}
-
-void QCALLTYPE EventPipeInternal::WriteEvent(
- INT_PTR eventHandle,
- UINT32 eventID,
- void *pData,
- UINT32 length,
- LPCGUID pActivityId,
- LPCGUID pRelatedActivityId)
-{
- QCALL_CONTRACT;
- BEGIN_QCALL;
-
- _ASSERTE(eventHandle != NULL);
- EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
- EventPipe::WriteEvent(*pEvent, (BYTE *)pData, length, pActivityId, pRelatedActivityId);
-
- END_QCALL;
-}
-
-void QCALLTYPE EventPipeInternal::WriteEventData(
- INT_PTR eventHandle,
- UINT32 eventID,
- EventData *pEventData,
- UINT32 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;
-}
-
-bool QCALLTYPE EventPipeInternal::GetNextEvent(
- EventPipeEventInstanceData *pInstance)
-{
- QCALL_CONTRACT;
-
- EventPipeEventInstance *pNextInstance = NULL;
- BEGIN_QCALL;
-
- _ASSERTE(pInstance != NULL);
-
- pNextInstance = EventPipe::GetNextEvent();
- if (pNextInstance)
- {
- pInstance->ProviderID = pNextInstance->GetEvent()->GetProvider();
- pInstance->EventID = pNextInstance->GetEvent()->GetEventID();
- pInstance->ThreadID = pNextInstance->GetThreadId();
- pInstance->TimeStamp.QuadPart = pNextInstance->GetTimeStamp()->QuadPart;
- pInstance->ActivityId = *pNextInstance->GetActivityId();
- pInstance->RelatedActivityId = *pNextInstance->GetRelatedActivityId();
- pInstance->Payload = pNextInstance->GetData();
- pInstance->PayloadLength = pNextInstance->GetDataLength();
- }
-
- END_QCALL;
- return pNextInstance != NULL;
-}
-
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h
index c77b94dbdc..494a8c5c98 100644
--- a/src/vm/eventpipe.h
+++ b/src/vm/eventpipe.h
@@ -14,8 +14,6 @@ class EventPipeConfiguration;
class EventPipeEvent;
class EventPipeEventInstance;
class EventPipeFile;
-class EventPipeJsonFile;
-class EventPipeBuffer;
class EventPipeBufferManager;
class EventPipeEventSource;
class EventPipeProvider;
@@ -35,13 +33,13 @@ struct EventFilterDescriptor
ULONGLONG Ptr;
// The size of the filter data, in bytes. The maximum size is 1024 bytes.
- ULONG Size;
+ ULONG Size;
// The type of filter data. The type is application-defined. An event
// controller that knows about the provider and knows details about the
// provider's events can use the Type field to send the provider an
// arbitrary set of data for use as enhancements to the filtering of events.
- ULONG Type;
+ ULONG Type;
};
// Define the event pipe callback to match the ETW callback signature.
@@ -56,7 +54,6 @@ typedef void (*EventPipeCallback)(
struct EventData
{
-public:
UINT64 Ptr;
unsigned int Size;
unsigned int Reserved;
@@ -91,7 +88,7 @@ public:
// 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();
+ BYTE *GetFlatData();
// Return true is the data is stored in a flat buffer
bool IsFlattened() const
@@ -109,7 +106,7 @@ public:
return m_size;
}
- EventData* GetEventDataArray() const
+ EventData *GetEventDataArray() const
{
LIMITED_METHOD_CONTRACT;
@@ -120,7 +117,6 @@ public:
class StackContents
{
private:
-
const static unsigned int MAX_STACK_DEPTH = 100;
// Array of IP values from a stack crawl.
@@ -130,14 +126,13 @@ private:
#ifdef _DEBUG
// Parallel array of MethodDesc pointers.
// Used for debug-only stack printing.
- MethodDesc* m_methods[MAX_STACK_DEPTH];
+ MethodDesc *m_methods[MAX_STACK_DEPTH];
#endif // _DEBUG
// The next available slot in StackFrames.
unsigned int m_nextAvailableFrame;
public:
-
StackContents()
{
LIMITED_METHOD_CONTRACT;
@@ -152,7 +147,7 @@ public:
memcpy_s(pDest->m_stackFrames, MAX_STACK_DEPTH * sizeof(UINT_PTR), m_stackFrames, sizeof(UINT_PTR) * m_nextAvailableFrame);
#ifdef _DEBUG
- memcpy_s(pDest->m_methods, MAX_STACK_DEPTH * sizeof(MethodDesc*), m_methods, sizeof(MethodDesc*) * m_nextAvailableFrame);
+ memcpy_s(pDest->m_methods, MAX_STACK_DEPTH * sizeof(MethodDesc *), m_methods, sizeof(MethodDesc *) * m_nextAvailableFrame);
#endif
pDest->m_nextAvailableFrame = m_nextAvailableFrame;
}
@@ -192,7 +187,7 @@ public:
}
#ifdef _DEBUG
- MethodDesc* GetMethod(unsigned int frameIndex)
+ MethodDesc *GetMethod(unsigned int frameIndex)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(frameIndex < MAX_STACK_DEPTH);
@@ -210,7 +205,7 @@ public:
{
LIMITED_METHOD_CONTRACT;
- if(m_nextAvailableFrame < MAX_STACK_DEPTH)
+ if (m_nextAvailableFrame < MAX_STACK_DEPTH)
{
m_stackFrames[m_nextAvailableFrame] = controlPC;
#ifdef _DEBUG
@@ -220,11 +215,11 @@ public:
}
}
- BYTE* GetPointer() const
+ BYTE *GetPointer() const
{
LIMITED_METHOD_CONTRACT;
- return (BYTE*)m_stackFrames;
+ return (BYTE *)m_stackFrames;
}
unsigned int GetSize() const
@@ -246,146 +241,128 @@ class EventPipe
friend class EventPipeBufferManager;
friend class SampleProfiler;
- public:
-
- // Initialize the event pipe.
- static void Initialize();
-
- // Shutdown the event pipe.
- static void Shutdown();
-
- // Enable tracing via the event pipe.
- static EventPipeSessionID Enable(
- LPCWSTR strOutputPath,
- unsigned int circularBufferSizeInMB,
- EventPipeProviderConfiguration *pProviders,
- int numProviders,
- UINT64 multiFileTraceLengthInSeconds);
-
- // Disable tracing via the event pipe.
- static void Disable(EventPipeSessionID id);
-
- // Get the session for the specified session ID.
- static EventPipeSession* GetSession(EventPipeSessionID id);
-
- // Specifies whether or not the event pipe is enabled.
- static bool Enabled();
-
- // Create a provider.
- static EventPipeProvider* CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction = NULL, void *pCallbackData = NULL);
-
- // Get a provider.
- static EventPipeProvider* GetProvider(const SString &providerName);
-
- // Delete a provider.
- static void DeleteProvider(EventPipeProvider *pProvider);
-
- // 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);
-
- // Get the managed call stack for the current thread.
- static bool WalkManagedStackForCurrentThread(StackContents &stackContents);
+public:
+ // Initialize the event pipe.
+ static void Initialize();
- // Get the managed call stack for the specified thread.
- static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
+ // Shutdown the event pipe.
+ static void Shutdown();
- // Save the command line for the current process.
- static void SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv);
+ // Enable tracing via the event pipe.
+ static EventPipeSessionID Enable(
+ LPCWSTR strOutputPath,
+ uint32_t circularBufferSizeInMB,
+ uint64_t profilerSamplingRateInNanoseconds,
+ const EventPipeProviderConfiguration *pProviders,
+ uint32_t numProviders,
+ uint64_t multiFileTraceLengthInSeconds);
- // Get next event.
- static EventPipeEventInstance* GetNextEvent();
+ // Disable tracing via the event pipe.
+ static void Disable(EventPipeSessionID id);
- protected:
+ // Get the session for the specified session ID.
+ static EventPipeSession *GetSession(EventPipeSessionID id);
- // The counterpart to WriteEvent which after the payload is constructed
- static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
+ // Specifies whether or not the event pipe is enabled.
+ static bool Enabled();
- private:
+ // Create a provider.
+ static EventPipeProvider *CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction = NULL, void *pCallbackData = NULL);
- // Enable the specified EventPipe session.
- static EventPipeSessionID Enable(LPCWSTR strOutputPath, EventPipeSession *pSession);
+ // Get a provider.
+ static EventPipeProvider *GetProvider(const SString &providerName);
- static void CreateFileSwitchTimer();
+ // Delete a provider.
+ static void DeleteProvider(EventPipeProvider *pProvider);
- static void DeleteFileSwitchTimer();
+ // 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);
- // Performs one polling operation to determine if it is necessary to switch to a new file.
- // If the polling operation decides it is time, it will perform the switch.
- // Called directly from the timer when the timer is triggered.
- static void WINAPI SwitchToNextFileTimerCallback(PVOID parameter, BOOLEAN timerFired);
+ // 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);
- // If event pipe has been configured to write multiple files, switch to the next file.
- static void SwitchToNextFile();
+ // Write out a sample profile event.
+ static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
- // Generate the file path for the next trace file.
- // This is used when event pipe has been configured to create multiple trace files with a specified maximum length of time.
- static void GetNextFilePath(EventPipeSession *pSession, SString &nextTraceFilePath);
+ // Get the managed call stack for the current thread.
+ static bool WalkManagedStackForCurrentThread(StackContents &stackContents);
- // Callback function for the stack walker. For each frame walked, this callback is invoked.
- static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
+ // Get the managed call stack for the specified thread.
+ static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
- // Get the configuration object.
- // This is called directly by the EventPipeProvider constructor to register the new provider.
- static EventPipeConfiguration* GetConfiguration();
+ // Save the command line for the current process.
+ static void SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv);
- // Get the event pipe configuration lock.
- static CrstStatic* GetLock();
+ // Get next event.
+ static EventPipeEventInstance *GetNextEvent();
- static CrstStatic s_configCrst;
- static bool s_tracingInitialized;
- static EventPipeConfiguration *s_pConfig;
- static EventPipeSession *s_pSession;
- static EventPipeBufferManager *s_pBufferManager;
- static LPCWSTR s_pOutputPath;
- static unsigned long s_nextFileIndex;
- static EventPipeFile *s_pFile;
- static EventPipeEventSource *s_pEventSource;
- static LPCWSTR s_pCommandLine;
- const static DWORD FileSwitchTimerPeriodMS = 1000;
- static HANDLE s_fileSwitchTimerHandle;
- static ULONGLONG s_lastFileSwitchTime;
+private:
+ // The counterpart to WriteEvent which after the payload is constructed
+ static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
+
+ // Enable the specified EventPipe session.
+ static EventPipeSessionID Enable(LPCWSTR strOutputPath, EventPipeSession *pSession);
+
+ static void CreateFileSwitchTimer();
+
+ static void DeleteFileSwitchTimer();
+
+ // Performs one polling operation to determine if it is necessary to switch to a new file.
+ // If the polling operation decides it is time, it will perform the switch.
+ // Called directly from the timer when the timer is triggered.
+ static void WINAPI SwitchToNextFileTimerCallback(PVOID parameter, BOOLEAN timerFired);
+
+ // If event pipe has been configured to write multiple files, switch to the next file.
+ static void SwitchToNextFile();
+
+ // Generate the file path for the next trace file.
+ // This is used when event pipe has been configured to create multiple trace files with a specified maximum length of time.
+ static void GetNextFilePath(EventPipeSession *pSession, SString &nextTraceFilePath);
+
+ // Callback function for the stack walker. For each frame walked, this callback is invoked.
+ static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
+
+ // Get the configuration object.
+ // This is called directly by the EventPipeProvider constructor to register the new provider.
+ static EventPipeConfiguration *GetConfiguration();
+
+ // Get the event pipe configuration lock.
+ static CrstStatic *GetLock();
+
+ static CrstStatic s_configCrst;
+ static bool s_tracingInitialized;
+ static EventPipeConfiguration *s_pConfig;
+ static EventPipeSession *s_pSession;
+ static EventPipeBufferManager *s_pBufferManager;
+ static LPCWSTR s_pOutputPath;
+ static unsigned long s_nextFileIndex;
+ static EventPipeFile *s_pFile;
+ static EventPipeEventSource *s_pEventSource;
+ static LPCWSTR s_pCommandLine;
+ const static DWORD FileSwitchTimerPeriodMS = 1000;
+ static HANDLE s_fileSwitchTimerHandle;
+ static ULONGLONG s_lastFileSwitchTime;
};
struct EventPipeProviderConfiguration
{
-
private:
-
- LPCWSTR m_pProviderName;
- UINT64 m_keywords;
- UINT32 m_loggingLevel;
- LPCWSTR m_pFilterData;
+ LPCWSTR m_pProviderName = nullptr;
+ UINT64 m_keywords = 0;
+ UINT32 m_loggingLevel = 0;
+ LPCWSTR m_pFilterData = nullptr;
public:
+ EventPipeProviderConfiguration() = default;
- EventPipeProviderConfiguration()
+ EventPipeProviderConfiguration(LPCWSTR pProviderName, UINT64 keywords, UINT32 loggingLevel, LPCWSTR pFilterData) :
+ m_pProviderName(pProviderName),
+ m_keywords(keywords),
+ m_loggingLevel(loggingLevel),
+ m_pFilterData(pFilterData)
{
- LIMITED_METHOD_CONTRACT;
- m_pProviderName = NULL;
- m_keywords = NULL;
- m_loggingLevel = 0;
- m_pFilterData = NULL;
- }
-
- EventPipeProviderConfiguration(
- LPCWSTR pProviderName,
- UINT64 keywords,
- UINT32 loggingLevel,
- LPCWSTR pFilterData)
- {
- LIMITED_METHOD_CONTRACT;
- m_pProviderName = pProviderName;
- m_keywords = keywords;
- m_loggingLevel = loggingLevel;
- m_pFilterData = pFilterData;
}
LPCWSTR GetProviderName() const
@@ -413,95 +390,6 @@ public:
}
};
-class EventPipeInternal
-{
-private:
-
- enum class ActivityControlCode
- {
- EVENT_ACTIVITY_CONTROL_GET_ID = 1,
- EVENT_ACTIVITY_CONTROL_SET_ID = 2,
- EVENT_ACTIVITY_CONTROL_CREATE_ID = 3,
- EVENT_ACTIVITY_CONTROL_GET_SET_ID = 4,
- EVENT_ACTIVITY_CONTROL_CREATE_SET_ID = 5
- };
-
- struct EventPipeEventInstanceData
- {
- public:
- void *ProviderID;
- unsigned int EventID;
- unsigned int ThreadID;
- LARGE_INTEGER TimeStamp;
- GUID ActivityId;
- GUID RelatedActivityId;
- const BYTE *Payload;
- unsigned int PayloadLength;
- };
-
- struct EventPipeSessionInfo
- {
- public:
- FILETIME StartTimeAsUTCFileTime;
- LARGE_INTEGER StartTimeStamp;
- LARGE_INTEGER TimeStampFrequency;
- };
-
-public:
-
- static UINT64 QCALLTYPE Enable(
- __in_z LPCWSTR outputFile,
- UINT32 circularBufferSizeInMB,
- INT64 profilerSamplingRateInNanoseconds,
- EventPipeProviderConfiguration *pProviders,
- INT32 numProviders,
- UINT64 multiFileTraceLengthInSeconds);
-
- static void QCALLTYPE Disable(UINT64 sessionID);
-
- static bool QCALLTYPE GetSessionInfo(UINT64 sessionID, EventPipeSessionInfo *pSessionInfo);
-
- static INT_PTR QCALLTYPE CreateProvider(
- __in_z LPCWSTR providerName,
- EventPipeCallback pCallbackFunc);
-
- static INT_PTR QCALLTYPE DefineEvent(
- INT_PTR provHandle,
- UINT32 eventID,
- __int64 keywords,
- UINT32 eventVersion,
- UINT32 level,
- void *pMetadata,
- UINT32 metadataLength);
-
- static INT_PTR QCALLTYPE GetProvider(
- __in_z LPCWSTR providerName);
-
- static void QCALLTYPE DeleteProvider(
- INT_PTR provHandle);
-
- static int QCALLTYPE EventActivityIdControl(
- uint controlCode,
- GUID *pActivityId);
-
- static void QCALLTYPE WriteEvent(
- INT_PTR eventHandle,
- UINT32 eventID,
- void *pData,
- UINT32 length,
- LPCGUID pActivityId, LPCGUID pRelatedActivityId);
-
- static void QCALLTYPE WriteEventData(
- INT_PTR eventHandle,
- UINT32 eventID,
- EventData *pEventData,
- UINT32 eventDataCount,
- LPCGUID pActivityId, LPCGUID pRelatedActivityId);
-
- static bool QCALLTYPE GetNextEvent(
- EventPipeEventInstanceData *pInstance);
-};
-
#endif // FEATURE_PERFTRACING
#endif // __EVENTPIPE_H__
diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp
index 9cf8280722..4667276753 100644
--- a/src/vm/eventpipeconfiguration.cpp
+++ b/src/vm/eventpipeconfiguration.cpp
@@ -6,12 +6,13 @@
#include "eventpipe.h"
#include "eventpipeconfiguration.h"
#include "eventpipeeventinstance.h"
+#include "eventpipesessionprovider.h"
#include "eventpipeprovider.h"
#include "eventpipesession.h"
#ifdef FEATURE_PERFTRACING
-const WCHAR* EventPipeConfiguration::s_configurationProviderName = W("Microsoft-DotNETCore-EventPipeConfiguration");
+const WCHAR *EventPipeConfiguration::s_configurationProviderName = W("Microsoft-DotNETCore-EventPipeConfiguration");
EventPipeConfiguration::EventPipeConfiguration()
{
@@ -22,7 +23,7 @@ EventPipeConfiguration::EventPipeConfiguration()
m_pRundownThread = NULL;
m_pConfigProvider = NULL;
m_pSession = NULL;
- m_pProviderList = new SList<SListElem<EventPipeProvider*>>();
+ m_pProviderList = new SList<SListElem<EventPipeProvider *>>();
}
EventPipeConfiguration::~EventPipeConfiguration()
@@ -35,25 +36,25 @@ EventPipeConfiguration::~EventPipeConfiguration()
}
CONTRACTL_END;
- if(m_pConfigProvider != NULL)
+ if (m_pConfigProvider != NULL)
{
// This unregisters the provider, which takes a
// HOST_BREAKABLE lock
EX_TRY
{
- DeleteProvider(m_pConfigProvider);
- m_pConfigProvider = NULL;
+ DeleteProvider(m_pConfigProvider);
+ m_pConfigProvider = NULL;
}
- EX_CATCH { }
+ EX_CATCH {}
EX_END_CATCH(SwallowAllExceptions);
}
- if(m_pSession != NULL)
+ if (m_pSession != NULL)
{
DeleteSession(m_pSession);
m_pSession = NULL;
}
- if(m_pProviderList != NULL)
+ if (m_pProviderList != NULL)
{
// We swallow exceptions here because the HOST_BREAKABLE
// lock may throw and this destructor gets called in throw
@@ -63,18 +64,18 @@ EventPipeConfiguration::~EventPipeConfiguration()
// Take the lock before manipulating the list.
CrstHolder _crst(EventPipe::GetLock());
- SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
- while(pElem != NULL)
+ SListElem<EventPipeProvider *> *pElem = m_pProviderList->GetHead();
+ while (pElem != NULL)
{
// We don't delete provider itself because it can be in-use
- SListElem<EventPipeProvider*> *pCurElem = pElem;
+ SListElem<EventPipeProvider *> *pCurElem = pElem;
pElem = m_pProviderList->GetNext(pElem);
- delete(pCurElem);
+ delete (pCurElem);
}
- delete(m_pProviderList);
+ delete (m_pProviderList);
}
- EX_CATCH { }
+ EX_CATCH {}
EX_END_CATCH(SwallowAllExceptions);
m_pProviderList = NULL;
@@ -96,14 +97,14 @@ void EventPipeConfiguration::Initialize()
// Create the metadata event.
m_pMetadataEvent = m_pConfigProvider->AddEvent(
- 0, /* eventID */
- 0, /* keywords */
- 0, /* eventVersion */
+ 0, /* eventID */
+ 0, /* keywords */
+ 0, /* eventVersion */
EventPipeEventLevel::LogAlways,
false); /* needStack */
}
-EventPipeProvider* EventPipeConfiguration::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
+EventPipeProvider *EventPipeConfiguration::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
{
CONTRACTL
{
@@ -134,18 +135,15 @@ void EventPipeConfiguration::DeleteProvider(EventPipeProvider *pProvider)
CONTRACTL_END;
if (pProvider == NULL)
- {
return;
- }
// Unregister the provider.
UnregisterProvider(*pProvider);
// Free the provider itself.
- delete(pProvider);
+ delete pProvider;
}
-
bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
{
CONTRACTL
@@ -161,7 +159,7 @@ bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
// See if we've already registered this provider.
EventPipeProvider *pExistingProvider = GetProviderNoLock(provider.GetProviderName());
- if(pExistingProvider != NULL)
+ if (pExistingProvider != NULL)
{
return false;
}
@@ -170,14 +168,14 @@ bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
if (m_pProviderList != NULL)
{
// The provider has not been registered, so register it.
- m_pProviderList->InsertTail(new SListElem<EventPipeProvider*>(&provider));
+ m_pProviderList->InsertTail(new SListElem<EventPipeProvider *>(&provider));
}
// Set the provider configuration and enable it if it has been requested by a session.
- if(m_pSession != NULL)
+ if (m_pSession != NULL)
{
EventPipeSessionProvider *pSessionProvider = GetSessionProvider(m_pSession, &provider);
- if(pSessionProvider != NULL)
+ if (pSessionProvider != NULL)
{
provider.SetConfiguration(
true /* providerEnabled */,
@@ -207,10 +205,10 @@ bool EventPipeConfiguration::UnregisterProvider(EventPipeProvider &provider)
if (m_pProviderList != NULL)
{
// Find the provider.
- SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
- while(pElem != NULL)
+ SListElem<EventPipeProvider *> *pElem = m_pProviderList->GetHead();
+ while (pElem != NULL)
{
- if(pElem->GetValue() == &provider)
+ if (pElem->GetValue() == &provider)
{
break;
}
@@ -219,11 +217,11 @@ bool EventPipeConfiguration::UnregisterProvider(EventPipeProvider &provider)
}
// If we found the provider, remove it.
- if(pElem != NULL)
+ if (pElem != NULL)
{
- if(m_pProviderList->FindAndRemove(pElem) != NULL)
+ if (m_pProviderList->FindAndRemove(pElem) != NULL)
{
- delete(pElem);
+ delete (pElem);
return true;
}
}
@@ -232,7 +230,7 @@ bool EventPipeConfiguration::UnregisterProvider(EventPipeProvider &provider)
return false;
}
-EventPipeProvider* EventPipeConfiguration::GetProvider(const SString &providerName)
+EventPipeProvider *EventPipeConfiguration::GetProvider(const SString &providerName)
{
CONTRACTL
{
@@ -249,7 +247,7 @@ EventPipeProvider* EventPipeConfiguration::GetProvider(const SString &providerNa
return GetProviderNoLock(providerName);
}
-EventPipeProvider* EventPipeConfiguration::GetProviderNoLock(const SString &providerName)
+EventPipeProvider *EventPipeConfiguration::GetProviderNoLock(const SString &providerName)
{
CONTRACTL
{
@@ -263,11 +261,11 @@ EventPipeProvider* EventPipeConfiguration::GetProviderNoLock(const SString &prov
// The provider list should be non-NULL, but can be NULL on shutdown.
if (m_pProviderList != NULL)
{
- SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
- while(pElem != NULL)
+ SListElem<EventPipeProvider *> *pElem = m_pProviderList->GetHead();
+ while (pElem != NULL)
{
EventPipeProvider *pProvider = pElem->GetValue();
- if(pProvider->GetProviderName().Equals(providerName))
+ if (pProvider->GetProviderName().Equals(providerName))
{
return pProvider;
}
@@ -279,7 +277,7 @@ EventPipeProvider* EventPipeConfiguration::GetProviderNoLock(const SString &prov
return NULL;
}
-EventPipeSessionProvider* EventPipeConfiguration::GetSessionProvider(EventPipeSession *pSession, EventPipeProvider *pProvider)
+EventPipeSessionProvider *EventPipeConfiguration::GetSessionProvider(EventPipeSession *pSession, EventPipeProvider *pProvider)
{
CONTRACTL
{
@@ -291,9 +289,9 @@ EventPipeSessionProvider* EventPipeConfiguration::GetSessionProvider(EventPipeSe
CONTRACTL_END;
EventPipeSessionProvider *pRet = NULL;
- if(pSession != NULL)
+ if (pSession != NULL)
{
- pRet = pSession->GetSessionProvider(pProvider);
+ pRet = pSession->GetSessionProvider(pProvider);
}
return pRet;
}
@@ -303,24 +301,35 @@ size_t EventPipeConfiguration::GetCircularBufferSize() const
LIMITED_METHOD_CONTRACT;
size_t ret = 0;
- if(m_pSession != NULL)
+ if (m_pSession != NULL)
{
ret = m_pSession->GetCircularBufferSize();
}
return ret;
}
-EventPipeSession* EventPipeConfiguration::CreateSession(EventPipeSessionType sessionType, unsigned int circularBufferSizeInMB, EventPipeProviderConfiguration *pProviders, unsigned int numProviders, UINT64 multiFileTraceLengthInSeconds)
+EventPipeSession *EventPipeConfiguration::CreateSession(
+ EventPipeSessionType sessionType,
+ unsigned int circularBufferSizeInMB,
+ const EventPipeProviderConfiguration *pProviders,
+ uint32_t numProviders,
+ uint64_t multiFileTraceLengthInSeconds)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
+ PRECONDITION((numProviders == 0) || (numProviders > 0 && pProviders != nullptr));
}
CONTRACTL_END;
- return new EventPipeSession(sessionType, circularBufferSizeInMB, pProviders, numProviders, multiFileTraceLengthInSeconds);
+ return new EventPipeSession(
+ sessionType,
+ circularBufferSizeInMB,
+ pProviders,
+ numProviders,
+ multiFileTraceLengthInSeconds);
}
void EventPipeConfiguration::DeleteSession(EventPipeSession *pSession)
@@ -336,9 +345,9 @@ void EventPipeConfiguration::DeleteSession(EventPipeSession *pSession)
CONTRACTL_END;
// TODO: Multiple session support will require individual enabled bits.
- if(pSession != NULL && !m_enabled)
+ if (pSession != NULL && !m_enabled)
{
- delete(pSession);
+ delete (pSession);
}
}
@@ -361,14 +370,14 @@ void EventPipeConfiguration::Enable(EventPipeSession *pSession)
// The provider list should be non-NULL, but can be NULL on shutdown.
if (m_pProviderList != NULL)
{
- SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
- while(pElem != NULL)
+ SListElem<EventPipeProvider *> *pElem = m_pProviderList->GetHead();
+ while (pElem != NULL)
{
EventPipeProvider *pProvider = pElem->GetValue();
// Enable the provider if it has been configured.
EventPipeSessionProvider *pSessionProvider = GetSessionProvider(m_pSession, pProvider);
- if(pSessionProvider != NULL)
+ if (pSessionProvider != NULL)
{
pProvider->SetConfiguration(
true /* providerEnabled */,
@@ -400,8 +409,8 @@ void EventPipeConfiguration::Disable(EventPipeSession *pSession)
// The provider list should be non-NULL, but can be NULL on shutdown.
if (m_pProviderList != NULL)
{
- SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
- while(pElem != NULL)
+ SListElem<EventPipeProvider *> *pElem = m_pProviderList->GetHead();
+ while (pElem != NULL)
{
EventPipeProvider *pProvider = pElem->GetValue();
pProvider->SetConfiguration(
@@ -458,7 +467,7 @@ void EventPipeConfiguration::EnableRundown(EventPipeSession *pSession)
Enable(pSession);
}
-EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, unsigned int metadataId)
+EventPipeEventInstance *EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, unsigned int metadataId)
{
CONTRACTL
{
@@ -490,7 +499,7 @@ EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPip
memcpy(currentPtr, &metadataId, sizeof(metadataId));
currentPtr += sizeof(metadataId);
- memcpy(currentPtr, (BYTE*)providerName.GetUnicode(), providerNameLength);
+ memcpy(currentPtr, (BYTE *)providerName.GetUnicode(), providerNameLength);
currentPtr += providerNameLength;
// Write the incoming payload data.
@@ -523,19 +532,18 @@ void EventPipeConfiguration::DeleteDeferredProviders()
MODE_ANY;
// Lock must be held by EventPipe::Disable.
PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
-
}
CONTRACTL_END;
// The provider list should be non-NULL, but can be NULL on shutdown.
if (m_pProviderList != NULL)
{
- SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead();
- while(pElem != NULL)
+ SListElem<EventPipeProvider *> *pElem = m_pProviderList->GetHead();
+ while (pElem != NULL)
{
EventPipeProvider *pProvider = pElem->GetValue();
pElem = m_pProviderList->GetNext(pElem);
- if(pProvider->GetDeleteDeferred())
+ if (pProvider->GetDeleteDeferred())
{
DeleteProvider(pProvider);
}
diff --git a/src/vm/eventpipeconfiguration.h b/src/vm/eventpipeconfiguration.h
index 5eec76ca80..6021305b82 100644
--- a/src/vm/eventpipeconfiguration.h
+++ b/src/vm/eventpipeconfiguration.h
@@ -13,10 +13,8 @@ class EventPipeSessionProvider;
class EventPipeEvent;
class EventPipeEventInstance;
class EventPipeProvider;
-struct EventPipeProviderConfiguration;
class EventPipeSession;
enum class EventPipeSessionType;
-class EventPipeSessionProvider;
enum class EventPipeEventLevel
{
@@ -31,7 +29,6 @@ enum class EventPipeEventLevel
class EventPipeConfiguration
{
public:
-
EventPipeConfiguration();
~EventPipeConfiguration();
@@ -39,7 +36,7 @@ public:
void Initialize();
// Create a new provider.
- EventPipeProvider* CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData);
+ EventPipeProvider *CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData);
// Delete a provider.
void DeleteProvider(EventPipeProvider *pProvider);
@@ -51,10 +48,15 @@ public:
bool UnregisterProvider(EventPipeProvider &provider);
// Get the provider with the specified provider ID if it exists.
- EventPipeProvider* GetProvider(const SString &providerID);
+ EventPipeProvider *GetProvider(const SString &providerID);
// Create a new session.
- EventPipeSession* CreateSession(EventPipeSessionType sessionType, unsigned int circularBufferSizeInMB, EventPipeProviderConfiguration *pProviders, unsigned int numProviders, UINT64 multiFileTraceLengthInSeconds = 0);
+ EventPipeSession *CreateSession(
+ EventPipeSessionType sessionType,
+ unsigned int circularBufferSizeInMB,
+ const EventPipeProviderConfiguration *pProviders,
+ uint32_t numProviders,
+ uint64_t multiFileTraceLengthInSeconds = 0);
// Delete a session.
void DeleteSession(EventPipeSession *pSession);
@@ -78,7 +80,7 @@ public:
void EnableRundown(EventPipeSession *pSession);
// Get the event used to write metadata to the event stream.
- EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, unsigned int metdataId);
+ EventPipeEventInstance *BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, unsigned int metdataId);
// Delete deferred providers.
void DeleteDeferredProviders();
@@ -93,12 +95,11 @@ public:
}
private:
-
// Get the provider without taking the lock.
- EventPipeProvider* GetProviderNoLock(const SString &providerID);
+ EventPipeProvider *GetProviderNoLock(const SString &providerID);
// Get the enabled provider.
- EventPipeSessionProvider* GetSessionProvider(EventPipeSession *pSession, EventPipeProvider *pProvider);
+ EventPipeSessionProvider *GetSessionProvider(EventPipeSession *pSession, EventPipeProvider *pProvider);
// The one and only EventPipe session.
EventPipeSession *m_pSession;
@@ -107,7 +108,7 @@ private:
Volatile<bool> m_enabled;
// The list of event pipe providers.
- SList<SListElem<EventPipeProvider*>> *m_pProviderList;
+ SList<SListElem<EventPipeProvider *>> *m_pProviderList;
// The provider used to write configuration events to the event stream.
EventPipeProvider *m_pConfigProvider;
@@ -117,7 +118,7 @@ private:
// The provider name for the configuration event pipe provider.
// This provider is used to emit configuration events.
- const static WCHAR* s_configurationProviderName;
+ const static WCHAR *s_configurationProviderName;
// True if rundown is enabled.
Volatile<bool> m_rundownEnabled;
diff --git a/src/vm/eventpipeeventinstance.h b/src/vm/eventpipeeventinstance.h
index 80fd49d946..cf995f2534 100644
--- a/src/vm/eventpipeeventinstance.h
+++ b/src/vm/eventpipeeventinstance.h
@@ -14,6 +14,8 @@
#include "fastserializableobject.h"
#include "fastserializer.h"
+class EventPipeJsonFile;
+
class EventPipeEventInstance
{
// Declare friends.
diff --git a/src/vm/eventpipeeventsource.cpp b/src/vm/eventpipeeventsource.cpp
index 20dc5b2686..20613b8d53 100644
--- a/src/vm/eventpipeeventsource.cpp
+++ b/src/vm/eventpipeeventsource.cpp
@@ -9,6 +9,7 @@
#include "eventpipemetadatagenerator.h"
#include "eventpipeprovider.h"
#include "eventpipesession.h"
+#include "eventpipesessionprovider.h"
#ifdef FEATURE_PERFTRACING
diff --git a/src/vm/eventpipefile.cpp b/src/vm/eventpipefile.cpp
index 424bbef5ad..2e98fd5ad7 100644
--- a/src/vm/eventpipefile.cpp
+++ b/src/vm/eventpipefile.cpp
@@ -11,8 +11,7 @@
#ifdef FEATURE_PERFTRACING
-EventPipeFile::EventPipeFile(
- SString &outputFilePath)
+EventPipeFile::EventPipeFile(SString &outputFilePath)
{
CONTRACTL
{
@@ -43,7 +42,7 @@ EventPipeFile::EventPipeFile(
m_samplingRateInNs = SampleProfiler::GetSamplingRate();
// Create the file stream and write the header.
- m_pSerializer = new FastSerializer(outputFilePath);
+ m_pSerializer = new FastSerializer(new FileStreamWriter(outputFilePath));
m_serializationLock.Init(LOCK_TYPE_DEFAULT);
m_pMetadataIds = new MapSHashWithRemove<EventPipeEvent*, unsigned int>();
@@ -101,7 +100,7 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance)
metadataId = GenerateMetadataId();
EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance, metadataId);
-
+
WriteToBlock(*pMetadataInstance, 0); // 0 breaks recursion and represents the metadata event.
SaveMetadataId(*instance.GetEvent(), metadataId);
@@ -129,7 +128,7 @@ void EventPipeFile::WriteEnd()
// "After the last EventBlock is emitted, the stream is ended by emitting a NullReference Tag which indicates that there are no more objects in the stream to read."
// see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more
- m_pSerializer->WriteTag(FastSerializerTags::NullReference);
+ m_pSerializer->WriteTag(FastSerializerTags::NullReference);
}
void EventPipeFile::WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId)
diff --git a/src/vm/eventpipeinternal.cpp b/src/vm/eventpipeinternal.cpp
new file mode 100644
index 0000000000..c02317f491
--- /dev/null
+++ b/src/vm/eventpipeinternal.cpp
@@ -0,0 +1,270 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "eventpipe.h"
+#include "eventpipeconfiguration.h"
+#include "eventpipeeventinstance.h"
+#include "eventpipeinternal.h"
+#include "eventpipeprovider.h"
+#include "eventpipesession.h"
+#include "eventpipesessionprovider.h"
+
+#ifdef FEATURE_PAL
+#include "pal.h"
+#endif // FEATURE_PAL
+
+#ifdef FEATURE_PERFTRACING
+
+UINT64 QCALLTYPE EventPipeInternal::Enable(
+ __in_z LPCWSTR outputFile,
+ UINT32 circularBufferSizeInMB,
+ INT64 profilerSamplingRateInNanoseconds,
+ EventPipeProviderConfiguration *pProviders,
+ UINT32 numProviders,
+ UINT64 multiFileTraceLengthInSeconds)
+{
+ QCALL_CONTRACT;
+
+ UINT64 sessionID = 0;
+
+ BEGIN_QCALL;
+ {
+ sessionID = EventPipe::Enable(
+ outputFile,
+ circularBufferSizeInMB,
+ profilerSamplingRateInNanoseconds,
+ pProviders,
+ numProviders,
+ multiFileTraceLengthInSeconds);
+ }
+ END_QCALL;
+
+ return sessionID;
+}
+
+void QCALLTYPE EventPipeInternal::Disable(UINT64 sessionID)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+ EventPipe::Disable(sessionID);
+ END_QCALL;
+}
+
+bool QCALLTYPE EventPipeInternal::GetSessionInfo(UINT64 sessionID, EventPipeSessionInfo *pSessionInfo)
+{
+ QCALL_CONTRACT;
+
+ bool retVal = false;
+ BEGIN_QCALL;
+
+ if (pSessionInfo != NULL)
+ {
+ EventPipeSession *pSession = EventPipe::GetSession(sessionID);
+ if (pSession != NULL)
+ {
+ pSessionInfo->StartTimeAsUTCFileTime = pSession->GetStartTime();
+ pSessionInfo->StartTimeStamp.QuadPart = pSession->GetStartTimeStamp().QuadPart;
+ QueryPerformanceFrequency(&pSessionInfo->TimeStampFrequency);
+ retVal = true;
+ }
+ }
+
+ END_QCALL;
+ return retVal;
+}
+
+INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
+ __in_z LPCWSTR providerName,
+ EventPipeCallback pCallbackFunc)
+{
+ QCALL_CONTRACT;
+
+ EventPipeProvider *pProvider = NULL;
+
+ BEGIN_QCALL;
+
+ pProvider = EventPipe::CreateProvider(providerName, pCallbackFunc, NULL);
+
+ END_QCALL;
+
+ return reinterpret_cast<INT_PTR>(pProvider);
+}
+
+INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
+ INT_PTR provHandle,
+ UINT32 eventID,
+ __int64 keywords,
+ UINT32 eventVersion,
+ UINT32 level,
+ void *pMetadata,
+ UINT32 metadataLength)
+{
+ QCALL_CONTRACT;
+
+ EventPipeEvent *pEvent = NULL;
+
+ BEGIN_QCALL;
+
+ _ASSERTE(provHandle != NULL);
+ EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
+ pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
+ _ASSERTE(pEvent != NULL);
+
+ END_QCALL;
+
+ return reinterpret_cast<INT_PTR>(pEvent);
+}
+
+INT_PTR QCALLTYPE EventPipeInternal::GetProvider(__in_z LPCWSTR providerName)
+{
+ QCALL_CONTRACT;
+
+ EventPipeProvider *pProvider = NULL;
+
+ BEGIN_QCALL;
+
+ pProvider = EventPipe::GetProvider(providerName);
+
+ END_QCALL;
+
+ return reinterpret_cast<INT_PTR>(pProvider);
+}
+
+void QCALLTYPE EventPipeInternal::DeleteProvider(INT_PTR provHandle)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
+
+ if (provHandle != NULL)
+ {
+ EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
+ EventPipe::DeleteProvider(pProvider);
+ }
+
+ END_QCALL;
+}
+
+int QCALLTYPE EventPipeInternal::EventActivityIdControl(uint32_t controlCode, GUID *pActivityId)
+{
+
+ QCALL_CONTRACT;
+
+ int retVal = 0;
+
+ BEGIN_QCALL;
+
+ Thread *pThread = GetThread();
+ if (pThread == NULL || pActivityId == NULL)
+ {
+ retVal = 1;
+ }
+ else
+ {
+ ActivityControlCode activityControlCode = (ActivityControlCode)controlCode;
+ GUID currentActivityId;
+ switch (activityControlCode)
+ {
+ case ActivityControlCode::EVENT_ACTIVITY_CONTROL_GET_ID:
+
+ *pActivityId = *pThread->GetActivityId();
+ break;
+
+ case ActivityControlCode::EVENT_ACTIVITY_CONTROL_SET_ID:
+
+ pThread->SetActivityId(pActivityId);
+ break;
+
+ case ActivityControlCode::EVENT_ACTIVITY_CONTROL_CREATE_ID:
+
+ CoCreateGuid(pActivityId);
+ break;
+
+ case ActivityControlCode::EVENT_ACTIVITY_CONTROL_GET_SET_ID:
+
+ currentActivityId = *pThread->GetActivityId();
+ pThread->SetActivityId(pActivityId);
+ *pActivityId = currentActivityId;
+ break;
+
+ case ActivityControlCode::EVENT_ACTIVITY_CONTROL_CREATE_SET_ID:
+
+ *pActivityId = *pThread->GetActivityId();
+ CoCreateGuid(&currentActivityId);
+ pThread->SetActivityId(&currentActivityId);
+ break;
+
+ default:
+ retVal = 1;
+ }
+ }
+
+ END_QCALL;
+ return retVal;
+}
+
+void QCALLTYPE EventPipeInternal::WriteEvent(
+ INT_PTR eventHandle,
+ UINT32 eventID,
+ void *pData,
+ UINT32 length,
+ LPCGUID pActivityId,
+ LPCGUID pRelatedActivityId)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
+
+ _ASSERTE(eventHandle != NULL);
+ EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
+ EventPipe::WriteEvent(*pEvent, (BYTE *)pData, length, pActivityId, pRelatedActivityId);
+
+ END_QCALL;
+}
+
+void QCALLTYPE EventPipeInternal::WriteEventData(
+ INT_PTR eventHandle,
+ UINT32 eventID,
+ EventData *pEventData,
+ UINT32 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;
+}
+
+bool QCALLTYPE EventPipeInternal::GetNextEvent(EventPipeEventInstanceData *pInstance)
+{
+ QCALL_CONTRACT;
+
+ EventPipeEventInstance *pNextInstance = NULL;
+ BEGIN_QCALL;
+
+ _ASSERTE(pInstance != NULL);
+
+ pNextInstance = EventPipe::GetNextEvent();
+ if (pNextInstance)
+ {
+ pInstance->ProviderID = pNextInstance->GetEvent()->GetProvider();
+ pInstance->EventID = pNextInstance->GetEvent()->GetEventID();
+ pInstance->ThreadID = pNextInstance->GetThreadId();
+ pInstance->TimeStamp.QuadPart = pNextInstance->GetTimeStamp()->QuadPart;
+ pInstance->ActivityId = *pNextInstance->GetActivityId();
+ pInstance->RelatedActivityId = *pNextInstance->GetRelatedActivityId();
+ pInstance->Payload = pNextInstance->GetData();
+ pInstance->PayloadLength = pNextInstance->GetDataLength();
+ }
+
+ END_QCALL;
+ return pNextInstance != NULL;
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeinternal.h b/src/vm/eventpipeinternal.h
new file mode 100644
index 0000000000..bbd4ad633b
--- /dev/null
+++ b/src/vm/eventpipeinternal.h
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __EVENTPIPEINTERNAL_H__
+#define __EVENTPIPEINTERNAL_H__
+
+#ifdef FEATURE_PERFTRACING
+
+// TODO: Maybe we should move the other types that are used on PInvoke here?
+
+class EventPipeInternal
+{
+private:
+ enum class ActivityControlCode
+ {
+ EVENT_ACTIVITY_CONTROL_GET_ID = 1,
+ EVENT_ACTIVITY_CONTROL_SET_ID = 2,
+ EVENT_ACTIVITY_CONTROL_CREATE_ID = 3,
+ EVENT_ACTIVITY_CONTROL_GET_SET_ID = 4,
+ EVENT_ACTIVITY_CONTROL_CREATE_SET_ID = 5
+ };
+
+ struct EventPipeEventInstanceData
+ {
+ void *ProviderID;
+ unsigned int EventID;
+ unsigned int ThreadID;
+ LARGE_INTEGER TimeStamp;
+ GUID ActivityId;
+ GUID RelatedActivityId;
+ const BYTE *Payload;
+ unsigned int PayloadLength;
+ };
+
+ struct EventPipeSessionInfo
+ {
+ FILETIME StartTimeAsUTCFileTime;
+ LARGE_INTEGER StartTimeStamp;
+ LARGE_INTEGER TimeStampFrequency;
+ };
+
+public:
+ //!
+ //! Sets the sampling rate and enables the event pipe for the specified configuration.
+ //!
+ static UINT64 QCALLTYPE Enable(
+ __in_z LPCWSTR outputFile,
+ UINT32 circularBufferSizeInMB,
+ INT64 profilerSamplingRateInNanoseconds,
+ EventPipeProviderConfiguration *pProviders,
+ UINT32 numProviders,
+ UINT64 multiFileTraceLengthInSeconds);
+
+ //! TODO: Add a ListActiveSessions to get the live SessionID in order to Disable?
+
+ //!
+ //! Disables the specified session Id.
+ //!
+ static void QCALLTYPE Disable(UINT64 sessionID);
+
+ static bool QCALLTYPE GetSessionInfo(UINT64 sessionID, EventPipeSessionInfo *pSessionInfo);
+
+ static INT_PTR QCALLTYPE CreateProvider(
+ __in_z LPCWSTR providerName,
+ EventPipeCallback pCallbackFunc);
+
+ static INT_PTR QCALLTYPE DefineEvent(
+ INT_PTR provHandle,
+ UINT32 eventID,
+ __int64 keywords,
+ UINT32 eventVersion,
+ UINT32 level,
+ void *pMetadata,
+ UINT32 metadataLength);
+
+ static INT_PTR QCALLTYPE GetProvider(
+ __in_z LPCWSTR providerName);
+
+ static void QCALLTYPE DeleteProvider(
+ INT_PTR provHandle);
+
+ static int QCALLTYPE EventActivityIdControl(
+ uint32_t controlCode,
+ GUID *pActivityId);
+
+ static void QCALLTYPE WriteEvent(
+ INT_PTR eventHandle,
+ UINT32 eventID,
+ void *pData,
+ UINT32 length,
+ LPCGUID pActivityId, LPCGUID pRelatedActivityId);
+
+ static void QCALLTYPE WriteEventData(
+ INT_PTR eventHandle,
+ UINT32 eventID,
+ EventData *pEventData,
+ UINT32 eventDataCount,
+ LPCGUID pActivityId, LPCGUID pRelatedActivityId);
+
+ static bool QCALLTYPE GetNextEvent(
+ EventPipeEventInstanceData *pInstance);
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPEINTERNAL_H__
diff --git a/src/vm/eventpipeprotocolhelper.cpp b/src/vm/eventpipeprotocolhelper.cpp
new file mode 100644
index 0000000000..bfcdcfa2f8
--- /dev/null
+++ b/src/vm/eventpipeprotocolhelper.cpp
@@ -0,0 +1,156 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "eventpipeprotocolhelper.h"
+#include "diagnosticsipc.h"
+#include "diagnosticsprotocol.h"
+
+#ifdef FEATURE_PERFTRACING
+
+bool EventPipeProtocolHelper::TryParseProviderConfigurations(uint8_t *&bufferCursor, uint32_t &bufferLen, CQuickArray<EventPipeProviderConfiguration> &result)
+{
+ // Picking an arbitrary upper bound,
+ // This should be larger than any reasonable client request.
+ const uint32_t MaxCountConfigs = 1000; // TODO: This might be too large.
+
+ uint32_t countConfigs = 0;
+ if (!TryParse(bufferCursor, bufferLen, countConfigs))
+ return false;
+ if (countConfigs > MaxCountConfigs)
+ return false;
+ EventPipeProviderConfiguration *pConfigs = result.AllocNoThrow(countConfigs);
+ if (pConfigs == nullptr)
+ return false;
+
+ for (uint32_t i = 0; i < countConfigs; i++)
+ {
+ uint64_t keywords = 0;
+ if (!TryParse(bufferCursor, bufferLen, keywords))
+ return false;
+
+ uint32_t logLevel = 0;
+ if (!TryParse(bufferCursor, bufferLen, logLevel))
+ return false;
+ if (logLevel > 5) // (logLevel > EventPipeEventLevel::Verbose)
+ return false;
+
+ LPCWSTR pProviderName = nullptr;
+ if (!TryParseString(bufferCursor, bufferLen, pProviderName))
+ return false;
+ if (wcslen(pProviderName) == 0)
+ return false; // TODO: Should we ignore these input?
+
+ LPCWSTR pFilterData = nullptr; // This parameter is optional.
+ TryParseString(bufferCursor, bufferLen, pFilterData);
+
+ pConfigs[i] = EventPipeProviderConfiguration(pProviderName, keywords, logLevel, pFilterData);
+ }
+ return true;
+}
+
+void EventPipeProtocolHelper::EnableFileTracingEventHandler(IpcStream *pStream)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(pStream != nullptr);
+ }
+ CONTRACTL_END;
+
+ // TODO: Read within a loop.
+ const uint32_t BufferSize = 8192;
+ uint8_t buffer[BufferSize]{};
+ uint32_t nNumberOfBytesRead = 0;
+ bool fSuccess = pStream->Read(buffer, sizeof(buffer), nNumberOfBytesRead);
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ delete pStream;
+ return;
+ }
+
+ // 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, ulong multiFileTraceLength, string outputPath, array<provider_config> providers
+ // uint = 4 little endian bytes
+ // ulong = 8 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
+
+ LPCWSTR strOutputPath;
+ uint32_t circularBufferSizeInMB = EventPipeProtocolHelper::DefaultCircularBufferMB;
+ uint64_t multiFileTraceLengthInSeconds = EventPipeProtocolHelper::DefaultMultiFileTraceLengthInSeconds;
+ CQuickArray<EventPipeProviderConfiguration> providerConfigs;
+
+ uint8_t *pBufferCursor = buffer;
+ uint32_t bufferLen = nNumberOfBytesRead;
+ if (!TryParse(pBufferCursor, bufferLen, circularBufferSizeInMB) ||
+ !TryParse(pBufferCursor, bufferLen, multiFileTraceLengthInSeconds) ||
+ !TryParseString(pBufferCursor, bufferLen, strOutputPath) ||
+ !TryParseProviderConfigurations(pBufferCursor, bufferLen, providerConfigs))
+ {
+ return; // TODO: error handling
+ }
+
+ EventPipeSessionID sessionId = (EventPipeSessionID) nullptr;
+ if (providerConfigs.Size() > 0)
+ {
+ sessionId = EventPipe::Enable(
+ strOutputPath, // outputFile
+ circularBufferSizeInMB, // circularBufferSizeInMB
+ DefaultProfilerSamplingRateInNanoseconds, // ProfilerSamplingRateInNanoseconds
+ providerConfigs.Ptr(), // pConfigs
+ static_cast<uint32_t>(providerConfigs.Size()), // numConfigs
+ multiFileTraceLengthInSeconds); // multiFileTraceLengthInSeconds
+ }
+
+ uint32_t nBytesWritten = 0;
+ fSuccess = pStream->Write(&sessionId, sizeof(sessionId), nBytesWritten);
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ delete pStream;
+ return;
+ }
+
+ fSuccess = pStream->Flush();
+ if (!fSuccess)
+ {
+ // TODO: Add error handling.
+ }
+ delete pStream;
+}
+
+void EventPipeProtocolHelper::DisableTracingEventHandler(IpcStream *pStream)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(pStream != nullptr);
+ }
+ CONTRACTL_END;
+
+ uint32_t nNumberOfBytesRead = 0;
+ EventPipeSessionID sessionId = (EventPipeSessionID) nullptr;
+ const bool fSuccess = pStream->Read(&sessionId, sizeof(sessionId), nNumberOfBytesRead);
+ if (!fSuccess || nNumberOfBytesRead != sizeof(sessionId))
+ {
+ // TODO: Add error handling.
+ delete pStream;
+ return;
+ }
+
+ EventPipe::Disable(sessionId);
+ // TODO: Should we acknowledge back?
+ delete pStream;
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeprotocolhelper.h b/src/vm/eventpipeprotocolhelper.h
new file mode 100644
index 0000000000..fb3f65a247
--- /dev/null
+++ b/src/vm/eventpipeprotocolhelper.h
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __EVENTPIPE_PROTOCOL_HELPER_H__
+#define __EVENTPIPE_PROTOCOL_HELPER_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "common.h"
+#include "eventpipe.h"
+
+class IpcStream;
+
+class EventPipeProtocolHelper
+{
+public:
+ // IPC event handlers.
+ static void EnableFileTracingEventHandler(IpcStream *pStream);
+ static void DisableTracingEventHandler(IpcStream *pStream);
+
+private:
+ const static uint32_t DefaultCircularBufferMB = 1024; // 1 GB
+ const static uint64_t DefaultMultiFileTraceLengthInSeconds = 0;
+ const static uint32_t DefaultProfilerSamplingRateInNanoseconds = 1000000;
+
+ //! Read a list of providers: "Provider[,Provider]"
+ //! Provider: "(GUID|KnownProviderName)[:Flags[:Level][:KeyValueArgs]]"
+ //! KeyValueArgs: "[key1=value1][;key2=value2]"
+ static bool TryParseProviderConfigurations(uint8_t *&bufferCursor, uint32_t &bufferLen, CQuickArray<EventPipeProviderConfiguration> &result);
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_PROTOCOL_HELPER_H__
diff --git a/src/vm/eventpipeprovider.h b/src/vm/eventpipeprovider.h
index dffdc7e3db..cf89cf3229 100644
--- a/src/vm/eventpipeprovider.h
+++ b/src/vm/eventpipeprovider.h
@@ -72,7 +72,7 @@ public:
// Create a new event.
EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
- private:
+private:
// Create a new event, but allow needStack to be specified.
// In general, we want stack walking to be controlled by the consumer and not the producer of events.
diff --git a/src/vm/eventpipesession.cpp b/src/vm/eventpipesession.cpp
index 7388472c7d..03bc6c681a 100644
--- a/src/vm/eventpipesession.cpp
+++ b/src/vm/eventpipesession.cpp
@@ -6,30 +6,30 @@
#include "eventpipe.h"
#include "eventpipeprovider.h"
#include "eventpipesession.h"
+#include "eventpipesessionprovider.h"
#ifdef FEATURE_PERFTRACING
EventPipeSession::EventPipeSession(
EventPipeSessionType sessionType,
unsigned int circularBufferSizeInMB,
- EventPipeProviderConfiguration *pProviders,
- unsigned int numProviders,
- UINT64 multiFileTraceLengthInSeconds)
+ const EventPipeProviderConfiguration *pProviders,
+ uint32_t numProviders,
+ uint64_t multiFileTraceLengthInSeconds)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
+ PRECONDITION((numProviders == 0) || (numProviders > 0 && pProviders != nullptr));
}
CONTRACTL_END;
m_sessionType = sessionType;
m_circularBufferSizeInBytes = circularBufferSizeInMB * 1024 * 1024; // 1MB;
m_rundownEnabled = false;
- m_pProviderList = new EventPipeSessionProviderList(
- pProviders,
- numProviders);
+ m_pProviderList = new EventPipeSessionProviderList(pProviders, numProviders);
m_multiFileTraceLengthInSeconds = multiFileTraceLengthInSeconds;
GetSystemTimeAsFileTime(&m_sessionStartTime);
QueryPerformanceCounter(&m_sessionStartTimeStamp);
@@ -90,218 +90,4 @@ EventPipeSessionProvider* EventPipeSession::GetSessionProvider(EventPipeProvider
return m_pProviderList->GetSessionProvider(pProvider);
}
-EventPipeSessionProviderList::EventPipeSessionProviderList(
- EventPipeProviderConfiguration *pConfigs,
- unsigned int numConfigs)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_pProviders = new SList<SListElem<EventPipeSessionProvider*>>();
- m_pCatchAllProvider = NULL;
- for(unsigned int i=0; i<numConfigs; i++)
- {
- EventPipeProviderConfiguration *pConfig = &pConfigs[i];
-
- // Enable all events if the provider name == '*', all keywords are on and the requested level == verbose.
- if((wcscmp(W("*"), pConfig->GetProviderName()) == 0) && (pConfig->GetKeywords() == 0xFFFFFFFFFFFFFFFF) && ((EventPipeEventLevel)pConfig->GetLevel() == EventPipeEventLevel::Verbose) && (m_pCatchAllProvider == NULL))
- {
- m_pCatchAllProvider = new EventPipeSessionProvider(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose, NULL);
- }
- else
- {
- EventPipeSessionProvider *pProvider = new EventPipeSessionProvider(
- pConfig->GetProviderName(),
- pConfig->GetKeywords(),
- (EventPipeEventLevel)pConfig->GetLevel(),
- pConfig->GetFilterData());
-
- m_pProviders->InsertTail(new SListElem<EventPipeSessionProvider*>(pProvider));
- }
- }
-}
-
-EventPipeSessionProviderList::~EventPipeSessionProviderList()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if(m_pProviders != NULL)
- {
- SListElem<EventPipeSessionProvider*> *pElem = m_pProviders->GetHead();
- while(pElem != NULL)
- {
- EventPipeSessionProvider *pProvider = pElem->GetValue();
- delete pProvider;
-
- SListElem<EventPipeSessionProvider*> *pCurElem = pElem;
- pElem = m_pProviders->GetNext(pElem);
- delete pCurElem;
- }
-
- delete m_pProviders;
- m_pProviders = NULL;
- }
- if(m_pCatchAllProvider != NULL)
- {
- delete(m_pCatchAllProvider);
- m_pCatchAllProvider = NULL;
- }
-}
-
-void EventPipeSessionProviderList::AddSessionProvider(EventPipeSessionProvider *pProvider)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if(pProvider != NULL)
- {
- m_pProviders->InsertTail(new SListElem<EventPipeSessionProvider*>(pProvider));
- }
-}
-
-EventPipeSessionProvider* EventPipeSessionProviderList::GetSessionProvider(
- EventPipeProvider *pProvider)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // Exists when tracing was enabled at start-up and all events were requested. This is a diagnostic config.
- if(m_pCatchAllProvider != NULL)
- {
- return m_pCatchAllProvider;
- }
-
- if(m_pProviders == NULL)
- {
- return NULL;
- }
-
- SString providerNameStr = pProvider->GetProviderName();
- LPCWSTR providerName = providerNameStr.GetUnicode();
-
- EventPipeSessionProvider *pSessionProvider = NULL;
- SListElem<EventPipeSessionProvider*> *pElem = m_pProviders->GetHead();
- while(pElem != NULL)
- {
- EventPipeSessionProvider *pCandidate = pElem->GetValue();
- if(wcscmp(providerName, pCandidate->GetProviderName()) == 0)
- {
- pSessionProvider = pCandidate;
- break;
- }
- pElem = m_pProviders->GetNext(pElem);
- }
-
- return pSessionProvider;
-}
-
-bool EventPipeSessionProviderList::IsEmpty() const
-{
- LIMITED_METHOD_CONTRACT;
-
- return (m_pProviders->IsEmpty() && m_pCatchAllProvider == NULL);
-}
-
-EventPipeSessionProvider::EventPipeSessionProvider(
- LPCWSTR providerName,
- UINT64 keywords,
- EventPipeEventLevel loggingLevel,
- LPCWSTR filterData)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if(providerName != NULL)
- {
- size_t bufSize = wcslen(providerName) + 1;
- m_pProviderName = new WCHAR[bufSize];
- wcscpy_s(m_pProviderName, bufSize, providerName);
- }
- else
- {
- m_pProviderName = NULL;
- }
- m_keywords = keywords;
- m_loggingLevel = loggingLevel;
-
- if(filterData != NULL)
- {
- size_t bufSize = wcslen(filterData) + 1;
- m_pFilterData = new WCHAR[bufSize];
- wcscpy_s(m_pFilterData, bufSize, filterData);
- }
- else
- {
- m_pFilterData = NULL;
- }
-}
-
-EventPipeSessionProvider::~EventPipeSessionProvider()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // C++ standard, $5.3.5/2: Deleting a NULL pointer is safe.
- delete[] m_pProviderName;
- m_pProviderName = NULL;
-
- delete[] m_pFilterData;
- m_pFilterData = NULL;
-}
-
-LPCWSTR EventPipeSessionProvider::GetProviderName() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_pProviderName;
-}
-
-UINT64 EventPipeSessionProvider::GetKeywords() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_keywords;
-}
-
-EventPipeEventLevel EventPipeSessionProvider::GetLevel() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_loggingLevel;
-}
-
-LPCWSTR EventPipeSessionProvider::GetFilterData() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_pFilterData;
-}
-
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipesession.h b/src/vm/eventpipesession.h
index 3c4f293407..0474c7cafe 100644
--- a/src/vm/eventpipesession.h
+++ b/src/vm/eventpipesession.h
@@ -7,15 +7,14 @@
#ifdef FEATURE_PERFTRACING
-enum class EventPipeEventLevel;
-struct EventPipeProviderConfiguration;
class EventPipeSessionProviderList;
class EventPipeSessionProvider;
enum class EventPipeSessionType
{
File,
- Streaming
+ Streaming,
+ IpcStream
};
class EventPipeSession
@@ -49,10 +48,9 @@ public:
EventPipeSession(
EventPipeSessionType sessionType,
unsigned int circularBufferSizeInMB,
- EventPipeProviderConfiguration *pProviders,
- unsigned int numProviders,
- UINT64 multiFileTraceLengthInSeconds);
-
+ const EventPipeProviderConfiguration *pProviders,
+ uint32_t numProviders,
+ uint64_t multiFileTraceLengthInSeconds);
~EventPipeSession();
// Determine if the session is valid or not. Invalid sessions can be detected before they are enabled.
@@ -113,68 +111,6 @@ public:
EventPipeSessionProvider* GetSessionProvider(EventPipeProvider *pProvider);
};
-class EventPipeSessionProviderList
-{
-
-private:
-
- // The list of providers.
- SList<SListElem<EventPipeSessionProvider*>> *m_pProviders;
-
- // A catch-all provider used when tracing is enabled for all events.
- EventPipeSessionProvider *m_pCatchAllProvider;
-
-public:
-
- // Create a new list based on the input.
- EventPipeSessionProviderList(EventPipeProviderConfiguration *pConfigs, unsigned int numConfigs);
- ~EventPipeSessionProviderList();
-
- // Add a new session provider to the list.
- void AddSessionProvider(EventPipeSessionProvider *pProvider);
-
- // Get the session provider for the specified provider.
- // Return NULL if one doesn't exist.
- EventPipeSessionProvider* GetSessionProvider(EventPipeProvider *pProvider);
-
- // Returns true if the list is empty.
- bool IsEmpty() const;
-};
-
-class EventPipeSessionProvider
-{
-private:
-
- // The provider name.
- WCHAR *m_pProviderName;
-
- // The enabled keywords.
- UINT64 m_keywords;
-
- // The loging level.
- EventPipeEventLevel m_loggingLevel;
-
- // The filter data.
- WCHAR *m_pFilterData;
-
-public:
-
- EventPipeSessionProvider(
- LPCWSTR providerName,
- UINT64 keywords,
- EventPipeEventLevel loggingLevel,
- LPCWSTR filterData);
- ~EventPipeSessionProvider();
-
- LPCWSTR GetProviderName() const;
-
- UINT64 GetKeywords() const;
-
- EventPipeEventLevel GetLevel() const;
-
- LPCWSTR GetFilterData() const;
-};
-
#endif // FEATURE_PERFTRACING
#endif // __EVENTPIPE_SESSION_H__
diff --git a/src/vm/eventpipesessionprovider.cpp b/src/vm/eventpipesessionprovider.cpp
new file mode 100644
index 0000000000..7e79c47958
--- /dev/null
+++ b/src/vm/eventpipesessionprovider.cpp
@@ -0,0 +1,195 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "eventpipeprovider.h"
+#include "eventpipesessionprovider.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeSessionProvider::EventPipeSessionProvider(
+ LPCWSTR providerName,
+ UINT64 keywords,
+ EventPipeEventLevel loggingLevel,
+ LPCWSTR filterData)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (providerName != NULL)
+ {
+ size_t bufSize = wcslen(providerName) + 1;
+ m_pProviderName = new WCHAR[bufSize];
+ wcscpy_s(m_pProviderName, bufSize, providerName);
+ }
+ else
+ {
+ m_pProviderName = NULL;
+ }
+
+ m_keywords = keywords;
+ m_loggingLevel = loggingLevel;
+
+ if (filterData != NULL)
+ {
+ size_t bufSize = wcslen(filterData) + 1;
+ m_pFilterData = new WCHAR[bufSize];
+ wcscpy_s(m_pFilterData, bufSize, filterData);
+ }
+ else
+ {
+ m_pFilterData = NULL;
+ }
+}
+
+EventPipeSessionProvider::~EventPipeSessionProvider()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ delete[] m_pProviderName;
+ delete[] m_pFilterData;
+}
+
+EventPipeSessionProviderList::EventPipeSessionProviderList(
+ const EventPipeProviderConfiguration *pConfigs,
+ uint32_t numConfigs)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION((numConfigs == 0) || (numConfigs > 0 && pConfigs != nullptr));
+ }
+ CONTRACTL_END;
+
+ m_pProviders = new SList<SListElem<EventPipeSessionProvider *>>();
+ m_pCatchAllProvider = NULL;
+
+ if ((numConfigs > 0) && (pConfigs == nullptr))
+ return; // TODO: This seems the logical thing to do here.
+
+ for (uint32_t i = 0; i < numConfigs; ++i)
+ {
+ const EventPipeProviderConfiguration *pConfig = &pConfigs[i];
+
+ // Enable all events if the provider name == '*', all keywords are on and the requested level == verbose.
+ if ((wcscmp(W("*"), pConfig->GetProviderName()) == 0) && (pConfig->GetKeywords() == 0xFFFFFFFFFFFFFFFF) && ((EventPipeEventLevel)pConfig->GetLevel() == EventPipeEventLevel::Verbose) && (m_pCatchAllProvider == NULL))
+ {
+ m_pCatchAllProvider = new EventPipeSessionProvider(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose, NULL);
+ }
+ else
+ {
+ EventPipeSessionProvider *pProvider = new EventPipeSessionProvider(
+ pConfig->GetProviderName(),
+ pConfig->GetKeywords(),
+ (EventPipeEventLevel)pConfig->GetLevel(),
+ pConfig->GetFilterData());
+
+ m_pProviders->InsertTail(new SListElem<EventPipeSessionProvider *>(pProvider));
+ }
+ }
+}
+
+EventPipeSessionProviderList::~EventPipeSessionProviderList()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (m_pProviders != NULL)
+ {
+ SListElem<EventPipeSessionProvider *> *pElem = m_pProviders->GetHead();
+ while (pElem != NULL)
+ {
+ EventPipeSessionProvider *pProvider = pElem->GetValue();
+ delete pProvider;
+
+ SListElem<EventPipeSessionProvider *> *pCurElem = pElem;
+ pElem = m_pProviders->GetNext(pElem);
+ delete pCurElem;
+ }
+
+ delete m_pProviders;
+ }
+
+ delete m_pCatchAllProvider;
+}
+
+void EventPipeSessionProviderList::AddSessionProvider(EventPipeSessionProvider *pProvider)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(pProvider != nullptr);
+ }
+ CONTRACTL_END;
+
+ if (pProvider != nullptr)
+ m_pProviders->InsertTail(new SListElem<EventPipeSessionProvider *>(pProvider));
+}
+
+EventPipeSessionProvider *EventPipeSessionProviderList::GetSessionProvider(
+ EventPipeProvider *pProvider)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(pProvider != nullptr); // TODO: This seems like a reasonable pre-condition
+ }
+ CONTRACTL_END;
+
+ // Exists when tracing was enabled at start-up and all events were requested. This is a diagnostic config.
+ if (m_pCatchAllProvider != NULL)
+ return m_pCatchAllProvider;
+
+ if (m_pProviders == NULL)
+ return NULL;
+
+ SString providerNameStr = pProvider->GetProviderName();
+ LPCWSTR providerName = providerNameStr.GetUnicode();
+
+ EventPipeSessionProvider *pSessionProvider = NULL;
+ SListElem<EventPipeSessionProvider *> *pElem = m_pProviders->GetHead();
+ while (pElem != NULL)
+ {
+ EventPipeSessionProvider *pCandidate = pElem->GetValue();
+ if (wcscmp(providerName, pCandidate->GetProviderName()) == 0)
+ {
+ pSessionProvider = pCandidate;
+ break;
+ }
+ pElem = m_pProviders->GetNext(pElem);
+ }
+
+ return pSessionProvider;
+}
+
+bool EventPipeSessionProviderList::IsEmpty() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_pProviders->IsEmpty() && m_pCatchAllProvider == NULL);
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipesessionprovider.h b/src/vm/eventpipesessionprovider.h
new file mode 100644
index 0000000000..7b500e4412
--- /dev/null
+++ b/src/vm/eventpipesessionprovider.h
@@ -0,0 +1,81 @@
+#ifndef __EVENTPIPE_SESSION_PROVIDER_SESSION_H__
+#define __EVENTPIPE_SESSION_PROVIDER_SESSION_H__
+
+#ifdef FEATURE_PERFTRACING
+
+enum class EventPipeEventLevel;
+class EventPipeProvider;
+
+class EventPipeSessionProvider
+{
+public:
+ EventPipeSessionProvider(
+ LPCWSTR providerName,
+ UINT64 keywords,
+ EventPipeEventLevel loggingLevel,
+ LPCWSTR filterData);
+ ~EventPipeSessionProvider();
+
+ LPCWSTR GetProviderName() const
+ {
+ return m_pProviderName;
+ }
+
+ UINT64 GetKeywords() const
+ {
+ return m_keywords;
+ }
+
+ EventPipeEventLevel GetLevel() const
+ {
+ return m_loggingLevel;
+ }
+
+ LPCWSTR GetFilterData() const
+ {
+ return m_pFilterData;
+ }
+
+private:
+ WCHAR *m_pProviderName;
+ UINT64 m_keywords;
+ EventPipeEventLevel m_loggingLevel;
+ WCHAR *m_pFilterData;
+};
+
+class EventPipeSessionProviderList
+{
+public:
+
+ // Create a new list based on the input.
+ EventPipeSessionProviderList(
+ const EventPipeProviderConfiguration *pConfigs,
+ uint32_t numConfigs);
+ ~EventPipeSessionProviderList();
+
+ // Add a new session provider to the list.
+ void AddSessionProvider(EventPipeSessionProvider *pProvider);
+
+ // Get the session provider for the specified provider.
+ // Return NULL if one doesn't exist.
+ EventPipeSessionProvider* GetSessionProvider(EventPipeProvider *pProvider);
+
+ // Returns true if the list is empty.
+ bool IsEmpty() const;
+
+ EventPipeSessionProviderList() = delete;
+ EventPipeSessionProviderList(const EventPipeSessionProviderList &other) = delete;
+ EventPipeSessionProviderList(EventPipeSessionProviderList &&other) = delete;
+ EventPipeSessionProviderList &operator=(const EventPipeSessionProviderList &rhs) = delete;
+ EventPipeSessionProviderList &&operator=(EventPipeSessionProviderList &&rhs) = delete;
+
+private:
+ SList<SListElem<EventPipeSessionProvider*>> *m_pProviders = nullptr;
+
+ // A catch-all provider used when tracing is enabled for all events.
+ EventPipeSessionProvider *m_pCatchAllProvider = nullptr;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_SESSION_PROVIDER_SESSION_H__
diff --git a/src/vm/fastserializer.cpp b/src/vm/fastserializer.cpp
index 7a79b2ff19..89dbe50728 100644
--- a/src/vm/fastserializer.cpp
+++ b/src/vm/fastserializer.cpp
@@ -11,7 +11,47 @@
// As a result of work on V3 of Event Pipe (https://github.com/Microsoft/perfview/pull/532) it got removed
// if you need it, please use git to restore it
-FastSerializer::FastSerializer(SString &outputFilePath)
+IpcStreamWriter::IpcStreamWriter(IpcStream *pStream) : _pStream(pStream)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(_pStream != nullptr);
+ }
+ CONTRACTL_END;
+}
+
+IpcStreamWriter::~IpcStreamWriter()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ delete _pStream;
+}
+
+bool IpcStreamWriter::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_PREEMPTIVE;
+ PRECONDITION(lpBuffer != nullptr);
+ PRECONDITION(nBytesToWrite > 0);
+ }
+ CONTRACTL_END;
+
+ return _pStream->Write(lpBuffer, nBytesToWrite, nBytesWritten);
+}
+
+FileStreamWriter::FileStreamWriter(const SString &outputFilePath)
{
CONTRACTL
{
@@ -21,21 +61,17 @@ FastSerializer::FastSerializer(SString &outputFilePath)
}
CONTRACTL_END;
- m_writeErrorEncountered = false;
- m_currentPos = 0;
m_pFileStream = new CFileStream();
- if(FAILED(m_pFileStream->OpenForWrite(outputFilePath)))
+ if (FAILED(m_pFileStream->OpenForWrite(outputFilePath)))
{
_ASSERTE(!"Unable to open file for write.");
- delete(m_pFileStream);
+ delete m_pFileStream;
m_pFileStream = NULL;
return;
}
-
- WriteFileHeader();
}
-FastSerializer::~FastSerializer()
+FileStreamWriter::~FileStreamWriter()
{
CONTRACTL
{
@@ -45,18 +81,54 @@ FastSerializer::~FastSerializer()
}
CONTRACTL_END;
- if(m_pFileStream != NULL)
+ delete m_pFileStream;
+}
+
+bool FileStreamWriter::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const
+{
+ CONTRACTL
{
- delete(m_pFileStream);
- m_pFileStream = NULL;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_PREEMPTIVE;
+ PRECONDITION(lpBuffer != nullptr);
+ PRECONDITION(nBytesToWrite > 0);
+ }
+ CONTRACTL_END;
+
+ ULONG outCount;
+ HRESULT hResult = m_pFileStream->Write(lpBuffer, nBytesToWrite, &outCount);
+ nBytesWritten = static_cast<uint32_t>(outCount);
+ return hResult == S_OK;
+}
+
+FastSerializer::FastSerializer(StreamWriter *pStreamWriter) : m_pStreamWriter(pStreamWriter)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(m_pStreamWriter != NULL);
}
+ CONTRACTL_END;
+
+ m_writeErrorEncountered = false;
+ m_currentPos = 0;
+ WriteFileHeader();
}
-StreamLabel FastSerializer::GetStreamLabel() const
+FastSerializer::~FastSerializer()
{
- LIMITED_METHOD_CONTRACT;
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
- return (StreamLabel)m_currentPos;
+ delete m_pStreamWriter;
}
void FastSerializer::WriteObject(FastSerializableObject *pObject)
@@ -92,15 +164,13 @@ void FastSerializer::WriteBuffer(BYTE *pBuffer, unsigned int length)
}
CONTRACTL_END;
- if(m_writeErrorEncountered || m_pFileStream == NULL)
- {
+ if (m_writeErrorEncountered || m_pStreamWriter == NULL)
return;
- }
EX_TRY
{
- ULONG outCount;
- m_pFileStream->Write(pBuffer, length, &outCount);
+ uint32_t outCount;
+ m_pStreamWriter->Write(pBuffer, length, outCount);
#ifdef _DEBUG
size_t prevPos = m_currentPos;
@@ -120,7 +190,7 @@ void FastSerializer::WriteBuffer(BYTE *pBuffer, unsigned int length)
EX_CATCH
{
m_writeErrorEncountered = true;
- }
+ }
EX_END_CATCH(SwallowAllExceptions);
}
@@ -142,10 +212,10 @@ void FastSerializer::WriteSerializationType(FastSerializableObject *pObject)
WriteTag(FastSerializerTags::NullReference);
// Write the SerializationType version fields.
- int serializationType[2];
- serializationType[0] = pObject->GetObjectVersion();
- serializationType[1] = pObject->GetMinReaderVersion();
- WriteBuffer((BYTE*) &serializationType, sizeof(serializationType));
+ int serializationType[2] = {
+ pObject->GetObjectVersion(),
+ pObject->GetMinReaderVersion()};
+ WriteBuffer((BYTE *)&serializationType, sizeof(serializationType));
// Write the SerializationType TypeName field.
const char *strTypeName = pObject->GetTypeName();
@@ -157,7 +227,6 @@ void FastSerializer::WriteSerializationType(FastSerializableObject *pObject)
WriteTag(FastSerializerTags::EndObject);
}
-
void FastSerializer::WriteTag(FastSerializerTags tag, BYTE *payload, unsigned int payloadLength)
{
CONTRACTL
@@ -169,7 +238,7 @@ void FastSerializer::WriteTag(FastSerializerTags tag, BYTE *payload, unsigned in
CONTRACTL_END;
WriteBuffer((BYTE *)&tag, sizeof(tag));
- if(payload != NULL)
+ if (payload != NULL)
{
_ASSERTE(payloadLength > 0);
WriteBuffer(payload, payloadLength);
@@ -202,10 +271,10 @@ void FastSerializer::WriteString(const char *strContents, unsigned int length)
CONTRACTL_END;
// Write the string length .
- WriteBuffer((BYTE*) &length, sizeof(length));
+ WriteBuffer((BYTE *)&length, sizeof(length));
// Write the string contents.
- WriteBuffer((BYTE*) strContents, length);
+ WriteBuffer((BYTE *)strContents, length);
}
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/fastserializer.h b/src/vm/fastserializer.h
index fad04de48c..3b4de65bf5 100644
--- a/src/vm/fastserializer.h
+++ b/src/vm/fastserializer.h
@@ -11,23 +11,20 @@
#include "fastserializableobject.h"
#include "fstream.h"
-
-class FastSerializer;
-
-typedef unsigned int StreamLabel;
+#include "diagnosticsipc.h"
// the enumeration has a specific set of values to keep it compatible with consumer library
// it's sibling is defined in https://github.com/Microsoft/perfview/blob/10d1f92b242c98073b3817ac5ee6d98cd595d39b/src/FastSerialization/FastSerialization.cs#L2295
-enum class FastSerializerTags : BYTE
+enum class FastSerializerTags : BYTE
{
- Error = 0, // To improve debugabilty, 0 is an illegal tag.
- NullReference = 1, // Tag for a null object forwardReference.
- ObjectReference = 2, // Followed by StreamLabel
- // 3 used to belong to ForwardReference, which got removed in V3
+ Error = 0, // To improve debugabilty, 0 is an illegal tag.
+ NullReference = 1, // Tag for a null object forwardReference.
+ ObjectReference = 2, // Followed by StreamLabel
+ // 3 used to belong to ForwardReference, which got removed in V3
BeginObject = 4, // Followed by Type object, object data, tagged EndObject
- BeginPrivateObject = 5, // Like beginObject, but not placed in interning table on deserialiation
- EndObject = 6, // Placed after an object to mark its end.
- // 7 used to belong to ForwardDefinition, which got removed in V3
+ BeginPrivateObject = 5, // Like beginObject, but not placed in interning table on deserialiation
+ EndObject = 6, // Placed after an object to mark its end.
+ // 7 used to belong to ForwardDefinition, which got removed in V3
Byte = 8,
Int16,
Int32,
@@ -35,17 +32,53 @@ enum class FastSerializerTags : BYTE
SkipRegion,
String,
Blob,
- Limit // Just past the last valid tag, used for asserts.
+ Limit // Just past the last valid tag, used for asserts.
};
-class FastSerializer
+//!
+//! Provides a generic interface for writing a sequence of bytes to a stream.
+//!
+class StreamWriter
{
public:
+ StreamWriter() = default;
+ virtual ~StreamWriter() = default;
+ virtual bool Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const = 0;
+};
- FastSerializer(SString &outputFilePath);
- ~FastSerializer();
+//!
+//! Implements a StreamWriter for writing bytes to an IPC.
+//!
+class IpcStreamWriter final : public StreamWriter
+{
+public:
+ IpcStreamWriter(IpcStream *pStream);
+ ~IpcStreamWriter();
+ bool Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const;
+
+private:
+ IpcStream *const _pStream;
+};
+
+//!
+//! Implements a StreamWriter for writing bytes to an File.
+//!
+class FileStreamWriter final : public StreamWriter
+{
+public:
+ FileStreamWriter(const SString &outputFilePath);
+ ~FileStreamWriter();
+ bool Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const;
+
+private:
+ CFileStream *m_pFileStream;
+};
- StreamLabel GetStreamLabel() const;
+class FastSerializer
+{
+public:
+ FastSerializer(StreamWriter *pStreamWriter);
+ ~FastSerializer();
void WriteObject(FastSerializableObject *pObject);
void WriteBuffer(BYTE *pBuffer, unsigned int length);
@@ -55,16 +88,14 @@ public:
size_t GetCurrentPosition() const
{
LIMITED_METHOD_CONTRACT;
-
return m_currentPos;
}
private:
-
void WriteSerializationType(FastSerializableObject *pObject);
void WriteFileHeader();
- CFileStream *m_pFileStream;
+ StreamWriter *const m_pStreamWriter;
bool m_writeErrorEncountered;
size_t m_currentPos;
};
diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp
index faec6e5c97..10ed4944b6 100644
--- a/src/vm/mscorlib.cpp
+++ b/src/vm/mscorlib.cpp
@@ -84,10 +84,12 @@
#if defined(FEATURE_EVENTSOURCE_XPLAT)
#include "nativeeventsource.h"
#include "eventpipe.h"
+#include "eventpipeinternal.h"
#endif //defined(FEATURE_EVENTSOURCE_XPLAT)
#ifdef FEATURE_PERFTRACING
#include "eventpipe.h"
+#include "eventpipeinternal.h"
#endif //FEATURE_PERFTRACING
#endif // CROSSGEN_MSCORLIB