Re-Factor EventSource to Support Writing to EventPipe (#11435)
[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 "eventpipe.h"
7 #include "eventpipeconfiguration.h"
8 #include "eventpipeevent.h"
9 #include "eventpipefile.h"
10 #include "eventpipeprovider.h"
11 #include "eventpipejsonfile.h"
12 #include "sampleprofiler.h"
13
14 #ifdef FEATURE_PAL
15 #include "pal.h"
16 #endif // FEATURE_PAL
17
18 #ifdef FEATURE_PERFTRACING
19
20 CrstStatic EventPipe::s_configCrst;
21 bool EventPipe::s_tracingInitialized = false;
22 EventPipeConfiguration* EventPipe::s_pConfig = NULL;
23 EventPipeFile* EventPipe::s_pFile = NULL;
24 EventPipeJsonFile* EventPipe::s_pJsonFile = NULL;
25
26 #ifdef FEATURE_PAL
27 // This function is auto-generated from /src/scripts/genEventPipe.py
28 extern "C" void InitProvidersAndEvents();
29 #endif
30
31 void EventPipe::Initialize()
32 {
33     STANDARD_VM_CONTRACT;
34
35     s_tracingInitialized = s_configCrst.InitNoThrow(
36         CrstEventPipe,
37         (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
38
39     s_pConfig = new EventPipeConfiguration();
40     s_pConfig->Initialize();
41
42 #ifdef FEATURE_PAL
43     // This calls into auto-generated code to initialize the runtime providers
44     // and events so that the EventPipe configuration lock isn't taken at runtime
45     InitProvidersAndEvents();
46 #endif
47 }
48
49 void EventPipe::EnableOnStartup()
50 {
51     CONTRACTL
52     {
53         THROWS;
54         GC_TRIGGERS;
55         MODE_ANY;
56     }
57     CONTRACTL_END;
58
59     // Test COMPLUS variable to enable tracing at start-up.
60     if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) != 0)
61     {
62         Enable();
63     }
64 }
65
66 void EventPipe::Shutdown()
67 {
68     CONTRACTL
69     {
70         THROWS;
71         GC_TRIGGERS;
72         MODE_ANY;
73     }
74     CONTRACTL_END;
75
76     Disable();
77 }
78
79 void EventPipe::Enable()
80 {
81     CONTRACTL
82     {
83         THROWS;
84         GC_TRIGGERS;
85         MODE_ANY;
86     }
87     CONTRACTL_END;
88
89     if(!s_tracingInitialized)
90     {
91         return;
92     }
93
94     // Take the lock before enabling tracing.
95     CrstHolder _crst(GetLock());
96
97     // Create the event pipe file.
98     SString eventPipeFileOutputPath;
99     eventPipeFileOutputPath.Printf("Process-%d.netperf", GetCurrentProcessId());
100     s_pFile = new EventPipeFile(eventPipeFileOutputPath);
101
102     if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) == 2)
103     {
104         // File placed in current working directory.
105         SString outputFilePath;
106         outputFilePath.Printf("Process-%d.PerfView.json", GetCurrentProcessId());
107         s_pJsonFile = new EventPipeJsonFile(outputFilePath);
108     }
109
110     // Enable tracing.
111     s_pConfig->Enable();
112
113     // Enable the sample profiler
114     SampleProfiler::Enable();
115
116     // TODO: Iterate through the set of providers, enable them as appropriate.
117     // This in-turn will iterate through all of the events and set their isEnabled bits.
118 }
119
120 void EventPipe::Disable()
121 {
122     CONTRACTL
123     {
124         THROWS;
125         GC_TRIGGERS;
126         MODE_ANY;
127     }
128     CONTRACTL_END;
129
130     // Don't block GC during clean-up.
131     GCX_PREEMP();
132
133     // Take the lock before disabling tracing.
134     CrstHolder _crst(GetLock());
135
136     // Disable the profiler.
137     SampleProfiler::Disable();
138
139     // Disable tracing.
140     s_pConfig->Disable();
141
142     if(s_pJsonFile != NULL)
143     {
144         delete(s_pJsonFile);
145         s_pJsonFile = NULL;
146     }
147
148     if(s_pFile != NULL)
149     {
150         delete(s_pFile);
151         s_pFile = NULL;
152     }
153
154     if(s_pConfig != NULL)
155     {
156         delete(s_pConfig);
157         s_pConfig = NULL;
158     }
159 }
160
161 void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length)
162 {
163     CONTRACTL
164     {
165         NOTHROW;
166         GC_NOTRIGGER;
167         MODE_ANY;
168     }
169     CONTRACTL_END;
170
171     // Exit early if the event is not enabled.
172     if(!event.IsEnabled())
173     {
174         return;
175     }
176
177     DWORD threadID = GetCurrentThreadId();
178
179     // Create an instance of the event.
180     EventPipeEventInstance instance(
181         event,
182         threadID,
183         pData,
184         length);
185
186     // Write to the EventPipeFile.
187     if(s_pFile != NULL)
188     {
189         s_pFile->WriteEvent(instance);
190     }
191
192     // Write to the EventPipeJsonFile if it exists.
193     if(s_pJsonFile != NULL)
194     {
195         s_pJsonFile->WriteEvent(instance);
196     }
197 }
198
199 void EventPipe::WriteSampleProfileEvent(SampleProfilerEventInstance &instance)
200 {
201     CONTRACTL
202     {
203         NOTHROW;
204         GC_TRIGGERS;
205         MODE_PREEMPTIVE;
206     }
207     CONTRACTL_END;
208
209     // Write to the EventPipeFile.
210     if(s_pFile != NULL)
211     {
212         s_pFile->WriteEvent(instance);
213     }
214
215     // Write to the EventPipeJsonFile if it exists.
216     if(s_pJsonFile != NULL)
217     {
218         s_pJsonFile->WriteEvent(instance);
219     }
220 }
221
222 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
223 {
224     CONTRACTL
225     {
226         NOTHROW;
227         GC_NOTRIGGER;
228         MODE_ANY;
229     }
230     CONTRACTL_END;
231
232     Thread *pThread = GetThread();
233     if(pThread != NULL)
234     {
235         return WalkManagedStackForThread(pThread, stackContents);
236     }
237
238     return false;
239 }
240
241 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
242 {
243     CONTRACTL
244     {
245         NOTHROW;
246         GC_NOTRIGGER;
247         MODE_ANY;
248         PRECONDITION(pThread != NULL);
249     }
250     CONTRACTL_END;
251
252     stackContents.Reset();
253
254     StackWalkAction swaRet = pThread->StackWalkFrames(
255         (PSTACKWALKFRAMESCALLBACK) &StackWalkCallback,
256         &stackContents,
257         ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES);
258
259     return ((swaRet == SWA_DONE) || (swaRet == SWA_CONTINUE));
260 }
261
262 StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pData)
263 {
264     CONTRACTL
265     {
266         NOTHROW;
267         GC_NOTRIGGER;
268         MODE_PREEMPTIVE;
269         PRECONDITION(pCf != NULL);
270         PRECONDITION(pData != NULL);
271     }
272     CONTRACTL_END;
273
274     // Get the IP.
275     UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
276     if(controlPC == 0)
277     {
278         if(pData->GetLength() == 0)
279         {
280             // This happens for pinvoke stubs on the top of the stack.
281             return SWA_CONTINUE;
282         }
283     }
284
285     _ASSERTE(controlPC != 0);
286
287     // Add the IP to the captured stack.
288     pData->Append(
289         controlPC,
290         pCf->GetFunction()
291         );
292
293     // Continue the stack walk.
294     return SWA_CONTINUE;
295 }
296
297 EventPipeConfiguration* EventPipe::GetConfiguration()
298 {
299     LIMITED_METHOD_CONTRACT;
300
301     return s_pConfig;
302 }
303
304 CrstStatic* EventPipe::GetLock()
305 {
306     LIMITED_METHOD_CONTRACT;
307
308     return &s_configCrst;
309 }
310
311 INT_PTR QCALLTYPE EventPipeInternal::CreateProvider(
312     GUID providerID,
313     EventPipeCallback pCallbackFunc)
314 {
315     QCALL_CONTRACT;
316
317     EventPipeProvider *pProvider = NULL;
318
319     BEGIN_QCALL;
320
321     pProvider = new EventPipeProvider(providerID, pCallbackFunc, NULL);
322
323     END_QCALL;
324
325     return reinterpret_cast<INT_PTR>(pProvider);
326 }
327
328 INT_PTR QCALLTYPE EventPipeInternal::AddEvent(
329     INT_PTR provHandle,
330     __int64 keywords,
331     unsigned int eventID,
332     unsigned int eventVersion,
333     unsigned int level,
334     bool needStack)
335 {
336     QCALL_CONTRACT;
337     BEGIN_QCALL;
338
339     // TODO
340
341     END_QCALL;
342
343     return 0;
344 }
345
346 void QCALLTYPE EventPipeInternal::DeleteProvider(
347     INT_PTR provHandle)
348 {
349     QCALL_CONTRACT;
350     BEGIN_QCALL;
351
352     if(provHandle != NULL)
353     {
354         EventPipeProvider *pProvider = reinterpret_cast<EventPipeProvider*>(provHandle);
355         delete pProvider;
356     }
357
358     END_QCALL;
359 }
360
361 void QCALLTYPE EventPipeInternal::WriteEvent(
362     INT_PTR eventHandle,
363     void *pData,
364     unsigned int length)
365 {
366     QCALL_CONTRACT;
367     BEGIN_QCALL;
368
369     // TODO
370
371     END_QCALL;
372 }
373
374 #endif // FEATURE_PERFTRACING