Create the concept of EventPipeSession and refactor EventPipe to use it. Also expose...
authorBrian Robbins <brianrob@microsoft.com>
Fri, 26 Jan 2018 04:29:23 +0000 (20:29 -0800)
committerGitHub <noreply@github.com>
Fri, 26 Jan 2018 04:29:23 +0000 (20:29 -0800)
src/inc/clrconfigvalues.h
src/vm/CMakeLists.txt
src/vm/eventpipe.cpp
src/vm/eventpipe.h
src/vm/eventpipeconfiguration.cpp
src/vm/eventpipeconfiguration.h
src/vm/eventpipeprovider.cpp
src/vm/eventpipesession.cpp [new file with mode: 0644]
src/vm/eventpipesession.h [new file with mode: 0644]

index 95179d8..afb6798 100644 (file)
@@ -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
 ///
index 67aece1..5a30bce 100644 (file)
@@ -189,6 +189,7 @@ set(VM_SOURCES_WKS
     eventpipeprovider.cpp
     eventpipebuffer.cpp
     eventpipebuffermanager.cpp
+    eventpipesession.cpp
     eventstore.cpp
     fastserializer.cpp
     fcall.cpp
index 37de4c3..2eeb64f 100644 (file)
@@ -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,
index 4fd3d88..d1f7d60 100644 (file)
@@ -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
index a74bdbc..4678fc3 100644 (file)
@@ -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
index baca069..d1a8a90 100644 (file)
@@ -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__
index 84a90e4..3e82706 100644 (file)
@@ -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 (file)
index 0000000..7fd7ac1
--- /dev/null
@@ -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 (file)
index 0000000..ba91c60
--- /dev/null
@@ -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__