Counter Strike : Global Offensive Source Code
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.

413 lines
13 KiB

  1. //============ Copyright (c) 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. #include <memory>
  11. #ifdef ETW_MARKS_ENABLED
  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. // We are contractually obliged to initialize this.
  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. bool ETWIsTracingEnabled()
  129. {
  130. if ( VALVE_MAIN_Context.IsEnabled )
  131. return true;
  132. return false;
  133. }
  134. int64 ETWMark( const char *pMessage )
  135. {
  136. int64 nTime = GetQPCTime();
  137. EventWriteMark( pMessage );
  138. return nTime;
  139. }
  140. void ETWMarkPrintf( const char *pMessage, ... )
  141. {
  142. // If we are running on Windows XP or if our providers have not been enabled
  143. // (by xperf or other) then this will be false and we can early out.
  144. // Be sure to check the appropriate context for the event. This is only
  145. // worth checking if there is some cost beyond the EventWrite that we can
  146. // avoid -- the redirectors in this file guarantee that EventWrite is always
  147. // safe to call.
  148. if ( !VALVE_MAIN_Context.IsEnabled )
  149. {
  150. return;
  151. }
  152. char buffer[1000];
  153. va_list args;
  154. va_start( args, pMessage );
  155. vsprintf_s( buffer, pMessage, args );
  156. va_end( args );
  157. EventWriteMark( buffer );
  158. }
  159. void ETWMark1F( const char *pMessage, float data1 )
  160. {
  161. EventWriteMark1F( pMessage, data1 );
  162. }
  163. void ETWMark2F( const char *pMessage, float data1, float data2 )
  164. {
  165. EventWriteMark2F( pMessage, data1, data2 );
  166. }
  167. void ETWMark3F( const char *pMessage, float data1, float data2, float data3 )
  168. {
  169. EventWriteMark3F( pMessage, data1, data2, data3 );
  170. }
  171. void ETWMark4F( const char *pMessage, float data1, float data2, float data3, float data4 )
  172. {
  173. EventWriteMark4F( pMessage, data1, data2, data3, data4 );
  174. }
  175. void ETWMark1I( const char *pMessage, int data1 )
  176. {
  177. EventWriteMark1I( pMessage, data1 );
  178. }
  179. void ETWMark2I( const char *pMessage, int data1, int data2 )
  180. {
  181. EventWriteMark2I( pMessage, data1, data2 );
  182. }
  183. void ETWMark3I( const char *pMessage, int data1, int data2, int data3 )
  184. {
  185. EventWriteMark3I( pMessage, data1, data2, data3 );
  186. }
  187. void ETWMark4I( const char *pMessage, int data1, int data2, int data3, int data4 )
  188. {
  189. EventWriteMark4I( pMessage, data1, data2, data3, data4 );
  190. }
  191. void ETWMark1S( const char *pMessage, const char* data1 )
  192. {
  193. EventWriteMark1S( pMessage, data1 );
  194. }
  195. void ETWMark2S( const char *pMessage, const char* data1, const char* data2 )
  196. {
  197. EventWriteMark2S( pMessage, data1, data2 );
  198. }
  199. // Track the depth of ETW Begin/End pairs. This needs to be per-thread
  200. // if we start emitting marks on multiple threads. Using __declspec(thread)
  201. // has some problems on Windows XP, but since these ETW functions only work
  202. // on Vista+ that doesn't matter.
  203. static __declspec( thread ) int s_nDepth;
  204. int64 ETWBegin( const char *pMessage )
  205. {
  206. // If we are running on Windows XP or if our providers have not been enabled
  207. // (by xperf or other) then this will be false and we can early out.
  208. // Be sure to check the appropriate context for the event. This is only
  209. // worth checking if there is some cost beyond the EventWrite that we can
  210. // avoid -- the redirectors in this file guarantee that EventWrite is always
  211. // safe to call.
  212. // In this case we also avoid the potentially unreliable TLS implementation
  213. // (for dynamically loaded DLLs) on Windows XP.
  214. if ( !VALVE_MAIN_Context.IsEnabled )
  215. {
  216. return 0;
  217. }
  218. int64 nTime = GetQPCTime();
  219. EventWriteStart( pMessage, s_nDepth++ );
  220. return nTime;
  221. }
  222. int64 ETWEnd( const char *pMessage, int64 nStartTime )
  223. {
  224. // If we are running on Windows XP or if our providers have not been enabled
  225. // (by xperf or other) then this will be false and we can early out.
  226. // Be sure to check the appropriate context for the event. This is only
  227. // worth checking if there is some cost beyond the EventWrite that we can
  228. // avoid -- the redirectors in this file guarantee that EventWrite is always
  229. // safe to call.
  230. // In this case we also avoid the potentially unreliable TLS implementation
  231. // (for dynamically loaded DLLs) on Windows XP.
  232. if ( !VALVE_MAIN_Context.IsEnabled )
  233. {
  234. return 0;
  235. }
  236. int64 nTime = GetQPCTime();
  237. EventWriteStop( pMessage, --s_nDepth, QPCToMS( nTime - nStartTime ) );
  238. return nTime;
  239. }
  240. // Record server and client frame counts separately, in case they are
  241. // in the same process.
  242. static int s_nRenderFrameCount[2];
  243. int ETWGetRenderFrameNumber()
  244. {
  245. return s_nRenderFrameCount[0];
  246. }
  247. // Insert a render frame marker using the Valve-FrameRate provider. Automatically
  248. // count the frame number and frame time.
  249. void ETWRenderFrameMark( bool bIsServerProcess )
  250. {
  251. Assert( bIsServerProcess == false || bIsServerProcess == true );
  252. // Record server and client frame counts separately, in case they are
  253. // in the same process.
  254. static int64 s_lastFrameTime[2];
  255. int64 nCurrentFrameTime = GetQPCTime();
  256. float flElapsedFrameTime = 0.0f;
  257. if ( s_nRenderFrameCount[bIsServerProcess] )
  258. {
  259. flElapsedFrameTime = QPCToMS( nCurrentFrameTime - s_lastFrameTime[bIsServerProcess] );
  260. }
  261. if ( bIsServerProcess )
  262. {
  263. EventWriteServerRenderFrameMark( s_nRenderFrameCount[bIsServerProcess], flElapsedFrameTime );
  264. }
  265. else
  266. {
  267. EventWriteRenderFrameMark( s_nRenderFrameCount[bIsServerProcess], flElapsedFrameTime );
  268. }
  269. ++s_nRenderFrameCount[bIsServerProcess];
  270. s_lastFrameTime[bIsServerProcess] = nCurrentFrameTime;
  271. }
  272. // Insert a simulation frame marker using the Valve-FrameRate provider. Automatically
  273. // count the frame number and frame time.
  274. void ETWSimFrameMark( bool bIsServerProcess )
  275. {
  276. Assert( bIsServerProcess == false || bIsServerProcess == true );
  277. // Record server and client frame counts separately, in case they are
  278. // in the same process.
  279. static int s_nFrameCount[2];
  280. static int64 s_lastFrameTime[2];
  281. int64 nCurrentFrameTime = GetQPCTime();
  282. float flElapsedFrameTime = 0.0f;
  283. if ( s_nFrameCount[bIsServerProcess] )
  284. {
  285. flElapsedFrameTime = QPCToMS( nCurrentFrameTime - s_lastFrameTime[bIsServerProcess] );
  286. }
  287. if ( bIsServerProcess )
  288. {
  289. EventWriteServerSimFrameMark( s_nFrameCount[bIsServerProcess], flElapsedFrameTime );
  290. }
  291. else
  292. {
  293. EventWriteSimFrameMark( s_nFrameCount[bIsServerProcess], flElapsedFrameTime );
  294. }
  295. ++s_nFrameCount[bIsServerProcess];
  296. s_lastFrameTime[bIsServerProcess] = nCurrentFrameTime;
  297. }
  298. void ETWMouseDown( int whichButton, int x, int y )
  299. {
  300. // Always have x/y first to make the summary tables easier to read.
  301. EventWriteMouse_down( x, y, whichButton );
  302. }
  303. void ETWMouseUp( int whichButton, int x, int y )
  304. {
  305. // Always have x/y first to make the summary tables easier to read.
  306. EventWriteMouse_up( x, y, whichButton );
  307. }
  308. void ETWMouseMove( int nX, int nY )
  309. {
  310. static int lastX, lastY;
  311. // Only emit mouse-move events if the mouse position has changed, since
  312. // otherwise source2 emits a continous stream of events which makes it
  313. // harder to find 'real' mouse-move events.
  314. if ( lastX != nX || lastY != nY )
  315. {
  316. lastX = nX;
  317. lastY = nY;
  318. // Always have x/y first to make the summary tables easier to read.
  319. EventWriteMouse_Move( nX, nY );
  320. }
  321. }
  322. void ETWMouseWheel( int nWheelDelta, int nX, int nY )
  323. {
  324. // Always have x/y first to make the summary tables easier to read.
  325. EventWriteMouse_Wheel( nX, nY, nWheelDelta );
  326. }
  327. void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar )
  328. {
  329. EventWriteKey_down( pChar, nScanCode, nVirtualCode );
  330. }
  331. void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck )
  332. {
  333. static int s_nCumulativeWireSize;
  334. s_nCumulativeWireSize += nWireSize;
  335. EventWriteSendPacket( pTo, nWireSize, nOutSequenceNR, nOutSequenceNrAck, s_nCumulativeWireSize );
  336. }
  337. void ETWThrottled()
  338. {
  339. EventWriteThrottled();
  340. }
  341. void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck )
  342. {
  343. static int s_nCumulativeWireSize;
  344. s_nCumulativeWireSize += nWireSize;
  345. EventWriteReadPacket( pFrom, nWireSize, nInSequenceNR, nOutSequenceNRAck, s_nCumulativeWireSize );
  346. }
  347. #endif // ETW_MARKS_ENABLED