summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Robbins <brianrob@microsoft.com>2018-01-25 20:29:23 -0800
committerGitHub <noreply@github.com>2018-01-25 20:29:23 -0800
commita118b0571d8ae8bd34c275d02294fa19251345b6 (patch)
tree505de85259c0263f556d7813fd388abf39eaf2c0
parent5c5695fb05c62f42b969cc33119399e6c8fcf04e (diff)
downloadcoreclr-a118b0571d8ae8bd34c275d02294fa19251345b6.tar.gz
coreclr-a118b0571d8ae8bd34c275d02294fa19251345b6.tar.bz2
coreclr-a118b0571d8ae8bd34c275d02294fa19251345b6.zip
Create the concept of EventPipeSession and refactor EventPipe to use it. Also expose COMPlus configuration variables to support session configuration and output file path. (#16018)
-rw-r--r--src/inc/clrconfigvalues.h10
-rw-r--r--src/vm/CMakeLists.txt1
-rw-r--r--src/vm/eventpipe.cpp192
-rw-r--r--src/vm/eventpipe.h9
-rw-r--r--src/vm/eventpipeconfiguration.cpp298
-rw-r--r--src/vm/eventpipeconfiguration.h95
-rw-r--r--src/vm/eventpipeprovider.cpp1
-rw-r--r--src/vm/eventpipesession.cpp296
-rw-r--r--src/vm/eventpipesession.h135
9 files changed, 730 insertions, 307 deletions
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index 95179d8ed2..afb67986ff 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -728,10 +728,12 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableRCWCleanupOnSTAShutdown, W("EnableRCWCle
RETAIL_CONFIG_STRING_INFO(INTERNAL_LocalWinMDPath, W("LocalWinMDPath"), "Additional path to probe for WinMD files in if a WinRT type is not resolved using the standard paths.")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_AllowDComReflection, W("AllowDComReflection"), 0, "Allows out of process DCOM clients to marshal blocked reflection types.")
-///
-/// Performance Tracing
-///
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_PerformanceTracing, W("PerformanceTracing"), 0, "Enable/disable performance tracing. Non-zero values enable tracing.")
+//
+// EventPipe
+//
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableEventPipe, W("EnableEventPipe"), 0, "Enable/disable event pipe. Non-zero values enable tracing.")
+RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeOutputFile, W("EventPipeOutputFile"), "The full path including file name for the trace file that will be written when COMPlus_EnableEventPipe&=1")
+RETAIL_CONFIG_STRING_INFO(INTERNAL_EventPipeConfig, W("EventPipeConfig"), "Configuration for EventPipe.")
#ifdef FEATURE_GDBJIT
///
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index 67aece1c8a..5a30bce6b8 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -189,6 +189,7 @@ set(VM_SOURCES_WKS
eventpipeprovider.cpp
eventpipebuffer.cpp
eventpipebuffermanager.cpp
+ eventpipesession.cpp
eventstore.cpp
fastserializer.cpp
fcall.cpp
diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp
index 37de4c3b36..2eeb64f4b2 100644
--- a/src/vm/eventpipe.cpp
+++ b/src/vm/eventpipe.cpp
@@ -11,6 +11,7 @@
#include "eventpipeevent.h"
#include "eventpipefile.h"
#include "eventpipeprovider.h"
+#include "eventpipesession.h"
#include "eventpipejsonfile.h"
#include "sampleprofiler.h"
@@ -23,6 +24,7 @@
CrstStatic EventPipe::s_configCrst;
bool EventPipe::s_tracingInitialized = false;
EventPipeConfiguration* EventPipe::s_pConfig = NULL;
+EventPipeSession* EventPipe::s_pSession = NULL;
EventPipeBufferManager* EventPipe::s_pBufferManager = NULL;
EventPipeFile* EventPipe::s_pFile = NULL;
#ifdef _DEBUG
@@ -206,15 +208,22 @@ void EventPipe::EnableOnStartup()
CONTRACTL_END;
// Test COMPLUS variable to enable tracing at start-up.
- if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
+ if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableEventPipe) & 1) == 1)
{
SString outputPath;
outputPath.Printf("Process-%d.netperf", GetCurrentProcessId());
- Enable(
- outputPath.GetUnicode(),
+
+ // Create a new session.
+ EventPipeSession *pSession = new EventPipeSession(
1024 /* 1 GB circular buffer */,
- NULL /* pProviders */,
+ NULL, /* pProviders */
0 /* numProviders */);
+
+ // Get the configuration from the environment.
+ GetConfigurationFromEnvironment(outputPath, pSession);
+
+ // Enable the session.
+ Enable(outputPath, pSession);
}
}
@@ -262,14 +271,32 @@ void EventPipe::Enable(
}
CONTRACTL_END;
+ // Create a new session.
+ EventPipeSession *pSession = s_pConfig->CreateSession(circularBufferSizeInMB, pProviders, static_cast<unsigned int>(numProviders));
+
+ // Enable the session.
+ Enable(strOutputPath, pSession);
+}
+
+void EventPipe::Enable(LPCWSTR strOutputPath, EventPipeSession *pSession)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(pSession != NULL);
+ }
+ CONTRACTL_END;
+
// If tracing is not initialized or is already enabled, bail here.
if(!s_tracingInitialized || s_pConfig == NULL || s_pConfig->Enabled())
{
return;
}
- // If the state or aurguments are invalid, bail
- if(pProviders == NULL || numProviders <= 0)
+ // If the state or arguments are invalid, bail here.
+ if(pSession == NULL || !pSession->IsValid())
{
return;
}
@@ -282,7 +309,7 @@ void EventPipe::Enable(
s_pFile = new EventPipeFile(eventPipeFileOutputPath);
#ifdef _DEBUG
- if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 2) == 2)
+ if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableEventPipe) & 2) == 2)
{
// Create a synchronous file.
SString eventPipeSyncFileOutputPath;
@@ -296,8 +323,11 @@ void EventPipe::Enable(
}
#endif // _DEBUG
+ // Save the session.
+ s_pSession = pSession;
+
// Enable tracing.
- s_pConfig->Enable(circularBufferSizeInMB, pProviders, numProviders);
+ s_pConfig->Enable(s_pSession);
// Enable the sample profiler
SampleProfiler::Enable();
@@ -325,7 +355,11 @@ void EventPipe::Disable()
SampleProfiler::Disable();
// Disable tracing.
- s_pConfig->Disable();
+ s_pConfig->Disable(s_pSession);
+
+ // Delete the session.
+ s_pConfig->DeleteSession(s_pSession);
+ s_pSession = NULL;
// Flush all write buffers to make sure that all threads see the change.
FlushProcessWriteBuffers();
@@ -336,7 +370,15 @@ void EventPipe::Disable()
s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
// Before closing the file, do rundown.
- s_pConfig->EnableRundown();
+ const unsigned int numRundownProviders = 2;
+ EventPipeProviderConfiguration rundownProviders[] =
+ {
+ { W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose) }, // Public provider.
+ { W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose) } // Rundown provider.
+ };
+ // The circular buffer size doesn't matter because all events are written synchronously during rundown.
+ s_pSession = s_pConfig->CreateSession(1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
+ s_pConfig->EnableRundown(s_pSession);
// Ask the runtime to emit rundown events.
if(g_fEEStarted && !g_fEEShutDown)
@@ -345,7 +387,11 @@ void EventPipe::Disable()
}
// Disable the event pipe now that rundown is complete.
- s_pConfig->Disable();
+ s_pConfig->Disable(s_pSession);
+
+ // Delete the rundown session.
+ s_pConfig->DeleteSession(s_pSession);
+ s_pSession = NULL;
if(s_pFile != NULL)
{
@@ -710,6 +756,130 @@ CrstStatic* EventPipe::GetLock()
return &s_configCrst;
}
+void EventPipe::GetConfigurationFromEnvironment(SString &outputPath, EventPipeSession *pSession)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // Set the output path if specified.
+ CLRConfigStringHolder wszOutputPath(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeOutputFile));
+ if(wszOutputPath != NULL)
+ {
+ outputPath.Set(wszOutputPath);
+ }
+
+ // Read the the provider configuration from the environment if specified.
+ CLRConfigStringHolder wszConfig(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeConfig));
+ if(wszConfig == NULL)
+ {
+ pSession->EnableAllEvents();
+ return;
+ }
+
+ size_t len = wcslen(wszConfig);
+ if(len <= 0)
+ {
+ pSession->EnableAllEvents();
+ return;
+ }
+
+ // Parses a string with the following format:
+ //
+ // ProviderName:Keywords:Level[,]*
+ //
+ // For example:
+ //
+ // Microsoft-Windows-DotNETRuntime:0xCAFEBABE:2,Microsoft-Windows-DotNETRuntimePrivate:0xDEADBEEF:1
+ //
+ // Each provider configuration is separated by a ',' and each component within the configuration is
+ // separated by a ':'.
+
+ const WCHAR ProviderSeparatorChar = ',';
+ const WCHAR ComponentSeparatorChar = ':';
+ size_t index = 0;
+ WCHAR *pProviderName = NULL;
+ UINT64 keywords = 0;
+ EventPipeEventLevel level = EventPipeEventLevel::Critical;
+
+ while(index < len)
+ {
+ WCHAR * pCurrentChunk = &wszConfig[index];
+ size_t currentChunkStartIndex = index;
+ size_t currentChunkEndIndex = 0;
+
+ // Find the next chunk.
+ while(index < len && wszConfig[index] != ProviderSeparatorChar)
+ {
+ index++;
+ }
+ currentChunkEndIndex = index++;
+
+ // Split the chunk into components.
+ size_t chunkIndex = currentChunkStartIndex;
+
+ // Get the provider name.
+ size_t provNameStartIndex = chunkIndex;
+ size_t provNameEndIndex = currentChunkEndIndex;
+
+ while(chunkIndex < currentChunkEndIndex && wszConfig[chunkIndex] != ComponentSeparatorChar)
+ {
+ chunkIndex++;
+ }
+ provNameEndIndex = chunkIndex++;
+
+ size_t provNameLen = provNameEndIndex - provNameStartIndex;
+ pProviderName = new WCHAR[provNameLen+1];
+ memcpy(pProviderName, &wszConfig[provNameStartIndex], provNameLen*sizeof(WCHAR));
+ pProviderName[provNameLen] = '\0';
+
+ // Get the keywords.
+ size_t keywordsStartIndex = chunkIndex;
+ size_t keywordsEndIndex = currentChunkEndIndex;
+
+ while(chunkIndex < currentChunkEndIndex && wszConfig[chunkIndex] != ComponentSeparatorChar)
+ {
+ chunkIndex++;
+ }
+ keywordsEndIndex = chunkIndex++;
+
+ size_t keywordsLen = keywordsEndIndex - keywordsStartIndex;
+ WCHAR *wszKeywords = new WCHAR[keywordsLen+1];
+ memcpy(wszKeywords, &wszConfig[keywordsStartIndex], keywordsLen*sizeof(WCHAR));
+ wszKeywords[keywordsLen] = '\0';
+ keywords = _wcstoui64(wszKeywords, NULL, 16);
+ delete[] wszKeywords;
+ wszKeywords = NULL;
+
+ // Get the level.
+ size_t levelStartIndex = chunkIndex;
+ size_t levelEndIndex = currentChunkEndIndex;
+
+ while(chunkIndex < currentChunkEndIndex && wszConfig[chunkIndex] != ComponentSeparatorChar)
+ {
+ chunkIndex++;
+ }
+ levelEndIndex = chunkIndex++;
+
+ size_t levelLen = levelEndIndex - levelStartIndex;
+ WCHAR *wszLevel = new WCHAR[levelLen+1];
+ memcpy(wszLevel, &wszConfig[levelStartIndex], levelLen*sizeof(WCHAR));
+ wszLevel[levelLen] = '\0';
+ level = (EventPipeEventLevel) wcstoul(wszLevel, NULL, 16);
+ delete[] wszLevel;
+ wszLevel = NULL;
+
+ // Add a new EventPipeSessionProvider.
+ EventPipeSessionProvider *pSessionProvider = new EventPipeSessionProvider(pProviderName, keywords, level);
+ pSession->AddSessionProvider(pSessionProvider);
+
+ // Free the provider name string.
+ if(pProviderName != NULL)
+ {
+ delete[] pProviderName;
+ pProviderName = NULL;
+ }
+ }
+}
+
void QCALLTYPE EventPipeInternal::Enable(
__in_z LPCWSTR outputFile,
UINT32 circularBufferSizeInMB,
diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h
index 4fd3d88127..d1f7d60f8e 100644
--- a/src/vm/eventpipe.h
+++ b/src/vm/eventpipe.h
@@ -20,6 +20,7 @@ class EventPipeProvider;
class MethodDesc;
class SampleProfilerEventInstance;
struct EventPipeProviderConfiguration;
+class EventPipeSession;
// Define the event pipe callback to match the ETW callback signature.
typedef void (*EventPipeCallback)(
@@ -275,6 +276,13 @@ class EventPipe
private:
+ // Enable the specified EventPipe session.
+ static void Enable(LPCWSTR strOutputPath, EventPipeSession *pSession);
+
+ // Get the EnableOnStartup configuration from environment.
+ static void GetConfigurationFromEnvironment(SString &outputPath, EventPipeSession *pSession);
+
+
// Callback function for the stack walker. For each frame walked, this callback is invoked.
static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
@@ -288,6 +296,7 @@ class EventPipe
static CrstStatic s_configCrst;
static bool s_tracingInitialized;
static EventPipeConfiguration *s_pConfig;
+ static EventPipeSession *s_pSession;
static EventPipeBufferManager *s_pBufferManager;
static EventPipeFile *s_pFile;
#ifdef _DEBUG
diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp
index a74bdbc28f..4678fc36fb 100644
--- a/src/vm/eventpipeconfiguration.cpp
+++ b/src/vm/eventpipeconfiguration.cpp
@@ -7,6 +7,7 @@
#include "eventpipeconfiguration.h"
#include "eventpipeeventinstance.h"
#include "eventpipeprovider.h"
+#include "eventpipesession.h"
#ifdef FEATURE_PERFTRACING
@@ -18,9 +19,8 @@ EventPipeConfiguration::EventPipeConfiguration()
m_enabled = false;
m_rundownEnabled = false;
- m_circularBufferSizeInBytes = 1024 * 1024 * 1000; // Default to 1000MB.
- m_pEnabledProviderList = NULL;
m_pConfigProvider = NULL;
+ m_pSession = NULL;
m_pProviderList = new SList<SListElem<EventPipeProvider*>>();
}
@@ -46,11 +46,10 @@ EventPipeConfiguration::~EventPipeConfiguration()
EX_CATCH { }
EX_END_CATCH(SwallowAllExceptions);
}
-
- if(m_pEnabledProviderList != NULL)
+ if(m_pSession != NULL)
{
- delete(m_pEnabledProviderList);
- m_pEnabledProviderList = NULL;
+ DeleteSession(m_pSession);
+ m_pSession = NULL;
}
if(m_pProviderList != NULL)
@@ -173,16 +172,16 @@ bool EventPipeConfiguration::RegisterProvider(EventPipeProvider &provider)
m_pProviderList->InsertTail(new SListElem<EventPipeProvider*>(&provider));
}
- // Set the provider configuration and enable it if we know anything about the provider before it is registered.
- if(m_pEnabledProviderList != NULL)
+ // Set the provider configuration and enable it if it has been requested by a session.
+ if(m_pSession != NULL)
{
- EventPipeEnabledProvider *pEnabledProvider = m_pEnabledProviderList->GetEnabledProvider(&provider);
- if(pEnabledProvider != NULL)
+ EventPipeSessionProvider *pSessionProvider = GetSessionProvider(m_pSession, &provider);
+ if(pSessionProvider != NULL)
{
provider.SetConfiguration(
true /* providerEnabled */,
- pEnabledProvider->GetKeywords(),
- pEnabledProvider->GetLevel());
+ pSessionProvider->GetKeywords(),
+ pSessionProvider->GetLevel());
}
}
@@ -278,40 +277,83 @@ EventPipeProvider* EventPipeConfiguration::GetProviderNoLock(const SString &prov
return NULL;
}
+EventPipeSessionProvider* EventPipeConfiguration::GetSessionProvider(EventPipeSession *pSession, EventPipeProvider *pProvider)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+ }
+ CONTRACTL_END;
+
+ EventPipeSessionProvider *pRet = NULL;
+ if(pSession != NULL)
+ {
+ pRet = pSession->GetSessionProvider(pProvider);
+ }
+ return pRet;
+}
+
size_t EventPipeConfiguration::GetCircularBufferSize() const
{
LIMITED_METHOD_CONTRACT;
- return m_circularBufferSizeInBytes;
+ size_t ret = 0;
+ if(m_pSession != NULL)
+ {
+ ret = m_pSession->GetCircularBufferSize();
+ }
+ return ret;
}
-void EventPipeConfiguration::SetCircularBufferSize(size_t circularBufferSize)
+EventPipeSession* EventPipeConfiguration::CreateSession(unsigned int circularBufferSizeInMB, EventPipeProviderConfiguration *pProviders, unsigned int numProviders)
{
- LIMITED_METHOD_CONTRACT;
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ return new EventPipeSession(circularBufferSizeInMB, pProviders, numProviders);
+}
+
+void EventPipeConfiguration::DeleteSession(EventPipeSession *pSession)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(pSession != NULL);
+ PRECONDITION(m_enabled == false);
+ }
+ CONTRACTL_END;
- if(!m_enabled)
+ // TODO: Multiple session support will require individual enabled bits.
+ if(pSession != NULL && !m_enabled)
{
- m_circularBufferSizeInBytes = circularBufferSize;
+ delete(pSession);
}
}
-void EventPipeConfiguration::Enable(
- unsigned int circularBufferSizeInMB,
- EventPipeProviderConfiguration *pProviders,
- int numProviders)
+void EventPipeConfiguration::Enable(EventPipeSession *pSession)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
+ PRECONDITION(pSession != NULL);
// Lock must be held by EventPipe::Enable.
PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
}
CONTRACTL_END;
- m_circularBufferSizeInBytes = circularBufferSizeInMB * 1024 * 1024;
- m_pEnabledProviderList = new EventPipeEnabledProviderList(pProviders, static_cast<unsigned int>(numProviders));
+ m_pSession = pSession;
m_enabled = true;
// The provider list should be non-NULL, but can be NULL on shutdown.
@@ -323,13 +365,13 @@ void EventPipeConfiguration::Enable(
EventPipeProvider *pProvider = pElem->GetValue();
// Enable the provider if it has been configured.
- EventPipeEnabledProvider *pEnabledProvider = m_pEnabledProviderList->GetEnabledProvider(pProvider);
- if(pEnabledProvider != NULL)
+ EventPipeSessionProvider *pSessionProvider = GetSessionProvider(m_pSession, pProvider);
+ if(pSessionProvider != NULL)
{
pProvider->SetConfiguration(
true /* providerEnabled */,
- pEnabledProvider->GetKeywords(),
- pEnabledProvider->GetLevel());
+ pSessionProvider->GetKeywords(),
+ pSessionProvider->GetLevel());
}
pElem = m_pProviderList->GetNext(pElem);
@@ -337,13 +379,16 @@ void EventPipeConfiguration::Enable(
}
}
-void EventPipeConfiguration::Disable()
+void EventPipeConfiguration::Disable(EventPipeSession *pSession)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
+ // TODO: Multiple session support will require that the session be specified.
+ PRECONDITION(pSession != NULL);
+ PRECONDITION(pSession == m_pSession);
// Lock must be held by EventPipe::Disable.
PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
}
@@ -364,13 +409,7 @@ void EventPipeConfiguration::Disable()
m_enabled = false;
m_rundownEnabled = false;
-
- // Free the enabled providers list.
- if(m_pEnabledProviderList != NULL)
- {
- delete(m_pEnabledProviderList);
- m_pEnabledProviderList = NULL;
- }
+ m_pSession = NULL;
}
bool EventPipeConfiguration::Enabled() const
@@ -385,30 +424,28 @@ bool EventPipeConfiguration::RundownEnabled() const
return m_rundownEnabled;
}
-void EventPipeConfiguration::EnableRundown()
+void EventPipeConfiguration::EnableRundown(EventPipeSession *pSession)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
+ PRECONDITION(pSession != NULL);
// Lock must be held by EventPipe::Disable.
PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
}
CONTRACTL_END;
// Build the rundown configuration.
- _ASSERTE(m_pEnabledProviderList == NULL);
- const unsigned int numRundownProviders = 2;
- EventPipeProviderConfiguration rundownProviders[numRundownProviders];
- rundownProviders[0] = EventPipeProviderConfiguration(W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose)); // Public provider.
- rundownProviders[1] = EventPipeProviderConfiguration(W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose)); // Rundown provider.
+ _ASSERTE(m_pSession == NULL);
// Enable rundown.
+ // TODO: Move this into EventPipeSession once Enable takes an EventPipeSession object.
m_rundownEnabled = true;
- // Enable tracing. The circular buffer size doesn't matter because we're going to write all events synchronously during rundown.
- Enable(1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
+ // Enable tracing.
+ Enable(pSession);
}
EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance)
@@ -506,179 +543,4 @@ void EventPipeConfiguration::DeleteDeferredProviders()
}
}
}
-
-EventPipeEnabledProviderList::EventPipeEnabledProviderList(
- EventPipeProviderConfiguration *pConfigs,
- unsigned int numConfigs)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_pProviders = NULL;
- m_pCatchAllProvider = NULL;
- m_numProviders = 0;
-
- // Test COMPLUS variable to enable tracing at start-up.
- // If tracing is enabled at start-up create the catch-all provider and always return it.
- if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
- {
- m_pCatchAllProvider = new EventPipeEnabledProvider();
- m_pCatchAllProvider->Set(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose);
- return;
- }
-
- m_pCatchAllProvider = NULL;
- m_numProviders = numConfigs;
- if(m_numProviders == 0)
- {
- return;
- }
-
- m_pProviders = new EventPipeEnabledProvider[m_numProviders];
- for(unsigned int i=0; i<m_numProviders; i++)
- {
- m_pProviders[i].Set(
- pConfigs[i].GetProviderName(),
- pConfigs[i].GetKeywords(),
- (EventPipeEventLevel)pConfigs[i].GetLevel());
- }
-}
-
-EventPipeEnabledProviderList::~EventPipeEnabledProviderList()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if(m_pProviders != NULL)
- {
- delete[] m_pProviders;
- m_pProviders = NULL;
- }
- if(m_pCatchAllProvider != NULL)
- {
- delete(m_pCatchAllProvider);
- m_pCatchAllProvider = NULL;
- }
-}
-
-EventPipeEnabledProvider* EventPipeEnabledProviderList::GetEnabledProvider(
- EventPipeProvider *pProvider)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // If tracing was enabled on start-up, all events should be on (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();
-
- EventPipeEnabledProvider *pEnabledProvider = NULL;
- for(unsigned int i=0; i<m_numProviders; i++)
- {
- EventPipeEnabledProvider *pCandidate = &m_pProviders[i];
- if(pCandidate != NULL)
- {
- if(wcscmp(providerName, pCandidate->GetProviderName()) == 0)
- {
- pEnabledProvider = pCandidate;
- break;
- }
- }
- }
-
- return pEnabledProvider;
-}
-
-EventPipeEnabledProvider::EventPipeEnabledProvider()
-{
- LIMITED_METHOD_CONTRACT;
- m_pProviderName = NULL;
- m_keywords = 0;
-}
-
-EventPipeEnabledProvider::~EventPipeEnabledProvider()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if(m_pProviderName != NULL)
- {
- delete[] m_pProviderName;
- m_pProviderName = NULL;
- }
-}
-
-void EventPipeEnabledProvider::Set(LPCWSTR providerName, UINT64 keywords, EventPipeEventLevel loggingLevel)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if(m_pProviderName != NULL)
- {
- delete(m_pProviderName);
- m_pProviderName = NULL;
- }
-
- if(providerName != NULL)
- {
- size_t bufSize = wcslen(providerName) + 1;
- m_pProviderName = new WCHAR[bufSize];
- wcscpy_s(m_pProviderName, bufSize, providerName);
- }
- m_keywords = keywords;
- m_loggingLevel = loggingLevel;
-}
-
-LPCWSTR EventPipeEnabledProvider::GetProviderName() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_pProviderName;
-}
-
-UINT64 EventPipeEnabledProvider::GetKeywords() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_keywords;
-}
-
-EventPipeEventLevel EventPipeEnabledProvider::GetLevel() const
-{
- LIMITED_METHOD_CONTRACT;
- return m_loggingLevel;
-}
-
#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipeconfiguration.h b/src/vm/eventpipeconfiguration.h
index baca06920a..d1a8a90c46 100644
--- a/src/vm/eventpipeconfiguration.h
+++ b/src/vm/eventpipeconfiguration.h
@@ -8,12 +8,13 @@
#include "slist.h"
-class EventPipeEnabledProvider;
-class EventPipeEnabledProviderList;
+class EventPipeSessionProvider;
class EventPipeEvent;
class EventPipeEventInstance;
class EventPipeProvider;
struct EventPipeProviderConfiguration;
+class EventPipeSession;
+class EventPipeSessionProvider;
enum class EventPipeEventLevel
{
@@ -50,20 +51,20 @@ public:
// Get the provider with the specified provider ID if it exists.
EventPipeProvider* GetProvider(const SString &providerID);
+ // Create a new session.
+ EventPipeSession* CreateSession(unsigned int circularBufferSizeInMB, EventPipeProviderConfiguration *pProviders, unsigned int numProviders);
+
+ // Delete a session.
+ void DeleteSession(EventPipeSession *pSession);
+
// Get the configured size of the circular buffer.
size_t GetCircularBufferSize() const;
- // Set the configured size of the circular buffer.
- void SetCircularBufferSize(size_t circularBufferSize);
-
- // Enable the event pipe.
- void Enable(
- unsigned int circularBufferSizeInMB,
- EventPipeProviderConfiguration *pProviders,
- int numProviders);
+ // Enable a session in the event pipe.
+ void Enable(EventPipeSession *pSession);
- // Disable the event pipe.
- void Disable();
+ // Disable a session in the event pipe.
+ void Disable(EventPipeSession *pSession);
// Get the status of the event pipe.
bool Enabled() const;
@@ -71,8 +72,8 @@ public:
// Determine if rundown is enabled.
bool RundownEnabled() const;
- // Enable the well-defined symbolic rundown configuration.
- void EnableRundown();
+ // Enable rundown using the specified configuration.
+ void EnableRundown(EventPipeSession *pSession);
// Get the event used to write metadata to the event stream.
EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance);
@@ -85,15 +86,14 @@ private:
// Get the provider without taking the lock.
EventPipeProvider* GetProviderNoLock(const SString &providerID);
- // Determines whether or not the event pipe is enabled.
- Volatile<bool> m_enabled;
+ // Get the enabled provider.
+ EventPipeSessionProvider* GetSessionProvider(EventPipeSession *pSession, EventPipeProvider *pProvider);
- // The configured size of the circular buffer.
- size_t m_circularBufferSizeInBytes;
+ // The one and only EventPipe session.
+ EventPipeSession *m_pSession;
- // EventPipeConfiguration only supports a single session.
- // This is the set of configurations for each enabled provider.
- EventPipeEnabledProviderList *m_pEnabledProviderList;
+ // Determines whether or not the event pipe is enabled.
+ Volatile<bool> m_enabled;
// The list of event pipe providers.
SList<SListElem<EventPipeProvider*>> *m_pProviderList;
@@ -112,59 +112,6 @@ private:
Volatile<bool> m_rundownEnabled;
};
-class EventPipeEnabledProviderList
-{
-
-private:
-
- // The number of providers in the list.
- unsigned int m_numProviders;
-
- // The list of providers.
- EventPipeEnabledProvider *m_pProviders;
-
- // A catch-all provider used when tracing is enabled at start-up
- // under (COMPlus_PerformanceTracing & 1) == 1.
- EventPipeEnabledProvider *m_pCatchAllProvider;
-
-public:
-
- // Create a new list based on the input.
- EventPipeEnabledProviderList(EventPipeProviderConfiguration *pConfigs, unsigned int numConfigs);
- ~EventPipeEnabledProviderList();
-
- // Get the enabled provider for the specified provider.
- // Return NULL if one doesn't exist.
- EventPipeEnabledProvider* GetEnabledProvider(EventPipeProvider *pProvider);
-};
-
-class EventPipeEnabledProvider
-{
-private:
-
- // The provider name.
- WCHAR *m_pProviderName;
-
- // The enabled keywords.
- UINT64 m_keywords;
-
- // The loging level.
- EventPipeEventLevel m_loggingLevel;
-
-public:
-
- EventPipeEnabledProvider();
- ~EventPipeEnabledProvider();
-
- void Set(LPCWSTR providerName, UINT64 keywords, EventPipeEventLevel loggingLevel);
-
- LPCWSTR GetProviderName() const;
-
- UINT64 GetKeywords() const;
-
- EventPipeEventLevel GetLevel() const;
-};
-
#endif // FEATURE_PERFTRACING
#endif // __EVENTPIPE_CONFIGURATION_H__
diff --git a/src/vm/eventpipeprovider.cpp b/src/vm/eventpipeprovider.cpp
index 84a90e4abb..3e82706801 100644
--- a/src/vm/eventpipeprovider.cpp
+++ b/src/vm/eventpipeprovider.cpp
@@ -31,6 +31,7 @@ EventPipeProvider::EventPipeProvider(EventPipeConfiguration *pConfig, const SStr
m_pCallbackFunction = pCallbackFunction;
m_pCallbackData = pCallbackData;
m_pConfig = pConfig;
+ m_deleteDeferred = false;
}
EventPipeProvider::~EventPipeProvider()
diff --git a/src/vm/eventpipesession.cpp b/src/vm/eventpipesession.cpp
new file mode 100644
index 0000000000..7fd7ac11cc
--- /dev/null
+++ b/src/vm/eventpipesession.cpp
@@ -0,0 +1,296 @@
+// 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 "eventpipeprovider.h"
+#include "eventpipesession.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeSession::EventPipeSession(
+ unsigned int circularBufferSizeInMB,
+ EventPipeProviderConfiguration *pProviders,
+ unsigned int numProviders)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_circularBufferSizeInBytes = circularBufferSizeInMB * 1024 * 1024; // 1MB;
+ m_rundownEnabled = false;
+ m_pProviderList = new EventPipeSessionProviderList(
+ pProviders,
+ numProviders);
+}
+
+EventPipeSession::~EventPipeSession()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if(m_pProviderList != NULL)
+ {
+ delete m_pProviderList;
+ m_pProviderList = NULL;
+ }
+}
+
+bool EventPipeSession::IsValid() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if((m_pProviderList == NULL) || (m_pProviderList->IsEmpty()))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void EventPipeSession::AddSessionProvider(EventPipeSessionProvider *pProvider)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_pProviderList->AddSessionProvider(pProvider);
+}
+
+void EventPipeSession::EnableAllEvents()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_pProviderList->EnableAllEvents();
+}
+
+EventPipeSessionProvider* EventPipeSession::GetSessionProvider(EventPipeProvider *pProvider)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ 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];
+ EventPipeSessionProvider *pProvider = new EventPipeSessionProvider(
+ pConfig->GetProviderName(),
+ pConfig->GetKeywords(),
+ (EventPipeEventLevel)pConfig->GetLevel());
+
+ 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));
+ }
+}
+
+void EventPipeSessionProviderList::EnableAllEvents()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if(m_pCatchAllProvider == NULL)
+ {
+ m_pCatchAllProvider = new EventPipeSessionProvider(NULL, 0xFFFFFFFFFFFFFFFF, EventPipeEventLevel::Verbose);
+ }
+}
+
+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)
+{
+ 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;
+
+}
+
+EventPipeSessionProvider::~EventPipeSessionProvider()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if(m_pProviderName != NULL)
+ {
+ delete[] m_pProviderName;
+ m_pProviderName = 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;
+}
+
+#endif // FEATURE_PERFTRACING
diff --git a/src/vm/eventpipesession.h b/src/vm/eventpipesession.h
new file mode 100644
index 0000000000..ba91c60aaa
--- /dev/null
+++ b/src/vm/eventpipesession.h
@@ -0,0 +1,135 @@
+// 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_SESSION_H__
+#define __EVENTPIPE_SESSION_H__
+
+#ifdef FEATURE_PERFTRACING
+
+enum class EventPipeEventLevel;
+struct EventPipeProviderConfiguration;
+class EventPipeSessionProviderList;
+class EventPipeSessionProvider;
+
+class EventPipeSession
+{
+private:
+ // The set of configurations for each provider in the session.
+ EventPipeSessionProviderList *m_pProviderList;
+
+ // The configured size of the circular buffer.
+ size_t m_circularBufferSizeInBytes;
+
+ // True if rundown is enabled.
+ Volatile<bool> m_rundownEnabled;
+
+public:
+
+ // TODO: This needs to be exposed via EventPipe::CreateSession() and EventPipe::DeleteSession() to avoid memory ownership issues.
+ EventPipeSession(
+ unsigned int circularBufferSizeInMB,
+ EventPipeProviderConfiguration *pProviders,
+ unsigned int numProviders);
+
+ ~EventPipeSession();
+
+ // Determine if the session is valid or not. Invalid sessions can be detected before they are enabled.
+ bool IsValid() const;
+
+ // Get the configured size of the circular buffer.
+ size_t GetCircularBufferSize() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_circularBufferSizeInBytes;
+ }
+
+ // Determine if rundown is enabled.
+ bool RundownEnabled() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_rundownEnabled;
+ }
+
+ // Set the rundown enabled flag.
+ void SetRundownEnabled(bool value)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_rundownEnabled = value;
+ }
+
+ // Enable all events.
+ // This is used for testing and is controlled via COMPLUS_EnableEventPipe.
+ void EnableAllEvents();
+
+ // Add a new provider to the session.
+ void AddSessionProvider(EventPipeSessionProvider *pProvider);
+
+ // Get the session provider for the specified provider if present.
+ 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 at start-up
+ // under (COMPlus_PerformanceTracing & 1) == 1.
+ EventPipeSessionProvider *m_pCatchAllProvider;
+
+public:
+
+ // Create a new list based on the input.
+ EventPipeSessionProviderList(EventPipeProviderConfiguration *pConfigs, unsigned int numConfigs);
+ ~EventPipeSessionProviderList();
+
+ // Enable all events.
+ // This is used for testing and is controlled via COMPLUS_EnableEventPipe.
+ void EnableAllEvents();
+
+ // 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;
+
+public:
+
+ EventPipeSessionProvider(
+ LPCWSTR providerName,
+ UINT64 keywords,
+ EventPipeEventLevel loggingLevel);
+ ~EventPipeSessionProvider();
+
+ LPCWSTR GetProviderName() const;
+
+ UINT64 GetKeywords() const;
+
+ EventPipeEventLevel GetLevel() const;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_SESSION_H__