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.
9 #include "eventpipebuffermanager.h"
10 #include "eventpipeconfiguration.h"
11 #include "eventpipeevent.h"
12 #include "eventpipefile.h"
13 #include "eventpipeprovider.h"
14 #include "eventpipejsonfile.h"
15 #include "sampleprofiler.h"
21 #ifdef FEATURE_PERFTRACING
23 CrstStatic EventPipe::s_configCrst;
24 bool EventPipe::s_tracingInitialized = false;
25 EventPipeConfiguration* EventPipe::s_pConfig = NULL;
26 EventPipeBufferManager* EventPipe::s_pBufferManager = NULL;
27 EventPipeFile* EventPipe::s_pFile = NULL;
29 EventPipeFile* EventPipe::s_pSyncFile = NULL;
30 EventPipeJsonFile* EventPipe::s_pJsonFile = NULL;
34 // This function is auto-generated from /src/scripts/genEventPipe.py
35 extern "C" void InitProvidersAndEvents();
39 // This function is auto-generated from /src/scripts/genEventPipe.py
40 extern "C" void InitProvidersAndEvents();
43 EventPipeEventPayload::EventPipeEventPayload(BYTE *pData, unsigned int length)
56 m_allocatedData = false;
61 EventPipeEventPayload::EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount)
72 m_pEventData = pEventData;
73 m_eventDataCount = eventDataCount;
74 m_allocatedData = false;
76 S_UINT32 tmp_size = S_UINT32(0);
77 for (unsigned int i=0; i<m_eventDataCount; i++)
79 tmp_size += S_UINT32((*m_pEventData)[i].Size);
82 if (tmp_size.IsOverflow())
84 // If there is an overflow, drop the data and create an empty payload
91 m_size = tmp_size.Value();
95 EventPipeEventPayload::~EventPipeEventPayload()
105 if(m_allocatedData && m_pData != NULL)
112 void EventPipeEventPayload::Flatten()
126 BYTE* tmp_pData = new (nothrow) BYTE[m_size];
127 if (tmp_pData != NULL)
129 m_allocatedData = true;
137 void EventPipeEventPayload::CopyData(BYTE *pDst)
151 memcpy(pDst, m_pData, m_size);
154 else if(m_pEventData != NULL)
156 unsigned int offset = 0;
157 for(unsigned int i=0; i<m_eventDataCount; i++)
159 memcpy(pDst + offset, (BYTE*)(*m_pEventData)[i].Ptr, (*m_pEventData)[i].Size);
160 offset += (*m_pEventData)[i].Size;
166 BYTE* EventPipeEventPayload::GetFlatData()
183 void EventPipe::Initialize()
185 STANDARD_VM_CONTRACT;
187 s_tracingInitialized = s_configCrst.InitNoThrow(
189 (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN | CRST_HOST_BREAKABLE));
191 s_pConfig = new EventPipeConfiguration();
192 s_pConfig->Initialize();
194 s_pBufferManager = new EventPipeBufferManager();
197 // This calls into auto-generated code to initialize the runtime providers
198 // and events so that the EventPipe configuration lock isn't taken at runtime
199 InitProvidersAndEvents();
203 void EventPipe::EnableOnStartup()
213 // Test COMPLUS variable to enable tracing at start-up.
214 if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
217 outputPath.Printf("Process-%d.netperf", GetCurrentProcessId());
219 outputPath.GetUnicode(),
220 1024 /* 1 GB circular buffer */,
221 NULL /* pProviders */,
222 0 /* numProviders */);
226 void EventPipe::Shutdown()
238 if(s_pConfig != NULL)
243 if(s_pBufferManager != NULL)
245 delete(s_pBufferManager);
246 s_pBufferManager = NULL;
250 void EventPipe::Enable(
251 LPCWSTR strOutputPath,
252 unsigned int circularBufferSizeInMB,
253 EventPipeProviderConfiguration *pProviders,
264 // If tracing is not initialized or is already enabled, bail here.
265 if(!s_tracingInitialized || s_pConfig->Enabled())
270 // Take the lock before enabling tracing.
271 CrstHolder _crst(GetLock());
273 // Create the event pipe file.
274 SString eventPipeFileOutputPath(strOutputPath);
275 s_pFile = new EventPipeFile(eventPipeFileOutputPath);
278 if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 2) == 2)
280 // Create a synchronous file.
281 SString eventPipeSyncFileOutputPath;
282 eventPipeSyncFileOutputPath.Printf("Process-%d.sync.netperf", GetCurrentProcessId());
283 s_pSyncFile = new EventPipeFile(eventPipeSyncFileOutputPath);
285 // Create a JSON file.
286 SString outputFilePath;
287 outputFilePath.Printf("Process-%d.PerfView.json", GetCurrentProcessId());
288 s_pJsonFile = new EventPipeJsonFile(outputFilePath);
293 s_pConfig->Enable(circularBufferSizeInMB, pProviders, numProviders);
295 // Enable the sample profiler
296 SampleProfiler::Enable();
299 void EventPipe::Disable()
309 // Don't block GC during clean-up.
312 // Take the lock before disabling tracing.
313 CrstHolder _crst(GetLock());
315 if(s_pConfig->Enabled())
317 // Disable the profiler.
318 SampleProfiler::Disable();
321 s_pConfig->Disable();
323 // Flush all write buffers to make sure that all threads see the change.
324 FlushProcessWriteBuffers();
326 // Write to the file.
327 LARGE_INTEGER disableTimeStamp;
328 QueryPerformanceCounter(&disableTimeStamp);
329 s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
331 // Before closing the file, do rundown.
332 s_pConfig->EnableRundown();
334 // Ask the runtime to emit rundown events.
335 if(g_fEEStarted && !g_fEEShutDown)
337 ETW::EnumerationLog::EndRundown();
340 // Disable the event pipe now that rundown is complete.
341 s_pConfig->Disable();
349 if(s_pSyncFile != NULL)
354 if(s_pJsonFile != NULL)
361 // De-allocate buffers.
362 s_pBufferManager->DeAllocateBuffers();
364 // Delete deferred providers.
365 // Providers can't be deleted during tracing because they may be needed when serializing the file.
366 s_pConfig->DeleteDeferredProviders();
370 bool EventPipe::Enabled()
372 LIMITED_METHOD_CONTRACT;
374 bool enabled = false;
375 if(s_pConfig != NULL)
377 enabled = s_pConfig->Enabled();
383 EventPipeProvider* EventPipe::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
393 return new EventPipeProvider(providerName, pCallbackFunction, pCallbackData);
396 void EventPipe::DeleteProvider(EventPipeProvider *pProvider)
406 // Take the lock to make sure that we don't have a race
407 // between disabling tracing and deleting a provider
408 // where we hold a provider after tracing has been disabled.
409 CrstHolder _crst(GetLock());
411 if(pProvider != NULL)
415 // Save the provider until the end of the tracing session.
416 pProvider->SetDeleteDeferred();
420 // Delete the provider now.
421 // NOTE: This will remove it from all of the EventPipe data structures.
427 void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
437 EventPipeEventPayload payload(pData, length);
438 EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
441 void EventPipe::WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
451 EventPipeEventPayload payload(pEventData, eventDataCount);
452 EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
455 void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
462 PRECONDITION(s_pBufferManager != NULL);
466 // Exit early if the event is not enabled.
467 if(!event.IsEnabled())
472 // Get the current thread;
473 Thread *pThread = GetThread();
476 // We can't write an event without the thread object.
480 if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
482 if(!s_pBufferManager->WriteEvent(pThread, event, payload, pActivityId, pRelatedActivityId))
484 // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
488 else if(s_pConfig->RundownEnabled())
490 BYTE *pData = payload.GetFlatData();
493 // Write synchronously to the file.
494 // We're under lock and blocking the disabling thread.
495 EventPipeEventInstance instance(
497 pThread->GetOSThreadId(),
505 s_pFile->WriteEvent(instance);
514 BYTE *pData = payload.GetFlatData();
517 // Create an instance of the event for the synchronous path.
518 EventPipeEventInstance instance(
520 pThread->GetOSThreadId(),
526 // Write to the EventPipeFile if it exists.
527 if(s_pSyncFile != NULL)
529 s_pSyncFile->WriteEvent(instance);
532 // Write to the EventPipeJsonFile if it exists.
533 if(s_pJsonFile != NULL)
535 s_pJsonFile->WriteEvent(instance);
542 void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData, unsigned int length)
552 EventPipeEventPayload payload(pData, length);
554 // Write the event to the thread's buffer.
555 if(s_pBufferManager != NULL)
557 // Specify the sampling thread as the "current thread", so that we select the right buffer.
558 // Specify the target thread so that the event gets properly attributed.
559 if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, payload, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents))
561 // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
570 // Create an instance for the synchronous path.
571 SampleProfilerEventInstance instance(*pEvent, pTargetThread, pData, length);
572 stackContents.CopyTo(instance.GetStack());
574 // Write to the EventPipeFile.
575 if(s_pSyncFile != NULL)
577 s_pSyncFile->WriteEvent(instance);
580 // Write to the EventPipeJsonFile if it exists.
581 if(s_pJsonFile != NULL)
583 s_pJsonFile->WriteEvent(instance);
589 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
599 Thread *pThread = GetThread();
602 return WalkManagedStackForThread(pThread, stackContents);
608 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
615 PRECONDITION(pThread != NULL);
619 stackContents.Reset();
621 StackWalkAction swaRet = pThread->StackWalkFrames(
622 (PSTACKWALKFRAMESCALLBACK) &StackWalkCallback,
624 ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES);
626 return ((swaRet == SWA_DONE) || (swaRet == SWA_CONTINUE));
629 StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pData)
636 PRECONDITION(pCf != NULL);
637 PRECONDITION(pData != NULL);
642 UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
645 if(pData->GetLength() == 0)
647 // This happens for pinvoke stubs on the top of the stack.
652 _ASSERTE(controlPC != 0);
654 // Add the IP to the captured stack.
660 // Continue the stack walk.
664 EventPipeConfiguration* EventPipe::GetConfiguration()
666 LIMITED_METHOD_CONTRACT;
671 CrstStatic* EventPipe::GetLock()
673 LIMITED_METHOD_CONTRACT;
675 return &s_configCrst;
678 void QCALLTYPE EventPipeInternal::Enable(
679 __in_z LPCWSTR outputFile,
680 unsigned int circularBufferSizeInMB,
681 long profilerSamplingRateInNanoseconds,
682 EventPipeProviderConfiguration *pProviders,
688 SampleProfiler::SetSamplingRate(profilerSamplingRateInNanoseconds);
689 EventPipe::Enable(outputFile, circularBufferSizeInMB, pProviders, numProviders);
693 void QCALLTYPE EventPipeInternal::Disable()
698 EventPipe::Disable();
702 INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
703 __in_z LPCWSTR providerName,
704 EventPipeCallback pCallbackFunc)
708 EventPipeProvider *pProvider = NULL;
712 pProvider = EventPipe::CreateProvider(providerName, pCallbackFunc, NULL);
716 return reinterpret_cast<INT_PTR>(pProvider);
719 INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
721 unsigned int eventID,
723 unsigned int eventVersion,
726 unsigned int metadataLength)
730 EventPipeEvent *pEvent = NULL;
734 _ASSERTE(provHandle != NULL);
735 _ASSERTE(pMetadata != NULL);
736 EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
737 pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
738 _ASSERTE(pEvent != NULL);
742 return reinterpret_cast<INT_PTR>(pEvent);
745 void QCALLTYPE EventPipeInternal::DeleteProvider(
751 if(provHandle != NULL)
753 EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider*>(provHandle);
754 EventPipe::DeleteProvider(pProvider);
760 void QCALLTYPE EventPipeInternal::WriteEvent(
762 unsigned int eventID,
766 LPCGUID pRelatedActivityId)
771 _ASSERTE(eventHandle != NULL);
772 EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
773 EventPipe::WriteEvent(*pEvent, (BYTE *)pData, length, pActivityId, pRelatedActivityId);
778 void QCALLTYPE EventPipeInternal::WriteEventData(
780 unsigned int eventID,
781 EventData **pEventData,
782 unsigned int eventDataCount,
784 LPCGUID pRelatedActivityId)
789 _ASSERTE(eventHandle != NULL);
790 EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
791 EventPipe::WriteEvent(*pEvent, pEventData, eventDataCount, pActivityId, pRelatedActivityId);
796 #endif // FEATURE_PERFTRACING