summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Rivero <jorive@microsoft.com>2019-03-18 10:23:30 -0700
committerGitHub <noreply@github.com>2019-03-18 10:23:30 -0700
commit4497df34cbe3d8bf7a21828714a3cf764da16e98 (patch)
tree894fc03e621e498cf6b5b33a34fdbb3c63c7d10a
parentb88f2f635b02c130ae00b4d8aee3e766a60698d5 (diff)
downloadcoreclr-4497df34cbe3d8bf7a21828714a3cf764da16e98.tar.gz
coreclr-4497df34cbe3d8bf7a21828714a3cf764da16e98.tar.bz2
coreclr-4497df34cbe3d8bf7a21828714a3cf764da16e98.zip
[EventPipe] Adding an IPC server to handle out of process communication. (#23106)
This is the first commit to enable a "diagnostic port" using IPC (Named Pipe on Windows and Unix Domain Socket on other platforms). This change currently enable EventPipe to be enabled/disabled without the use of a file drop. - Split the DiagnosticsIpc into (DiagnosticsIpc/IpcStream) - DiagnosticsIpc (IPC listener) is meant to be used by the Diagnostic server. - IpcStream (IPC channel) is meant to be use to communicate with the connected client. - Change the FastSerializer dependency from `CFileStream` to `StreamWriter` This abstraction is meant decouple the writing of objects in order to extend its usability. The main objective is to reuse FastSerializer to stream data through the open IPC channel. - Moved the EventPipeSessionProvider* classes to their own file. - Added a more streamlined parsing achievable by defining a simpler binary protocol (by noahfalk). 1. Only one allocation is needed for the EventPipeProviderConfiguration array, no allocations or copies are needed for strings because we can refer to them directly out of the incoming command buffer 2. No change to the EventPipe API for enable is required. EventPipeProviderConfiguration retains its current behavior of not deleting the string pointers it holds. 3. No leaks happen because the command buffer owns the string memory and ensures that it stays alive for the duration of the Enable() call.
-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