Merge pull request #18504 from mikedn/comp-small
[platform/upstream/coreclr.git] / src / vm / eventpipe.cpp
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.
4
5 #include "common.h"
6 #include "clrtypes.h"
7 #include "safemath.h"
8 #include "eventpipe.h"
9 #include "eventpipebuffermanager.h"
10 #include "eventpipeconfiguration.h"
11 #include "eventpipeevent.h"
12 #include "eventpipeeventsource.h"
13 #include "eventpipefile.h"
14 #include "eventpipeprovider.h"
15 #include "eventpipesession.h"
16 #include "eventpipejsonfile.h"
17 #include "eventtracebase.h"
18 #include "sampleprofiler.h"
19
20 #ifdef FEATURE_PAL
21 #include "pal.h"
22 #endif // FEATURE_PAL
23
24 #ifdef FEATURE_PERFTRACING
25
26 CrstStatic EventPipe::s_configCrst;
27 bool EventPipe::s_tracingInitialized = false;
28 EventPipeConfiguration* EventPipe::s_pConfig = NULL;
29 EventPipeSession* EventPipe::s_pSession = NULL;
30 EventPipeBufferManager* EventPipe::s_pBufferManager = NULL;
31 EventPipeFile* EventPipe::s_pFile = NULL;
32 EventPipeEventSource* EventPipe::s_pEventSource = NULL;
33 LPCWSTR EventPipe::s_pCommandLine = NULL;
34 #ifdef _DEBUG
35 EventPipeFile* EventPipe::s_pSyncFile = NULL;
36 EventPipeJsonFile* EventPipe::s_pJsonFile = NULL;
37 #endif // _DEBUG
38
39 #ifdef FEATURE_PAL
40 // This function is auto-generated from /src/scripts/genEventPipe.py
41 extern "C" void InitProvidersAndEvents();
42 #else
43 void InitProvidersAndEvents();
44 #endif
45
46 EventPipeEventPayload::EventPipeEventPayload(BYTE *pData, unsigned int length)
47 {
48     CONTRACTL
49     {
50         NOTHROW;
51         GC_NOTRIGGER;
52         MODE_ANY;
53     }
54     CONTRACTL_END;
55
56     m_pData = pData;
57     m_pEventData = NULL;
58     m_eventDataCount = 0;
59     m_allocatedData = false;
60
61     m_size = length;
62 }
63
64 EventPipeEventPayload::EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount)
65 {
66     CONTRACTL
67     {
68         NOTHROW;
69         GC_NOTRIGGER;
70         MODE_ANY;
71     }
72     CONTRACTL_END;
73
74     m_pData = NULL;
75     m_pEventData = pEventData;
76     m_eventDataCount = eventDataCount;
77     m_allocatedData = false;
78
79     S_UINT32 tmp_size = S_UINT32(0);
80     for (unsigned int i=0; i<m_eventDataCount; i++)
81     {
82         tmp_size += S_UINT32(m_pEventData[i].Size);
83     }
84
85     if (tmp_size.IsOverflow())
86     {
87         // If there is an overflow, drop the data and create an empty payload
88         m_pEventData = NULL;
89         m_eventDataCount = 0;
90         m_size = 0;
91     }
92     else
93     {
94         m_size = tmp_size.Value();
95     }
96 }
97
98 EventPipeEventPayload::~EventPipeEventPayload()
99 {
100     CONTRACTL
101     {
102         NOTHROW;
103         GC_NOTRIGGER;
104         MODE_ANY;
105     }
106     CONTRACTL_END;
107
108     if(m_allocatedData && m_pData != NULL)
109     {
110         delete[] m_pData;
111         m_pData = NULL;
112     }
113 }
114
115 void EventPipeEventPayload::Flatten()
116 {
117     CONTRACTL
118     {
119         NOTHROW;
120         GC_NOTRIGGER;
121         MODE_ANY;
122     }
123     CONTRACTL_END;
124
125     if(m_size > 0)
126     {
127         if (!IsFlattened())
128         {
129             BYTE* tmp_pData = new (nothrow) BYTE[m_size];
130             if (tmp_pData != NULL)
131             {
132                 m_allocatedData = true;
133                 CopyData(tmp_pData);
134                 m_pData = tmp_pData;
135             }
136         }
137     }
138 }
139
140 void EventPipeEventPayload::CopyData(BYTE *pDst)
141 {
142     CONTRACTL
143     {
144         NOTHROW;
145         GC_NOTRIGGER;
146         MODE_ANY;
147     }
148     CONTRACTL_END;
149
150     if(m_size > 0)
151     {
152         if(IsFlattened())
153         {
154             memcpy(pDst, m_pData, m_size);
155         }
156
157         else if(m_pEventData != NULL)
158         {
159             unsigned int offset = 0;
160             for(unsigned int i=0; i<m_eventDataCount; i++)
161             {
162                 memcpy(pDst + offset, (BYTE*) m_pEventData[i].Ptr, m_pEventData[i].Size);
163                 offset += m_pEventData[i].Size;
164             }
165         }
166     }
167 }
168
169 BYTE* EventPipeEventPayload::GetFlatData()
170 {
171     CONTRACTL
172     {
173         NOTHROW;
174         GC_NOTRIGGER;
175         MODE_ANY;
176     }
177     CONTRACTL_END;
178
179     if (!IsFlattened())
180     {
181         Flatten();
182     }
183     return m_pData;
184 }
185
186 void EventPipe::Initialize()
187 {
188     STANDARD_VM_CONTRACT;
189
190     s_tracingInitialized = s_configCrst.InitNoThrow(
191         CrstEventPipe,
192         (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN | CRST_HOST_BREAKABLE));
193
194     s_pConfig = new EventPipeConfiguration();
195     s_pConfig->Initialize();
196
197     s_pBufferManager = new EventPipeBufferManager();
198
199     s_pEventSource = new EventPipeEventSource();
200
201     // This calls into auto-generated code to initialize the runtime providers
202     // and events so that the EventPipe configuration lock isn't taken at runtime
203     InitProvidersAndEvents();
204 }
205
206 void EventPipe::EnableOnStartup()
207 {
208     CONTRACTL
209     {
210         THROWS;
211         GC_TRIGGERS;
212         MODE_ANY;
213     }
214     CONTRACTL_END;
215
216     // Test COMPLUS variable to enable tracing at start-up.
217     if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableEventPipe) & 1) == 1)
218     {
219         SString outputPath;
220         outputPath.Printf("Process-%d.netperf", GetCurrentProcessId());
221
222         // Create a new session.
223         EventPipeSession *pSession = new EventPipeSession(
224             EventPipeSessionType::File,
225             1024 /* 1 GB circular buffer */,
226             NULL, /* pProviders */
227             0 /* numProviders */);
228
229         // Get the configuration from the environment.
230         GetConfigurationFromEnvironment(outputPath, pSession);
231
232         // Enable the session.
233         Enable(outputPath, pSession);
234     }
235 }
236
237 void EventPipe::Shutdown()
238 {
239     CONTRACTL
240     {
241         NOTHROW;
242         GC_TRIGGERS;
243         MODE_ANY;
244     }
245     CONTRACTL_END;
246
247     // Mark tracing as no longer initialized.
248     s_tracingInitialized = false;
249
250     // We are shutting down, so if disabling EventPipe throws, we need to move along anyway.
251     EX_TRY
252     {
253         Disable();
254     }
255     EX_CATCH { }
256     EX_END_CATCH(SwallowAllExceptions);
257
258     // Save pointers to the configuration and buffer manager.
259     EventPipeConfiguration *pConfig = s_pConfig;
260     EventPipeBufferManager *pBufferManager = s_pBufferManager;
261
262     // Set the static pointers to NULL so that the rest of the EventPipe knows that they are no longer available.
263     // Flush process write buffers to make sure other threads can see the change.
264     s_pConfig = NULL;
265     s_pBufferManager = NULL;
266     FlushProcessWriteBuffers();
267
268     // Free resources.
269     delete(pConfig);
270     delete(pBufferManager);
271     delete(s_pEventSource);
272     s_pEventSource = NULL;
273
274     // On Windows, this is just a pointer to the return value from
275     // GetCommandLineW(), so don't attempt to free it.
276 #ifdef FEATURE_PAL
277     delete[](s_pCommandLine);
278     s_pCommandLine = NULL;
279 #endif
280 }
281
282 void EventPipe::Enable(
283     LPCWSTR strOutputPath,
284     unsigned int circularBufferSizeInMB,
285     EventPipeProviderConfiguration *pProviders,
286     int numProviders)
287 {
288     CONTRACTL
289     {
290         THROWS;
291         GC_TRIGGERS;
292         MODE_ANY;
293     }
294     CONTRACTL_END;
295
296     // Create a new session.
297     EventPipeSession *pSession = s_pConfig->CreateSession(
298         (strOutputPath != NULL) ? EventPipeSessionType::File : EventPipeSessionType::Streaming,
299         circularBufferSizeInMB,
300         pProviders,
301         static_cast<unsigned int>(numProviders));
302
303     // Enable the session.
304     Enable(strOutputPath, pSession);
305 }
306
307 void EventPipe::Enable(LPCWSTR strOutputPath, EventPipeSession *pSession)
308 {
309     CONTRACTL
310     {
311         THROWS;
312         GC_TRIGGERS;
313         MODE_ANY;
314         PRECONDITION(pSession != NULL);
315     }
316     CONTRACTL_END;
317
318     // If tracing is not initialized or is already enabled, bail here.
319     if(!s_tracingInitialized || s_pConfig == NULL || s_pConfig->Enabled())
320     {
321         return;
322     }
323
324     // If the state or arguments are invalid, bail here.
325     if(pSession == NULL || !pSession->IsValid())
326     {
327         return;
328     }
329
330     // Enable the EventPipe EventSource.
331     s_pEventSource->Enable(pSession);
332
333     // Take the lock before enabling tracing.
334     CrstHolder _crst(GetLock());
335
336     // Create the event pipe file.
337     // A NULL output path means that we should not write the results to a file.
338     // This is used in the EventListener streaming case.
339     if (strOutputPath != NULL)
340     {
341         SString eventPipeFileOutputPath(strOutputPath);
342         s_pFile = new EventPipeFile(eventPipeFileOutputPath);
343     }
344
345 #ifdef _DEBUG
346     if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableEventPipe) & 2) == 2)
347     {
348         // Create a synchronous file.
349         SString eventPipeSyncFileOutputPath;
350         eventPipeSyncFileOutputPath.Printf("Process-%d.sync.netperf", GetCurrentProcessId());
351         s_pSyncFile = new EventPipeFile(eventPipeSyncFileOutputPath);
352
353         // Create a JSON file.
354         SString outputFilePath;
355         outputFilePath.Printf("Process-%d.PerfView.json", GetCurrentProcessId());
356         s_pJsonFile = new EventPipeJsonFile(outputFilePath);
357     }
358 #endif // _DEBUG
359
360     // Save the session.
361     s_pSession = pSession;
362
363     // Enable tracing.
364     s_pConfig->Enable(s_pSession);
365
366     // Enable the sample profiler
367     SampleProfiler::Enable();
368 }
369
370 void EventPipe::Disable()
371 {
372     CONTRACTL
373     {
374         THROWS;
375         GC_TRIGGERS;
376         MODE_ANY;
377     }
378     CONTRACTL_END;
379
380     // Don't block GC during clean-up.
381     GCX_PREEMP();
382
383     // Take the lock before disabling tracing.
384     CrstHolder _crst(GetLock());
385
386     if(s_pConfig != NULL && s_pConfig->Enabled())
387     {
388         // Disable the profiler.
389         SampleProfiler::Disable();
390
391         // Log the process information event.
392         s_pEventSource->SendProcessInfo(s_pCommandLine);
393
394         // Log the runtime information event.
395         ETW::InfoLog::RuntimeInformation(ETW::InfoLog::InfoStructs::Normal);
396
397         // Disable tracing.
398         s_pConfig->Disable(s_pSession);
399
400         // Delete the session.
401         s_pConfig->DeleteSession(s_pSession);
402         s_pSession = NULL;
403
404         // Flush all write buffers to make sure that all threads see the change.
405         FlushProcessWriteBuffers();
406
407         // Write to the file.
408         if(s_pFile != NULL)
409         {
410             LARGE_INTEGER disableTimeStamp;
411             QueryPerformanceCounter(&disableTimeStamp);
412             s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
413
414             if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeRundown) > 0)
415             {
416                 // Before closing the file, do rundown.
417                 const unsigned int numRundownProviders = 2;
418                 EventPipeProviderConfiguration rundownProviders[] =
419                 {
420                     { W("Microsoft-Windows-DotNETRuntime"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose) }, // Public provider.
421                     { W("Microsoft-Windows-DotNETRuntimeRundown"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose) } // Rundown provider.
422                 };
423                 // The circular buffer size doesn't matter because all events are written synchronously during rundown.
424                 s_pSession = s_pConfig->CreateSession(EventPipeSessionType::File, 1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
425                 s_pConfig->EnableRundown(s_pSession);
426
427                 // Ask the runtime to emit rundown events.
428                 if(g_fEEStarted && !g_fEEShutDown)
429                 {
430                     ETW::EnumerationLog::EndRundown();
431                 }
432
433                 // Disable the event pipe now that rundown is complete.
434                 s_pConfig->Disable(s_pSession);
435
436                 // Delete the rundown session.
437                 s_pConfig->DeleteSession(s_pSession);
438                 s_pSession = NULL;
439             }
440
441             delete(s_pFile);
442             s_pFile = NULL;
443         }
444 #ifdef _DEBUG
445         if(s_pSyncFile != NULL)
446         {
447             delete(s_pSyncFile);
448             s_pSyncFile = NULL;
449         }
450         if(s_pJsonFile != NULL)
451         {
452             delete(s_pJsonFile);
453             s_pJsonFile = NULL;
454         }
455 #endif // _DEBUG
456
457         // De-allocate buffers.
458         s_pBufferManager->DeAllocateBuffers();
459
460         // Delete deferred providers.
461         // Providers can't be deleted during tracing because they may be needed when serializing the file.
462         s_pConfig->DeleteDeferredProviders();
463     }
464 }
465
466 bool EventPipe::Enabled()
467 {
468     LIMITED_METHOD_CONTRACT;
469
470     bool enabled = false;
471     if(s_pConfig != NULL)
472     {
473         enabled = s_pConfig->Enabled();
474     }
475
476     return enabled;
477 }
478
479 EventPipeProvider* EventPipe::CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction, void *pCallbackData)
480 {
481     CONTRACTL
482     {
483         THROWS;
484         GC_TRIGGERS;
485         MODE_ANY;
486     }
487     CONTRACTL_END;
488
489     EventPipeProvider *pProvider = NULL;
490     if (s_pConfig != NULL)
491     {
492         pProvider = s_pConfig->CreateProvider(providerName, pCallbackFunction, pCallbackData);
493     }
494
495     return pProvider;
496
497 }
498
499 EventPipeProvider* EventPipe::GetProvider(const SString &providerName)
500 {
501     CONTRACTL
502     {
503         THROWS;
504         GC_NOTRIGGER;
505         MODE_ANY;
506     }
507     CONTRACTL_END;
508
509     EventPipeProvider *pProvider = NULL;
510     if (s_pConfig != NULL)
511     {
512         pProvider = s_pConfig->GetProvider(providerName);
513     }
514
515     return pProvider;
516 }
517
518 void EventPipe::DeleteProvider(EventPipeProvider *pProvider)
519 {
520     CONTRACTL
521     {
522         THROWS;
523         GC_TRIGGERS;
524         MODE_ANY;
525     }
526     CONTRACTL_END;
527
528     // Take the lock to make sure that we don't have a race
529     // between disabling tracing and deleting a provider
530     // where we hold a provider after tracing has been disabled.
531     CrstHolder _crst(GetLock());
532
533     if(pProvider != NULL)
534     {
535         if(Enabled())
536         {
537             // Save the provider until the end of the tracing session.
538             pProvider->SetDeleteDeferred();
539         }
540         else
541         {
542             // Delete the provider now.
543             if (s_pConfig != NULL)
544             {
545                 s_pConfig->DeleteProvider(pProvider);
546             }
547         }
548     }
549 }
550
551 void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
552 {
553     CONTRACTL
554     {
555         NOTHROW;
556         GC_NOTRIGGER;
557         MODE_ANY;
558     }
559     CONTRACTL_END;
560
561     EventPipeEventPayload payload(pData, length);
562     EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
563 }
564
565 void EventPipe::WriteEvent(EventPipeEvent &event, EventData *pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
566 {
567     CONTRACTL
568     {
569         NOTHROW;
570         GC_NOTRIGGER;
571         MODE_ANY;
572     }
573     CONTRACTL_END;
574
575     EventPipeEventPayload payload(pEventData, eventDataCount);
576     EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
577 }
578
579 void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
580 {
581     CONTRACTL
582     {
583         NOTHROW;
584         GC_NOTRIGGER;
585         MODE_ANY;
586     }
587     CONTRACTL_END;
588
589     // Exit early if the event is not enabled.
590     if(!event.IsEnabled())
591     {
592         return;
593     }
594
595     // Get the current thread;
596     Thread *pThread = GetThread();
597     if(pThread == NULL)
598     {
599         // We can't write an event without the thread object.
600         return;
601     }
602
603     if(s_pConfig == NULL)
604     {
605         // We can't procede without a configuration
606         return;
607     }
608     _ASSERTE(s_pSession != NULL);
609
610     // If the activity id isn't specified, pull it from the current thread.
611     if(pActivityId == NULL)
612     {
613         pActivityId = pThread->GetActivityId();
614     }
615
616     if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
617     {
618         if(!s_pBufferManager->WriteEvent(pThread, *s_pSession, event, payload, pActivityId, pRelatedActivityId))
619         {
620             // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
621             return;
622         }
623     }
624     else if(s_pConfig->RundownEnabled())
625     {
626         // It is possible that some events that are enabled on rundown can be emitted from other threads.
627         // We're not interested in these events and they can cause corrupted trace files because rundown
628         // events are written synchronously and not under lock.
629         // If we encounter an event that did not originate on the thread that is doing rundown, ignore it.
630         if(!s_pConfig->IsRundownThread(pThread))
631         {
632             return;
633         }
634
635         BYTE *pData = payload.GetFlatData();
636         if (pData != NULL)
637         {
638             // Write synchronously to the file.
639             // We're under lock and blocking the disabling thread.
640             // This copy occurs here (rather than at file write) because
641             // A) The FastSerializer API would need to change if we waited
642             // B) It is unclear there is a benefit to multiple file write calls
643             //    as opposed a a buffer copy here
644             EventPipeEventInstance instance(
645                 *s_pSession,
646                 event,
647                 pThread->GetOSThreadId(),
648                 pData,
649                 payload.GetSize(),
650                 pActivityId,
651                 pRelatedActivityId);
652
653             if(s_pFile != NULL)
654             {
655                 // EventPipeFile::WriteEvent needs to allocate a metadata event
656                 // and can therefore throw. In this context we will silently
657                 // fail rather than disrupt the caller
658                 EX_TRY
659                 {
660                     s_pFile->WriteEvent(instance);
661                 }
662                 EX_CATCH { }
663                 EX_END_CATCH(SwallowAllExceptions);
664             }
665         }
666     }
667
668 // This section requires a call to GCX_PREEMP which violates the GC_NOTRIGGER contract
669 // It should only be enabled when debugging this specific component and contracts are off
670 #ifdef DEBUG_JSON_EVENT_FILE
671     {
672         GCX_PREEMP();
673
674         BYTE *pData = payload.GetFlatData();
675         if (pData != NULL)
676         {
677             // Create an instance of the event for the synchronous path.
678             EventPipeEventInstance instance(
679                 event,
680                 pThread->GetOSThreadId(),
681                 pData,
682                 payload.GetSize(),
683                 pActivityId,
684                 pRelatedActivityId);
685
686             // Write to the EventPipeFile if it exists.
687             if(s_pSyncFile != NULL)
688             {
689                 s_pSyncFile->WriteEvent(instance);
690             }
691
692             // Write to the EventPipeJsonFile if it exists.
693             if(s_pJsonFile != NULL)
694             {
695                 s_pJsonFile->WriteEvent(instance);
696             }
697         }
698     }
699 #endif // DEBUG_JSON_EVENT_FILE
700 }
701
702 void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData, unsigned int length)
703 {
704     CONTRACTL
705     {
706         NOTHROW;
707         GC_TRIGGERS;
708         MODE_PREEMPTIVE;
709     }
710     CONTRACTL_END;
711
712     EventPipeEventPayload payload(pData, length);
713
714     // Write the event to the thread's buffer.
715     if(s_pBufferManager != NULL)
716     {
717         // Specify the sampling thread as the "current thread", so that we select the right buffer.
718         // Specify the target thread so that the event gets properly attributed.
719         if(!s_pBufferManager->WriteEvent(pSamplingThread, *s_pSession, *pEvent, payload, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents))
720         {
721             // This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
722             return;
723         }
724     }
725
726 #ifdef _DEBUG
727     {
728         GCX_PREEMP();
729
730         // Create an instance for the synchronous path.
731         SampleProfilerEventInstance instance(*s_pSession, *pEvent, pTargetThread, pData, length);
732         stackContents.CopyTo(instance.GetStack());
733
734         // Write to the EventPipeFile.
735         if(s_pSyncFile != NULL)
736         {
737             s_pSyncFile->WriteEvent(instance);
738         }
739
740         // Write to the EventPipeJsonFile if it exists.
741         if(s_pJsonFile != NULL)
742         {
743             s_pJsonFile->WriteEvent(instance);
744         }
745     }
746 #endif // _DEBUG
747 }
748
749 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
750 {
751     CONTRACTL
752     {
753         NOTHROW;
754         GC_NOTRIGGER;
755         MODE_ANY;
756     }
757     CONTRACTL_END;
758
759     Thread *pThread = GetThread();
760     if(pThread != NULL)
761     {
762         return WalkManagedStackForThread(pThread, stackContents);
763     }
764
765     return false;
766 }
767
768 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
769 {
770     CONTRACTL
771     {
772         NOTHROW;
773         GC_NOTRIGGER;
774         MODE_ANY;
775         PRECONDITION(pThread != NULL);
776     }
777     CONTRACTL_END;
778
779     // Calling into StackWalkFrames in preemptive mode violates the host contract,
780     // but this contract is not used on CoreCLR.
781     CONTRACT_VIOLATION( HostViolation );
782
783     stackContents.Reset();
784
785     StackWalkAction swaRet = pThread->StackWalkFrames(
786         (PSTACKWALKFRAMESCALLBACK) &StackWalkCallback,
787         &stackContents,
788         ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES);
789
790     return ((swaRet == SWA_DONE) || (swaRet == SWA_CONTINUE));
791 }
792
793 StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pData)
794 {
795     CONTRACTL
796     {
797         NOTHROW;
798         GC_NOTRIGGER;
799         MODE_ANY;
800         PRECONDITION(pCf != NULL);
801         PRECONDITION(pData != NULL);
802     }
803     CONTRACTL_END;
804
805     // Get the IP.
806     UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
807     if(controlPC == 0)
808     {
809         if(pData->GetLength() == 0)
810         {
811             // This happens for pinvoke stubs on the top of the stack.
812             return SWA_CONTINUE;
813         }
814     }
815
816     _ASSERTE(controlPC != 0);
817
818     // Add the IP to the captured stack.
819     pData->Append(
820         controlPC,
821         pCf->GetFunction()
822         );
823
824     // Continue the stack walk.
825     return SWA_CONTINUE;
826 }
827
828 EventPipeConfiguration* EventPipe::GetConfiguration()
829 {
830     LIMITED_METHOD_CONTRACT;
831
832     return s_pConfig;
833 }
834
835 CrstStatic* EventPipe::GetLock()
836 {
837     LIMITED_METHOD_CONTRACT;
838
839     return &s_configCrst;
840 }
841
842 void EventPipe::GetConfigurationFromEnvironment(SString &outputPath, EventPipeSession *pSession)
843 {
844     LIMITED_METHOD_CONTRACT;
845
846     // Set the output path if specified.
847     CLRConfigStringHolder wszOutputPath(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeOutputFile));
848     if(wszOutputPath != NULL)
849     {
850         outputPath.Set(wszOutputPath);
851     }
852
853     // Read the the provider configuration from the environment if specified.
854     CLRConfigStringHolder wszConfig(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EventPipeConfig));
855     if(wszConfig == NULL)
856     {
857         pSession->EnableAllEvents();
858         return;
859     }
860
861     size_t len = wcslen(wszConfig);
862     if(len <= 0)
863     {
864         pSession->EnableAllEvents();
865         return;
866     }
867
868     // Parses a string with the following format:
869     //
870     //      ProviderName:Keywords:Level[,]*
871     //
872     // For example:
873     //
874     //      Microsoft-Windows-DotNETRuntime:0xCAFEBABE:2,Microsoft-Windows-DotNETRuntimePrivate:0xDEADBEEF:1
875     //
876     // Each provider configuration is separated by a ',' and each component within the configuration is
877     // separated by a ':'.
878
879     const WCHAR ProviderSeparatorChar = ',';
880     const WCHAR ComponentSeparatorChar = ':';
881     size_t index = 0;
882     WCHAR *pProviderName = NULL;
883     UINT64 keywords = 0;
884     EventPipeEventLevel level = EventPipeEventLevel::Critical;
885
886     while(index < len)
887     {
888         WCHAR * pCurrentChunk = &wszConfig[index];
889         size_t currentChunkStartIndex = index;
890         size_t currentChunkEndIndex = 0;
891
892         // Find the next chunk.
893         while(index < len && wszConfig[index] != ProviderSeparatorChar)
894         {
895             index++;
896         }
897         currentChunkEndIndex = index++;
898
899         // Split the chunk into components.
900         size_t chunkIndex = currentChunkStartIndex;
901
902         // Get the provider name.
903         size_t provNameStartIndex = chunkIndex;
904         size_t provNameEndIndex = currentChunkEndIndex;
905
906         while(chunkIndex < currentChunkEndIndex && wszConfig[chunkIndex] != ComponentSeparatorChar)
907         {
908             chunkIndex++;
909         }
910         provNameEndIndex = chunkIndex++;
911
912         size_t provNameLen = provNameEndIndex - provNameStartIndex;
913         pProviderName = new WCHAR[provNameLen+1];
914         memcpy(pProviderName, &wszConfig[provNameStartIndex], provNameLen*sizeof(WCHAR));
915         pProviderName[provNameLen] = '\0';
916
917         // Get the keywords.
918         size_t keywordsStartIndex = chunkIndex;
919         size_t keywordsEndIndex = currentChunkEndIndex;
920
921         while(chunkIndex < currentChunkEndIndex && wszConfig[chunkIndex] != ComponentSeparatorChar)
922         {
923             chunkIndex++;
924         }
925         keywordsEndIndex = chunkIndex++;
926
927         size_t keywordsLen = keywordsEndIndex - keywordsStartIndex;
928         WCHAR *wszKeywords = new WCHAR[keywordsLen+1];
929         memcpy(wszKeywords, &wszConfig[keywordsStartIndex], keywordsLen*sizeof(WCHAR));
930         wszKeywords[keywordsLen] = '\0';
931         keywords = _wcstoui64(wszKeywords, NULL, 16);
932         delete[] wszKeywords;
933         wszKeywords = NULL;
934
935         // Get the level.
936         size_t levelStartIndex = chunkIndex;
937         size_t levelEndIndex = currentChunkEndIndex;
938
939         while(chunkIndex < currentChunkEndIndex && wszConfig[chunkIndex] != ComponentSeparatorChar)
940         {
941             chunkIndex++;
942         }
943         levelEndIndex = chunkIndex++;
944
945         size_t levelLen = levelEndIndex - levelStartIndex;
946         WCHAR *wszLevel = new WCHAR[levelLen+1];
947         memcpy(wszLevel, &wszConfig[levelStartIndex], levelLen*sizeof(WCHAR));
948         wszLevel[levelLen] = '\0';
949         level = (EventPipeEventLevel) wcstoul(wszLevel, NULL, 16);
950         delete[] wszLevel;
951         wszLevel = NULL;
952
953         // Add a new EventPipeSessionProvider.
954         EventPipeSessionProvider *pSessionProvider = new EventPipeSessionProvider(pProviderName, keywords, level);
955         pSession->AddSessionProvider(pSessionProvider);
956
957         // Free the provider name string.
958         if(pProviderName != NULL)
959         {
960             delete[] pProviderName;
961             pProviderName = NULL;
962         }
963     }
964 }
965
966 void EventPipe::SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv)
967 {
968     CONTRACTL
969     {
970         THROWS;
971         GC_TRIGGERS;
972         MODE_COOPERATIVE;
973         PRECONDITION(pwzAssemblyPath != NULL);
974         PRECONDITION(argc <= 0 || argv != NULL);
975     }
976     CONTRACTL_END;
977
978     // Get the command line.
979     LPCWSTR osCommandLine = GetCommandLineW();
980
981 #ifndef FEATURE_PAL
982     // On Windows, osCommandLine contains the executable and all arguments.
983     s_pCommandLine = osCommandLine;
984 #else
985     // On UNIX, the PAL doesn't have the command line arguments, so we must build the command line.
986     // osCommandLine contains the full path to the executable.
987     SString commandLine(osCommandLine);
988     commandLine.Append((WCHAR)' ');
989     commandLine.Append(pwzAssemblyPath);
990
991     for(int i=0; i<argc; i++)
992     {
993         commandLine.Append((WCHAR)' ');
994         commandLine.Append(argv[i]);
995     }
996
997     // Allocate a new string for the command line.
998     SIZE_T commandLineLen = commandLine.GetCount();
999     WCHAR *pCommandLine = new WCHAR[commandLineLen + 1];
1000     wcsncpy(pCommandLine, commandLine.GetUnicode(), commandLineLen);
1001     pCommandLine[commandLineLen] = '\0';
1002
1003     s_pCommandLine = pCommandLine;
1004 #endif
1005 }
1006
1007 EventPipeEventInstance* EventPipe::GetNextEvent()
1008 {
1009     CONTRACTL
1010     {
1011         THROWS;
1012         GC_TRIGGERS;
1013         MODE_PREEMPTIVE;
1014     }
1015     CONTRACTL_END;
1016
1017     EventPipeEventInstance *pInstance = NULL;
1018
1019     // Only fetch the next event if a tracing session exists.
1020     // The buffer manager is not disposed until the process is shutdown.
1021     if (s_pSession != NULL)
1022     {
1023         pInstance = s_pBufferManager->GetNextEvent();
1024     }
1025
1026     return pInstance;
1027 }
1028
1029 void QCALLTYPE EventPipeInternal::Enable(
1030         __in_z LPCWSTR outputFile,
1031         UINT32 circularBufferSizeInMB,
1032         INT64 profilerSamplingRateInNanoseconds,
1033         EventPipeProviderConfiguration *pProviders,
1034         INT32 numProviders)
1035 {
1036     QCALL_CONTRACT;
1037
1038     BEGIN_QCALL;
1039     SampleProfiler::SetSamplingRate((unsigned long)profilerSamplingRateInNanoseconds);
1040     EventPipe::Enable(outputFile, circularBufferSizeInMB, pProviders, numProviders);
1041     END_QCALL;
1042 }
1043
1044 void QCALLTYPE EventPipeInternal::Disable()
1045 {
1046     QCALL_CONTRACT;
1047
1048     BEGIN_QCALL;
1049     EventPipe::Disable();
1050     END_QCALL;
1051 }
1052
1053 INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
1054     __in_z LPCWSTR providerName,
1055     EventPipeCallback pCallbackFunc)
1056 {
1057     QCALL_CONTRACT;
1058
1059     EventPipeProvider *pProvider = NULL;
1060
1061     BEGIN_QCALL;
1062
1063     pProvider = EventPipe::CreateProvider(providerName, pCallbackFunc, NULL);
1064
1065     END_QCALL;
1066
1067     return reinterpret_cast<INT_PTR>(pProvider);
1068 }
1069
1070 INT_PTR QCALLTYPE EventPipeInternal::DefineEvent(
1071     INT_PTR provHandle,
1072     UINT32 eventID,
1073     __int64 keywords,
1074     UINT32 eventVersion,
1075     UINT32 level,
1076     void *pMetadata,
1077     UINT32 metadataLength)
1078 {
1079     QCALL_CONTRACT;
1080
1081     EventPipeEvent *pEvent = NULL;
1082
1083     BEGIN_QCALL;
1084
1085     _ASSERTE(provHandle != NULL);
1086     EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider *>(provHandle);
1087     pEvent = pProvider->AddEvent(eventID, keywords, eventVersion, (EventPipeEventLevel)level, (BYTE *)pMetadata, metadataLength);
1088     _ASSERTE(pEvent != NULL);
1089
1090     END_QCALL;
1091
1092     return reinterpret_cast<INT_PTR>(pEvent);
1093 }
1094
1095 INT_PTR QCALLTYPE EventPipeInternal::GetProvider(
1096     __in_z LPCWSTR providerName)
1097 {
1098     QCALL_CONTRACT;
1099
1100     EventPipeProvider *pProvider = NULL;
1101
1102     BEGIN_QCALL;
1103     
1104     pProvider = EventPipe::GetProvider(providerName);
1105
1106     END_QCALL;
1107
1108     return reinterpret_cast<INT_PTR>(pProvider);
1109 }
1110
1111 void QCALLTYPE EventPipeInternal::DeleteProvider(
1112     INT_PTR provHandle)
1113 {
1114     QCALL_CONTRACT;
1115     BEGIN_QCALL;
1116
1117     if(provHandle != NULL)
1118     {
1119         EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider*>(provHandle);
1120         EventPipe::DeleteProvider(pProvider);
1121     }
1122
1123     END_QCALL;
1124 }
1125
1126 int QCALLTYPE EventPipeInternal::EventActivityIdControl(
1127     uint controlCode,
1128     GUID *pActivityId)
1129 {
1130
1131     QCALL_CONTRACT;
1132
1133     int retVal = 0;
1134
1135     BEGIN_QCALL;
1136
1137     Thread *pThread = GetThread();
1138     if(pThread == NULL || pActivityId == NULL)
1139     {
1140         retVal = 1;
1141     }
1142     else
1143     {
1144         ActivityControlCode activityControlCode = (ActivityControlCode)controlCode;
1145         GUID currentActivityId;
1146         switch(activityControlCode)
1147         {
1148             case ActivityControlCode::EVENT_ACTIVITY_CONTROL_GET_ID:
1149
1150                 *pActivityId = *pThread->GetActivityId();
1151                 break;
1152
1153             case ActivityControlCode::EVENT_ACTIVITY_CONTROL_SET_ID:
1154
1155                 pThread->SetActivityId(pActivityId);
1156                 break;
1157
1158             case ActivityControlCode::EVENT_ACTIVITY_CONTROL_CREATE_ID:
1159
1160                 CoCreateGuid(pActivityId);
1161                 break;
1162
1163             case ActivityControlCode::EVENT_ACTIVITY_CONTROL_GET_SET_ID:
1164
1165                 currentActivityId = *pThread->GetActivityId();
1166                 pThread->SetActivityId(pActivityId);
1167                 *pActivityId = currentActivityId;
1168
1169                 break;
1170
1171             case ActivityControlCode::EVENT_ACTIVITY_CONTROL_CREATE_SET_ID:
1172
1173                 *pActivityId = *pThread->GetActivityId();
1174                 CoCreateGuid(&currentActivityId);
1175                 pThread->SetActivityId(&currentActivityId);
1176                 break;
1177
1178             default:
1179                 retVal = 1;
1180         };
1181     }
1182
1183     END_QCALL;
1184     return retVal;
1185 }
1186
1187 void QCALLTYPE EventPipeInternal::WriteEvent(
1188     INT_PTR eventHandle,
1189     UINT32 eventID,
1190     void *pData,
1191     UINT32 length,
1192     LPCGUID pActivityId,
1193     LPCGUID pRelatedActivityId)
1194 {
1195     QCALL_CONTRACT;
1196     BEGIN_QCALL;
1197
1198     _ASSERTE(eventHandle != NULL);
1199     EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
1200     EventPipe::WriteEvent(*pEvent, (BYTE *)pData, length, pActivityId, pRelatedActivityId);
1201
1202     END_QCALL;
1203 }
1204
1205 void QCALLTYPE EventPipeInternal::WriteEventData(
1206     INT_PTR eventHandle,
1207     UINT32 eventID,
1208     EventData *pEventData,
1209     UINT32 eventDataCount,
1210     LPCGUID pActivityId,
1211     LPCGUID pRelatedActivityId)
1212 {
1213     QCALL_CONTRACT;
1214     BEGIN_QCALL;
1215
1216     _ASSERTE(eventHandle != NULL);
1217     EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
1218     EventPipe::WriteEvent(*pEvent, pEventData, eventDataCount, pActivityId, pRelatedActivityId);
1219
1220     END_QCALL;
1221 }
1222
1223 bool QCALLTYPE EventPipeInternal::GetNextEvent(
1224     EventPipeEventInstanceData *pInstance)
1225 {
1226     QCALL_CONTRACT;
1227
1228     EventPipeEventInstance *pNextInstance = NULL;
1229     BEGIN_QCALL;
1230
1231     _ASSERTE(pInstance != NULL);
1232
1233     pNextInstance = EventPipe::GetNextEvent();
1234     if (pNextInstance)
1235     {
1236         pInstance->ProviderID = pNextInstance->GetEvent()->GetProvider();
1237         pInstance->EventID = pNextInstance->GetEvent()->GetEventID();
1238         pInstance->Payload = pNextInstance->GetData();
1239         pInstance->PayloadLength = pNextInstance->GetDataLength();
1240     }
1241
1242     END_QCALL;
1243     return pNextInstance != NULL;
1244
1245
1246 #endif // FEATURE_PERFTRACING