summaryrefslogtreecommitdiff
path: root/gcsdk/messagelist.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /gcsdk/messagelist.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'gcsdk/messagelist.cpp')
-rw-r--r--gcsdk/messagelist.cpp673
1 files changed, 673 insertions, 0 deletions
diff --git a/gcsdk/messagelist.cpp b/gcsdk/messagelist.cpp
new file mode 100644
index 0000000..f1d9732
--- /dev/null
+++ b/gcsdk/messagelist.cpp
@@ -0,0 +1,673 @@
+//====== Copyright , Valve Corporation, All rights reserved. =======
+//
+// Purpose: Provides names for GC message types
+//
+//=============================================================================
+
+
+#include "stdafx.h"
+
+
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+namespace GCSDK
+{
+
+//-----------------------------------------------------------------------------
+// Purpose: allow global initializers for a list of message infos. The message
+// list will assemble them all into a single list when it initializes.
+//-----------------------------------------------------------------------------
+class CMessageListRegistration
+{
+public:
+ CMessageListRegistration( MsgInfo_t *pMsgInfo, int cMsgInfo, void *pExtra = NULL );
+
+ static CMessageListRegistration *sm_pFirst;
+ CMessageListRegistration *m_pNext;
+ MsgInfo_t *m_pMsgInfo;
+ int m_cMsgInfo;
+};
+
+
+DECLARE_GC_EMIT_GROUP( g_EGMessages, messages );
+
+//function called when a message is tallied but not registered properly. Used to help consolidate behavior for untracked messages
+static void HandleUntrackedMsg( const char* pszMsgOperation, uint32 nMsgID )
+{
+ //for now output this as verbose so that we can clean up the initial spam. Then promote this to warnings in the future
+ EG_VERBOSE( g_EGMessages, "Found %s message with ID %d that was not properly registered. Unable to tally information\n", pszMsgOperation, nMsgID );
+}
+
+
+CMessageListRegistration::CMessageListRegistration( MsgInfo_t *pMsgInfo, int cMsgInfo, void *pExtra )
+: m_pMsgInfo( pMsgInfo ),
+ m_cMsgInfo( cMsgInfo )
+{
+ m_pNext = sm_pFirst;
+ sm_pFirst = this;
+}
+
+CMessageListRegistration *CMessageListRegistration::sm_pFirst = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the name of a message type
+//-----------------------------------------------------------------------------
+const char *PchMsgNameFromEMsg( MsgType_t eMsg )
+{
+ const char *pchMsgName = k_rgchUnknown;
+ g_theMessageList.GetMessage( eMsg, &pchMsgName, MT_GC );
+ return pchMsgName;
+}
+
+
+//-----------------------------------------------------------------------------
+void MsgRegistrationFromEnumDescriptor( const ::google::protobuf::EnumDescriptor *pEnumDescriptor, int nTypeMask )
+{
+ // build the struct list for messages
+ MsgInfo_t *pMsgInfos = new MsgInfo_t[ pEnumDescriptor->value_count() ];
+ memset( pMsgInfos, 0, sizeof( MsgInfo_t ) * pEnumDescriptor->value_count() );
+
+ for ( int i = 0; i < pEnumDescriptor->value_count(); ++i )
+ {
+ const ::google::protobuf::EnumValueDescriptor *pEnumValueDescriptor = pEnumDescriptor->value(i);
+ pMsgInfos[ i ].eMsg = pEnumValueDescriptor->number();
+ pMsgInfos[ i ].pchMsgName = pEnumValueDescriptor->name().c_str();
+ pMsgInfos[ i ].nFlags = nTypeMask;
+ }
+
+ new CMessageListRegistration( pMsgInfos, pEnumDescriptor->value_count() );
+}
+
+//-----------------------------------------------------------------------------
+
+CMessageList g_theMessageList;
+
+//-----------------------------------------------------------------------------
+// CMessageList
+//
+// builds a hash of the MsgInfo_t table so that information about messages
+// can be found without searching.
+//-----------------------------------------------------------------------------
+
+CMessageList::CMessageList( ) : m_bProfiling( false ), m_ulProfileMicrosecs( 0 )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// CMessageList
+//
+// builds a hash of the MsgInfo_t table so that information about messages
+// can be found without searching.
+//-----------------------------------------------------------------------------
+bool CMessageList::BInit( )
+{
+ m_bProfiling = false;
+ m_ulProfileMicrosecs = 0;
+
+ // figure out our message count
+ int cMessageInfos = 0;
+ for( CMessageListRegistration *pReg = CMessageListRegistration::sm_pFirst; pReg != NULL; pReg = pReg->m_pNext)
+ {
+ cMessageInfos += pReg->m_cMsgInfo;
+ }
+
+ // message indexes should fit in a short
+ Assert( cMessageInfos < SHRT_MAX );
+
+ m_vecMsgInfo.EnsureCapacity( cMessageInfos );
+ m_vecMsgInfo.RemoveAll();
+ m_vecMessageInfoBuckets.RemoveAll();
+
+ int nIndex = 0;
+ for( CMessageListRegistration *pReg = CMessageListRegistration::sm_pFirst; pReg != NULL; pReg = pReg->m_pNext)
+ {
+ for ( int nRegIndex = 0; nRegIndex < pReg->m_cMsgInfo; nRegIndex++ )
+ {
+ nIndex = m_vecMsgInfo.AddToTail( pReg->m_pMsgInfo[nRegIndex] );
+
+ int nSlot;
+ int nBucket = HashMessage( pReg->m_pMsgInfo[nRegIndex].eMsg, nSlot );
+
+ AssureBucket( nBucket );
+
+ if ( m_vecMessageInfoBuckets[nBucket][nSlot] != -1 )
+ {
+ int otherIndex = m_vecMessageInfoBuckets[nBucket][nSlot];
+ MsgInfo_t &otherMsg = m_vecMsgInfo[ otherIndex ];
+ AssertFatalMsg2( false, "Message collision: %s redefined as %s",
+ otherMsg.pchMsgName,
+ pReg->m_pMsgInfo[nRegIndex].pchMsgName);
+ }
+ else
+ {
+ m_vecMessageInfoBuckets[nBucket][nSlot] = (short) nIndex;
+ }
+ }
+ }
+
+ //start our window
+ ResetWindow();
+ //and start our global timer
+ m_sCollectTime[ MsgInfo_t::k_EStatsGroupGlobal ].SetToJobTime();
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tally the sending of a message
+//-----------------------------------------------------------------------------
+void CMessageList::TallySendMessage( MsgType_t eMsgType, uint32 unMsgSize, uint32 nSourceMask )
+{
+ short nIndex = GetMessageIndex( eMsgType );
+ if ( nIndex == - 1 )
+ {
+ HandleUntrackedMsg( "send", eMsgType );
+ return;
+ }
+
+ TallyMessageInternal( m_vecMsgInfo[nIndex],MsgInfo_t::k_EStatsTypeSent, unMsgSize, nSourceMask );
+}
+
+
+//-----------------------------------------------------------------------------
+// Tally the receiving of a message
+//-----------------------------------------------------------------------------
+void CMessageList::TallyReceiveMessage( MsgType_t eMsgType, uint32 unMsgSize, uint32 nSourceMask )
+{
+ short nIndex = GetMessageIndex( eMsgType );
+ if ( nIndex == - 1 )
+ {
+ HandleUntrackedMsg( "receive", eMsgType );
+ return;
+ }
+
+ TallyMessageInternal( m_vecMsgInfo[nIndex], MsgInfo_t::k_EStatsTypeReceived, unMsgSize, nSourceMask );
+}
+
+
+//-----------------------------------------------------------------------------
+// Tally the receiving of a message
+//-----------------------------------------------------------------------------
+void CMessageList::TallyMultiplexedMessage( MsgType_t eMsgType, uint32 uSent, uint32 cRecipients, uint32 uMsgSize, uint32 nSourceMask )
+{
+ short nIndex = GetMessageIndex( eMsgType );
+ if ( nIndex == - 1 )
+ {
+ HandleUntrackedMsg( "multiplex", eMsgType );
+ return;
+ }
+
+ MsgInfo_t &msgInfo = m_vecMsgInfo[nIndex];
+ TallyMessageInternal( msgInfo, MsgInfo_t::k_EStatsTypeMultiplexedSends, uSent, nSourceMask, 1 );
+ TallyMessageInternal( msgInfo, MsgInfo_t::k_EStatsTypeMultiplexedSendsRaw, uMsgSize * cRecipients, nSourceMask, cRecipients );
+}
+
+
+//-----------------------------------------------------------------------------
+// Tally the receiving of a message
+//-----------------------------------------------------------------------------
+void CMessageList::TallyMessageInternal( MsgInfo_t &msgInfo, MsgInfo_t::EStatsType eBucket, uint32 unMsgSize, uint32 nSourceMask, uint32 cMessages )
+{
+ //log this for global stats
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupGlobal ][ eBucket ].nCount += cMessages;
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupGlobal ][ eBucket ].uBytes += unMsgSize;
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupGlobal ][ eBucket ].nSourceMask |= nSourceMask;
+
+ //track this in our current timing window
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupWindow ][ eBucket ].nCount += cMessages;
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupWindow ][ eBucket ].uBytes += unMsgSize;
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupWindow ][ eBucket ].nSourceMask |= nSourceMask;
+
+ //track our window totals as well
+ m_WindowTotals[ eBucket ].nCount += cMessages;
+ m_WindowTotals[ eBucket ].uBytes += unMsgSize;
+ m_WindowTotals[ eBucket ].nSourceMask |= nSourceMask;
+
+ //and if we are profiling, track the data into our profiling window
+ if ( m_bProfiling )
+ {
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupProfile ][ eBucket ].nCount += cMessages;
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupProfile ][ eBucket ].uBytes += unMsgSize;
+ msgInfo.stats[ MsgInfo_t::k_EStatsGroupProfile ][ eBucket ].nSourceMask |= nSourceMask;
+ }
+}
+
+//called to obtain the totals for the timing window
+const MsgInfo_t::Stats_t& CMessageList::GetWindowTotal( MsgInfo_t::EStatsType eType ) const
+{
+ return m_WindowTotals[ eType ];
+}
+
+//called to reset the window timings
+void CMessageList::ResetWindow()
+{
+ //reset when our window started
+ m_sCollectTime[ MsgInfo_t::k_EStatsGroupWindow ].SetToJobTime();
+
+ // starting a new window... clear everything
+ FOR_EACH_VEC( m_vecMsgInfo, nIndex )
+ {
+ for( uint32 nType = 0; nType < MsgInfo_t::k_EStatsType_Count; nType++ )
+ {
+ m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupWindow ][ nType ].nCount = 0;
+ m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupWindow ][ nType ].uBytes = 0;
+ m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupWindow ][ nType ].nSourceMask = 0;
+ }
+ }
+
+ //and clear our totals
+ for( uint32 nType = 0; nType < MsgInfo_t::k_EStatsType_Count; nType++ )
+ {
+ m_WindowTotals[ nType ].nCount = 0;
+ m_WindowTotals[ nType ].uBytes = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Turns snapshot profiling on and off
+//-----------------------------------------------------------------------------
+void CMessageList::EnableProfiling( bool bEnableProfiling )
+{
+ m_bProfiling = bEnableProfiling;
+ if ( m_bProfiling )
+ {
+ m_sCollectTime[ MsgInfo_t::k_EStatsGroupProfile ].SetToJobTime();
+
+ // starting a new profile... clear everything
+ FOR_EACH_VEC( m_vecMsgInfo, nIndex )
+ {
+ for( uint32 nType = 0; nType < MsgInfo_t::k_EStatsType_Count; nType++ )
+ {
+ m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupProfile ][ nType ].nCount = 0;
+ m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupProfile ][ nType ].uBytes = 0;
+ m_vecMsgInfo[ nIndex ].stats[ MsgInfo_t::k_EStatsGroupProfile ][ nType ].nSourceMask = 0;
+ }
+ }
+ }
+ else
+ {
+ m_ulProfileMicrosecs = m_sCollectTime[ MsgInfo_t::k_EStatsGroupProfile ].CServerMicroSecsPassed();
+ }
+}
+
+
+uint64 CMessageList::GetGroupDuration( MsgInfo_t::EStatsGroup eGroup ) const
+{
+ //handle the special case of it being a profile, where if we are no longer profiling, we want to use our cached value
+ if( ( eGroup == MsgInfo_t::k_EStatsGroupProfile ) && !m_bProfiling )
+ {
+ return m_ulProfileMicrosecs;
+ }
+
+ //otherwise we can just use the timer directly
+ return m_sCollectTime[ eGroup ].CServerMicroSecsPassed();
+}
+
+//-----------------------------------------------------------------------------
+// print statistics bout each message we handle
+//-----------------------------------------------------------------------------
+void CMessageList::PrintStats( bool bShowAll, bool bSortByFrequency, MsgInfo_t::EStatsGroup eGroup, MsgInfo_t::EStatsType eType, uint32 nSourceMask ) const
+{
+ // Figure out which time value we should use for rate calcs
+ uint64 ulMicroseconds = GetGroupDuration( eGroup );
+
+ // work out a sorted list
+ CUtlMap<uint64, uint32> mapValueToMsg( DefLessFunc( uint64 ) );
+ uint64 unTotalBytes = 0;
+ uint32 unTotalMessages = 0;
+
+ FOR_EACH_VEC( m_vecMsgInfo, n )
+ {
+ //see if we are looking for a particular source, and if so, if this has that source set
+ if( nSourceMask && ( ( m_vecMsgInfo[n].stats[ eGroup ][ eType ].nSourceMask & nSourceMask ) == 0 ) )
+ continue;
+
+ uint32 nCount = m_vecMsgInfo[n].stats[ eGroup ][ eType ].nCount;
+ uint64 uBytes = m_vecMsgInfo[n].stats[ eGroup ][ eType ].uBytes;
+
+ unTotalMessages += nCount;
+ unTotalBytes += uBytes;
+
+ if ( nCount == 0 && !bShowAll )
+ continue;
+
+ mapValueToMsg.Insert( bSortByFrequency ? (uint64)nCount : uBytes, n );
+ }
+
+ double fSeconds = ulMicroseconds / ( 1000.0 * 1000.0 );
+
+ // 5, 46, 10, 6, 14, 6, 10, 10
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "EMsg MessageName Count % Bytes % MsgPS Avg/Msg KBPS\n" );
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "----- ---------------------------------------------- ---------- ------ -------------- ------ --------- ---------- ----------\n" );
+
+ for ( uint16 iValue = mapValueToMsg.LastInorder(); iValue != mapValueToMsg.InvalidIndex(); iValue = mapValueToMsg.PrevInorder( iValue ) )
+ {
+ uint32 n = mapValueToMsg[iValue];
+
+ //see if we are looking for a particular source, and if so, if this has that source set
+ if( nSourceMask && ( ( m_vecMsgInfo[n].stats[ eGroup ][ eType ].nSourceMask & nSourceMask ) == 0 ) )
+ continue;
+
+ uint32 nCount = m_vecMsgInfo[n].stats[ eGroup ][ eType].nCount;
+ uint64 uBytes = m_vecMsgInfo[n].stats[ eGroup ][ eType].uBytes;
+
+ uint32 uAvgMsg = 0;
+ if ( nCount > 0 )
+ uAvgMsg = uBytes / nCount;
+
+ float flCountPerc = 0;
+ if ( unTotalMessages > 0 )
+ flCountPerc = nCount * 100.0f / unTotalMessages;
+ float flBytesPerc = 0;
+ if ( unTotalBytes > 0 )
+ flBytesPerc = uBytes * 100.0f / unTotalBytes;
+ double fMsgPS = 0.0;
+ if ( ulMicroseconds > 0 )
+ fMsgPS = nCount / fSeconds;
+ double fKBPS = 0.0f;
+ if ( ulMicroseconds > 0 )
+ fKBPS = uBytes / ( fSeconds * 1000.0 );
+
+
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%5u %-46s %10u %5.1f%% %14llu %5.1f%% %9.1f %10u %10.2f\n",
+ m_vecMsgInfo[n].eMsg,
+ m_vecMsgInfo[n].pchMsgName,
+ nCount,
+ flCountPerc,
+ uBytes,
+ flBytesPerc,
+ fMsgPS,
+ uAvgMsg,
+ fKBPS );
+ }
+
+ uint32 uAvgMsgTotal = 0;
+ if ( unTotalMessages > 0 )
+ uAvgMsgTotal = unTotalBytes / unTotalMessages;
+ double fMsgPS = 0.0;
+ if ( ulMicroseconds > 0 )
+ fMsgPS = unTotalMessages / fSeconds;
+ double fKBPSTotal = 0.0;
+ if ( ulMicroseconds > 0 )
+ fKBPSTotal = unTotalBytes / ( fSeconds * 1000.0 );
+
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "----- ---------------------------------------------- ---------- ------ -------------- ------ --------- ---------- ----------\n" );
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "Totals %10u 100.0%% %14llu 100.0%% %9.1f %10u %10.2f\n",
+ unTotalMessages,
+ unTotalBytes,
+ fMsgPS,
+ uAvgMsgTotal,
+ fKBPSTotal );
+}
+
+
+//-----------------------------------------------------------------------------
+// print statistics bout each message we handle
+//-----------------------------------------------------------------------------
+void CMessageList::PrintMultiplexStats( MsgInfo_t::EStatsGroup eGroup, bool bSortByFrequency, uint32 nSourceMask ) const
+{
+ // Figure out which time value we should use for rate calcs
+ uint64 ulMicroseconds = GetGroupDuration( eGroup );
+
+ MsgInfo_t::Stats_t rgTotals[MsgInfo_t::k_EStatsType_Count];
+
+ const MsgInfo_t::EStatsType eMultiType = MsgInfo_t::k_EStatsTypeMultiplexedSends;
+ const MsgInfo_t::EStatsType eRawType = MsgInfo_t::k_EStatsTypeMultiplexedSendsRaw;
+
+ // work out a sorted list
+ CUtlMap<uint64, uint32> mapValueToMsg( DefLessFunc( uint64 ) );
+ FOR_EACH_VEC( m_vecMsgInfo, n )
+ {
+ const MsgInfo_t &msgInfo = m_vecMsgInfo[n];
+
+ //see if we are looking for a particular source, and if so, if this has that source set
+ if( nSourceMask && ( msgInfo.stats[ eGroup ][ eMultiType ].nSourceMask & nSourceMask ) == 0 )
+ continue;
+
+ rgTotals[eMultiType].nCount += msgInfo.stats[ eGroup ][ eMultiType ].nCount;
+ rgTotals[eMultiType].uBytes += msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
+ rgTotals[eRawType].nCount += msgInfo.stats[ eGroup ][ eRawType ].nCount;
+ rgTotals[eRawType].uBytes += msgInfo.stats[ eGroup ][ eRawType ].uBytes;
+
+ if ( msgInfo.stats[ eGroup ][ eMultiType ].nCount == 0 )
+ continue;
+
+ uint32 nCount = msgInfo.stats[ eGroup ][ eMultiType ].nCount;
+ uint64 uBytes = msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
+ mapValueToMsg.Insert( bSortByFrequency ? (uint64)nCount : uBytes, n );
+ }
+
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "EMsg MessageName Count % KB % Avg/Msg KBPS Msg Saved % KB Saved %\n" );
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "----- ---------------------------------------------- ---------- ------ -------------- ------ ---------- ---------- ---------- ------ -------------- ------\n" );
+
+ uint32 unTotalMessages = 0;
+ uint64 unTotalBytes = 0;
+
+ for ( uint16 iValue = mapValueToMsg.LastInorder(); iValue != mapValueToMsg.InvalidIndex(); iValue = mapValueToMsg.PrevInorder( iValue ) )
+ {
+ const MsgInfo_t &msgInfo = m_vecMsgInfo[ mapValueToMsg[iValue] ];
+
+ //see if we are looking for a particular source, and if so, if this has that source set
+ if( nSourceMask && ( msgInfo.stats[ eGroup ][ eMultiType ].nSourceMask & nSourceMask ) == 0 )
+ continue;
+
+ uint32 nCount = msgInfo.stats[ eGroup ][ eMultiType ].nCount;
+ uint64 uBytes = msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
+
+ unTotalMessages += nCount;
+ unTotalBytes += uBytes;
+
+ int32 nMessagesSaved = msgInfo.stats[ eGroup ][ eRawType ].nCount - msgInfo.stats[ eGroup ][ eMultiType ].nCount;
+ int64 uBytesSaved = msgInfo.stats[ eGroup ][ eRawType ].uBytes - msgInfo.stats[ eGroup ][ eMultiType ].uBytes;
+
+ uint32 nMessagesIfNotMultiplex = msgInfo.stats[ eGroup ][ eRawType ].nCount;
+ uint64 uBytesIfNotMultiplex = msgInfo.stats[ eGroup ][ eRawType ].uBytes;
+
+ uint32 uAvgMsg = 0;
+ if ( nCount > 0 )
+ uAvgMsg = uBytes / nCount;
+
+ float flCountPerc = 0;
+ if ( rgTotals[eMultiType].nCount > 0 )
+ flCountPerc = nCount * 100.0f / rgTotals[eMultiType].nCount;
+ float flBytesPerc = 0;
+ if ( rgTotals[eMultiType].uBytes > 0 )
+ flBytesPerc = uBytes * 100.0f / rgTotals[eMultiType].uBytes;
+ float fKBPS = 0.0f;
+ if ( ulMicroseconds > 0 )
+ fKBPS = uBytes * 1000.0f / ulMicroseconds;
+
+ float flMessagesSavedPerc = 0.0f;
+ if ( nMessagesIfNotMultiplex > 0 )
+ flMessagesSavedPerc = nMessagesSaved * 100.0f / nMessagesIfNotMultiplex;
+ float flBytesSavedPerc = 0.0f;
+ if ( uBytesIfNotMultiplex > 0 )
+ flBytesSavedPerc = uBytesSaved * 100.0f / uBytesIfNotMultiplex;
+
+ 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",
+ msgInfo.eMsg,
+ msgInfo.pchMsgName,
+ nCount,
+ flCountPerc,
+ uBytes / 1024,
+ flBytesPerc,
+ uAvgMsg,
+ fKBPS,
+ nMessagesSaved,
+ flMessagesSavedPerc,
+ uBytesSaved / 1024,
+ flBytesSavedPerc );
+ }
+
+ uint32 uAvgMsgTotal = 0;
+ if ( unTotalMessages > 0 )
+ uAvgMsgTotal = unTotalBytes / unTotalMessages;
+
+ float fKBPSTotal = 0.0f;
+ if ( ulMicroseconds > 0 )
+ fKBPSTotal = unTotalBytes * 1000.0f / ulMicroseconds;
+
+ float flTotalMessagesPct = 0.0f;
+ if ( rgTotals[eMultiType].nCount > 0 )
+ flTotalMessagesPct = unTotalMessages * 100.0f / rgTotals[eMultiType].nCount;
+
+ float flTotalBytesPct = 0.0f;
+ if ( rgTotals[eMultiType].uBytes > 0 )
+ flTotalBytesPct = unTotalBytes * 100.0f / rgTotals[eMultiType].uBytes;
+
+ int32 nTotalMessagesSaved = rgTotals[eRawType].nCount - rgTotals[eMultiType].nCount;
+ int64 nTotalBytesSaved = rgTotals[eRawType].uBytes - rgTotals[eMultiType].uBytes;
+
+ int32 nTotalMessagesIfNotMultiplex = unTotalMessages - rgTotals[eMultiType].nCount + rgTotals[eRawType].nCount;
+ int64 uTotalBytesIfNotMultiplex = unTotalBytes - rgTotals[eMultiType].uBytes + rgTotals[eRawType].uBytes;
+
+ float flTotalMessagesSavedPct = 0.0f;
+ if ( nTotalMessagesIfNotMultiplex > 0 )
+ flTotalMessagesSavedPct = nTotalMessagesSaved * 100.0f / nTotalMessagesIfNotMultiplex;
+
+ float flTotalBytesSavedPct = 0.0f;
+ if ( uTotalBytesIfNotMultiplex > 0 )
+ flTotalBytesSavedPct = nTotalBytesSaved * 100.0f / uTotalBytesIfNotMultiplex;
+
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "----- ---------------------------------------------- ---------- ------ -------------- ------ ---------- ---------- ---------- ------ -------------- ------\n" );
+ EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "Totals %10u %5.1f%% %14llu %5.1f%% %10u %10.2f %10d %5.1f%% %14lld %5.1f%%\n",
+ unTotalMessages,
+ flTotalMessagesPct,
+ unTotalBytes / 1024,
+ flTotalBytesPct,
+ uAvgMsgTotal,
+ fKBPSTotal,
+ nTotalMessagesSaved,
+ flTotalMessagesSavedPct,
+ nTotalBytesSaved / 1024,
+ flTotalBytesSavedPct );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys a message list by deallocating everything it's got
+//-----------------------------------------------------------------------------
+CMessageList::~CMessageList()
+{
+ int nUsedBuckets = 0;
+ for ( int nIndex = 0; nIndex < m_vecMessageInfoBuckets.Count(); nIndex++ )
+ {
+ if ( m_vecMessageInfoBuckets[nIndex] != NULL )
+ {
+ FreePv( m_vecMessageInfoBuckets[nIndex] );
+ m_vecMessageInfoBuckets[nIndex] = NULL;
+ nUsedBuckets++;
+ }
+ }
+
+ m_vecMessageInfoBuckets.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// assure that we've got the slots in the given bucket allocated
+//-----------------------------------------------------------------------------
+void CMessageList::AssureBucket( int nBucket )
+{
+ // if this bucket is bigger then the array, extend the array
+ if ( nBucket >= m_vecMessageInfoBuckets.Count() )
+ {
+ int nOldCount = m_vecMessageInfoBuckets.Count();
+ // message ID "clumps" are usually 100 apart, so we'll try
+ // to grow by 100 each time. Divide 100 by the bucket size and add
+ // one for truncation to figure out our grow-by.
+ int nNewCount = nBucket + (1 + (100 / m_kcBucketSize));
+
+ // get that count
+ m_vecMessageInfoBuckets.EnsureCount( nNewCount );
+
+ // initialize the new ones to NULL
+ for ( int nIndex = nOldCount; nIndex < nNewCount; nIndex++ )
+ {
+ m_vecMessageInfoBuckets[nIndex] = NULL;
+ }
+ }
+
+ // is the bucket we want allocated?
+ if ( m_vecMessageInfoBuckets[nBucket] == NULL )
+ {
+ // nope; get one and initialize it
+ m_vecMessageInfoBuckets[nBucket] = (short*) PvAlloc( sizeof(short) * m_kcBucketSize );
+ for ( int nIndex = 0; nIndex < m_kcBucketSize; nIndex++)
+ m_vecMessageInfoBuckets[nBucket][nIndex] = -1;
+ }
+
+ return;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Hash an MsgType_t and return the index into m_vecMsgInfo where it can be found
+// returns -1 if the MsgType_t is unknown
+//-----------------------------------------------------------------------------
+short CMessageList::GetMessageIndex( MsgType_t eMsg )
+{
+ // find the slot and bucket for this message in our hash
+ int nSlot;
+ int nBucket = HashMessage( eMsg, nSlot );
+
+ // taller than the hash?
+ if ( nBucket >= m_vecMessageInfoBuckets.Count() )
+ return -1;
+
+ // not a bucket?
+ if ( m_vecMessageInfoBuckets[nBucket] == NULL )
+ return -1;
+
+ // get the index back to the global array
+ short nIndex = m_vecMessageInfoBuckets[nBucket][nSlot];
+ return nIndex;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tests to see if a message is valid; if so, return a pointer to its name.
+// A message must match at least one of the nTypeMask flags to be considered
+// valid. If provided, ppMsgName is set to k_rgchUnknown if no match,
+// or the message name if matched.
+//-----------------------------------------------------------------------------
+
+bool CMessageList::GetMessage( MsgType_t eMsg, const char **ppMsgName, int nTypeMask )
+{
+ VPROF_BUDGET( "GetMessage", VPROF_BUDGETGROUP_JOBS_COROUTINES );
+
+ // if an out variable for the name is provided,
+ // initialize it with a pointer to "unknown" string
+ if ( ppMsgName != NULL )
+ *ppMsgName = k_rgchUnknown;
+
+ short nIndex = GetMessageIndex( eMsg );
+
+ // good index?
+ if ( nIndex == -1 )
+ {
+ if ( ppMsgName != NULL )
+ {
+ *ppMsgName = "Unknown MsgType - Not Found";
+ }
+ return false;
+ }
+
+ const MsgInfo_t &msgInfo = m_vecMsgInfo[nIndex];
+
+ // get the string out
+ if ( ppMsgName != NULL )
+ *ppMsgName = msgInfo.pchMsgName;
+
+ // it's good if it matches the flags
+ return ( 0 != ( msgInfo.nFlags & nTypeMask ) );
+}
+
+
+} // namespace GCSDK
+