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.

183 lines
7.4 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #ifndef RELIABLETIMER_H
  7. #define RELIABLETIMER_H
  8. #include "tier0/dbg.h"
  9. //#include "constants.h"
  10. #include "tier0/fasttimer.h"
  11. #include "tier1/tier1.h"
  12. #include "tier1/strtools.h"
  13. #define DbgAssert Assert
  14. #define kMILLION (1000000)
  15. #define kTHOUSAND (1000)
  16. // Timer class that uses QueryPerformanceCounter. This is heavier-weight than CFastTimer which uses rdtsc,
  17. // but this is reliable on multi-core systems whereas CFastTimer is not.
  18. class CReliableTimer
  19. {
  20. public:
  21. CReliableTimer();
  22. void Start();
  23. void End();
  24. int64 GetMicroseconds();
  25. int64 GetMilliseconds();
  26. void SetLimit( uint64 m_cMicroSecDuration );
  27. bool BLimitReached();
  28. int64 CMicroSecOverage();
  29. int64 CMicroSecLeft();
  30. int64 CMilliSecLeft();
  31. private:
  32. int64 GetPerformanceCountNow();
  33. int64 m_nPerformanceCounterStart;
  34. int64 m_nPerformanceCounterEnd;
  35. int64 m_nPerformanceCounterLimit;
  36. static int64 sm_nPerformanceFrequency;
  37. static bool sm_bUseQPC;
  38. };
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Records timer start time
  41. //-----------------------------------------------------------------------------
  42. inline void CReliableTimer::Start()
  43. {
  44. m_nPerformanceCounterStart = GetPerformanceCountNow();
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Purpose: Records timer end time
  48. //-----------------------------------------------------------------------------
  49. inline void CReliableTimer::End()
  50. {
  51. m_nPerformanceCounterEnd = GetPerformanceCountNow();
  52. // enforce that we've advanced at least one cycle
  53. if ( m_nPerformanceCounterEnd < m_nPerformanceCounterStart )
  54. {
  55. #ifdef _SERVER
  56. if ( m_nPerformanceCounterEnd+10000 < m_nPerformanceCounterStart )
  57. AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
  58. #endif
  59. m_nPerformanceCounterEnd = m_nPerformanceCounterStart + 1;
  60. }
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose: Gets microseconds elapsed between start and end
  64. //-----------------------------------------------------------------------------
  65. inline int64 CReliableTimer::GetMicroseconds()
  66. {
  67. DbgAssert( m_nPerformanceCounterStart ); // timer must have been started
  68. DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended
  69. DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
  70. return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kMILLION / sm_nPerformanceFrequency );
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Purpose: Gets microseconds elapsed between start and end
  74. //-----------------------------------------------------------------------------
  75. inline int64 CReliableTimer::GetMilliseconds()
  76. {
  77. DbgAssert( m_nPerformanceCounterStart ); // timer must have been started
  78. DbgAssert( m_nPerformanceCounterEnd ); // timer must have been ended
  79. DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
  80. return ( ( m_nPerformanceCounterEnd - m_nPerformanceCounterStart ) * kTHOUSAND / sm_nPerformanceFrequency );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Sets a limit on this timer that can subsequently be checked against
  84. //-----------------------------------------------------------------------------
  85. inline void CReliableTimer::SetLimit( uint64 cMicroSecDuration )
  86. {
  87. DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
  88. m_nPerformanceCounterStart = GetPerformanceCountNow();
  89. m_nPerformanceCounterLimit = m_nPerformanceCounterStart + ( ( cMicroSecDuration * sm_nPerformanceFrequency ) / kMILLION );
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: Returns if previously set limit has been reached
  93. //-----------------------------------------------------------------------------
  94. inline bool CReliableTimer::BLimitReached()
  95. {
  96. DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
  97. DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
  98. int64 nPerformanceCountNow = GetPerformanceCountNow();
  99. // make sure time advances
  100. if ( nPerformanceCountNow < m_nPerformanceCounterStart )
  101. {
  102. #ifdef _SERVER
  103. if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
  104. AssertMsgOnce( false, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
  105. #endif
  106. // reset the limit to be lower, to match our new clock
  107. m_nPerformanceCounterLimit = nPerformanceCountNow + (m_nPerformanceCounterLimit - m_nPerformanceCounterStart);
  108. }
  109. return ( nPerformanceCountNow >= m_nPerformanceCounterLimit );
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose: Returns microseconds current time is past limit, or 0 if not past limit
  113. //-----------------------------------------------------------------------------
  114. inline int64 CReliableTimer::CMicroSecOverage()
  115. {
  116. DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
  117. DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
  118. int64 nPerformanceCountNow = GetPerformanceCountNow();
  119. #ifdef _SERVER
  120. if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
  121. AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
  122. #endif
  123. int64 nPerformanceCountOver = ( nPerformanceCountNow > m_nPerformanceCounterLimit ?
  124. nPerformanceCountNow - m_nPerformanceCounterLimit : 0 );
  125. Assert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
  126. return ( nPerformanceCountOver * kMILLION / sm_nPerformanceFrequency );
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: Returns microseconds remaining until limit
  130. //-----------------------------------------------------------------------------
  131. inline int64 CReliableTimer::CMicroSecLeft()
  132. {
  133. DbgAssert( m_nPerformanceCounterStart ); // SetLimit must have been called
  134. DbgAssert( m_nPerformanceCounterLimit ); // SetLimit must have been called
  135. int64 nPerformanceCountNow = GetPerformanceCountNow();
  136. #ifdef _SERVER
  137. if ( nPerformanceCountNow+10000 < m_nPerformanceCounterStart )
  138. AssertMsgOnce( nPerformanceCountNow >= m_nPerformanceCounterStart, CDbgFmtMsg( "CReliableTimer went backwards - start:%lld end:%lld", m_nPerformanceCounterStart, m_nPerformanceCounterEnd ).ToString() );
  139. #endif
  140. int64 nPerformanceCountLeft = ( nPerformanceCountNow < m_nPerformanceCounterLimit ?
  141. m_nPerformanceCounterLimit - nPerformanceCountNow : 0 );
  142. DbgAssert( 0 != sm_nPerformanceFrequency ); // must have calc'd performance counter frequency
  143. return ( nPerformanceCountLeft * kMILLION / sm_nPerformanceFrequency );
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose: Returns milliseconds remaining until limit
  147. //-----------------------------------------------------------------------------
  148. inline int64 CReliableTimer::CMilliSecLeft()
  149. {
  150. return CMicroSecLeft() / 1000;
  151. }
  152. #endif // TICKLIMITTIMER_H