Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // ETW (Event Tracing for Windows) profiling helpers.
  4. // This allows easy insertion of Generic Event markers into ETW/xperf tracing
  5. // which then aids in analyzing the traces and finding performance problems.
  6. //
  7. //===============================================================================
  8. #include "pch_tier0.h"
  9. #include "tier0/etwprof.h"
  10. #ifdef ETW_MARKS_ENABLED
  11. #include <memory>
  12. // After building the DLL if it has never been registered on this machine or
  13. // if the providers have changed you need to go:
  14. // xcopy /y %vgame%\bin\tier0.dll %temp%
  15. // wevtutil um %vgame%\..\src\tier0\ValveETWProvider.man
  16. // wevtutil im %vgame%\..\src\tier0\ValveETWProvider.man
  17. #define WIN32_LEAN_AND_MEAN
  18. #include <windows.h>
  19. // These are defined in evntrace.h but you need a Vista+ Windows
  20. // SDK to have them available, so I define them here.
  21. #define EVENT_CONTROL_CODE_DISABLE_PROVIDER 0
  22. #define EVENT_CONTROL_CODE_ENABLE_PROVIDER 1
  23. #define EVENT_CONTROL_CODE_CAPTURE_STATE 2
  24. // EVNTAPI is used in evntprov.h which is included by ValveETWProviderEvents.h
  25. // We define EVNTAPI without the DECLSPEC_IMPORT specifier so that
  26. // we can implement these functions locally instead of using the import library,
  27. // and can therefore still run on Windows XP.
  28. #define EVNTAPI __stdcall
  29. // Include the event register/write/unregister macros compiled from the manifest file.
  30. // Note that this includes evntprov.h which requires a Vista+ Windows SDK
  31. // which we don't currently have, so evntprov.h is checked in.
  32. #include "ValveETWProviderEvents.h"
  33. // Typedefs for use with GetProcAddress
  34. typedef ULONG (__stdcall *tEventRegister)( LPCGUID ProviderId, PENABLECALLBACK EnableCallback, PVOID CallbackContext, PREGHANDLE RegHandle);
  35. typedef ULONG (__stdcall *tEventWrite)( REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData);
  36. typedef ULONG (__stdcall *tEventUnregister)( REGHANDLE RegHandle );
  37. // Helper class to dynamically load Advapi32.dll, find the ETW functions,
  38. // register the providers if possible, and get the performance counter frequency.
  39. class CETWRegister
  40. {
  41. public:
  42. CETWRegister()
  43. {
  44. QueryPerformanceFrequency( &m_frequency );
  45. // Find Advapi32.dll. This should always succeed.
  46. HMODULE pAdvapiDLL = LoadLibraryW( L"Advapi32.dll" );
  47. if ( pAdvapiDLL )
  48. {
  49. // Try to find the ETW functions. This will fail on XP.
  50. m_pEventRegister = ( tEventRegister )GetProcAddress( pAdvapiDLL, "EventRegister" );
  51. m_pEventWrite = ( tEventWrite )GetProcAddress( pAdvapiDLL, "EventWrite" );
  52. m_pEventUnregister = ( tEventUnregister )GetProcAddress( pAdvapiDLL, "EventUnregister" );
  53. // Register two ETW providers. If registration fails then the event logging calls will fail.
  54. // On XP these calls will do nothing.
  55. // On Vista and above, if these providers have been enabled by xperf or logman then
  56. // the VALVE_FRAMERATE_Context and VALVE_MAIN_Context globals will be modified
  57. // like this:
  58. // MatchAnyKeyword: 0xffffffffffffffff
  59. // IsEnabled: 1
  60. // Level: 255
  61. // In other words, fully enabled.
  62. EventRegisterValve_FrameRate();
  63. EventRegisterValve_ServerFrameRate();
  64. EventRegisterValve_Main();
  65. EventRegisterValve_Input();
  66. EventRegisterValve_Network();
  67. // Emit the thread ID for the main thread. This also indicates that
  68. // the main provider is initialized.
  69. EventWriteThread_ID( GetCurrentThreadId(), "Main thread" );
  70. // Emit an input system event so we know that it is active.
  71. EventWriteKey_down( "Valve input provider initialized.", 0, 0 );
  72. }
  73. }
  74. ~CETWRegister()
  75. {
  76. // Unregister our providers.
  77. EventUnregisterValve_Network();
  78. EventUnregisterValve_Input();
  79. EventUnregisterValve_Main();
  80. EventUnregisterValve_ServerFrameRate();
  81. EventUnregisterValve_FrameRate();
  82. }
  83. tEventRegister m_pEventRegister;
  84. tEventWrite m_pEventWrite;
  85. tEventUnregister m_pEventUnregister;
  86. // QPC frequency
  87. LARGE_INTEGER m_frequency;
  88. } g_ETWRegister;
  89. // Redirector function for EventRegister. Called by macros in ValveETWProviderEvents.h
  90. ULONG EVNTAPI EventRegister( LPCGUID ProviderId, PENABLECALLBACK EnableCallback, PVOID CallbackContext, PREGHANDLE RegHandle )
  91. {
  92. if ( g_ETWRegister.m_pEventRegister )
  93. return g_ETWRegister.m_pEventRegister( ProviderId, EnableCallback, CallbackContext, RegHandle );
  94. // RegHandle is an _Out_ parameter and must always be initialized.
  95. *RegHandle = 0;
  96. return 0;
  97. }
  98. // Redirector function for EventWrite. Called by macros in ValveETWProviderEvents.h
  99. ULONG EVNTAPI EventWrite( REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData )
  100. {
  101. if ( g_ETWRegister.m_pEventWrite )
  102. return g_ETWRegister.m_pEventWrite( RegHandle, EventDescriptor, UserDataCount, UserData );
  103. return 0;
  104. }
  105. // Redirector function for EventUnregister. Called by macros in ValveETWProviderEvents.h
  106. ULONG EVNTAPI EventUnregister( REGHANDLE RegHandle )
  107. {
  108. if ( g_ETWRegister.m_pEventUnregister )
  109. return g_ETWRegister.m_pEventUnregister( RegHandle );
  110. return 0;
  111. }
  112. // Call QueryPerformanceCounter
  113. static int64 GetQPCTime()
  114. {
  115. LARGE_INTEGER time;
  116. QueryPerformanceCounter( &time );
  117. return time.QuadPart;
  118. }
  119. // Convert a QueryPerformanceCounter delta into milliseconds
  120. static float QPCToMS( int64 nDelta )
  121. {
  122. // Convert from a QPC delta to seconds.
  123. float flSeconds = ( float )( nDelta / double( g_ETWRegister.m_frequency.QuadPart ) );
  124. // Convert from seconds to milliseconds
  125. return flSeconds * 1000;
  126. }
  127. // Public functions for emitting ETW events.
  128. int64 ETWMark( const char *pMessage )
  129. {
  130. int64 nTime = GetQPCTime();
  131. EventWriteMark( pMessage );
  132. return nTime;
  133. }
  134. void ETWMarkPrintf( const char *pMessage, ... )
  135. {
  136. // If we are running on Windows XP or if our providers have not been enabled
  137. // (by xperf or other) then this will be false and we can early out.
  138. // Be sure to check the appropriate context for the event. This is only
  139. // worth checking if there is some cost beyond the EventWrite that we can
  140. // avoid -- the redirectors in this file guarantee that EventWrite is always
  141. // safe to call.
  142. if ( !VALVE_MAIN_Context.IsEnabled )
  143. {
  144. return;
  145. }
  146. char buffer[1000];
  147. va_list args;
  148. va_start( args, pMessage );
  149. vsprintf_s( buffer, pMessage, args );
  150. va_end( args );
  151. EventWriteMark( buffer );
  152. }
  153. void ETWMark1F( const char *pMessage, float data1 )
  154. {
  155. EventWriteMark1F( pMessage, data1 );
  156. }
  157. void ETWMark2F( const char *pMessage, float data1, float data2 )
  158. {
  159. EventWriteMark2F( pMessage, data1, data2 );
  160. }
  161. void ETWMark3F( const char *pMessage, float data1, float data2, float data3 )
  162. {
  163. EventWriteMark3F( pMessage, data1, data2, data3 );
  164. }
  165. void ETWMark4F( const char *pMessage, float data1, float data2, float data3, float data4 )
  166. {
  167. EventWriteMark4F( pMessage, data1, data2, data3, data4 );
  168. }
  169. void ETWMark1I( const char *pMessage, int data1 )
  170. {
  171. EventWriteMark1I( pMessage, data1 );
  172. }
  173. void ETWMark2I( const char *pMessage, int data1, int data2 )
  174. {
  175. EventWriteMark2I( pMessage, data1, data2 );
  176. }
  177. void ETWMark3I( const char *pMessage, int data1, int data2, int data3 )
  178. {
  179. EventWriteMark3I( pMessage, data1, data2, data3 );
  180. }
  181. void ETWMark4I( const char *pMessage, int data1, int data2, int data3, int data4 )
  182. {
  183. EventWriteMark4I( pMessage, data1, data2, data3, data4 );
  184. }
  185. void ETWMark1S( const char *pMessage, const char* data1 )
  186. {
  187. EventWriteMark1S( pMessage, data1 );
  188. }
  189. void ETWMark2S( const char *pMessage, const char* data1, const char* data2 )
  190. {
  191. EventWriteMark2S( pMessage, data1, data2 );
  192. }
  193. // Track the depth of ETW Begin/End pairs. This needs to be per-thread
  194. // if we start emitting marks on multiple threads. Using __declspec(thread)
  195. // has some problems on Windows XP, but since these ETW functions only work
  196. // on Vista+ that doesn't matter.
  197. static __declspec( thread ) int s_nDepth;
  198. int64 ETWBegin( const char *pMessage )
  199. {
  200. // If we are running on Windows XP or if our providers have not been enabled
  201. // (by xperf or other) then this will be false and we can early out.
  202. // Be sure to check the appropriate context for the event. This is only
  203. // worth checking if there is some cost beyond the EventWrite that we can
  204. // avoid -- the redirectors in this file guarantee that EventWrite is always
  205. // safe to call.
  206. // In this case we also avoid the potentially unreliable TLS implementation
  207. // (for dynamically loaded DLLs) on Windows XP.
  208. if ( !VALVE_MAIN_Context.IsEnabled )
  209. {
  210. return 0;
  211. }
  212. int64 nTime = GetQPCTime();
  213. EventWriteStart( pMessage, s_nDepth++ );
  214. return nTime;
  215. }
  216. int64 ETWEnd( const char *pMessage, int64 nStartTime )
  217. {
  218. // If we are running on Windows XP or if our providers have not been enabled
  219. // (by xperf or other) then this will be false and we can early out.
  220. // Be sure to check the appropriate context for the event. This is only
  221. // worth checking if there is some cost beyond the EventWrite that we can
  222. // avoid -- the redirectors in this file guarantee that EventWrite is always
  223. // safe to call.
  224. // In this case we also avoid the potentially unreliable TLS implementation
  225. // (for dynamically loaded DLLs) on Windows XP.
  226. if ( !VALVE_MAIN_Context.IsEnabled )
  227. {
  228. return 0;
  229. }
  230. int64 nTime = GetQPCTime();
  231. EventWriteStop( pMessage, --s_nDepth, QPCToMS( nTime - nStartTime ) );
  232. return nTime;
  233. }
  234. // Record server and client frame counts separately, in case they are
  235. // in the same process.
  236. static int s_nRenderFrameCount[2];
  237. int ETWGetRenderFrameNumber()
  238. {
  239. return s_nRenderFrameCount[0];
  240. }
  241. // Insert a render frame marker using the Valve-FrameRate provider. Automatically
  242. // count the frame number and frame time.
  243. void ETWRenderFrameMark( bool bIsServerProcess )
  244. {
  245. Assert( bIsServerProcess == false || bIsServerProcess == true );
  246. // Record server and client frame counts separately, in case they are
  247. // in the same process.
  248. static int64 s_lastFrameTime[2];
  249. int64 nCurrentFrameTime = GetQPCTime();
  250. float flElapsedFrameTime = 0.0f;
  251. if ( s_nRenderFrameCount[bIsServerProcess] )
  252. {
  253. flElapsedFrameTime = QPCToMS( nCurrentFrameTime - s_lastFrameTime[bIsServerProcess] );
  254. }
  255. if ( bIsServerProcess )
  256. {
  257. EventWriteServerRenderFrameMark( s_nRenderFrameCount[bIsServerProcess], flElapsedFrameTime );
  258. }
  259. else
  260. {
  261. EventWriteRenderFrameMark( s_nRenderFrameCount[bIsServerProcess], flElapsedFrameTime );
  262. }
  263. ++s_nRenderFrameCount[bIsServerProcess];
  264. s_lastFrameTime[bIsServerProcess] = nCurrentFrameTime;
  265. }
  266. // Insert a simulation frame marker using the Valve-FrameRate provider. Automatically
  267. // count the frame number and frame time.
  268. void ETWSimFrameMark( bool bIsServerProcess )
  269. {
  270. Assert( bIsServerProcess == false || bIsServerProcess == true );
  271. // Record server and client frame counts separately, in case they are
  272. // in the same process.
  273. static int s_nFrameCount[2];
  274. static int64 s_lastFrameTime[2];
  275. int64 nCurrentFrameTime = GetQPCTime();
  276. float flElapsedFrameTime = 0.0f;
  277. if ( s_nFrameCount[bIsServerProcess] )
  278. {
  279. flElapsedFrameTime = QPCToMS( nCurrentFrameTime - s_lastFrameTime[bIsServerProcess] );
  280. }
  281. if ( bIsServerProcess )
  282. {
  283. EventWriteServerSimFrameMark( s_nFrameCount[bIsServerProcess], flElapsedFrameTime );
  284. }
  285. else
  286. {
  287. EventWriteSimFrameMark( s_nFrameCount[bIsServerProcess], flElapsedFrameTime );
  288. }
  289. ++s_nFrameCount[bIsServerProcess];
  290. s_lastFrameTime[bIsServerProcess] = nCurrentFrameTime;
  291. }
  292. void ETWMouseDown( int whichButton, int x, int y )
  293. {
  294. // Always have x/y first to make the summary tables easier to read.
  295. EventWriteMouse_down( x, y, whichButton );
  296. }
  297. void ETWMouseUp( int whichButton, int x, int y )
  298. {
  299. // Always have x/y first to make the summary tables easier to read.
  300. EventWriteMouse_up( x, y, whichButton );
  301. }
  302. void ETWMouseMove( int nX, int nY )
  303. {
  304. static int lastX, lastY;
  305. // Only emit mouse-move events if the mouse position has changed, since
  306. // otherwise source2 emits a continous stream of events which makes it
  307. // harder to find 'real' mouse-move events.
  308. if ( lastX != nX || lastY != nY )
  309. {
  310. lastX = nX;
  311. lastY = nY;
  312. // Always have x/y first to make the summary tables easier to read.
  313. EventWriteMouse_Move( nX, nY );
  314. }
  315. }
  316. void ETWMouseWheel( int nWheelDelta, int nX, int nY )
  317. {
  318. // Always have x/y first to make the summary tables easier to read.
  319. EventWriteMouse_Wheel( nX, nY, nWheelDelta );
  320. }
  321. void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar )
  322. {
  323. EventWriteKey_down( pChar, nScanCode, nVirtualCode );
  324. }
  325. void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck )
  326. {
  327. static int s_nCumulativeWireSize;
  328. s_nCumulativeWireSize += nWireSize;
  329. EventWriteSendPacket( pTo, nWireSize, nOutSequenceNR, nOutSequenceNrAck, s_nCumulativeWireSize );
  330. }
  331. void ETWThrottled()
  332. {
  333. EventWriteThrottled();
  334. }
  335. void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck )
  336. {
  337. static int s_nCumulativeWireSize;
  338. s_nCumulativeWireSize += nWireSize;
  339. EventWriteReadPacket( pFrom, nWireSize, nInSequenceNR, nOutSequenceNRAck, s_nCumulativeWireSize );
  340. }
  341. #endif // ETW_MARKS_ENABLED