8ea3f0867e186ce5bba45a53c39326070ad37f19
[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     _ASSERTE(s_pFile != NULL);
188     s_pFile->WriteEvent(instance);
189
190     // Write to the EventPipeJsonFile if it exists.
191     if(s_pJsonFile != NULL)
192     {
193         s_pJsonFile->WriteEvent(instance);
194     }
195 }
196
197 void EventPipe::WriteSampleProfileEvent(SampleProfilerEventInstance &instance)
198 {
199     CONTRACTL
200     {
201         NOTHROW;
202         GC_TRIGGERS;
203         MODE_PREEMPTIVE;
204     }
205     CONTRACTL_END;
206
207     // Write to the EventPipeFile.
208     if(s_pFile != NULL)
209     {
210         s_pFile->WriteEvent(instance);
211     }
212
213     // Write to the EventPipeJsonFile if it exists.
214     if(s_pJsonFile != NULL)
215     {
216         s_pJsonFile->WriteEvent(instance);
217     }
218 }
219
220 bool EventPipe::WalkManagedStackForCurrentThread(StackContents &stackContents)
221 {
222     CONTRACTL
223     {
224         NOTHROW;
225         GC_NOTRIGGER;
226         MODE_ANY;
227     }
228     CONTRACTL_END;
229
230     Thread *pThread = GetThread();
231     if(pThread != NULL)
232     {
233         return WalkManagedStackForThread(pThread, stackContents);
234     }
235
236     return false;
237 }
238
239 bool EventPipe::WalkManagedStackForThread(Thread *pThread, StackContents &stackContents)
240 {
241     CONTRACTL
242     {
243         NOTHROW;
244         GC_NOTRIGGER;
245         MODE_ANY;
246         PRECONDITION(pThread != NULL);
247     }
248     CONTRACTL_END;
249
250     stackContents.Reset();
251
252     StackWalkAction swaRet = pThread->StackWalkFrames(
253         (PSTACKWALKFRAMESCALLBACK) &StackWalkCallback,
254         &stackContents,
255         ALLOW_ASYNC_STACK_WALK | FUNCTIONSONLY | HANDLESKIPPEDFRAMES);
256
257     return ((swaRet == SWA_DONE) || (swaRet == SWA_CONTINUE));
258 }
259
260 StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pData)
261 {
262     CONTRACTL
263     {
264         NOTHROW;
265         GC_NOTRIGGER;
266         MODE_PREEMPTIVE;
267         PRECONDITION(pCf != NULL);
268         PRECONDITION(pData != NULL);
269     }
270     CONTRACTL_END;
271
272     // Get the IP.
273     UINT_PTR controlPC = (UINT_PTR)pCf->GetRegisterSet()->ControlPC;
274     if(controlPC == 0)
275     {
276         if(pData->GetLength() == 0)
277         {
278             // This happens for pinvoke stubs on the top of the stack.
279             return SWA_CONTINUE;
280         }
281     }
282
283     _ASSERTE(controlPC != 0);
284
285     // Add the IP to the captured stack.
286     pData->Append(
287         controlPC,
288         pCf->GetFunction()
289         );
290
291     // Continue the stack walk.
292     return SWA_CONTINUE;
293 }
294
295 EventPipeConfiguration* EventPipe::GetConfiguration()
296 {
297     LIMITED_METHOD_CONTRACT;
298
299     return s_pConfig;
300 }
301
302 CrstStatic* EventPipe::GetLock()
303 {
304     LIMITED_METHOD_CONTRACT;
305
306     return &s_configCrst;
307 }
308
309 #endif // FEATURE_PERFTRACING