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.

271 lines
8.0 KiB

  1. //===== Copyright 1996-2013, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifdef _WIN32
  7. #if !defined(_X360)
  8. #include "winlite.h"
  9. #endif
  10. #include "tier0/memdbgon.h" // needed because in release builds crtdbg.h is handled specially if USE_MEM_DEBUG is defined
  11. #include "tier0/memdbgoff.h"
  12. #include <crtdbg.h> // For getting at current heap size
  13. #endif
  14. #include "tier0/vprof.h"
  15. #include "tier0/etwprof.h"
  16. #include "tier0/icommandline.h"
  17. #include "tier0/systeminformation.h"
  18. #include "tier1/utlbuffer.h"
  19. #include "tier1/keyvalues.h"
  20. #include "matchmaking/imatchframework.h"
  21. #include "edict.h"
  22. #include "cdll_engine_int.h"
  23. #include "igame.h"
  24. #include "host_cmd.h"
  25. #include "status.h"
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. //-----------------------------------------------------------------------------
  29. class CKeyValuesDumpForStatusReport : public IKeyValuesDumpContextAsText
  30. {
  31. public:
  32. CKeyValuesDumpForStatusReport( CUtlBuffer &buffer ) : m_buffer( buffer ) {}
  33. public:
  34. virtual bool KvWriteText( char const *szText ) { m_buffer.Printf( "%s", szText ); return true; }
  35. protected:
  36. CUtlBuffer &m_buffer;
  37. };
  38. //-----------------------------------------------------------------------------
  39. static char g_szCombinedStatusBuffer[10240] = {0};
  40. static char g_szMinidumpInfoBuffer[4094] = {0}; // 4094 because ETW marks are limited to this.
  41. static char g_szHostStatusBuffer[1024] = {0};
  42. static char g_szMemoryStatusBuffer[1024] = {0};
  43. static char g_szMatchmakingStatusBuffer[4094] = {0}; // 4094 because ETW marks are limited to this.
  44. static char* g_szAudioStatusBuffer; // Returned by audio code
  45. extern CGlobalVars g_ServerGlobalVariables;
  46. extern int gHostSpawnCount;
  47. extern int g_nMapLoadCount;
  48. #ifdef DEDICATED
  49. PAGED_POOL_INFO_t g_pagedpoolinfo;
  50. char g_minidumpinfo[ 4094 ] = {0};
  51. #else
  52. extern PAGED_POOL_INFO_t g_pagedpoolinfo;
  53. extern char g_minidumpinfo[ 4094 ];
  54. #endif
  55. extern bool g_bUpdateMinidumpComment;
  56. static PAGED_POOL_INFO_t final;
  57. //-----------------------------------------------------------------------------
  58. static void Status_UpdateMemoryStatus( bool bIncludeFullMemoryInfo )
  59. {
  60. g_szMemoryStatusBuffer[0] = 0;
  61. CUtlBuffer buf( g_szMemoryStatusBuffer, sizeof(g_szMemoryStatusBuffer), CUtlBuffer::TEXT_BUFFER );
  62. if ( bIncludeFullMemoryInfo )
  63. {
  64. #ifdef _WIN32
  65. MEMORYSTATUSEX memStat;
  66. ZeroMemory(&memStat, sizeof(MEMORYSTATUSEX));
  67. memStat.dwLength = sizeof(MEMORYSTATUSEX);
  68. if ( GlobalMemoryStatusEx( &memStat ) )
  69. {
  70. double MbDiv = 1024.0 * 1024.0;
  71. buf.Printf( "Windows OS memory status:\nmemusage( %d %% )\ntotalPhysical Mb(%.2f)\nfreePhysical Mb(%.2f)\ntotalPaging Mb(%.2f)\nfreePaging Mb(%.2f)\ntotalVirtualMem Mb(%.2f)\nfreeVirtualMem Mb(%.2f)\nextendedVirtualFree Mb(%.2f)\n\n",
  72. memStat.dwMemoryLoad,
  73. (double)memStat.ullTotalPhys/MbDiv,
  74. (double)memStat.ullAvailPhys/MbDiv,
  75. (double)memStat.ullTotalPageFile/MbDiv,
  76. (double)memStat.ullAvailPageFile/MbDiv,
  77. (double)memStat.ullTotalVirtual/MbDiv,
  78. (double)memStat.ullAvailVirtual/MbDiv,
  79. (double)memStat.ullAvailExtendedVirtual/MbDiv);
  80. }
  81. #endif
  82. }
  83. if ( g_pMemAlloc->MemoryAllocFailed() )
  84. {
  85. buf.Printf( "*** Memory allocation failed for %d bytes! ***\n", g_pMemAlloc->MemoryAllocFailed() );
  86. }
  87. GenericMemoryStat_t *pMemoryStats = NULL;
  88. int nMemoryStatCount = g_pMemAlloc->GetGenericMemoryStats( &pMemoryStats );
  89. if ( nMemoryStatCount > 0 )
  90. {
  91. buf.Printf( "g_pMemAlloc->GetGenericMemoryStats(): %d\n", nMemoryStatCount );
  92. for ( int i = 0; i < nMemoryStatCount; i++ )
  93. {
  94. buf.Printf( "%d. %s : %d \n", i + 1, pMemoryStats[i].name, pMemoryStats[i].value );
  95. }
  96. }
  97. buf.Printf( "\n" );
  98. }
  99. static void Status_UpdateMinidumpCommentBuffer()
  100. {
  101. g_szMinidumpInfoBuffer[0] = 0;
  102. CUtlBuffer minidumpInfoBuffer( g_szMinidumpInfoBuffer, sizeof(g_szMinidumpInfoBuffer), CUtlBuffer::TEXT_BUFFER );
  103. minidumpInfoBuffer.Printf( "Uptime: %f\n", Plat_FloatTime() );
  104. if ( g_minidumpinfo[0] != 0 )
  105. {
  106. minidumpInfoBuffer.Printf( "%s", g_minidumpinfo );
  107. }
  108. minidumpInfoBuffer.Printf( "Active: %s\nSpawnCount %d\nMapLoad Count %d\n", ( game && game->IsActiveApp() ) ? "active" : "inactive", gHostSpawnCount, g_nMapLoadCount );
  109. }
  110. static CUtlBuffer *s_pStatusBuffer = NULL;
  111. static void Status_PrintCallback( const char *fmt, ... )
  112. {
  113. if ( s_pStatusBuffer )
  114. {
  115. va_list argptr;
  116. va_start (argptr,fmt);
  117. s_pStatusBuffer->VaPrintf( fmt, argptr );
  118. va_end (argptr);
  119. }
  120. }
  121. static void Status_UpdateHostStatusBuffer()
  122. {
  123. g_szHostStatusBuffer[0] = 0;
  124. CUtlBuffer hostStatusBuffer( g_szHostStatusBuffer, sizeof(g_szHostStatusBuffer), CUtlBuffer::TEXT_BUFFER );
  125. s_pStatusBuffer = &hostStatusBuffer;
  126. Host_PrintStatus( kCommandSrcCode, Status_PrintCallback, false );
  127. s_pStatusBuffer = NULL;
  128. }
  129. static void Status_UpdateMatchmakingBuffer()
  130. {
  131. // matchmaking status text
  132. g_szMatchmakingStatusBuffer[0] = 0;
  133. if ( g_pMatchFramework )
  134. {
  135. if ( IMatchSession *pMatchSession = g_pMatchFramework->GetMatchSession() )
  136. {
  137. CUtlBuffer matchmakingStatusBuffer( g_szMatchmakingStatusBuffer, sizeof(g_szMatchmakingStatusBuffer), CUtlBuffer::TEXT_BUFFER );
  138. matchmakingStatusBuffer.Printf( "match session %p\n", pMatchSession );
  139. CKeyValuesDumpForStatusReport kvDumpContext( matchmakingStatusBuffer );
  140. matchmakingStatusBuffer.Printf( "session system data:\n" );
  141. pMatchSession->GetSessionSystemData()->Dump( &kvDumpContext );
  142. matchmakingStatusBuffer.Printf( "session settings:\n" );
  143. pMatchSession->GetSessionSettings()->Dump( &kvDumpContext );
  144. }
  145. }
  146. if ( !g_szMatchmakingStatusBuffer[0] )
  147. {
  148. V_sprintf_safe( g_szMatchmakingStatusBuffer, "No matchmaking.\n" );
  149. }
  150. }
  151. static void ConvertNewlinesToTabsinPlace( char *pBuffer )
  152. {
  153. while( pBuffer && *pBuffer != 0 )
  154. {
  155. pBuffer = V_strstr(pBuffer, "\n");
  156. if ( pBuffer )
  157. {
  158. *pBuffer = '\t';
  159. }
  160. }
  161. }
  162. static void Status_UpdateBuffers( bool bForETW )
  163. {
  164. Status_UpdateMinidumpCommentBuffer();
  165. Status_UpdateMemoryStatus( !bForETW );
  166. Status_UpdateHostStatusBuffer();
  167. Status_UpdateMatchmakingBuffer();
  168. #ifndef DEDICATED
  169. extern char* Status_UpdateAudioBuffer();
  170. g_szAudioStatusBuffer = Status_UpdateAudioBuffer();
  171. #else
  172. static char chNoAudio[8] = { 'n', '/', 'a', 0 };
  173. g_szAudioStatusBuffer = chNoAudio;
  174. #endif
  175. if ( bForETW )
  176. {
  177. // walk through buffers converting \n to \t
  178. ConvertNewlinesToTabsinPlace( g_szMinidumpInfoBuffer );
  179. ConvertNewlinesToTabsinPlace( g_szMemoryStatusBuffer );
  180. ConvertNewlinesToTabsinPlace( g_szHostStatusBuffer );
  181. ConvertNewlinesToTabsinPlace( g_szMatchmakingStatusBuffer );
  182. ConvertNewlinesToTabsinPlace( g_szAudioStatusBuffer );
  183. }
  184. }
  185. static void Status_UpdateCombinedBuffer()
  186. {
  187. Status_UpdateBuffers( false );
  188. g_szCombinedStatusBuffer[0] = 0;
  189. CUtlBuffer combinedStatusBuffer( g_szCombinedStatusBuffer, sizeof(g_szCombinedStatusBuffer), CUtlBuffer::TEXT_BUFFER );
  190. combinedStatusBuffer.Printf( "\nGame Info:\n%s", g_szMinidumpInfoBuffer );
  191. combinedStatusBuffer.Printf( "\nMemory Info:\n%s", g_szMemoryStatusBuffer );
  192. combinedStatusBuffer.Printf( "\nHost Info:\n%s", g_szHostStatusBuffer );
  193. combinedStatusBuffer.Printf( "\nMatchmaking Info:\n%s", g_szMatchmakingStatusBuffer );
  194. combinedStatusBuffer.Printf( "\nAudio Info:\n%s", g_szAudioStatusBuffer );
  195. }
  196. // public functions
  197. const char *Status_GetBuffer()
  198. {
  199. return g_szCombinedStatusBuffer;
  200. }
  201. void Status_Update()
  202. {
  203. Status_UpdateCombinedBuffer();
  204. }
  205. void Status_CheckSendETWMark()
  206. {
  207. // If ETW (Event Tracing for Windows) is available,
  208. // collect status text every 5 seconds
  209. #ifdef ETW_MARKS_ENABLED
  210. // Don't emit status events if nobody is listening.
  211. if ( ETWIsTracingEnabled() )
  212. {
  213. static double fLastETWUpdateTime = -5.0;
  214. double fCurrentTime = Plat_FloatTime();
  215. // update status buffer every 5 seconds and write to vtrace/xperf mark
  216. if ( fCurrentTime - fLastETWUpdateTime > 5.0 )
  217. {
  218. fLastETWUpdateTime = fCurrentTime;
  219. Status_UpdateBuffers( true );
  220. ETWMark( g_szMinidumpInfoBuffer );
  221. ETWMark( g_szMemoryStatusBuffer );
  222. ETWMark( g_szHostStatusBuffer );
  223. ETWMark( g_szMatchmakingStatusBuffer );
  224. ETWMark( g_szAudioStatusBuffer );
  225. }
  226. }
  227. #endif
  228. }