@@ -25,6 +25,109 @@ struct Session
2525 CONTROLTRACE_ID handle = 0 ;
2626};
2727
28+ // ---- ETW Events ----------
29+
30+ struct CSwitch
31+ {
32+ // V2 fields:
33+ static constexpr UCHAR Opcode = 36 ;
34+ uint32_t newThreadId;
35+ uint32_t oldThreadId;
36+ int8_t newThreadPriority;
37+ int8_t oldThreadPriority;
38+ uint8_t previousCState;
39+ int8_t spareByte;
40+ int8_t oldThreadWaitReason;
41+ int8_t oldThreadWaitMode;
42+ int8_t oldThreadState;
43+ int8_t oldThreadWaitIdealProcessor;
44+ uint32_t newThreadWaitTime;
45+ uint32_t reserved;
46+ };
47+ static_assert ( sizeof ( CSwitch ) == 24 , " unexpected CSwitch struct size/alignment" );
48+
49+ struct ReadyThread
50+ {
51+ // V2 fields:
52+ static constexpr UCHAR Opcode = 50 ;
53+ uint32_t threadId;
54+ int8_t adjustReason;
55+ int8_t adjustIncrement;
56+ int8_t flag;
57+ int8_t reserverd;
58+ };
59+ static_assert ( sizeof ( ReadyThread ) == 8 , " unexpected ReadyThread struct size/alignment" );
60+
61+ struct ThreadInfo
62+ {
63+ // V0 (Thread_V0_TypeGroup1) fields:
64+ uint32_t processId;
65+ uint32_t threadId;
66+ // NOTE: we only care about PID and TID for now, and these two are "invariant"
67+ // across all revisions (versions) of this event. As such, let's omit the other
68+ // fields since they vary based on the event version; their sizes also vary by
69+ // target architecture (32bit or 64bit), and this is not even mentioned in the
70+ // MSDN documentation, and worse, have not been updated in the official schemas
71+ // either (which ETW Explorer uses), but can be introspected via the TDH API.
72+ };
73+ static_assert ( sizeof ( ThreadInfo ) == 8 , " unexpected ThreadInfo struct size/alignment" );
74+
75+ struct ThreadStart : public ThreadInfo
76+ {
77+ static constexpr UCHAR Opcode = 1 ;
78+ };
79+ static_assert ( sizeof ( ThreadStart ) == 8 , " unexpected ThreadStart struct size/alignment" ) ;
80+
81+ // DC: Data Collection (associated with the "rundown" phase)
82+ struct ThreadDCStart : public ThreadInfo
83+ {
84+ static constexpr UCHAR Opcode = 3 ;
85+ };
86+ static_assert ( sizeof ( ThreadDCStart ) == 8 , " unexpected ThreadDCStart struct size/alignment" );
87+
88+ struct SampledProfile
89+ {
90+ static constexpr UCHAR Opcode = 46 ;
91+ // NOTE: we don't handle SampledProfile events directly; instead, we handle
92+ // the StackWalk event associated with each SampledProfile event. Just like
93+ // ThreadInfo, the data layout varies based on the target architecture, and
94+ // the MSDN documentation and schemas are outdated.
95+ // uint64_t instructionPointer; // 32/64 bits
96+ // uint32_t threadId;
97+ // uint32_t count; // Not used.
98+ };
99+ static_assert ( sizeof ( SampledProfile ) == 1 , " unexpected SampledProfile struct size/alignment" );
100+
101+ struct StackWalkEvent
102+ {
103+ // V2 fields:
104+ static constexpr UCHAR Opcode = 32 ;
105+ uint64_t eventTimeStamp;
106+ uint32_t stackProcess;
107+ uint32_t stackThread;
108+ uint64_t stack[192 ]; // arbitrary upperbound limit; schema stops at [32]
109+ };
110+ static_assert ( offsetof( StackWalkEvent, stackProcess ) == 8 , " unexpected StackWalkEvent struct size/alignment" );
111+ static_assert ( offsetof( StackWalkEvent, stackThread ) == 12 , " unexpected StackWalkEvent struct size/alignment" );
112+ static_assert ( offsetof( StackWalkEvent, stack ) == 16 , " unexpected StackWalkEvent struct size/alignment" );
113+
114+ struct VSyncDPC
115+ {
116+ static constexpr USHORT EventId = 17 ; // 0x11
117+ void * dxgAdapter;
118+ uint32_t vidPnTargetId;
119+ uint64_t scannedPhysicalAddress;
120+ uint32_t vidPnSourceId;
121+ uint32_t frameNumber;
122+ int64_t frameQpcTime;
123+ void * hFlipDevice;
124+ uint32_t flipType;
125+ uint64_t flipFenceId;
126+ };
127+ static_assert ( sizeof ( VSyncDPC ) == 64 , " unexpected VSyncInfo struct size/alignment" );
128+
129+ // --------------------------
130+
28131static void ETWErrorAction ( ULONG error_code, const char * message, int length )
29132{
30133#ifdef TRACY_HAS_CALLSTACK
@@ -73,6 +176,18 @@ static DWORD ElevatePrivilege( LPCTSTR PrivilegeName )
73176 return ETWError ( status );
74177}
75178
179+ static bool IsOS64Bit ()
180+ {
181+ #if defined _WIN64
182+ constexpr bool isOs64Bit = true ;
183+ #else
184+ BOOL _iswow64;
185+ IsWow64Process (GetCurrentProcess (), &_iswow64);
186+ const bool isOs64Bit = _iswow64;
187+ #endif
188+ return isOs64Bit;
189+ }
190+
76191static ULONG StartSession ( Session& session )
77192{
78193 ULONG status = StartTraceA ( &session.handle , session.name , &session.properties );
@@ -116,14 +231,7 @@ static ULONG EnableProvider(
116231
117232static ULONG EnableStackWalk ( Session& session, GUID EventGuid, UCHAR Opcode )
118233{
119- #if defined _WIN64
120- constexpr bool isOs64Bit = true ;
121- #else
122- BOOL _iswow64;
123- IsWow64Process ( GetCurrentProcess (), &_iswow64 );
124- const bool isOs64Bit = _iswow64;
125- #endif
126- if ( !isOs64Bit )
234+ if ( !IsOS64Bit () )
127235 return 0 /* ERROR_SUCCESS */ ; // TODO: return error instead?
128236 CLASSIC_EVENT_ID stackId[1 ] = {};
129237 stackId[0 ].EventGuid = EventGuid;
@@ -136,11 +244,9 @@ static Session StartPrivateKernelSession( const CHAR* name )
136244{
137245 Session session = {};
138246
139- size_t maxlen = sizeof ( session.name );
140- for ( size_t i = 0 ; i < maxlen && name[i] != 0 ; ++i )
141- {
142- session.name [i] = name[i];
143- }
247+ size_t maxlen = sizeof ( session.name ) - 1 ;
248+ strncpy (session.name , name, maxlen);
249+ session.name [maxlen] = ' \0 ' ;
144250
145251 auto & props = session.properties ;
146252 props.LoggerNameOffset = offsetof ( Session, name );
@@ -156,7 +262,7 @@ static Session StartPrivateKernelSession( const CHAR* name )
156262 props.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
157263
158264 // TODO: should we really be tweaking the buffering parameters?
159- props.BufferSize = 1024 ;
265+ props.BufferSize = 1024 ; // in KB
160266 props.MinimumBuffers = std::thread::hardware_concurrency () * 4 ;
161267 props.MaximumBuffers = std::thread::hardware_concurrency () * 6 ;
162268
@@ -187,15 +293,18 @@ static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KH
187293 if ( status != ERROR_SUCCESS )
188294 return status;
189295
190- TRACE_PROFILE_INTERVAL interval = {};
191- interval.Source = 0 ; // 0: ProfileTime
192- interval.Interval = ( microseconds * 1000 ) / 100 ; // in 100's of nanoseconds
193- CONTROLTRACE_ID TraceId = 0 ; // must be zero for TraceSampledProfileIntervalInfo
194- status = TraceSetInformation ( TraceId, TraceSampledProfileIntervalInfo, &interval, sizeof ( interval ) );
195- if ( status != ERROR_SUCCESS )
196- return ETWError ( status );
296+ if ( IsOS64Bit () )
297+ {
298+ TRACE_PROFILE_INTERVAL interval = {};
299+ interval.Source = 0 ; // 0: ProfileTime (from enum KPROFILE_SOURCE in wdm.h)
300+ interval.Interval = ( microseconds * 1000 ) / 100 ; // in 100's of nanoseconds
301+ CONTROLTRACE_ID TraceId = 0 ; // must be zero for TraceSampledProfileIntervalInfo
302+ status = TraceSetInformation ( TraceId, TraceSampledProfileIntervalInfo, &interval, sizeof ( interval ) );
303+ if ( status != ERROR_SUCCESS )
304+ return ETWError ( status );
305+ }
197306
198- status = EnableStackWalk ( session, PerfInfoGuid, 46 ); // PerfInfoGuid Opcode 46: SampledProfile event
307+ status = EnableStackWalk ( session, PerfInfoGuid, SampledProfile::Opcode );
199308 return status;
200309}
201310
@@ -208,7 +317,7 @@ static ULONG EnableContextSwitchMonitoring( Session& session )
208317 EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, MatchAnyKeyword );
209318 if ( status != ERROR_SUCCESS )
210319 return status;
211- status = EnableStackWalk ( session, ThreadGuid, 36 ); // ThreadGuid Opcode 36: CSwitch event
320+ status = EnableStackWalk ( session, ThreadGuid, CSwitch::Opcode );
212321 return status;
213322}
214323
@@ -232,7 +341,7 @@ static ULONG EnableVSyncMonitoring( Session& session )
232341 EVENT_FILTER_EVENT_ID fe = {};
233342 fe.FilterIn = TRUE ;
234343 fe.Count = 1 ;
235- fe.Events [0 ] = 0x0011 ; // 0x11 = 17 : VSyncDPC_Info
344+ fe.Events [0 ] = VSyncDPC::EventId;
236345 EVENT_FILTER_DESCRIPTOR desc = {};
237346 desc.Ptr = (ULONGLONG)&fe;
238347 desc.Size = sizeof ( fe );
@@ -294,91 +403,5 @@ static ULONG EventConsumerLoop( PROCESSTRACE_HANDLE hEventConsumer )
294403 return status;
295404}
296405
297- struct CSwitch
298- {
299- // V2 fields:
300- static constexpr UCHAR Opcode = 36 ;
301- uint32_t newThreadId;
302- uint32_t oldThreadId;
303- int8_t newThreadPriority;
304- int8_t oldThreadPriority;
305- uint8_t previousCState;
306- int8_t spareByte;
307- int8_t oldThreadWaitReason;
308- int8_t oldThreadWaitMode;
309- int8_t oldThreadState;
310- int8_t oldThreadWaitIdealProcessor;
311- uint32_t newThreadWaitTime;
312- uint32_t reserved;
313- };
314- static_assert (sizeof (CSwitch) == 24 , " unexpected CSwitch struct size/alignment" );
315-
316- struct ReadyThread
317- {
318- // V2 fields:
319- static constexpr UCHAR Opcode = 50 ;
320- uint32_t threadId;
321- int8_t adjustReason;
322- int8_t adjustIncrement;
323- int8_t flag;
324- int8_t reserverd;
325- };
326- static_assert (sizeof (ReadyThread) == 8 , " unexpected ReadyThread struct size/alignment" );
327-
328- struct ThreadInfo
329- {
330- // V0 (Thread_V0_TypeGroup1) fields:
331- uint32_t processId;
332- uint32_t threadId;
333- // NOTE: we only care about PID and TID for now, and these two are "invariant"
334- // across all revisions (versions) of this event. As such, let's omit the other
335- // fields since they vary based on the event version; their sizes also vary by
336- // target architecture (32bit or 64bit), and this is not even mentioned in the
337- // MSDN documentation, and worse, have not been updated in the official schemas
338- // either (which ETW Explorer uses), but can be introspected via the TDH API.
339- };
340- static_assert (sizeof (ThreadInfo) == 8 , " unexpected ThreadInfo struct size/alignment" );
341-
342- struct ThreadStart : public ThreadInfo
343- {
344- static constexpr UCHAR Opcode = 1 ;
345- };
346- static_assert (sizeof (ThreadStart) == 8 , " unexpected ThreadStart struct size/alignment" );
347-
348- // DC: Data Collection (associated with the "rundown" phase)
349- struct ThreadDCStart : public ThreadInfo
350- {
351- static constexpr UCHAR Opcode = 3 ;
352- };
353- static_assert (sizeof (ThreadDCStart) == 8 , " unexpected ThreadDCStart struct size/alignment" );
354-
355- struct StackWalkEvent
356- {
357- // V2 fields:
358- static constexpr UCHAR Opcode = 32 ;
359- uint64_t eventTimeStamp;
360- uint32_t stackProcess;
361- uint32_t stackThread;
362- uint64_t stack[192 ]; // arbitrary upperbound limit; schema stops at [32]
363- };
364- static_assert (offsetof(StackWalkEvent, stackProcess) == 8 , " unexpected StackWalkEvent struct size/alignment" );
365- static_assert (offsetof(StackWalkEvent, stackThread) == 12 , " unexpected StackWalkEvent struct size/alignment" );
366- static_assert (offsetof(StackWalkEvent, stack) == 16 , " unexpected StackWalkEvent struct size/alignment" );
367-
368- struct VSyncInfo
369- {
370- static constexpr USHORT EventId = 17 ; // 0x11
371- void * dxgAdapter;
372- uint32_t vidPnTargetId;
373- uint64_t scannedPhysicalAddress;
374- uint32_t vidPnSourceId;
375- uint32_t frameNumber;
376- int64_t frameQpcTime;
377- void * hFlipDevice;
378- uint32_t flipType;
379- uint64_t flipFenceId;
380- };
381- static_assert (sizeof (VSyncInfo) == 64 , " unexpected VSyncInfo struct size/alignment" );
382-
383406}
384407}
0 commit comments