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.

673 lines
24 KiB

  1. //====== Copyright , Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Provides names for GC message types
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. // memdbgon must be the last include file in a .cpp file!!!
  8. #include "tier0/memdbgon.h"
  9. namespace GCSDK
  10. {
  11. //-----------------------------------------------------------------------------
  12. // Purpose: allow global initializers for a list of message infos. The message
  13. // list will assemble them all into a single list when it initializes.
  14. //-----------------------------------------------------------------------------
  15. class CMessageListRegistration
  16. {
  17. public:
  18. CMessageListRegistration( MsgInfo_t *pMsgInfo, int cMsgInfo, void *pExtra = NULL );
  19. static CMessageListRegistration *sm_pFirst;
  20. CMessageListRegistration *m_pNext;
  21. MsgInfo_t *m_pMsgInfo;
  22. int m_cMsgInfo;
  23. };
  24. DECLARE_GC_EMIT_GROUP( g_EGMessages, messages );
  25. //function called when a message is tallied but not registered properly. Used to help consolidate behavior for untracked messages
  26. static void HandleUntrackedMsg( const char* pszMsgOperation, uint32 nMsgID )
  27. {
  28. //for now output this as verbose so that we can clean up the initial spam. Then promote this to warnings in the future
  29. EG_VERBOSE( g_EGMessages, "Found %s message with ID %d that was not properly registered. Unable to tally information\n", pszMsgOperation, nMsgID );
  30. }
  31. CMessageListRegistration::CMessageListRegistration( MsgInfo_t *pMsgInfo, int cMsgInfo, void *pExtra )
  32. : m_pMsgInfo( pMsgInfo ),
  33. m_cMsgInfo( cMsgInfo )
  34. {
  35. m_pNext = sm_pFirst;
  36. sm_pFirst = this;
  37. }
  38. CMessageListRegistration *CMessageListRegistration::sm_pFirst = NULL;
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Returns the name of a message type
  41. //-----------------------------------------------------------------------------
  42. const char *PchMsgNameFromEMsg( MsgType_t eMsg )
  43. {
  44. const char *pchMsgName = k_rgchUnknown;
  45. g_theMessageList.GetMessage( eMsg, &pchMsgName, MT_GC );
  46. return pchMsgName;
  47. }
  48. //-----------------------------------------------------------------------------
  49. void MsgRegistrationFromEnumDescriptor( const ::google::protobuf::EnumDescriptor *pEnumDescriptor, int nTypeMask )
  50. {
  51. // build the struct list for messages
  52. MsgInfo_t *pMsgInfos = new MsgInfo_t[ pEnumDescriptor->value_count() ];
  53. memset( pMsgInfos, 0, sizeof( MsgInfo_t ) * pEnumDescriptor->value_count() );
  54. for ( int i = 0; i < pEnumDescriptor->value_count(); ++i )
  55. {
  56. const ::google::protobuf::EnumValueDescriptor *pEnumValueDescriptor = pEnumDescriptor->value(i);
  57. pMsgInfos[ i ].eMsg = pEnumValueDescriptor->number();
  58. pMsgInfos[ i ].pchMsgName = pEnumValueDescriptor->name().c_str();
  59. pMsgInfos[ i ].nFlags = nTypeMask;
  60. }
  61. new CMessageListRegistration( pMsgInfos, pEnumDescriptor->value_count() );
  62. }
  63. //-----------------------------------------------------------------------------
  64. CMessageList g_theMessageList;
  65. //-----------------------------------------------------------------------------
  66. // CMessageList
  67. //
  68. // builds a hash of the MsgInfo_t table so that information about messages
  69. // can be found without searching.
  70. //-----------------------------------------------------------------------------
  71. CMessageList::CMessageList( ) : m_bProfiling( false ), m_ulProfileMicrosecs( 0 )
  72. {
  73. }
  74. //-----------------------------------------------------------------------------
  75. // CMessageList
  76. //
  77. // builds a hash of the MsgInfo_t table so that information about messages
  78. // can be found without searching.
  79. //-----------------------------------------------------------------------------
  80. bool CMessageList::BInit( )
  81. {
  82. m_bProfiling = false;
  83. m_ulProfileMicrosecs = 0;
  84. // figure out our message count
  85. int cMessageInfos = 0;
  86. for( CMessageListRegistration *pReg = CMessageListRegistration::sm_pFirst; pReg != NULL; pReg = pReg->m_pNext)
  87. {
  88. cMessageInfos += pReg->m_cMsgInfo;
  89. }
  90. // message indexes should fit in a short
  91. Assert( cMessageInfos < SHRT_MAX );
  92. m_vecMsgInfo.EnsureCapacity( cMessageInfos );
  93. m_vecMsgInfo.RemoveAll();
  94. m_vecMessageInfoBuckets.RemoveAll();
  95. int nIndex = 0;
  96. for( CMessageListRegistration *pReg = CMessageListRegistration::sm_pFirst; pReg != NULL; pReg = pReg->m_pNext)
  97. {
  98. for ( int nRegIndex = 0; nRegIndex < pReg->m_cMsgInfo; nRegIndex++ )
  99. {
  100. nIndex = m_vecMsgInfo.AddToTail( pReg->m_pMsgInfo[nRegIndex] );
  101. int nSlot;
  102. int nBucket = HashMessage( pReg->m_pMsgInfo[nRegIndex].eMsg, nSlot );
  103. AssureBucket( nBucket );
  104. if ( m_vecMessageInfoBuckets[nBucket][nSlot] != -1 )
  105. {
  106. int otherIndex = m_vecMessageInfoBuckets[nBucket][nSlot];
  107. MsgInfo_t &otherMsg = m_vecMsgInfo[ otherIndex ];
  108. AssertFatalMsg2( false, "Message collision: %s redefined as %s",
  109. otherMsg.pchMsgName,
  110. pReg->m_pMsgInfo[nRegIndex].pchMsgName);
  111. }
  112. else
  113. {
  114. m_vecMessageInfoBuckets[nBucket][nSlot] = (short) nIndex;
  115. }
  116. }
  117. }
  118. //start our window
  119. ResetWindow();
  120. //and start our global timer
  121. m_sCollectTime[ MsgInfo_t::k_EStatsGroupGlobal ].SetToJobTime();
  122. return true;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Tally the sending of a message
  126. //-----------------------------------------------------------------------------
  127. void CMessageList::TallySendMessage( MsgType_t eMsgType, uint32 unMsgSize, uint32 nSourceMask )
  128. {
  129. short nIndex = GetMessageIndex( eMsgType );
  130. if ( nIndex == - 1 )
  131. {
  132. HandleUntrackedMsg( "send", eMsgType );
  133. return;
  134. }
  135. TallyMessageInternal( m_vecMsgInfo[nIndex],MsgInfo_t::k_EStatsTypeSent, unMsgSize, nSourceMask );
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Tally the receiving of a message
  139. //-----------------------------------------------------------------------------
  140. void CMessageList::TallyReceiveMessage( MsgType_t eMsgType, uint32 unMsgSize, uint32 nSourceMask )
  141. {
  142. short nIndex = GetMessageIndex( eMsgType );
  143. if ( nIndex == - 1 )
  144. {
  145. HandleUntrackedMsg( "receive", eMsgType );
  146. return;
  147. }
  148. TallyMessageInternal( m_vecMsgInfo[nIndex], MsgInfo_t::k_EStatsTypeReceived, unMsgSize, nSourceMask );
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Tally the receiving of a message
  152. //-----------------------------------------------------------------------------
  153. void CMessageList::TallyMultiplexedMessage( MsgType_t eMsgType, uint32 uSent, uint32 cRecipients, uint32 uMsgSize, uint32 nSourceMask )
  154. {
  155. short nIndex = GetMessageIndex( eMsgType );
  156. if ( nIndex == - 1 )
  157. {
  158. HandleUntrackedMsg( "multiplex", eMsgType );
  159. return;
  160. }
  161. MsgInfo_t &msgInfo = m_vecMsgInfo[nIndex];
  162. TallyMessageInternal( msgInfo, MsgInfo_t::k_EStatsTypeMultiplexedSends, uSent, nSourceMask, 1 );
  163. TallyMessageInternal( msgInfo, MsgInfo_t::k_EStatsTypeMultiplexedSendsRaw, uMsgSize * cRecipients, nSourceMask, cRecipients );
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Tally the receiving of a message
  167. //-----------------------------------------------------------------------------
  168. void CMessageList::TallyMessageInternal( MsgInfo_t &msgInfo, MsgInfo_t::EStatsType eBucket, uint32 unMsgSize, uint32 nSourceMask, uint32 cMessages )
  169. {
  170. //log this for global stats
  171. msgInfo.stats[ MsgInfo_t::k_EStatsGroupGlobal ][ eBucket ].nCount += cMessages;
  172. msgInfo.stats[ MsgInfo_t::k_EStatsGroupGlobal ][ eBucket ].uBytes += unMsgSize;
  173. msgInfo.stats[ MsgInfo_t::k_EStatsGroupGlobal ][ eBucket ].nSourceMask |= nSourceMask;
  174. //track this in our current timing window
  175. msgInfo.stats[ MsgInfo_t::k_EStatsGroupWindow ][ eBucket ].nCount += cMessages;
  176. msgInfo.stats[ MsgInfo_t::k_EStatsGroupWindow ][ eBucket ].uBytes += unMsgSize;
  177. msgInfo.stats[ MsgInfo_t::k_EStatsGroupWindow ][ eBucket ].nSourceMask |= nSourceMask;
  178. //track our window totals as well
  179. m_WindowTotals[ eBucket ].nCount += cMessages;
  180. m_WindowTotals[ eBucket ].uBytes += unMsgSize;
  181. m_WindowTotals[ eBucket ].nSourceMask |= nSourceMask;
  182. //and if we are profiling, track the data into our profiling window
  183. if ( m_bProfiling )
  184. {
  185. msgInfo.stats[ MsgInfo_t::k_EStatsGroupProfile ][ eBucket ].nCount += cMessages;
  186. msgInfo.stats[ MsgInfo_t::k_EStatsGroupProfile ][ eBucket ].uBytes += unMsgSize;
  187. msgInfo.stats[ MsgInfo_t::k_EStatsGroupProfile ][ eBucket ].nSourceMask |= nSourceMask;
  188. }
  189. }
  190. //called to obtain the totals for the timing window
  191. const MsgInfo_t::Stats_t& CMessageList::GetWindowTotal( MsgInfo_t::EStatsType eType ) const
  192. {
  193. return m_WindowTotals[ eType ];
  194. }
  195. //called to reset the window timings
  196. void CMessageList::ResetWindow()
  197. {
  198. //reset when our window started
  199. m_sCollectTime[ MsgInfo_t::k_EStatsGroupWindow ].SetToJobTime();
  200. // starting a new window... clear everything
  201. FOR_EACH_VEC( m_vecMsgInfo, nIndex )
  202. {
  203. for( uint32 nType = 0; nType < MsgInfo_t::k_EStatsType_Count; nType++ )
  204. {
  205. m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupWindow ][ nType ].nCount = 0;
  206. m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupWindow ][ nType ].uBytes = 0;
  207. m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupWindow ][ nType ].nSourceMask = 0;
  208. }
  209. }
  210. //and clear our totals
  211. for( uint32 nType = 0; nType < MsgInfo_t::k_EStatsType_Count; nType++ )
  212. {
  213. m_WindowTotals[ nType ].nCount = 0;
  214. m_WindowTotals[ nType ].uBytes = 0;
  215. }
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Turns snapshot profiling on and off
  219. //-----------------------------------------------------------------------------
  220. void CMessageList::EnableProfiling( bool bEnableProfiling )
  221. {
  222. m_bProfiling = bEnableProfiling;
  223. if ( m_bProfiling )
  224. {
  225. m_sCollectTime[ MsgInfo_t::k_EStatsGroupProfile ].SetToJobTime();
  226. // starting a new profile... clear everything
  227. FOR_EACH_VEC( m_vecMsgInfo, nIndex )
  228. {
  229. for( uint32 nType = 0; nType < MsgInfo_t::k_EStatsType_Count; nType++ )
  230. {
  231. m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupProfile ][ nType ].nCount = 0;
  232. m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupProfile ][ nType ].uBytes = 0;
  233. m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupProfile ][ nType ].nSourceMask = 0;
  234. }
  235. }
  236. }
  237. else
  238. {
  239. m_ulProfileMicrosecs = m_sCollectTime[ MsgInfo_t::k_EStatsGroupProfile ].CServerMicroSecsPassed();
  240. }
  241. }
  242. uint64 CMessageList::GetGroupDuration( MsgInfo_t::EStatsGroup eGroup ) const
  243. {
  244. //handle the special case of it being a profile, where if we are no longer profiling, we want to use our cached value
  245. if( ( eGroup == MsgInfo_t::k_EStatsGroupProfile ) && !m_bProfiling )
  246. {
  247. return m_ulProfileMicrosecs;
  248. }
  249. //otherwise we can just use the timer directly
  250. return m_sCollectTime[ eGroup ].CServerMicroSecsPassed();
  251. }
  252. //-----------------------------------------------------------------------------
  253. // print statistics bout each message we handle
  254. //-----------------------------------------------------------------------------
  255. void CMessageList::PrintStats( bool bShowAll, bool bSortByFrequency, MsgInfo_t::EStatsGroup eGroup, MsgInfo_t::EStatsType eType, uint32 nSourceMask ) const
  256. {
  257. // Figure out which time value we should use for rate calcs
  258. uint64 ulMicroseconds = GetGroupDuration( eGroup );
  259. // work out a sorted list
  260. CUtlMap<uint64, uint32> mapValueToMsg( DefLessFunc( uint64 ) );
  261. uint64 unTotalBytes = 0;
  262. uint32 unTotalMessages = 0;
  263. FOR_EACH_VEC( m_vecMsgInfo, n )
  264. {
  265. //see if we are looking for a particular source, and if so, if this has that source set
  266. if( nSourceMask && ( ( m_vecMsgInfo[n].stats[ eGroup ][ eType ].nSourceMask & nSourceMask ) == 0 ) )
  267. continue;
  268. uint32 nCount = m_vecMsgInfo[n].stats[ eGroup ][ eType ].nCount;
  269. uint64 uBytes = m_vecMsgInfo[n].stats[ eGroup ][ eType ].uBytes;
  270. unTotalMessages += nCount;
  271. unTotalBytes += uBytes;
  272. if ( nCount == 0 && !bShowAll )
  273. continue;
  274. mapValueToMsg.Insert( bSortByFrequency ? (uint64)nCount : uBytes, n );
  275. }
  276. double fSeconds = ulMicroseconds / ( 1000.0 * 1000.0 );
  277. // 5, 46, 10, 6, 14, 6, 10, 10
  278. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "EMsg MessageName Count % Bytes % MsgPS Avg/Msg KBPS\n" );
  279. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "----- ---------------------------------------------- ---------- ------ -------------- ------ --------- ---------- ----------\n" );
  280. for ( uint16 iValue = mapValueToMsg.LastInorder(); iValue != mapValueToMsg.InvalidIndex(); iValue = mapValueToMsg.PrevInorder( iValue ) )
  281. {
  282. uint32 n = mapValueToMsg[iValue];
  283. //see if we are looking for a particular source, and if so, if this has that source set
  284. if( nSourceMask && ( ( m_vecMsgInfo[n].stats[ eGroup ][ eType ].nSourceMask & nSourceMask ) == 0 ) )
  285. continue;
  286. uint32 nCount = m_vecMsgInfo[n].stats[ eGroup ][ eType].nCount;
  287. uint64 uBytes = m_vecMsgInfo[n].stats[ eGroup ][ eType].uBytes;
  288. uint32 uAvgMsg = 0;
  289. if ( nCount > 0 )
  290. uAvgMsg = uBytes / nCount;
  291. float flCountPerc = 0;
  292. if ( unTotalMessages > 0 )
  293. flCountPerc = nCount * 100.0f / unTotalMessages;
  294. float flBytesPerc = 0;
  295. if ( unTotalBytes > 0 )
  296. flBytesPerc = uBytes * 100.0f / unTotalBytes;
  297. double fMsgPS = 0.0;
  298. if ( ulMicroseconds > 0 )
  299. fMsgPS = nCount / fSeconds;
  300. double fKBPS = 0.0f;
  301. if ( ulMicroseconds > 0 )
  302. fKBPS = uBytes / ( fSeconds * 1000.0 );
  303. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%5u %-46s %10u %5.1f%% %14llu %5.1f%% %9.1f %10u %10.2f\n",
  304. m_vecMsgInfo[n].eMsg,
  305. m_vecMsgInfo[n].pchMsgName,
  306. nCount,
  307. flCountPerc,
  308. uBytes,
  309. flBytesPerc,
  310. fMsgPS,
  311. uAvgMsg,
  312. fKBPS );
  313. }
  314. uint32 uAvgMsgTotal = 0;
  315. if ( unTotalMessages > 0 )
  316. uAvgMsgTotal = unTotalBytes / unTotalMessages;
  317. double fMsgPS = 0.0;
  318. if ( ulMicroseconds > 0 )
  319. fMsgPS = unTotalMessages / fSeconds;
  320. double fKBPSTotal = 0.0;
  321. if ( ulMicroseconds > 0 )
  322. fKBPSTotal = unTotalBytes / ( fSeconds * 1000.0 );
  323. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "----- ---------------------------------------------- ---------- ------ -------------- ------ --------- ---------- ----------\n" );
  324. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "Totals %10u 100.0%% %14llu 100.0%% %9.1f %10u %10.2f\n",
  325. unTotalMessages,
  326. unTotalBytes,
  327. fMsgPS,
  328. uAvgMsgTotal,
  329. fKBPSTotal );
  330. }
  331. //-----------------------------------------------------------------------------
  332. // print statistics bout each message we handle
  333. //-----------------------------------------------------------------------------
  334. void CMessageList::PrintMultiplexStats( MsgInfo_t::EStatsGroup eGroup, bool bSortByFrequency, uint32 nSourceMask ) const
  335. {
  336. // Figure out which time value we should use for rate calcs
  337. uint64 ulMicroseconds = GetGroupDuration( eGroup );
  338. MsgInfo_t::Stats_t rgTotals[MsgInfo_t::k_EStatsType_Count];
  339. const MsgInfo_t::EStatsType eMultiType = MsgInfo_t::k_EStatsTypeMultiplexedSends;
  340. const MsgInfo_t::EStatsType eRawType = MsgInfo_t::k_EStatsTypeMultiplexedSendsRaw;
  341. // work out a sorted list
  342. CUtlMap<uint64, uint32> mapValueToMsg( DefLessFunc( uint64 ) );
  343. FOR_EACH_VEC( m_vecMsgInfo, n )
  344. {
  345. const MsgInfo_t &msgInfo = m_vecMsgInfo[n];
  346. //see if we are looking for a particular source, and if so, if this has that source set
  347. if( nSourceMask && ( msgInfo.stats[ eGroup ][ eMultiType ].nSourceMask & nSourceMask ) == 0 )
  348. continue;
  349. rgTotals[eMultiType].nCount += msgInfo.stats[ eGroup ][ eMultiType ].nCount;
  350. rgTotals[eMultiType].uBytes += msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
  351. rgTotals[eRawType].nCount += msgInfo.stats[ eGroup ][ eRawType ].nCount;
  352. rgTotals[eRawType].uBytes += msgInfo.stats[ eGroup ][ eRawType ].uBytes;
  353. if ( msgInfo.stats[ eGroup ][ eMultiType ].nCount == 0 )
  354. continue;
  355. uint32 nCount = msgInfo.stats[ eGroup ][ eMultiType ].nCount;
  356. uint64 uBytes = msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
  357. mapValueToMsg.Insert( bSortByFrequency ? (uint64)nCount : uBytes, n );
  358. }
  359. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "EMsg MessageName Count % KB % Avg/Msg KBPS Msg Saved % KB Saved %\n" );
  360. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "----- ---------------------------------------------- ---------- ------ -------------- ------ ---------- ---------- ---------- ------ -------------- ------\n" );
  361. uint32 unTotalMessages = 0;
  362. uint64 unTotalBytes = 0;
  363. for ( uint16 iValue = mapValueToMsg.LastInorder(); iValue != mapValueToMsg.InvalidIndex(); iValue = mapValueToMsg.PrevInorder( iValue ) )
  364. {
  365. const MsgInfo_t &msgInfo = m_vecMsgInfo[ mapValueToMsg[iValue] ];
  366. //see if we are looking for a particular source, and if so, if this has that source set
  367. if( nSourceMask && ( msgInfo.stats[ eGroup ][ eMultiType ].nSourceMask & nSourceMask ) == 0 )
  368. continue;
  369. uint32 nCount = msgInfo.stats[ eGroup ][ eMultiType ].nCount;
  370. uint64 uBytes = msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
  371. unTotalMessages += nCount;
  372. unTotalBytes += uBytes;
  373. int32 nMessagesSaved = msgInfo.stats[ eGroup ][ eRawType ].nCount - msgInfo.stats[ eGroup ][ eMultiType ].nCount;
  374. int64 uBytesSaved = msgInfo.stats[ eGroup ][ eRawType ].uBytes - msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
  375. uint32 nMessagesIfNotMultiplex = msgInfo.stats[ eGroup ][ eRawType ].nCount;
  376. uint64 uBytesIfNotMultiplex = msgInfo.stats[ eGroup ][ eRawType ].uBytes;
  377. uint32 uAvgMsg = 0;
  378. if ( nCount > 0 )
  379. uAvgMsg = uBytes / nCount;
  380. float flCountPerc = 0;
  381. if ( rgTotals[eMultiType].nCount > 0 )
  382. flCountPerc = nCount * 100.0f / rgTotals[eMultiType].nCount;
  383. float flBytesPerc = 0;
  384. if ( rgTotals[eMultiType].uBytes > 0 )
  385. flBytesPerc = uBytes * 100.0f / rgTotals[eMultiType].uBytes;
  386. float fKBPS = 0.0f;
  387. if ( ulMicroseconds > 0 )
  388. fKBPS = uBytes * 1000.0f / ulMicroseconds;
  389. float flMessagesSavedPerc = 0.0f;
  390. if ( nMessagesIfNotMultiplex > 0 )
  391. flMessagesSavedPerc = nMessagesSaved * 100.0f / nMessagesIfNotMultiplex;
  392. float flBytesSavedPerc = 0.0f;
  393. if ( uBytesIfNotMultiplex > 0 )
  394. flBytesSavedPerc = uBytesSaved * 100.0f / uBytesIfNotMultiplex;
  395. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%5u %-46s %10u %5.1f%% %14llu %5.1f%% %10u %10.2f %10d %5.1f%% %14lld %5.1f%%\n",
  396. msgInfo.eMsg,
  397. msgInfo.pchMsgName,
  398. nCount,
  399. flCountPerc,
  400. uBytes / 1024,
  401. flBytesPerc,
  402. uAvgMsg,
  403. fKBPS,
  404. nMessagesSaved,
  405. flMessagesSavedPerc,
  406. uBytesSaved / 1024,
  407. flBytesSavedPerc );
  408. }
  409. uint32 uAvgMsgTotal = 0;
  410. if ( unTotalMessages > 0 )
  411. uAvgMsgTotal = unTotalBytes / unTotalMessages;
  412. float fKBPSTotal = 0.0f;
  413. if ( ulMicroseconds > 0 )
  414. fKBPSTotal = unTotalBytes * 1000.0f / ulMicroseconds;
  415. float flTotalMessagesPct = 0.0f;
  416. if ( rgTotals[eMultiType].nCount > 0 )
  417. flTotalMessagesPct = unTotalMessages * 100.0f / rgTotals[eMultiType].nCount;
  418. float flTotalBytesPct = 0.0f;
  419. if ( rgTotals[eMultiType].uBytes > 0 )
  420. flTotalBytesPct = unTotalBytes * 100.0f / rgTotals[eMultiType].uBytes;
  421. int32 nTotalMessagesSaved = rgTotals[eRawType].nCount - rgTotals[eMultiType].nCount;
  422. int64 nTotalBytesSaved = rgTotals[eRawType].uBytes - rgTotals[eMultiType].uBytes;
  423. int32 nTotalMessagesIfNotMultiplex = unTotalMessages - rgTotals[eMultiType].nCount + rgTotals[eRawType].nCount;
  424. int64 uTotalBytesIfNotMultiplex = unTotalBytes - rgTotals[eMultiType].uBytes + rgTotals[eRawType].uBytes;
  425. float flTotalMessagesSavedPct = 0.0f;
  426. if ( nTotalMessagesIfNotMultiplex > 0 )
  427. flTotalMessagesSavedPct = nTotalMessagesSaved * 100.0f / nTotalMessagesIfNotMultiplex;
  428. float flTotalBytesSavedPct = 0.0f;
  429. if ( uTotalBytesIfNotMultiplex > 0 )
  430. flTotalBytesSavedPct = nTotalBytesSaved * 100.0f / uTotalBytesIfNotMultiplex;
  431. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "----- ---------------------------------------------- ---------- ------ -------------- ------ ---------- ---------- ---------- ------ -------------- ------\n" );
  432. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "Totals %10u %5.1f%% %14llu %5.1f%% %10u %10.2f %10d %5.1f%% %14lld %5.1f%%\n",
  433. unTotalMessages,
  434. flTotalMessagesPct,
  435. unTotalBytes / 1024,
  436. flTotalBytesPct,
  437. uAvgMsgTotal,
  438. fKBPSTotal,
  439. nTotalMessagesSaved,
  440. flTotalMessagesSavedPct,
  441. nTotalBytesSaved / 1024,
  442. flTotalBytesSavedPct );
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Destroys a message list by deallocating everything it's got
  446. //-----------------------------------------------------------------------------
  447. CMessageList::~CMessageList()
  448. {
  449. int nUsedBuckets = 0;
  450. for ( int nIndex = 0; nIndex < m_vecMessageInfoBuckets.Count(); nIndex++ )
  451. {
  452. if ( m_vecMessageInfoBuckets[nIndex] != NULL )
  453. {
  454. FreePv( m_vecMessageInfoBuckets[nIndex] );
  455. m_vecMessageInfoBuckets[nIndex] = NULL;
  456. nUsedBuckets++;
  457. }
  458. }
  459. m_vecMessageInfoBuckets.RemoveAll();
  460. }
  461. //-----------------------------------------------------------------------------
  462. // assure that we've got the slots in the given bucket allocated
  463. //-----------------------------------------------------------------------------
  464. void CMessageList::AssureBucket( int nBucket )
  465. {
  466. // if this bucket is bigger then the array, extend the array
  467. if ( nBucket >= m_vecMessageInfoBuckets.Count() )
  468. {
  469. int nOldCount = m_vecMessageInfoBuckets.Count();
  470. // message ID "clumps" are usually 100 apart, so we'll try
  471. // to grow by 100 each time. Divide 100 by the bucket size and add
  472. // one for truncation to figure out our grow-by.
  473. int nNewCount = nBucket + (1 + (100 / m_kcBucketSize));
  474. // get that count
  475. m_vecMessageInfoBuckets.EnsureCount( nNewCount );
  476. // initialize the new ones to NULL
  477. for ( int nIndex = nOldCount; nIndex < nNewCount; nIndex++ )
  478. {
  479. m_vecMessageInfoBuckets[nIndex] = NULL;
  480. }
  481. }
  482. // is the bucket we want allocated?
  483. if ( m_vecMessageInfoBuckets[nBucket] == NULL )
  484. {
  485. // nope; get one and initialize it
  486. m_vecMessageInfoBuckets[nBucket] = (short*) PvAlloc( sizeof(short) * m_kcBucketSize );
  487. for ( int nIndex = 0; nIndex < m_kcBucketSize; nIndex++)
  488. m_vecMessageInfoBuckets[nBucket][nIndex] = -1;
  489. }
  490. return;
  491. }
  492. //-----------------------------------------------------------------------------
  493. // Purpose: Hash an MsgType_t and return the index into m_vecMsgInfo where it can be found
  494. // returns -1 if the MsgType_t is unknown
  495. //-----------------------------------------------------------------------------
  496. short CMessageList::GetMessageIndex( MsgType_t eMsg )
  497. {
  498. // find the slot and bucket for this message in our hash
  499. int nSlot;
  500. int nBucket = HashMessage( eMsg, nSlot );
  501. // taller than the hash?
  502. if ( nBucket >= m_vecMessageInfoBuckets.Count() )
  503. return -1;
  504. // not a bucket?
  505. if ( m_vecMessageInfoBuckets[nBucket] == NULL )
  506. return -1;
  507. // get the index back to the global array
  508. short nIndex = m_vecMessageInfoBuckets[nBucket][nSlot];
  509. return nIndex;
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Tests to see if a message is valid; if so, return a pointer to its name.
  513. // A message must match at least one of the nTypeMask flags to be considered
  514. // valid. If provided, ppMsgName is set to k_rgchUnknown if no match,
  515. // or the message name if matched.
  516. //-----------------------------------------------------------------------------
  517. bool CMessageList::GetMessage( MsgType_t eMsg, const char **ppMsgName, int nTypeMask )
  518. {
  519. VPROF_BUDGET( "GetMessage", VPROF_BUDGETGROUP_JOBS_COROUTINES );
  520. // if an out variable for the name is provided,
  521. // initialize it with a pointer to "unknown" string
  522. if ( ppMsgName != NULL )
  523. *ppMsgName = k_rgchUnknown;
  524. short nIndex = GetMessageIndex( eMsg );
  525. // good index?
  526. if ( nIndex == -1 )
  527. {
  528. if ( ppMsgName != NULL )
  529. {
  530. *ppMsgName = "Unknown MsgType - Not Found";
  531. }
  532. return false;
  533. }
  534. const MsgInfo_t &msgInfo = m_vecMsgInfo[nIndex];
  535. // get the string out
  536. if ( ppMsgName != NULL )
  537. *ppMsgName = msgInfo.pchMsgName;
  538. // it's good if it matches the flags
  539. return ( 0 != ( msgInfo.nFlags & nTypeMask ) );
  540. }
  541. } // namespace GCSDK