Enable EventPipe across Unix and Windows (#14772)
[platform/upstream/coreclr.git] / src / vm / eventpipe.h
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 #ifndef __EVENTPIPE_H__
6 #define __EVENTPIPE_H__
7
8 #ifdef FEATURE_PERFTRACING
9 #include "common.h"
10
11 class CrstStatic;
12 class CrawlFrame;
13 class EventPipeConfiguration;
14 class EventPipeEvent;
15 class EventPipeFile;
16 class EventPipeJsonFile;
17 class EventPipeBuffer;
18 class EventPipeBufferManager;
19 class EventPipeProvider;
20 class MethodDesc;
21 class SampleProfilerEventInstance;
22 struct EventPipeProviderConfiguration;
23
24 // Define the event pipe callback to match the ETW callback signature.
25 typedef void (*EventPipeCallback)(
26     LPCGUID SourceID,
27     ULONG IsEnabled,
28     UCHAR Level,
29     ULONGLONG MatchAnyKeywords,
30     ULONGLONG MatchAllKeywords,
31     void *FilterData,
32     void *CallbackContext);
33
34 struct EventData
35 {
36 public:
37     unsigned long Ptr;
38     unsigned int Size;
39     unsigned int Reserved;
40 };
41
42 class EventPipeEventPayload
43 {
44 private:
45     BYTE *m_pData;
46     EventData **m_pEventData;
47     unsigned int m_eventDataCount;
48     unsigned int m_size;
49     bool m_allocatedData;
50
51     // If the data is stored only as an array of EventData objects, create a flat buffer and copy into it
52     void Flatten();
53
54 public:
55     // Build this payload with a flat buffer inside
56     EventPipeEventPayload(BYTE *pData, unsigned int length);
57
58     // Build this payload to contain an array of EventData objects
59     EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount);
60
61     // If a buffer was allocated internally, delete it
62     ~EventPipeEventPayload();
63
64     // Copy the data (whether flat or array of objects) into a flat buffer at pDst
65     // Assumes that pDst points to an appropriatly sized buffer
66     void CopyData(BYTE *pDst);
67
68     // Get the flat formatted data in this payload
69     // This method will allocate a buffer if it does not already contain flattened data
70     // This method will return NULL on OOM if a buffer needed to be allocated
71     BYTE* GetFlatData();
72
73     // Return true is the data is stored in a flat buffer
74     bool IsFlattened() const
75     {
76         LIMITED_METHOD_CONTRACT;
77
78         return m_pData != NULL;
79     }
80
81     // The the size of buffer needed to contain the stored data
82     unsigned int GetSize() const
83     {
84         LIMITED_METHOD_CONTRACT;
85
86         return m_size;
87     }
88
89     EventData** GetEventDataArray() const
90     {
91         LIMITED_METHOD_CONTRACT;
92
93         return m_pEventData;
94     }
95 };
96
97 class StackContents
98 {
99 private:
100
101     const static unsigned int MAX_STACK_DEPTH = 100;
102
103     // Array of IP values from a stack crawl.
104     // Top of stack is at index 0.
105     UINT_PTR m_stackFrames[MAX_STACK_DEPTH];
106
107 #ifdef _DEBUG
108     // Parallel array of MethodDesc pointers.
109     // Used for debug-only stack printing.
110     MethodDesc* m_methods[MAX_STACK_DEPTH];
111 #endif // _DEBUG
112
113     // The next available slot in StackFrames.
114     unsigned int m_nextAvailableFrame;
115
116 public:
117
118     StackContents()
119     {
120         LIMITED_METHOD_CONTRACT;
121
122         Reset();
123     }
124
125     void CopyTo(StackContents *pDest)
126     {
127         LIMITED_METHOD_CONTRACT;
128         _ASSERTE(pDest != NULL);
129
130         memcpy_s(pDest->m_stackFrames, MAX_STACK_DEPTH * sizeof(UINT_PTR), m_stackFrames, sizeof(UINT_PTR) * m_nextAvailableFrame);
131 #ifdef _DEBUG
132         memcpy_s(pDest->m_methods, MAX_STACK_DEPTH * sizeof(MethodDesc*), m_methods, sizeof(MethodDesc*) * m_nextAvailableFrame);
133 #endif
134         pDest->m_nextAvailableFrame = m_nextAvailableFrame;
135     }
136
137     void Reset()
138     {
139         LIMITED_METHOD_CONTRACT;
140
141         m_nextAvailableFrame = 0;
142     }
143
144     bool IsEmpty()
145     {
146         LIMITED_METHOD_CONTRACT;
147
148         return (m_nextAvailableFrame == 0);
149     }
150
151     unsigned int GetLength()
152     {
153         LIMITED_METHOD_CONTRACT;
154
155         return m_nextAvailableFrame;
156     }
157
158     UINT_PTR GetIP(unsigned int frameIndex)
159     {
160         LIMITED_METHOD_CONTRACT;
161         _ASSERTE(frameIndex < MAX_STACK_DEPTH);
162
163         if (frameIndex >= MAX_STACK_DEPTH)
164         {
165             return 0;
166         }
167
168         return m_stackFrames[frameIndex];
169     }
170
171 #ifdef _DEBUG
172     MethodDesc* GetMethod(unsigned int frameIndex)
173     {
174         LIMITED_METHOD_CONTRACT;
175         _ASSERTE(frameIndex < MAX_STACK_DEPTH);
176
177         if (frameIndex >= MAX_STACK_DEPTH)
178         {
179             return NULL;
180         }
181
182         return m_methods[frameIndex];
183     }
184 #endif // _DEBUG
185
186     void Append(UINT_PTR controlPC, MethodDesc *pMethod)
187     {
188         LIMITED_METHOD_CONTRACT;
189
190         if(m_nextAvailableFrame < MAX_STACK_DEPTH)
191         {
192             m_stackFrames[m_nextAvailableFrame] = controlPC;
193 #ifdef _DEBUG
194             m_methods[m_nextAvailableFrame] = pMethod;
195 #endif
196             m_nextAvailableFrame++;
197         }
198     }
199
200     BYTE* GetPointer() const
201     {
202         LIMITED_METHOD_CONTRACT;
203
204         return (BYTE*)m_stackFrames;
205     }
206
207     unsigned int GetSize() const
208     {
209         LIMITED_METHOD_CONTRACT;
210
211         return (m_nextAvailableFrame * sizeof(UINT_PTR));
212     }
213 };
214
215 class EventPipe
216 {
217     // Declare friends.
218     friend class EventPipeConfiguration;
219     friend class EventPipeFile;
220     friend class EventPipeProvider;
221     friend class EventPipeBufferManager;
222     friend class SampleProfiler;
223
224     public:
225
226         // Initialize the event pipe.
227         static void Initialize();
228
229         // Shutdown the event pipe.
230         static void Shutdown();
231
232         // Enable tracing from the start-up path based on COMPLUS variable.
233         static void EnableOnStartup();
234
235         // Enable tracing via the event pipe.
236         static void Enable(
237             LPCWSTR strOutputPath,
238             unsigned int circularBufferSizeInMB,
239             EventPipeProviderConfiguration *pProviders,
240             int numProviders);
241
242         // Disable tracing via the event pipe.
243         static void Disable();
244
245         // Specifies whether or not the event pipe is enabled.
246         static bool Enabled();
247
248         // Create a provider.
249         static EventPipeProvider* CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction = NULL, void *pCallbackData = NULL);
250
251         // Delete a provider.
252         static void DeleteProvider(EventPipeProvider *pProvider);
253
254         // Write out an event from a flat buffer.
255         // Data is written as a serialized blob matching the ETW serialization conventions.
256         static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
257
258         // Write out an event from an EventData array.
259         // Data is written as a serialized blob matching the ETW serialization conventions.
260         static void WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
261
262         // Write out a sample profile event.
263         static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
264
265         // Get the managed call stack for the current thread.
266         static bool WalkManagedStackForCurrentThread(StackContents &stackContents);
267
268         // Get the managed call stack for the specified thread.
269         static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
270
271     protected:
272
273         // The counterpart to WriteEvent which after the payload is constructed
274         static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
275
276     private:
277
278         // Callback function for the stack walker.  For each frame walked, this callback is invoked.
279         static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
280
281         // Get the configuration object.
282         // This is called directly by the EventPipeProvider constructor to register the new provider.
283         static EventPipeConfiguration* GetConfiguration();
284
285         // Get the event pipe configuration lock.
286         static CrstStatic* GetLock();
287
288         static CrstStatic s_configCrst;
289         static bool s_tracingInitialized;
290         static EventPipeConfiguration *s_pConfig;
291         static EventPipeBufferManager *s_pBufferManager;
292         static EventPipeFile *s_pFile;
293 #ifdef _DEBUG
294         static EventPipeFile *s_pSyncFile;
295         static EventPipeJsonFile *s_pJsonFile;
296 #endif // _DEBUG
297 };
298
299 struct EventPipeProviderConfiguration
300 {
301
302 private:
303
304     LPCWSTR m_pProviderName;
305     UINT64 m_keywords;
306     UINT32 m_loggingLevel;
307
308 public:
309
310     EventPipeProviderConfiguration()
311     {
312         LIMITED_METHOD_CONTRACT;
313         m_pProviderName = NULL;
314         m_keywords = NULL;
315         m_loggingLevel = 0;
316     }
317
318     EventPipeProviderConfiguration(
319         LPCWSTR pProviderName,
320         UINT64 keywords,
321         UINT32 loggingLevel)
322     {
323         LIMITED_METHOD_CONTRACT;
324         m_pProviderName = pProviderName;
325         m_keywords = keywords;
326         m_loggingLevel = loggingLevel;
327     }
328
329     LPCWSTR GetProviderName() const
330     {
331         LIMITED_METHOD_CONTRACT;
332         return m_pProviderName;
333     }
334
335     UINT64 GetKeywords() const
336     {
337         LIMITED_METHOD_CONTRACT;
338         return m_keywords;
339     }
340
341     UINT32 GetLevel() const
342     {
343         LIMITED_METHOD_CONTRACT;
344         return m_loggingLevel;
345     }
346 };
347
348 class EventPipeInternal
349 {
350
351 public:
352
353     static void QCALLTYPE Enable(
354         __in_z LPCWSTR outputFile,
355         UINT32 circularBufferSizeInMB,
356         INT64 profilerSamplingRateInNanoseconds,
357         EventPipeProviderConfiguration *pProviders,
358         INT32 numProviders);
359
360     static void QCALLTYPE Disable();
361
362     static INT_PTR QCALLTYPE CreateProvider(
363         __in_z LPCWSTR providerName,
364         EventPipeCallback pCallbackFunc);
365
366     static INT_PTR QCALLTYPE DefineEvent(
367         INT_PTR provHandle,
368         UINT32 eventID,
369         __int64 keywords,
370         UINT32 eventVersion,
371         UINT32 level,
372         void *pMetadata,
373         UINT32 metadataLength);
374
375     static void QCALLTYPE DeleteProvider(
376         INT_PTR provHandle);
377
378     static void QCALLTYPE WriteEvent(
379         INT_PTR eventHandle,
380         UINT32 eventID,
381         void *pData,
382         UINT32 length,
383         LPCGUID pActivityId, LPCGUID pRelatedActivityId);
384
385     static void QCALLTYPE WriteEventData(
386         INT_PTR eventHandle,
387         UINT32 eventID,
388         EventData **pEventData,
389         UINT32 eventDataCount,
390         LPCGUID pActivityId, LPCGUID pRelatedActivityId);
391 };
392
393 #endif // FEATURE_PERFTRACING
394
395 #endif // __EVENTPIPE_H__