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.

357 lines
8.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "filesystem_engine.h"
  8. #include "filesystem.h"
  9. #include "dt_instrumentation_server.h"
  10. #include "dt_send.h"
  11. #include "tier1/utlstring.h"
  12. #include "utllinkedlist.h"
  13. #include "dt.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. #define DELTA_DISTANCE_BAND 200
  17. #define NUM_DELTA_DISTANCE_BANDS (8000/DELTA_DISTANCE_BAND)
  18. // Data we track per SendTable on the server.
  19. class CDTISendTable
  20. {
  21. public:
  22. // Which SendTable we're interested in.
  23. CUtlString m_NetTableName;
  24. // How many cycles we've spent in certain calls.
  25. CCycleCount m_nCalcDeltaCycles;
  26. int m_nCalcDeltaCalls;
  27. CCycleCount m_nEncodeCycles;
  28. int m_nEncodeCalls;
  29. CCycleCount m_nShouldTransmitCycles;
  30. int m_nShouldTransmitCalls;
  31. CCycleCount m_nWriteDeltaPropsCycles;
  32. // Used to determine how much the class uses manual mode.
  33. int m_nChangeAutoDetects;
  34. int m_nNoChanges;
  35. // Set to false if no events were recorded for this class.
  36. bool HadAnyAction() const { return m_nCalcDeltaCalls || m_nEncodeCalls || m_nShouldTransmitCalls; }
  37. // This tracks how many times an entity was delta'd for each distance from a client.
  38. unsigned short m_DistanceDeltaCounts[NUM_DELTA_DISTANCE_BANDS];
  39. };
  40. static CCycleCount g_TotalServerDTICycles;
  41. static CUtlLinkedList<CDTISendTable*, unsigned short> g_DTISendTables;
  42. bool g_bServerDTIEnabled = false;
  43. static char const *g_pServerDTIFilename = 0;
  44. static bool g_bFirstHookTimer = true;
  45. static CCycleCount g_ServerDTITimer;
  46. void ServerDTI_Init( char const *pFilename )
  47. {
  48. g_pServerDTIFilename = pFilename;
  49. g_bServerDTIEnabled = true;
  50. g_TotalServerDTICycles.Init();
  51. g_bFirstHookTimer = true;
  52. }
  53. void ServerDTI_Term()
  54. {
  55. if ( !g_pServerDTIFilename )
  56. return;
  57. ServerDTI_Flush();
  58. g_DTISendTables.PurgeAndDeleteElements();
  59. g_pServerDTIFilename = 0;
  60. g_bServerDTIEnabled = false;
  61. }
  62. void ServerDTI_Flush()
  63. {
  64. if ( !g_pServerDTIFilename )
  65. return;
  66. CCycleCount curTime;
  67. curTime.Sample();
  68. CCycleCount runningTime;
  69. CCycleCount::Sub( curTime, g_ServerDTITimer, runningTime );
  70. // Write out a file that can be used by Excel.
  71. FileHandle_t fp = g_pFileSystem->Open( g_pServerDTIFilename, "wt", "LOGDIR" );
  72. if( fp != FILESYSTEM_INVALID_HANDLE )
  73. {
  74. // Write the header.
  75. g_pFileSystem->FPrintf( fp,
  76. "DTName"
  77. "\tCalcDelta calls"
  78. "\tCalcDelta ms"
  79. "\tEncode calls"
  80. "\tEncode ms"
  81. "\tShouldTransmit calls"
  82. "\tShouldTransmit ms"
  83. "\tWriteDeltaProps ms"
  84. "\t%% manual mode"
  85. "\tTotal"
  86. "\tPercent"
  87. "\n"
  88. );
  89. // Calculate totals.
  90. CCycleCount totalCalcDelta, totalEncode, totalShouldTransmit, totalDeltaProps;
  91. totalCalcDelta.Init();
  92. totalEncode.Init();
  93. totalShouldTransmit.Init();
  94. FOR_EACH_LL( g_DTISendTables, i )
  95. {
  96. CDTISendTable *pTable = g_DTISendTables[i];
  97. CCycleCount::Add( pTable->m_nCalcDeltaCycles, totalCalcDelta, totalCalcDelta );
  98. CCycleCount::Add( pTable->m_nEncodeCycles, totalEncode, totalEncode );
  99. CCycleCount::Add( pTable->m_nShouldTransmitCycles, totalShouldTransmit, totalShouldTransmit );
  100. CCycleCount::Add( pTable->m_nWriteDeltaPropsCycles, totalDeltaProps, totalDeltaProps );
  101. }
  102. FOR_EACH_LL( g_DTISendTables, j )
  103. {
  104. CDTISendTable *pTable = g_DTISendTables[j];
  105. if ( !pTable->HadAnyAction() )
  106. continue;
  107. CCycleCount total;
  108. CCycleCount::Add( pTable->m_nEncodeCycles, pTable->m_nCalcDeltaCycles, total );
  109. CCycleCount::Add( pTable->m_nShouldTransmitCycles, total, total );
  110. g_pFileSystem->FPrintf( fp,
  111. "%s"
  112. "\t%d"
  113. "\t%.3f"
  114. "\t%d"
  115. "\t%.3f"
  116. "\t%d"
  117. "\t%.3f"
  118. "\t%.3f"
  119. "\t%.2f"
  120. "\t%.3f"
  121. "\t%.3f"
  122. "\n",
  123. pTable->m_NetTableName.String(),
  124. pTable->m_nCalcDeltaCalls,
  125. pTable->m_nCalcDeltaCycles.GetMillisecondsF(),
  126. pTable->m_nEncodeCalls,
  127. pTable->m_nEncodeCycles.GetMillisecondsF(),
  128. pTable->m_nShouldTransmitCalls,
  129. pTable->m_nShouldTransmitCycles.GetMillisecondsF(),
  130. pTable->m_nWriteDeltaPropsCycles.GetMillisecondsF(),
  131. (float)pTable->m_nNoChanges * 100.0f / (pTable->m_nNoChanges + pTable->m_nChangeAutoDetects),
  132. total.GetMillisecondsF(),
  133. total.GetMillisecondsF() * 100 / runningTime.GetMillisecondsF()
  134. );
  135. }
  136. g_pFileSystem->FPrintf( fp, "\n\n" );
  137. g_pFileSystem->FPrintf( fp,
  138. "Total profile ms:"
  139. "\t%.3f\n",
  140. runningTime.GetMillisecondsF()
  141. );
  142. g_pFileSystem->FPrintf( fp,
  143. "Total CalcDelta ms:"
  144. "\t%.3f"
  145. "\tPercent:"
  146. "\t%.3f\n",
  147. totalCalcDelta.GetMillisecondsF(),
  148. totalCalcDelta.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF()
  149. );
  150. g_pFileSystem->FPrintf( fp,
  151. "Total Encode ms:"
  152. "\t%.3f"
  153. "\tPercent:"
  154. "\t%.3f\n",
  155. totalEncode.GetMillisecondsF(),
  156. totalEncode.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF()
  157. );
  158. g_pFileSystem->FPrintf( fp,
  159. "Total ShouldTransmit ms:"
  160. "\t%.3f"
  161. "\tPercent:"
  162. "\t%.3f\n",
  163. totalShouldTransmit.GetMillisecondsF(),
  164. totalShouldTransmit.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF()
  165. );
  166. g_pFileSystem->FPrintf( fp,
  167. "Total WriteDeltaProps ms:"
  168. "\t%.3f"
  169. "\tPercent:"
  170. "\t%.3f\n",
  171. totalDeltaProps.GetMillisecondsF(),
  172. totalDeltaProps.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF()
  173. );
  174. g_pFileSystem->Close( fp );
  175. Msg( "DTI: Wrote delta distances into %s.\n", g_pServerDTIFilename );
  176. }
  177. // Write the delta distances.
  178. const char *pDeltaDistancesFilename = "dti_delta_distances.txt";
  179. fp = g_pFileSystem->Open( pDeltaDistancesFilename, "wt", "LOGDIR" );
  180. if( fp != FILESYSTEM_INVALID_HANDLE )
  181. {
  182. // Write the column labels.
  183. g_pFileSystem->FPrintf( fp, "ClassName" );
  184. for ( int i=0; i < NUM_DELTA_DISTANCE_BANDS; i++ )
  185. {
  186. g_pFileSystem->FPrintf( fp, "\t<%d", (i+1) * DELTA_DISTANCE_BAND );
  187. }
  188. g_pFileSystem->FPrintf( fp, "\n" );
  189. // Now write the data.
  190. FOR_EACH_LL( g_DTISendTables, j )
  191. {
  192. CDTISendTable *pTable = g_DTISendTables[j];
  193. if ( !pTable->HadAnyAction() )
  194. continue;
  195. g_pFileSystem->FPrintf( fp, "%s", pTable->m_NetTableName.String() );
  196. for ( int i=0; i < NUM_DELTA_DISTANCE_BANDS; i++ )
  197. {
  198. g_pFileSystem->FPrintf( fp, "\t%d", pTable->m_DistanceDeltaCounts[i] );
  199. }
  200. g_pFileSystem->FPrintf( fp, "\n" );
  201. }
  202. g_pFileSystem->Close( fp );
  203. Msg( "DTI: Wrote instrumentation data into %s.\n", pDeltaDistancesFilename );
  204. }
  205. }
  206. CDTISendTable* ServerDTI_HookTable( SendTable *pTable )
  207. {
  208. if ( !g_bServerDTIEnabled )
  209. return NULL;
  210. CDTISendTable *pRet = new CDTISendTable;
  211. memset( pRet, 0, sizeof( *pRet ) );
  212. pRet->m_NetTableName.Set( pTable->m_pNetTableName );
  213. g_DTISendTables.AddToTail( pRet );
  214. return pRet;
  215. }
  216. void ServerDTI_AddEntityEncodeEvent( SendTable *pSendTable, float distToPlayer )
  217. {
  218. CSendTablePrecalc *pPrecalc = pSendTable->m_pPrecalc;
  219. if ( !pPrecalc || !pPrecalc->m_pDTITable )
  220. return;
  221. CDTISendTable *pTable = pPrecalc->m_pDTITable;
  222. if ( !pTable )
  223. return;
  224. int iDist = (int)( distToPlayer / DELTA_DISTANCE_BAND );
  225. iDist = clamp( iDist, 0, NUM_DELTA_DISTANCE_BANDS - 1 );
  226. pTable->m_DistanceDeltaCounts[iDist]++;
  227. }
  228. void _ServerDTI_HookTimer( const SendTable *pSendTable, ServerDTITimerType timerType, CCycleCount const &count )
  229. {
  230. CSendTablePrecalc *pPrecalc = pSendTable->m_pPrecalc;
  231. if ( !pPrecalc || !pPrecalc->m_pDTITable )
  232. return;
  233. CDTISendTable *pTable = pPrecalc->m_pDTITable;
  234. if ( g_bFirstHookTimer )
  235. {
  236. g_ServerDTITimer.Sample();
  237. g_bFirstHookTimer = false;
  238. }
  239. // Add to the total cycles.
  240. CCycleCount::Add( count, g_TotalServerDTICycles, g_TotalServerDTICycles );
  241. if ( timerType == SERVERDTI_CALCDELTA )
  242. {
  243. CCycleCount::Add( count, pTable->m_nCalcDeltaCycles, pTable->m_nCalcDeltaCycles );
  244. ++pTable->m_nCalcDeltaCalls;
  245. }
  246. else if ( timerType == SERVERDTI_ENCODE )
  247. {
  248. CCycleCount::Add( count, pTable->m_nEncodeCycles, pTable->m_nEncodeCycles );
  249. ++pTable->m_nEncodeCalls;
  250. }
  251. else if ( timerType == SERVERDTI_SHOULDTRANSMIT )
  252. {
  253. CCycleCount::Add( count, pTable->m_nShouldTransmitCycles, pTable->m_nShouldTransmitCycles );
  254. ++pTable->m_nShouldTransmitCalls;
  255. }
  256. else if ( timerType == SERVERDTI_WRITE_DELTA_PROPS )
  257. {
  258. CCycleCount::Add( count, pTable->m_nWriteDeltaPropsCycles, pTable->m_nWriteDeltaPropsCycles );
  259. }
  260. }
  261. void _ServerDTI_RegisterNetworkStateChange( SendTable *pSendTable, bool bStateChanged )
  262. {
  263. CSendTablePrecalc *pPrecalc = pSendTable->m_pPrecalc;
  264. if ( !pPrecalc || !pPrecalc->m_pDTITable )
  265. return;
  266. CDTISendTable *pTable = pPrecalc->m_pDTITable;
  267. if ( bStateChanged )
  268. ++pTable->m_nChangeAutoDetects;
  269. else
  270. ++pTable->m_nNoChanges;
  271. }