diff options
Diffstat (limited to 'mp/src/public/tier1/reliabletimer.h')
| -rw-r--r-- | mp/src/public/tier1/reliabletimer.h | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/mp/src/public/tier1/reliabletimer.h b/mp/src/public/tier1/reliabletimer.h new file mode 100644 index 00000000..f20f3bdf --- /dev/null +++ b/mp/src/public/tier1/reliabletimer.h @@ -0,0 +1,183 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef RELIABLETIMER_H
+#define RELIABLETIMER_H
+
+#include "tier0/dbg.h"
+//#include "constants.h"
+#include "tier0/fasttimer.h"
+#include "tier1/tier1.h"
+#include "tier1/strtools.h"
+
+#define DbgAssert Assert
+#define kMILLION (1000000)
+#define kTHOUSAND (1000)
+
+// Timer class that uses QueryPerformanceCounter. This is heavier-weight than CFastTimer which uses rdtsc,
+// but this is reliable on multi-core systems whereas CFastTimer is not.
+
+class CReliableTimer
+{
+public:
+ CReliableTimer();
+ void Start();
+ void End();
+ int64 GetMicroseconds();
+ int64 GetMilliseconds();
+ void SetLimit( uint64 m_cMicroSecDuration );
+ bool BLimitReached();
+ int64 CMicroSecOverage();
+ int64 CMicroSecLeft();
+ int64 CMilliSecLeft();
+private:
+ int64 GetPerformanceCountNow();
+
+ int64 m_nPerformanceCounterStart;
+ int64 m_nPerformanceCounterEnd;
+ int64 m_nPerformanceCounterLimit;
+
+ static int64 sm_nPerformanceFrequency;
+ static bool sm_bUseQPC;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Records timer start time
+//-----------------------------------------------------------------------------
+inline void CReliableTimer::Start()
+{
+ m_nPerformanceCounterStart = GetPerformanceCountNow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Records timer end time
+//-----------------------------------------------------------------------------
+inline void CReliableTimer::End()
+{
+ m_nPerformanceCounterEnd = GetPerformanceCountNow();
+
+ // enforce that we've advanced at least one cycle
+ if ( m_nPerformanceCounterEnd < m_nPerformanceCounterStart )
+ {
+#ifdef _SERVER
+ if ( m_nPerformanceCounterEnd+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ m_nPerformanceCounterEnd = m_nPerformanceCounterStart + 1;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets microseconds elapsed between start and end
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::GetMicroseconds()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // timer must have been started
+ DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kMILLION / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets microseconds elapsed between start and end
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::GetMilliseconds()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // timer must have been started
+ DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kTHOUSAND / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets a limit on this timer that can subsequently be checked against
+//-----------------------------------------------------------------------------
+inline void CReliableTimer::SetLimit( uint64 cMicroSecDuration )
+{
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ m_nPerformanceCounterStart = GetPerformanceCountNow();
+ m_nPerformanceCounterLimit = m_nPerformanceCounterStart + ( ( cMicroSecDuration * sm_nPerformanceFrequency ) / kMILLION );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns if previously set limit has been reached
+//-----------------------------------------------------------------------------
+inline bool CReliableTimer::BLimitReached()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
+ DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
+ int64 nPerformanceCountNow = GetPerformanceCountNow();
+
+ // make sure time advances
+ if ( nPerformanceCountNow < m_nPerformanceCounterStart )
+ {
+#ifdef _SERVER
+ if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ // reset the limit to be lower, to match our new clock
+ m_nPerformanceCounterLimit = nPerformanceCountNow + (m_nPerformanceCounterLimit - m_nPerformanceCounterStart);
+ }
+
+ return ( nPerformanceCountNow >= m_nPerformanceCounterLimit );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns microseconds current time is past limit, or 0 if not past limit
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::CMicroSecOverage()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
+ DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
+ int64 nPerformanceCountNow = GetPerformanceCountNow();
+#ifdef _SERVER
+ if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ int64 nPerformanceCountOver = ( nPerformanceCountNow > m_nPerformanceCounterLimit ?
+ nPerformanceCountNow - m_nPerformanceCounterLimit : 0 );
+
+ Assert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( nPerformanceCountOver * kMILLION / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns microseconds remaining until limit
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::CMicroSecLeft()
+{
+ DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
+ DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
+ int64 nPerformanceCountNow = GetPerformanceCountNow();
+#ifdef _SERVER
+ if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
+ AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
+#endif
+ int64 nPerformanceCountLeft = ( nPerformanceCountNow < m_nPerformanceCounterLimit ?
+ m_nPerformanceCounterLimit - nPerformanceCountNow : 0 );
+
+ DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
+ return ( nPerformanceCountLeft * kMILLION / sm_nPerformanceFrequency );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns milliseconds remaining until limit
+//-----------------------------------------------------------------------------
+inline int64 CReliableTimer::CMilliSecLeft()
+{
+ return CMicroSecLeft() / 1000;
+}
+
+
+#endif // TICKLIMITTIMER_H
|