1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
7 #include "eventpipebuffermanager.h"
8 #include "eventpipefile.h"
9 #include "eventpipeprovider.h"
10 #include "eventpipesession.h"
11 #include "eventpipesessionprovider.h"
13 #ifdef FEATURE_PERFTRACING
15 EventPipeSession::EventPipeSession(
17 LPCWSTR strOutputPath,
18 IpcStream *const pStream,
19 EventPipeSessionType sessionType,
20 EventPipeSerializationFormat format,
22 uint32_t circularBufferSizeInMB,
23 const EventPipeProviderConfiguration *pProviders,
24 uint32_t numProviders,
25 bool rundownEnabled) : m_index(index),
26 m_pProviderList(new EventPipeSessionProviderList(pProviders, numProviders)),
27 m_rundownEnabled(rundownEnabled),
28 m_SessionType(sessionType),
30 m_rundownRequested(rundownSwitch)
37 PRECONDITION(index < EventPipe::MaxNumberOfSessions);
38 PRECONDITION(format < EventPipeSerializationFormat::Count);
39 PRECONDITION(circularBufferSizeInMB > 0);
40 PRECONDITION(numProviders > 0 && pProviders != nullptr);
41 PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
45 size_t sequencePointAllocationBudget = 0;
46 // Hard coded 10MB for now, we'll probably want to make
47 // this configurable later.
48 if (GetSessionType() != EventPipeSessionType::Listener &&
49 GetSerializationFormat() >= EventPipeSerializationFormat::NetTraceV4)
51 sequencePointAllocationBudget = 10 * 1024 * 1024;
54 m_pBufferManager = new EventPipeBufferManager(this, static_cast<size_t>(circularBufferSizeInMB) << 20, sequencePointAllocationBudget);
56 // Create the event pipe file.
57 // A NULL output path means that we should not write the results to a file.
58 // This is used in the EventListener case.
62 case EventPipeSessionType::File:
63 if (strOutputPath != nullptr)
64 m_pFile = new EventPipeFile(new FileStreamWriter(SString(strOutputPath)), format);
67 case EventPipeSessionType::IpcStream:
68 m_pFile = new EventPipeFile(new IpcStreamWriter(reinterpret_cast<uint64_t>(this), pStream), format);
76 GetSystemTimeAsFileTime(&m_sessionStartTime);
77 QueryPerformanceCounter(&m_sessionStartTimeStamp);
80 void EventPipeSession::Close()
90 // FIXME: **ONLY** closes the stream. This explicitly **LEAKS** the
91 // provider list and buffer manager.
95 EventPipeSession::~EventPipeSession()
102 PRECONDITION(!m_ipcStreamingEnabled);
106 delete m_pProviderList;
107 delete m_pBufferManager;
111 bool EventPipeSession::HasIpcStreamingStarted()
121 return m_pIpcStreamingThread != nullptr ? m_pIpcStreamingThread->HasStarted() : false;
124 void EventPipeSession::SetThreadShutdownEvent()
134 // Signal Disable() that the thread has been destroyed.
135 m_threadShutdownEvent.Set();
138 static void PlatformSleep()
148 // Wait until it's time to sample again.
149 const uint32_t PeriodInNanoSeconds = 100000000; // 100 msec.
152 PAL_nanosleep(PeriodInNanoSeconds);
154 const uint32_t NUM_NANOSECONDS_IN_1_MS = 1000000;
155 ClrSleepEx(PeriodInNanoSeconds / NUM_NANOSECONDS_IN_1_MS, FALSE);
159 DWORD WINAPI EventPipeSession::ThreadProc(void *args)
166 PRECONDITION(args != nullptr);
173 EventPipeSession *const pEventPipeSession = reinterpret_cast<EventPipeSession *>(args);
174 if (pEventPipeSession->GetSessionType() != EventPipeSessionType::IpcStream)
177 if (!pEventPipeSession->HasIpcStreamingStarted())
180 Thread *const pThisThread = pEventPipeSession->GetIpcStreamingThread();
181 bool fSuccess = true;
182 CLREvent *waitEvent = pEventPipeSession->GetWaitEvent();
188 while (pEventPipeSession->IsIpcStreamingEnabled())
190 bool eventsWritten = false;
191 if (!pEventPipeSession->WriteAllBuffersToFile(&eventsWritten))
199 // No events were available, sleep until more are available
200 waitEvent->Wait(INFINITE, FALSE);
203 // Wait until it's time to sample again.
207 pEventPipeSession->SetThreadShutdownEvent();
211 pEventPipeSession->SetThreadShutdownEvent();
212 // TODO: STRESS_LOG ?
213 // TODO: Notify `EventPipe` itself to remove this session from the list.
215 EX_END_CATCH(SwallowAllExceptions);
221 EventPipe::Disable(reinterpret_cast<EventPipeSessionID>(pEventPipeSession));
225 // TODO: STRESS_LOG ?
227 EX_END_CATCH(SwallowAllExceptions);
229 if (pThisThread != nullptr)
230 ::DestroyThread(pThisThread);
235 void EventPipeSession::CreateIpcStreamingThread()
242 PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
246 m_ipcStreamingEnabled = true;
247 m_pIpcStreamingThread = SetupUnstartedThread();
248 if (m_pIpcStreamingThread->CreateNewThread(0, ThreadProc, this))
250 m_pIpcStreamingThread->SetBackground(TRUE);
251 m_pIpcStreamingThread->StartThread();
255 _ASSERT(!"Unable to create IPC stream flushing thread.");
257 m_threadShutdownEvent.CreateManualEvent(FALSE);
260 bool EventPipeSession::IsValid() const
267 PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
271 return !m_pProviderList->IsEmpty();
274 void EventPipeSession::AddSessionProvider(EventPipeSessionProvider *pProvider)
284 m_pProviderList->AddSessionProvider(pProvider);
287 EventPipeSessionProvider *EventPipeSession::GetSessionProvider(const EventPipeProvider *pProvider) const
297 return m_pProviderList->GetSessionProvider(pProvider);
300 bool EventPipeSession::WriteAllBuffersToFile(bool *pEventsWritten)
310 if (m_pFile == nullptr)
313 // Get the current time stamp.
314 // EventPipeBufferManager::WriteAllBuffersToFile will use this to ensure that no events after
315 // the current timestamp are written into the file.
316 LARGE_INTEGER stopTimeStamp;
317 QueryPerformanceCounter(&stopTimeStamp);
318 m_pBufferManager->WriteAllBuffersToFile(m_pFile, stopTimeStamp, pEventsWritten);
319 return !m_pFile->HasErrors();
322 bool EventPipeSession::WriteEventBuffered(
324 EventPipeEvent &event,
325 EventPipeEventPayload &payload,
327 LPCGUID pRelatedActivityId,
328 Thread *pEventThread,
329 StackContents *pStack)
339 // Filter events specific to "this" session based on precomputed flag on provider/events.
340 return event.IsEnabled(GetMask()) ?
341 m_pBufferManager->WriteEvent(pThread, *this, event, payload, pActivityId, pRelatedActivityId, pEventThread, pStack) :
345 void EventPipeSession::WriteSequencePointUnbuffered()
355 if (m_pFile == nullptr)
357 EventPipeSequencePoint sequencePoint;
358 m_pBufferManager->InitSequencePointThreadList(&sequencePoint);
359 m_pFile->WriteSequencePoint(&sequencePoint);
362 EventPipeEventInstance *EventPipeSession::GetNextEvent()
369 PRECONDITION(!EventPipe::IsLockOwnedByCurrentThread());
373 return m_pBufferManager->GetNextEvent();
376 CLREvent *EventPipeSession::GetWaitEvent()
378 LIMITED_METHOD_CONTRACT;
380 return m_pBufferManager->GetWaitEvent();
383 void EventPipeSession::Enable()
390 // Lock must be held by EventPipe::Enable.
391 PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
395 if (m_SessionType == EventPipeSessionType::IpcStream)
396 CreateIpcStreamingThread();
399 void EventPipeSession::EnableRundown()
406 // Lock must be held by EventPipe::Enable.
407 PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
411 //! The keywords below seems to correspond to:
412 //! LoaderKeyword (0x00000008)
413 //! JitKeyword (0x00000010)
414 //! NgenKeyword (0x00000020)
415 //! unused_keyword (0x00000100)
416 //! JittedMethodILToNativeMapKeyword (0x00020000)
417 //! ThreadTransferKeyword (0x80000000)
418 const UINT64 Keywords = 0x80020138;
419 const UINT32 VerboseLoggingLevel = static_cast<UINT32>(EventPipeEventLevel::Verbose);
420 const EventPipeProviderConfiguration RundownProviders[] = {
421 {W("Microsoft-Windows-DotNETRuntime"), Keywords, VerboseLoggingLevel, NULL}, // Public provider.
422 {W("Microsoft-Windows-DotNETRuntimeRundown"), Keywords, VerboseLoggingLevel, NULL} // Rundown provider.
424 const uint32_t RundownProvidersSize = sizeof(RundownProviders) / sizeof(EventPipeProviderConfiguration);
426 // update the provider context here since the callback doesn't happen till we actually try to do rundown.
427 MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.Level = VerboseLoggingLevel;
428 MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.EnabledKeywordsBitmask = Keywords;
429 MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled = true;
431 // Update provider list with rundown configuration.
432 for (uint32_t i = 0; i < RundownProvidersSize; ++i)
434 const EventPipeProviderConfiguration &Config = RundownProviders[i];
435 m_pProviderList->AddSessionProvider(new EventPipeSessionProvider(
436 Config.GetProviderName(),
437 Config.GetKeywords(),
438 (EventPipeEventLevel)Config.GetLevel(),
439 Config.GetFilterData()));
442 m_rundownEnabled = true;
445 void EventPipeSession::DisableIpcStreamingThread()
452 PRECONDITION(m_SessionType == EventPipeSessionType::IpcStream);
453 PRECONDITION(m_ipcStreamingEnabled);
457 _ASSERTE(!g_fProcessDetach);
459 // The IPC streaming thread will watch this value and exit
460 // when profiling is disabled.
461 m_ipcStreamingEnabled = false;
463 // Thread could be waiting on the event that there is new data to read.
464 m_pBufferManager->GetWaitEvent()->Set();
466 // Wait for the sampling thread to clean itself up.
467 m_threadShutdownEvent.Wait(INFINITE, FALSE /* bAlertable */);
468 m_threadShutdownEvent.CloseEvent();
471 void EventPipeSession::Disable()
481 if ((m_SessionType == EventPipeSessionType::IpcStream) && m_ipcStreamingEnabled)
482 DisableIpcStreamingThread();
485 WriteAllBuffersToFile(&ignored);
486 m_pProviderList->Clear();
489 void EventPipeSession::SuspendWriteEvent()
499 // Force all in-progress writes to either finish or cancel
500 // This is required to ensure we can safely flush and delete the buffers
501 m_pBufferManager->SuspendWriteEvent(GetIndex());
504 void EventPipeSession::ExecuteRundown()
511 // Lock must be held by EventPipe::Disable.
512 PRECONDITION(EventPipe::IsLockOwnedByCurrentThread());
516 if (m_pFile == nullptr)
519 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeRundown) > 0)
521 // Ask the runtime to emit rundown events.
522 if (g_fEEStarted && !g_fEEShutDown)
523 ETW::EnumerationLog::EndRundown();
527 #endif // FEATURE_PERFTRACING