//====== Copyright ©, Valve Corporation, All rights reserved. ======= // // Purpose: Maps message types to strings and vice versa // //============================================================================= #ifndef MESSAGELIST_H #define MESSAGELIST_H #ifdef _WIN32 #pragma once #endif // Protobuf headers interfere with the valve min/max/malloc overrides. so we need to do all // this funky wrapping to make the include happy. #include #include "google/protobuf/descriptor.h" #include #include "gcsdk/jobtime.h" namespace GCSDK { extern CGCEmitGroup g_EGMessages; extern const char *PchMsgNameFromEMsg( MsgType_t eMsg ); //----------------------------------------------------------------------------- // message type flags //----------------------------------------------------------------------------- static const int MT_GC = 0x01; // this message is sent to or from a Game Coordinator (will be proxied by servers along the way) static const int MT_GC_SYSTEM = 0x02; // this message was sent to or from the steam servers as a system message. Clients can't send these //----------------------------------------------------------------------------- // Various info about each message type //----------------------------------------------------------------------------- struct MsgInfo_t { MsgType_t eMsg; int nFlags; const char *pchMsgName; struct Stats_t { Stats_t() : nSourceMask(0), nCount( 0 ), uBytes( 0 ) {} uint32 nSourceMask; uint32 nCount; uint64 uBytes; }; enum EStatsType { k_EStatsTypeSent, k_EStatsTypeReceived, k_EStatsTypeMultiplexedSends, k_EStatsTypeMultiplexedSendsRaw, k_EStatsType_Count }; enum EStatsGroup { k_EStatsGroupGlobal, k_EStatsGroupProfile, k_EStatsGroupWindow, k_EStatsGroup_Count }; Stats_t stats[ k_EStatsGroup_Count ][ k_EStatsType_Count ]; }; //----------------------------------------------------------------------------- // Purpose: Using protobuf reflection, bind them into a message list //----------------------------------------------------------------------------- void MsgRegistrationFromEnumDescriptor( const ::google::protobuf::EnumDescriptor *pEnumDescriptor, int nTypeMask ); //----------------------------------------------------------------------------- // manages a hashed list of messages, allowing fast tests for validity and // info lookup. //----------------------------------------------------------------------------- class CMessageList { public: CMessageList(); ~CMessageList(); bool BInit( ); // returns false if a message isn't valid or isn't one of the types specified // or true if the message is valid. ppMsgName can be NULL. bool GetMessage( MsgType_t eMsg, const char **ppMsgName, int nTypeMask ); // make stats about sending messages void TallySendMessage( MsgType_t eMsg, uint32 uMsgSize, uint32 nSourceMask = 0 ); void TallyReceiveMessage( MsgType_t eMsg, uint32 uMsgSize, uint32 nSourceMask = 0); void TallyMultiplexedMessage( MsgType_t eMsg, uint32 uSent, uint32 cRecipients, uint32 uMsgSize, uint32 nSourceMask = 0 ); // profiling void EnableProfiling( bool bEnableProfiling ); // print out our stats void PrintStats( bool bShowAll, bool bSortByFrequency, MsgInfo_t::EStatsGroup eGroup, MsgInfo_t::EStatsType eType, uint32 nSourceMask = 0 ) const; void PrintMultiplexStats( MsgInfo_t::EStatsGroup eGroup, bool bSortByFrequency, uint32 nSourceMask = 0 ) const; // Window management - This is similar to profiling in many ways, but is separate so that the base system can monitor traffic rates without // interfering with profiles. //called to obtain the totals for the timing window const MsgInfo_t::Stats_t& GetWindowTotal( MsgInfo_t::EStatsType eType ) const; //called to reset the window timings void ResetWindow(); //returns how long this window has been running in microseconds uint64 GetWindowDuration() const { return GetGroupDuration( MsgInfo_t::k_EStatsGroupWindow ); } private: void TallyMessageInternal( MsgInfo_t &msgInfo, MsgInfo_t::EStatsType eBucket, uint32 unMsgSize, uint32 nSourceMask, uint32 cMessages = 1 ); void AssureBucket( int nBucket ); //----------------------------------------------------------------------------- // given a particular message ID, find out what bucket it would be in, // as well as which slot in that bucket. //----------------------------------------------------------------------------- static int HashMessage( MsgType_t eMsg, int &nSlot ) { // hash is everything except the lowest nibble, // because buckets are 16 entries int nBucket = eMsg / m_kcBucketSize; nSlot = eMsg % m_kcBucketSize; return nBucket; } short GetMessageIndex( MsgType_t eMsg ); //given a group, this will return the time that the stats have been collected over uint64 GetGroupDuration( MsgInfo_t::EStatsGroup eGroup ) const; private: //totalled stats for the current window. It would be too costly to total these all the time MsgInfo_t::Stats_t m_WindowTotals[ MsgInfo_t::k_EStatsType_Count ]; //the time that we have been collecting each of these buckets CJobTime m_sCollectTime[ MsgInfo_t::k_EStatsGroup_Count ]; //are we currently actively tracking a profile? bool m_bProfiling; //the duration of the last finished profile (if it is no longer running, otherwise use the timer) uint64 m_ulProfileMicrosecs; CUtlVector< short* > m_vecMessageInfoBuckets; CUtlVector m_vecMsgInfo; static const int m_kcBucketSize = 16; }; extern CMessageList g_theMessageList; //----------------------------------------------------------------------------- // Purpose: Returns the true if the specified message is a valid GC system message. // Input : eMsg - message type to test // ppMsgName - Optional pointer to receive message name //----------------------------------------------------------------------------- inline bool BIsValidSystemMsg( MsgType_t eMsg, const char **ppMsgName ) { return g_theMessageList.GetMessage( eMsg, ppMsgName, MT_GC_SYSTEM ); } } // namespace GCSDK #endif // MESSAGELIST_H