Counter Strike : Global Offensive Source Code
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.

175 lines
7.2 KiB

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