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 "eventpipeconfiguration.h"
9 #include "eventpipeevent.h"
10 #include "eventpipefile.h"
11 #include "eventpipeprovider.h"
12 #include "eventpipejsonfile.h"
13 #include "sampleprofiler.h"
19 #ifdef FEATURE_PERFTRACING
21 CrstStatic EventPipe::s_configCrst;
22 bool EventPipe::s_tracingInitialized = false;
23 EventPipeConfiguration* EventPipe::s_pConfig = NULL;
24 EventPipeBufferManager* EventPipe::s_pBufferManager = NULL;
25 EventPipeFile* EventPipe::s_pFile = NULL;
27 EventPipeFile* EventPipe::s_pSyncFile = NULL;
28 EventPipeJsonFile* EventPipe::s_pJsonFile = NULL;
32 // This function is auto-generated from /src/scripts/genEventPipe.py
33 extern "C" void InitProvidersAndEvents();
37 // This function is auto-generated from /src/scripts/genEventPipe.py
38 extern "C" void InitProvidersAndEvents();
41 void EventPipe::Initialize()
45 s_tracingInitialized = s_configCrst.InitNoThrow(
47 (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN | CRST_HOST_BREAKABLE));
49 s_pConfig = new EventPipeConfiguration();
50 s_pConfig->Initialize();
52 s_pBufferManager = new EventPipeBufferManager();
55 // This calls into auto-generated code to initialize the runtime providers
56 // and events so that the EventPipe configuration lock isn't taken at runtime
57 InitProvidersAndEvents();
61 void EventPipe::EnableOnStartup()
71 // Test COMPLUS variable to enable tracing at start-up.
72 if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
75 outputPath.Printf("Process-%d.netperf", GetCurrentProcessId());
77 outputPath.GetUnicode(),
78 1024 /* 1 GB circular buffer */,
79 NULL /* pProviders */,
80 0 /* numProviders */);
84 void EventPipe::Shutdown()
101 if(s_pBufferManager != NULL)
103 delete(s_pBufferManager);
104 s_pBufferManager = NULL;
108 void EventPipe::Enable(
109 LPCWSTR strOutputPath,
110 unsigned int circularBufferSizeInMB,
111 EventPipeProviderConfiguration *pProviders,
122 // If tracing is not initialized or is already enabled, bail here.
123 if(!s_tracingInitialized || s_pConfig->Enabled())
128 // Take the lock before enabling tracing.
129 CrstHolder _crst(GetLock());
131 // Create the event pipe file.
132 SString eventPipeFileOutputPath(strOutputPath);
133 s_pFile = new EventPipeFile(eventPipeFileOutputPath);
136 if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 2) == 2)
138 // Create a synchronous file.
139 SString eventPipeSyncFileOutputPath;
140 eventPipeSyncFileOutputPath.Printf("Process-%d.sync.netperf", GetCurrentProcessId());
141 s_pSyncFile = new EventPipeFile(eventPipeSyncFileOutputPath);
143 // Create a JSON file.
144 SString outputFilePath;
145 outputFilePath.Printf("Process-%d.PerfView.json", GetCurrentProcessId());
146 s_pJsonFile = new EventPipeJsonFile(outputFilePath);
151 s_pConfig->Enable(circularBufferSizeInMB, pProviders, numProviders);
153 // Enable the sample profiler
154 SampleProfiler::Enable();
157 void EventPipe::Disable()
167 // Don't block GC during clean-up.
170 // Take the lock before disabling tracing.
171 CrstHolder _crst(GetLock());
173 if(s_pConfig->Enabled())
175 // Disable the profiler.
176 SampleProfiler::Disable();
179 s_pConfig->Disable();
181 // Flush all write buffers to make sure that all threads see the change.
182 FlushProcessWriteBuffers();
184 // Write to the file.
185 LARGE_INTEGER disableTimeStamp;
186 QueryPerformanceCounter(&disableTimeStamp);
187 s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
189 // Before closing the file, do rundown.
190 s_pConfig->EnableRundown();
192 // Ask the runtime to emit rundown events.
193 if(g_fEEStarted && !g_fEEShutDown)
195 ETW::EnumerationLog::EndRundown();
198 // Disable the event pipe now that rundown is complete.
199 s_pConfig->Disable();
207 if(s_pSyncFile != NULL)
212 if(s_pJsonFile != NULL)
219 // De-allocate buffers.
220 s_pBufferManager->DeAllocateBuffers();
222 // Delete deferred providers.
223 // Providers can't be deleted during tracing because they may be needed when serializing the file.
224 s_pConfig->DeleteDeferredProviders();
228 bool EventPipe::Enabled()
230 LIMITED_METHOD_CONTRACT;
232 bool enabled = false;
233 if(s_pConfig != NULL)
235 enabled = s_pConfig->Enabled();
241 EventPipeProvider* EventPipe::CreateProvider(const GUID &providerID, EventPipeCallback pCallbackFunction, void *pCallbackData)
251 return new EventPipeProvider(providerID, pCallbackFunction, pCallbackData);
254 void EventPipe::DeleteProvider(EventPipeProvider *pProvider)
264 // Take the lock to make sure that we don't have a race
265 // between disabling tracing and deleting a provider
266 // where we hold a provider after tracing has been disabled.
267 CrstHolder _crst(GetLock());
269 if(pProvider != NULL)
273 // Save the provider until the end of the tracing session.
274 pProvider->SetDeleteDeferred();
278 // Delete the provider now.
279 // NOTE: This will remove it from all of the EventPipe data structures.
285 void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
292 PRECONDITION(s_pBufferManager != NULL);
296 // Exit early if the event is not enabled.
297 if(!event.IsEnabled())
302 // Get the current thread;
303 Thread *pThread = GetThread();
306 // We can't write an event without the thread object.
310 if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
312 if(!s_pBufferManager->WriteEvent(pThread, event, pData, length, pActivityId, pRelatedActivityId))
314 // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
318 else if(s_pConfig->RundownEnabled())
320 // Write synchronously to the file.
321 // We're under lock and blocking the disabling thread.
322 EventPipeEventInstance instance(
324 pThread->GetOSThreadId(),
332 s_pFile->WriteEvent(instance);
340 // Create an instance of the event for the synchronous path.
341 EventPipeEventInstance instance(
343 pThread->GetOSThreadId(),
349 // Write to the EventPipeFile if it exists.
350 if(s_pSyncFile != NULL)
352 s_pSyncFile->WriteEvent(instance);
355 // Write to the EventPipeJsonFile if it exists.
356 if(s_pJsonFile != NULL)
358 s_pJsonFile->WriteEvent(instance);
364 void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData, unsigned int length)
374 // Write the event to the thread's buffer.
375 if(s_pBufferManager != NULL)
377 // Specify the sampling thread as the "current thread", so that we select the right buffer.
378 // Specify the target thread so that the event gets properly attributed.
379 if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, pData, length, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents))
381 // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
390 // Create an instance for the synchronous path.
391 SampleProfilerEventInstance instance(*pEvent, pTargetThread, pData, length);
392 stackContents.CopyTo(instance.GetStack());
394 // Write to the EventPipeFile.
395 if(s_pSyncFile != NULL)
397 s_pSyncFile->WriteEvent(instance);
400 // Write to the EventPipeJsonFile if it exists.
401 if(s_pJsonFile != NULL)
403 s_pJsonFile->WriteEvent(instance);
409 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
419 Thread *pThread = GetThread();
422 return WalkManagedStackForThread(pThread, stackContents);
428 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
435 PRECONDITION(pThread != NULL);
439 stackContents.Reset();
441 StackWalkAction swaRet = pThread->StackWalkFrames(
442 (PSTACKWALKFRAMESCALLBACK) &StackWalkCallback,
444 ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES);
446 return ((swaRet == SWA_DONE) || (swaRet == SWA_CONTINUE));
449 StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pData)
456 PRECONDITION(pCf != NULL);
457 PRECONDITION(pData != NULL);
462 UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
465 if(pData->GetLength() == 0)
467 // This happens for pinvoke stubs on the top of the stack.
472 _ASSERTE(controlPC != 0);
474 // Add the IP to the captured stack.
480 // Continue the stack walk.
484 EventPipeConfiguration* EventPipe::GetConfiguration()
486 LIMITED_METHOD_CONTRACT;
491 CrstStatic* EventPipe::GetLock()
493 LIMITED_METHOD_CONTRACT;
495 return &s_configCrst;
498 void QCALLTYPE EventPipeInternal::Enable(
499 __in_z LPCWSTR outputFile,
500 unsigned int circularBufferSizeInMB,
501 long profilerSamplingRateInNanoseconds,
502 EventPipeProviderConfiguration *pProviders,
508 SampleProfiler::SetSamplingRate(profilerSamplingRateInNanoseconds);
509 EventPipe::Enable(outputFile, circularBufferSizeInMB, pProviders, numProviders);
513 void QCALLTYPE EventPipeInternal::Disable()
518 EventPipe::Disable();
522 INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
524 EventPipeCallback pCallbackFunc)
528 EventPipeProvider *pProvider = NULL;
532 pProvider = EventPipe::CreateProvider(providerID, pCallbackFunc, NULL);
536 return reinterpret_cast<INT_PTR>(pProvider);
539 INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
541 unsigned int eventID,
543 unsigned int eventVersion,
546 unsigned int metadataLength)
550 EventPipeEvent *pEvent = NULL;
554 _ASSERTE(provHandle != NULL);
555 _ASSERTE(pMetadata != NULL);
556 EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
557 pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
558 _ASSERTE(pEvent != NULL);
562 return reinterpret_cast<INT_PTR>(pEvent);
565 void QCALLTYPE EventPipeInternal::DeleteProvider(
571 if(provHandle != NULL)
573 EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider*>(provHandle);
574 EventPipe::DeleteProvider(pProvider);
580 void QCALLTYPE EventPipeInternal::WriteEvent(
582 unsigned int eventID,
586 LPCGUID pRelatedActivityId)
591 _ASSERTE(eventHandle != NULL);
592 EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
593 EventPipe::WriteEvent(*pEvent, (BYTE *)pData, length, pActivityId, pRelatedActivityId);
598 #endif // FEATURE_PERFTRACING