summaryrefslogtreecommitdiff
path: root/src/vm/eventpipeprovider.cpp
diff options
context:
space:
mode:
authorBrian Robbins <brianrob@microsoft.com>2017-05-06 12:36:08 -0700
committerVance Morrison <vancem@microsoft.com>2017-05-06 12:36:08 -0700
commit72ac46450bec8ea88ed023d9c1faf5a04556c834 (patch)
tree59085824f4268257d041ed9870f038216cd8ed45 /src/vm/eventpipeprovider.cpp
parent3ababc21ab334a2e37c6ba4115c946ea26a6f2fb (diff)
downloadcoreclr-72ac46450bec8ea88ed023d9c1faf5a04556c834.tar.gz
coreclr-72ac46450bec8ea88ed023d9c1faf5a04556c834.tar.bz2
coreclr-72ac46450bec8ea88ed023d9c1faf5a04556c834.zip
Log Events to EventPipe on Linux (#11433)
* Implement the EventPipe object model for providers and events. * Plumb Runtime Events into EventPipe (#11145) Plumb runtime ETW events into the EventPipe. * Fix bug where all events except for SampleProfiler events were never enabled. * Plumb EventPipeEventInstance through the EventPipe. * Implement EventPipeFile and FastSerializer. * Write event contents to the EventPipeFile. * Only build EventPipe on Linux. * Conditionally add a sentinel value marking event end. * Send SampleProfiler events to the EventPipeFile. * Fix provider ID printing to JSON file. * Write the start date/time, timestamp, and clock frequency into the trace file. * Support unloading of EventPipeProviders. * Handle failure cases when we can't walk the stack or are shutting down. * Fix a bug where we pass a null src pointer to memcpy.
Diffstat (limited to 'src/vm/eventpipeprovider.cpp')
-rw-r--r--src/vm/eventpipeprovider.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/vm/eventpipeprovider.cpp b/src/vm/eventpipeprovider.cpp
new file mode 100644
index 0000000000..da185334a9
--- /dev/null
+++ b/src/vm/eventpipeprovider.cpp
@@ -0,0 +1,253 @@
+// 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 "eventpipeevent.h"
+#include "eventpipeprovider.h"
+
+#ifdef FEATURE_PERFTRACING
+
+EventPipeProvider::EventPipeProvider(const GUID &providerID)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_providerID = providerID;
+ m_enabled = false;
+ m_keywords = 0;
+ m_providerLevel = EventPipeEventLevel::Critical;
+ m_pEventList = new SList<SListElem<EventPipeEvent*>>();
+ m_pCallbackFunction = NULL;
+ m_pCallbackData = NULL;
+
+ // Register the provider.
+ EventPipeConfiguration* pConfig = EventPipe::GetConfiguration();
+ _ASSERTE(pConfig != NULL);
+ pConfig->RegisterProvider(*this);
+}
+
+EventPipeProvider::~EventPipeProvider()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Unregister the provider.
+ // This call is re-entrant.
+ EventPipeConfiguration* pConfig = EventPipe::GetConfiguration();
+ _ASSERTE(pConfig != NULL);
+ pConfig->UnregisterProvider(*this);
+
+ // Free all of the events.
+ if(m_pEventList != NULL)
+ {
+ // Take the lock before manipulating the list.
+ CrstHolder _crst(EventPipe::GetLock());
+
+ SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead();
+ while(pElem != NULL)
+ {
+ EventPipeEvent *pEvent = pElem->GetValue();
+ delete pEvent;
+
+ pElem = m_pEventList->GetNext(pElem);
+ }
+
+ delete m_pEventList;
+ m_pEventList = NULL;
+ }
+}
+
+const GUID& EventPipeProvider::GetProviderID() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_providerID;
+}
+
+bool EventPipeProvider::Enabled() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_enabled;
+}
+
+bool EventPipeProvider::EventEnabled(INT64 keywords) const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // The event is enabled if:
+ // - The provider is enabled.
+ // - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0.
+ return (Enabled() && ((keywords == 0) || ((m_keywords & keywords) != 0)));
+}
+
+bool EventPipeProvider::EventEnabled(INT64 keywords, EventPipeEventLevel eventLevel) const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // The event is enabled if:
+ // - The provider is enabled.
+ // - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0.
+ // - The event level is LogAlways or the provider's verbosity level is set to greater than the event's verbosity level in the manifest.
+ return (EventEnabled(keywords) &&
+ ((eventLevel == EventPipeEventLevel::LogAlways) || (m_providerLevel >= eventLevel)));
+}
+
+void EventPipeProvider::SetConfiguration(bool providerEnabled, INT64 keywords, EventPipeEventLevel providerLevel)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+ }
+ CONTRACTL_END;
+
+ m_enabled = providerEnabled;
+ m_keywords = keywords;
+ m_providerLevel = providerLevel;
+
+ RefreshAllEvents();
+ InvokeCallback();
+}
+
+EventPipeEvent* EventPipeProvider::AddEvent(INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Create the event.
+ EventPipeEvent *pEvent = new EventPipeEvent(
+ *this,
+ keywords,
+ eventID,
+ eventVersion,
+ level,
+ needStack);
+
+ // Add it to the list of events.
+ AddEvent(*pEvent);
+ return pEvent;
+}
+
+void EventPipeProvider::AddEvent(EventPipeEvent &event)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Take the config lock before inserting a new event.
+ CrstHolder _crst(EventPipe::GetLock());
+
+ m_pEventList->InsertTail(new SListElem<EventPipeEvent*>(&event));
+}
+
+void EventPipeProvider::RegisterCallback(EventPipeCallback pCallbackFunction, void *pData)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Take the config lock before setting the callback.
+ CrstHolder _crst(EventPipe::GetLock());
+
+ if(m_pCallbackFunction == NULL)
+ {
+ m_pCallbackFunction = pCallbackFunction;
+ m_pCallbackData = pData;
+ }
+}
+
+void EventPipeProvider::UnregisterCallback(EventPipeCallback pCallbackFunction)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Take the config lock before setting the callback.
+ CrstHolder _crst(EventPipe::GetLock());
+
+ if(m_pCallbackFunction == pCallbackFunction)
+ {
+ m_pCallbackFunction = NULL;
+ m_pCallbackData = NULL;
+ }
+}
+
+void EventPipeProvider::InvokeCallback()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+ }
+ CONTRACTL_END;
+
+ if(m_pCallbackFunction != NULL)
+ {
+ (*m_pCallbackFunction)(
+ &m_providerID,
+ m_enabled,
+ (UCHAR) m_providerLevel,
+ m_keywords,
+ 0 /* matchAllKeywords */,
+ NULL /* FilterData */,
+ m_pCallbackData /* CallbackContext */);
+ }
+}
+
+void EventPipeProvider::RefreshAllEvents()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
+ }
+ CONTRACTL_END;
+
+ SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead();
+ while(pElem != NULL)
+ {
+ EventPipeEvent *pEvent = pElem->GetValue();
+ pEvent->RefreshState();
+
+ pElem = m_pEventList->GetNext(pElem);
+ }
+}
+
+#endif // FEATURE_PERFTRACING