If IPC connections fails, then remove active session. (#24082)
[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 EventPipeEventInstance;
16 class EventPipeFile;
17 class EventPipeBufferManager;
18 class EventPipeEventSource;
19 class EventPipeProvider;
20 class MethodDesc;
21 struct EventPipeProviderConfiguration;
22 class EventPipeSession;
23 class IpcStream;
24 enum class EventPipeSessionType;
25
26 // EVENT_FILTER_DESCRIPTOR (This type does not exist on non-Windows platforms.)
27 //  https://docs.microsoft.com/en-us/windows/desktop/api/evntprov/ns-evntprov-_event_filter_descriptor
28 //  The structure supplements the event provider, level, and keyword data that
29 //  determines which events are reported and traced. The structure gives the
30 //  event provider greater control over the selection of events for reporting
31 //  and tracing.
32 // TODO: EventFilterDescriptor and EventData (defined below) are the same.
33 struct EventFilterDescriptor
34 {
35     // A pointer to the filter data.
36     ULONGLONG Ptr;
37
38     // The size of the filter data, in bytes. The maximum size is 1024 bytes.
39     ULONG Size;
40
41     // The type of filter data. The type is application-defined. An event
42     // controller that knows about the provider and knows details about the
43     // provider's events can use the Type field to send the provider an
44     // arbitrary set of data for use as enhancements to the filtering of events.
45     ULONG Type;
46 };
47
48 // Define the event pipe callback to match the ETW callback signature.
49 typedef void (*EventPipeCallback)(
50     LPCGUID SourceID,
51     ULONG IsEnabled,
52     UCHAR Level,
53     ULONGLONG MatchAnyKeywords,
54     ULONGLONG MatchAllKeywords,
55     EventFilterDescriptor *FilterData,
56     void *CallbackContext);
57
58 struct EventData
59 {
60     UINT64 Ptr;
61     unsigned int Size;
62     unsigned int Reserved;
63 };
64
65 class EventPipeEventPayload
66 {
67 private:
68     BYTE *m_pData;
69     EventData *m_pEventData;
70     unsigned int m_eventDataCount;
71     unsigned int m_size;
72     bool m_allocatedData;
73
74     // If the data is stored only as an array of EventData objects, create a flat buffer and copy into it
75     void Flatten();
76
77 public:
78     // Build this payload with a flat buffer inside
79     EventPipeEventPayload(BYTE *pData, unsigned int length) :
80         m_pData(pData),
81         m_pEventData(nullptr),
82         m_eventDataCount(0),
83         m_size(length),
84         m_allocatedData(false)
85     {
86         LIMITED_METHOD_CONTRACT;
87     }
88
89     // Build this payload to contain an array of EventData objects
90     EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount);
91
92     // If a buffer was allocated internally, delete it
93     ~EventPipeEventPayload();
94
95     // Copy the data (whether flat or array of objects) into a flat buffer at pDst
96     // Assumes that pDst points to an appropriatly sized buffer
97     void CopyData(BYTE *pDst);
98
99     // Get the flat formatted data in this payload
100     // This method will allocate a buffer if it does not already contain flattened data
101     // This method will return NULL on OOM if a buffer needed to be allocated
102     BYTE *GetFlatData();
103
104     // Return true is the data is stored in a flat buffer
105     bool IsFlattened() const
106     {
107         LIMITED_METHOD_CONTRACT;
108         return m_pData != NULL;
109     }
110
111     // The the size of buffer needed to contain the stored data
112     unsigned int GetSize() const
113     {
114         LIMITED_METHOD_CONTRACT;
115         return m_size;
116     }
117
118     EventData *GetEventDataArray() const
119     {
120         LIMITED_METHOD_CONTRACT;
121         return m_pEventData;
122     }
123 };
124
125 class StackContents
126 {
127 private:
128     const static unsigned int MAX_STACK_DEPTH = 100;
129
130     // Array of IP values from a stack crawl.
131     // Top of stack is at index 0.
132     UINT_PTR m_stackFrames[MAX_STACK_DEPTH];
133
134 #ifdef _DEBUG
135     // Parallel array of MethodDesc pointers.
136     // Used for debug-only stack printing.
137     MethodDesc *m_methods[MAX_STACK_DEPTH];
138 #endif // _DEBUG
139
140     // The next available slot in StackFrames.
141     unsigned int m_nextAvailableFrame;
142
143 public:
144     StackContents()
145     {
146         LIMITED_METHOD_CONTRACT;
147         Reset();
148     }
149
150     void CopyTo(StackContents *pDest)
151     {
152         LIMITED_METHOD_CONTRACT;
153         _ASSERTE(pDest != NULL);
154
155         memcpy_s(pDest->m_stackFrames, MAX_STACK_DEPTH * sizeof(UINT_PTR), m_stackFrames, sizeof(UINT_PTR) * m_nextAvailableFrame);
156 #ifdef _DEBUG
157         memcpy_s(pDest->m_methods, MAX_STACK_DEPTH * sizeof(MethodDesc *), m_methods, sizeof(MethodDesc *) * m_nextAvailableFrame);
158 #endif
159         pDest->m_nextAvailableFrame = m_nextAvailableFrame;
160     }
161
162     void Reset()
163     {
164         LIMITED_METHOD_CONTRACT;
165         m_nextAvailableFrame = 0;
166     }
167
168     bool IsEmpty()
169     {
170         LIMITED_METHOD_CONTRACT;
171         return (m_nextAvailableFrame == 0);
172     }
173
174     unsigned int GetLength()
175     {
176         LIMITED_METHOD_CONTRACT;
177         return m_nextAvailableFrame;
178     }
179
180     UINT_PTR GetIP(unsigned int frameIndex)
181     {
182         LIMITED_METHOD_CONTRACT;
183         _ASSERTE(frameIndex < MAX_STACK_DEPTH);
184
185         if (frameIndex >= MAX_STACK_DEPTH)
186         {
187             return 0;
188         }
189
190         return m_stackFrames[frameIndex];
191     }
192
193 #ifdef _DEBUG
194     MethodDesc *GetMethod(unsigned int frameIndex)
195     {
196         LIMITED_METHOD_CONTRACT;
197         _ASSERTE(frameIndex < MAX_STACK_DEPTH);
198
199         if (frameIndex >= MAX_STACK_DEPTH)
200         {
201             return NULL;
202         }
203
204         return m_methods[frameIndex];
205     }
206 #endif // _DEBUG
207
208     void Append(UINT_PTR controlPC, MethodDesc *pMethod)
209     {
210         LIMITED_METHOD_CONTRACT;
211
212         if (m_nextAvailableFrame < MAX_STACK_DEPTH)
213         {
214             m_stackFrames[m_nextAvailableFrame] = controlPC;
215 #ifdef _DEBUG
216             m_methods[m_nextAvailableFrame] = pMethod;
217 #endif
218             m_nextAvailableFrame++;
219         }
220     }
221
222     BYTE *GetPointer() const
223     {
224         LIMITED_METHOD_CONTRACT;
225         return (BYTE *)m_stackFrames;
226     }
227
228     unsigned int GetSize() const
229     {
230         LIMITED_METHOD_CONTRACT;
231         return (m_nextAvailableFrame * sizeof(UINT_PTR));
232     }
233 };
234
235 typedef UINT64 EventPipeSessionID;
236
237 class EventPipe
238 {
239     // Declare friends.
240     friend class EventPipeConfiguration;
241     friend class EventPipeFile;
242     friend class EventPipeProvider;
243     friend class EventPipeBufferManager;
244     friend class SampleProfiler;
245
246 public:
247     // Initialize the event pipe.
248     static void Initialize();
249
250     // Shutdown the event pipe.
251     static void Shutdown();
252
253     // Enable tracing via the event pipe.
254     static EventPipeSessionID Enable(
255         LPCWSTR strOutputPath,
256         uint32_t circularBufferSizeInMB,
257         uint64_t profilerSamplingRateInNanoseconds,
258         const EventPipeProviderConfiguration *pProviders,
259         uint32_t numProviders,
260         EventPipeSessionType sessionType,
261         IpcStream *const pStream);
262
263     // Disable tracing via the event pipe.
264     static void Disable(EventPipeSessionID id);
265
266     // Get the session for the specified session ID.
267     static EventPipeSession *GetSession(EventPipeSessionID id);
268
269     // Specifies whether or not the event pipe is enabled.
270     static bool Enabled();
271
272     // Create a provider.
273     static EventPipeProvider *CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction = NULL, void *pCallbackData = NULL);
274
275     // Get a provider.
276     static EventPipeProvider *GetProvider(const SString &providerName);
277
278     // Delete a provider.
279     static void DeleteProvider(EventPipeProvider *pProvider);
280
281     // Write out an event from a flat buffer.
282     // Data is written as a serialized blob matching the ETW serialization conventions.
283     static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
284
285     // Write out an event from an EventData array.
286     // Data is written as a serialized blob matching the ETW serialization conventions.
287     static void WriteEvent(EventPipeEvent &event, EventData *pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
288
289     // Write out a sample profile event.
290     static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
291
292     // Get the managed call stack for the current thread.
293     static bool WalkManagedStackForCurrentThread(StackContents &stackContents);
294
295     // Get the managed call stack for the specified thread.
296     static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
297
298     // Save the command line for the current process.
299     static void SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv);
300
301     // Get next event.
302     static EventPipeEventInstance *GetNextEvent();
303
304 private:
305     // The counterpart to WriteEvent which after the payload is constructed
306     static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
307
308     static void DisableInternal(EventPipeSessionID id);
309
310     // Enable the specified EventPipe session.
311     static EventPipeSessionID Enable(
312         LPCWSTR strOutputPath,
313         EventPipeSession *const pSession,
314         EventPipeSessionType sessionType,
315         IpcStream *const pStream);
316
317     static void CreateFlushTimerCallback();
318
319     static void DeleteFlushTimerCallback();
320
321     static void WINAPI FlushTimer(PVOID parameter, BOOLEAN timerFired);
322
323     // Callback function for the stack walker.  For each frame walked, this callback is invoked.
324     static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
325
326     // Get the configuration object.
327     // This is called directly by the EventPipeProvider constructor to register the new provider.
328     static EventPipeConfiguration *GetConfiguration()
329     {
330         LIMITED_METHOD_CONTRACT;
331         return s_pConfig;
332     }
333
334     // Get the event pipe configuration lock.
335     static CrstStatic *GetLock()
336     {
337         LIMITED_METHOD_CONTRACT;
338         return &s_configCrst;
339     }
340
341     static CrstStatic s_configCrst;
342     static bool s_tracingInitialized;
343     static EventPipeConfiguration *s_pConfig;
344     static EventPipeSession *s_pSession;
345     static EventPipeBufferManager *s_pBufferManager;
346     static EventPipeFile *s_pFile;
347     static EventPipeEventSource *s_pEventSource;
348     static LPCWSTR s_pCommandLine;
349     static HANDLE s_fileSwitchTimerHandle;
350     static ULONGLONG s_lastFlushSwitchTime;
351 };
352
353 struct EventPipeProviderConfiguration
354 {
355 private:
356     LPCWSTR m_pProviderName = nullptr;
357     UINT64 m_keywords = 0;
358     UINT32 m_loggingLevel = 0;
359     LPCWSTR m_pFilterData = nullptr;
360
361 public:
362     EventPipeProviderConfiguration() = default;
363
364     EventPipeProviderConfiguration(LPCWSTR pProviderName, UINT64 keywords, UINT32 loggingLevel, LPCWSTR pFilterData) :
365         m_pProviderName(pProviderName),
366         m_keywords(keywords),
367         m_loggingLevel(loggingLevel),
368         m_pFilterData(pFilterData)
369     {
370     }
371
372     LPCWSTR GetProviderName() const
373     {
374         LIMITED_METHOD_CONTRACT;
375         return m_pProviderName;
376     }
377
378     UINT64 GetKeywords() const
379     {
380         LIMITED_METHOD_CONTRACT;
381         return m_keywords;
382     }
383
384     UINT32 GetLevel() const
385     {
386         LIMITED_METHOD_CONTRACT;
387         return m_loggingLevel;
388     }
389
390     LPCWSTR GetFilterData() const
391     {
392         LIMITED_METHOD_CONTRACT;
393         return m_pFilterData;
394     }
395 };
396
397 #endif // FEATURE_PERFTRACING
398
399 #endif // __EVENTPIPE_H__