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
11class CrstStatic;
12class CrawlFrame;
13class EventPipeConfiguration;
14class EventPipeEvent;
15class EventPipeEventInstance;
16class EventPipeFile;
17class EventPipeJsonFile;
18class EventPipeBuffer;
19class EventPipeBufferManager;
20class EventPipeEventSource;
21class EventPipeProvider;
22class MethodDesc;
23class SampleProfilerEventInstance;
24struct EventPipeProviderConfiguration;
25class EventPipeSession;
26
27// EVENT_FILTER_DESCRIPTOR (This type does not exist on non-Windows platforms.)
28// https://docs.microsoft.com/en-us/windows/desktop/api/evntprov/ns-evntprov-_event_filter_descriptor
29// The structure supplements the event provider, level, and keyword data that
30// determines which events are reported and traced. The structure gives the
31// event provider greater control over the selection of events for reporting
32// and tracing.
33struct 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.
49typedef void (*EventPipeCallback)(
50 LPCGUID SourceID,
51 ULONG IsEnabled,
52 UCHAR Level,
53 ULONGLONG MatchAnyKeywords,
54 ULONGLONG MatchAllKeywords,
55 EventFilterDescriptor *FilterData,
56 void *CallbackContext);
57
58struct EventData
59{
60public:
61 UINT64 Ptr;
62 unsigned int Size;
63 unsigned int Reserved;
64};
65
66class EventPipeEventPayload
67{
68private:
69 BYTE *m_pData;
70 EventData *m_pEventData;
71 unsigned int m_eventDataCount;
72 unsigned int m_size;
73 bool m_allocatedData;
74
75 // If the data is stored only as an array of EventData objects, create a flat buffer and copy into it
76 void Flatten();
77
78public:
79 // Build this payload with a flat buffer inside
80 EventPipeEventPayload(BYTE *pData, unsigned int length);
81
82 // Build this payload to contain an array of EventData objects
83 EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount);
84
85 // If a buffer was allocated internally, delete it
86 ~EventPipeEventPayload();
87
88 // Copy the data (whether flat or array of objects) into a flat buffer at pDst
89 // Assumes that pDst points to an appropriatly sized buffer
90 void CopyData(BYTE *pDst);
91
92 // Get the flat formatted data in this payload
93 // This method will allocate a buffer if it does not already contain flattened data
94 // This method will return NULL on OOM if a buffer needed to be allocated
95 BYTE* GetFlatData();
96
97 // Return true is the data is stored in a flat buffer
98 bool IsFlattened() const
99 {
100 LIMITED_METHOD_CONTRACT;
101
102 return m_pData != NULL;
103 }
104
105 // The the size of buffer needed to contain the stored data
106 unsigned int GetSize() const
107 {
108 LIMITED_METHOD_CONTRACT;
109
110 return m_size;
111 }
112
113 EventData* GetEventDataArray() const
114 {
115 LIMITED_METHOD_CONTRACT;
116
117 return m_pEventData;
118 }
119};
120
121class StackContents
122{
123private:
124
125 const static unsigned int MAX_STACK_DEPTH = 100;
126
127 // Array of IP values from a stack crawl.
128 // Top of stack is at index 0.
129 UINT_PTR m_stackFrames[MAX_STACK_DEPTH];
130
131#ifdef _DEBUG
132 // Parallel array of MethodDesc pointers.
133 // Used for debug-only stack printing.
134 MethodDesc* m_methods[MAX_STACK_DEPTH];
135#endif // _DEBUG
136
137 // The next available slot in StackFrames.
138 unsigned int m_nextAvailableFrame;
139
140public:
141
142 StackContents()
143 {
144 LIMITED_METHOD_CONTRACT;
145
146 Reset();
147 }
148
149 void CopyTo(StackContents *pDest)
150 {
151 LIMITED_METHOD_CONTRACT;
152 _ASSERTE(pDest != NULL);
153
154 memcpy_s(pDest->m_stackFrames, MAX_STACK_DEPTH * sizeof(UINT_PTR), m_stackFrames, sizeof(UINT_PTR) * m_nextAvailableFrame);
155#ifdef _DEBUG
156 memcpy_s(pDest->m_methods, MAX_STACK_DEPTH * sizeof(MethodDesc*), m_methods, sizeof(MethodDesc*) * m_nextAvailableFrame);
157#endif
158 pDest->m_nextAvailableFrame = m_nextAvailableFrame;
159 }
160
161 void Reset()
162 {
163 LIMITED_METHOD_CONTRACT;
164
165 m_nextAvailableFrame = 0;
166 }
167
168 bool IsEmpty()
169 {
170 LIMITED_METHOD_CONTRACT;
171
172 return (m_nextAvailableFrame == 0);
173 }
174
175 unsigned int GetLength()
176 {
177 LIMITED_METHOD_CONTRACT;
178
179 return m_nextAvailableFrame;
180 }
181
182 UINT_PTR GetIP(unsigned int frameIndex)
183 {
184 LIMITED_METHOD_CONTRACT;
185 _ASSERTE(frameIndex < MAX_STACK_DEPTH);
186
187 if (frameIndex >= MAX_STACK_DEPTH)
188 {
189 return 0;
190 }
191
192 return m_stackFrames[frameIndex];
193 }
194
195#ifdef _DEBUG
196 MethodDesc* GetMethod(unsigned int frameIndex)
197 {
198 LIMITED_METHOD_CONTRACT;
199 _ASSERTE(frameIndex < MAX_STACK_DEPTH);
200
201 if (frameIndex >= MAX_STACK_DEPTH)
202 {
203 return NULL;
204 }
205
206 return m_methods[frameIndex];
207 }
208#endif // _DEBUG
209
210 void Append(UINT_PTR controlPC, MethodDesc *pMethod)
211 {
212 LIMITED_METHOD_CONTRACT;
213
214 if(m_nextAvailableFrame < MAX_STACK_DEPTH)
215 {
216 m_stackFrames[m_nextAvailableFrame] = controlPC;
217#ifdef _DEBUG
218 m_methods[m_nextAvailableFrame] = pMethod;
219#endif
220 m_nextAvailableFrame++;
221 }
222 }
223
224 BYTE* GetPointer() const
225 {
226 LIMITED_METHOD_CONTRACT;
227
228 return (BYTE*)m_stackFrames;
229 }
230
231 unsigned int GetSize() const
232 {
233 LIMITED_METHOD_CONTRACT;
234
235 return (m_nextAvailableFrame * sizeof(UINT_PTR));
236 }
237};
238
239typedef UINT64 EventPipeSessionID;
240
241class EventPipe
242{
243 // Declare friends.
244 friend class EventPipeConfiguration;
245 friend class EventPipeFile;
246 friend class EventPipeProvider;
247 friend class EventPipeBufferManager;
248 friend class SampleProfiler;
249
250 public:
251
252 // Initialize the event pipe.
253 static void Initialize();
254
255 // Shutdown the event pipe.
256 static void Shutdown();
257
258 // Enable tracing via the event pipe.
259 static EventPipeSessionID Enable(
260 LPCWSTR strOutputPath,
261 unsigned int circularBufferSizeInMB,
262 EventPipeProviderConfiguration *pProviders,
263 int numProviders,
264 UINT64 multiFileTraceLengthInSeconds);
265
266 // Disable tracing via the event pipe.
267 static void Disable(EventPipeSessionID id);
268
269 // Get the session for the specified session ID.
270 static EventPipeSession* GetSession(EventPipeSessionID id);
271
272 // Specifies whether or not the event pipe is enabled.
273 static bool Enabled();
274
275 // Create a provider.
276 static EventPipeProvider* CreateProvider(const SString &providerName, EventPipeCallback pCallbackFunction = NULL, void *pCallbackData = NULL);
277
278 // Get a provider.
279 static EventPipeProvider* GetProvider(const SString &providerName);
280
281 // Delete a provider.
282 static void DeleteProvider(EventPipeProvider *pProvider);
283
284 // Write out an event from a flat buffer.
285 // Data is written as a serialized blob matching the ETW serialization conventions.
286 static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
287
288 // Write out an event from an EventData array.
289 // Data is written as a serialized blob matching the ETW serialization conventions.
290 static void WriteEvent(EventPipeEvent &event, EventData *pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
291
292 // Write out a sample profile event.
293 static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
294
295 // Get the managed call stack for the current thread.
296 static bool WalkManagedStackForCurrentThread(StackContents &stackContents);
297
298 // Get the managed call stack for the specified thread.
299 static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
300
301 // Save the command line for the current process.
302 static void SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv);
303
304 // Get next event.
305 static EventPipeEventInstance* GetNextEvent();
306
307 protected:
308
309 // The counterpart to WriteEvent which after the payload is constructed
310 static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
311
312 private:
313
314 // Enable the specified EventPipe session.
315 static EventPipeSessionID Enable(LPCWSTR strOutputPath, EventPipeSession *pSession);
316
317 static void CreateFileSwitchTimer();
318
319 static void DeleteFileSwitchTimer();
320
321 // Performs one polling operation to determine if it is necessary to switch to a new file.
322 // If the polling operation decides it is time, it will perform the switch.
323 // Called directly from the timer when the timer is triggered.
324 static void WINAPI SwitchToNextFileTimerCallback(PVOID parameter, BOOLEAN timerFired);
325
326 // If event pipe has been configured to write multiple files, switch to the next file.
327 static void SwitchToNextFile();
328
329 // Generate the file path for the next trace file.
330 // This is used when event pipe has been configured to create multiple trace files with a specified maximum length of time.
331 static void GetNextFilePath(EventPipeSession *pSession, SString &nextTraceFilePath);
332
333 // Callback function for the stack walker. For each frame walked, this callback is invoked.
334 static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
335
336 // Get the configuration object.
337 // This is called directly by the EventPipeProvider constructor to register the new provider.
338 static EventPipeConfiguration* GetConfiguration();
339
340 // Get the event pipe configuration lock.
341 static CrstStatic* GetLock();
342
343 static CrstStatic s_configCrst;
344 static bool s_tracingInitialized;
345 static EventPipeConfiguration *s_pConfig;
346 static EventPipeSession *s_pSession;
347 static EventPipeBufferManager *s_pBufferManager;
348 static LPCWSTR s_pOutputPath;
349 static unsigned long s_nextFileIndex;
350 static EventPipeFile *s_pFile;
351 static EventPipeEventSource *s_pEventSource;
352 static LPCWSTR s_pCommandLine;
353 const static DWORD FileSwitchTimerPeriodMS = 1000;
354 static HANDLE s_fileSwitchTimerHandle;
355 static ULONGLONG s_lastFileSwitchTime;
356};
357
358struct EventPipeProviderConfiguration
359{
360
361private:
362
363 LPCWSTR m_pProviderName;
364 UINT64 m_keywords;
365 UINT32 m_loggingLevel;
366 LPCWSTR m_pFilterData;
367
368public:
369
370 EventPipeProviderConfiguration()
371 {
372 LIMITED_METHOD_CONTRACT;
373 m_pProviderName = NULL;
374 m_keywords = NULL;
375 m_loggingLevel = 0;
376 m_pFilterData = NULL;
377 }
378
379 EventPipeProviderConfiguration(
380 LPCWSTR pProviderName,
381 UINT64 keywords,
382 UINT32 loggingLevel,
383 LPCWSTR pFilterData)
384 {
385 LIMITED_METHOD_CONTRACT;
386 m_pProviderName = pProviderName;
387 m_keywords = keywords;
388 m_loggingLevel = loggingLevel;
389 m_pFilterData = pFilterData;
390 }
391
392 LPCWSTR GetProviderName() const
393 {
394 LIMITED_METHOD_CONTRACT;
395 return m_pProviderName;
396 }
397
398 UINT64 GetKeywords() const
399 {
400 LIMITED_METHOD_CONTRACT;
401 return m_keywords;
402 }
403
404 UINT32 GetLevel() const
405 {
406 LIMITED_METHOD_CONTRACT;
407 return m_loggingLevel;
408 }
409
410 LPCWSTR GetFilterData() const
411 {
412 LIMITED_METHOD_CONTRACT;
413 return m_pFilterData;
414 }
415};
416
417class EventPipeInternal
418{
419private:
420
421 enum class ActivityControlCode
422 {
423 EVENT_ACTIVITY_CONTROL_GET_ID = 1,
424 EVENT_ACTIVITY_CONTROL_SET_ID = 2,
425 EVENT_ACTIVITY_CONTROL_CREATE_ID = 3,
426 EVENT_ACTIVITY_CONTROL_GET_SET_ID = 4,
427 EVENT_ACTIVITY_CONTROL_CREATE_SET_ID = 5
428 };
429
430 struct EventPipeEventInstanceData
431 {
432 public:
433 void *ProviderID;
434 unsigned int EventID;
435 unsigned int ThreadID;
436 LARGE_INTEGER TimeStamp;
437 GUID ActivityId;
438 GUID RelatedActivityId;
439 const BYTE *Payload;
440 unsigned int PayloadLength;
441 };
442
443 struct EventPipeSessionInfo
444 {
445 public:
446 FILETIME StartTimeAsUTCFileTime;
447 LARGE_INTEGER StartTimeStamp;
448 LARGE_INTEGER TimeStampFrequency;
449 };
450
451public:
452
453 static UINT64 QCALLTYPE Enable(
454 __in_z LPCWSTR outputFile,
455 UINT32 circularBufferSizeInMB,
456 INT64 profilerSamplingRateInNanoseconds,
457 EventPipeProviderConfiguration *pProviders,
458 INT32 numProviders,
459 UINT64 multiFileTraceLengthInSeconds);
460
461 static void QCALLTYPE Disable(UINT64 sessionID);
462
463 static bool QCALLTYPE GetSessionInfo(UINT64 sessionID, EventPipeSessionInfo *pSessionInfo);
464
465 static INT_PTR QCALLTYPE CreateProvider(
466 __in_z LPCWSTR providerName,
467 EventPipeCallback pCallbackFunc);
468
469 static INT_PTR QCALLTYPE DefineEvent(
470 INT_PTR provHandle,
471 UINT32 eventID,
472 __int64 keywords,
473 UINT32 eventVersion,
474 UINT32 level,
475 void *pMetadata,
476 UINT32 metadataLength);
477
478 static INT_PTR QCALLTYPE GetProvider(
479 __in_z LPCWSTR providerName);
480
481 static void QCALLTYPE DeleteProvider(
482 INT_PTR provHandle);
483
484 static int QCALLTYPE EventActivityIdControl(
485 uint controlCode,
486 GUID *pActivityId);
487
488 static void QCALLTYPE WriteEvent(
489 INT_PTR eventHandle,
490 UINT32 eventID,
491 void *pData,
492 UINT32 length,
493 LPCGUID pActivityId, LPCGUID pRelatedActivityId);
494
495 static void QCALLTYPE WriteEventData(
496 INT_PTR eventHandle,
497 UINT32 eventID,
498 EventData *pEventData,
499 UINT32 eventDataCount,
500 LPCGUID pActivityId, LPCGUID pRelatedActivityId);
501
502 static bool QCALLTYPE GetNextEvent(
503 EventPipeEventInstanceData *pInstance);
504};
505
506#endif // FEATURE_PERFTRACING
507
508#endif // __EVENTPIPE_H__
509