CmTimer.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "CmTimer.h"
  2. #include "CmBitwise.h"
  3. using namespace CamelotFramework;
  4. //-------------------------------------------------------------------------
  5. Timer::Timer()
  6. : mTimerMask( 0 )
  7. {
  8. reset();
  9. }
  10. //-------------------------------------------------------------------------
  11. Timer::~Timer()
  12. {
  13. }
  14. //-------------------------------------------------------------------------
  15. bool Timer::setOption( const String & key, const void * val )
  16. {
  17. if ( key == "QueryAffinityMask" )
  18. {
  19. // Telling timer what core to use for a timer read
  20. DWORD newTimerMask = * static_cast < const DWORD * > ( val );
  21. // Get the current process core mask
  22. DWORD_PTR procMask;
  23. DWORD_PTR sysMask;
  24. GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
  25. // If new mask is 0, then set to default behavior, otherwise check
  26. // to make sure new timer core mask overlaps with process core mask
  27. // and that new timer core mask is a power of 2 (i.e. a single core)
  28. if( ( newTimerMask == 0 ) ||
  29. ( ( ( newTimerMask & procMask ) != 0 ) && Bitwise::isPO2( newTimerMask ) ) )
  30. {
  31. mTimerMask = newTimerMask;
  32. return true;
  33. }
  34. }
  35. return false;
  36. }
  37. //-------------------------------------------------------------------------
  38. void Timer::reset()
  39. {
  40. // Get the current process core mask
  41. DWORD_PTR procMask;
  42. DWORD_PTR sysMask;
  43. GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
  44. // If procMask is 0, consider there is only one core available
  45. // (using 0 as procMask will cause an infinite loop below)
  46. if (procMask == 0)
  47. procMask = 1;
  48. // Find the lowest core that this process uses
  49. if( mTimerMask == 0 )
  50. {
  51. mTimerMask = 1;
  52. while( ( mTimerMask & procMask ) == 0 )
  53. {
  54. mTimerMask <<= 1;
  55. }
  56. }
  57. HANDLE thread = GetCurrentThread();
  58. // Set affinity to the first core
  59. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
  60. // Get the constant frequency
  61. QueryPerformanceFrequency(&mFrequency);
  62. // Query the timer
  63. QueryPerformanceCounter(&mStartTime);
  64. mStartTick = GetTickCount();
  65. // Reset affinity
  66. SetThreadAffinityMask(thread, oldMask);
  67. mLastTime = 0;
  68. mZeroClock = clock();
  69. }
  70. //-------------------------------------------------------------------------
  71. unsigned long Timer::getMilliseconds()
  72. {
  73. LARGE_INTEGER curTime;
  74. HANDLE thread = GetCurrentThread();
  75. // Set affinity to the first core
  76. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
  77. // Query the timer
  78. QueryPerformanceCounter(&curTime);
  79. // Reset affinity
  80. SetThreadAffinityMask(thread, oldMask);
  81. LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
  82. // scale by 1000 for milliseconds
  83. unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
  84. // detect and compensate for performance counter leaps
  85. // (surprisingly common, see Microsoft KB: Q274323)
  86. unsigned long check = GetTickCount() - mStartTick;
  87. signed long msecOff = (signed long)(newTicks - check);
  88. if (msecOff < -100 || msecOff > 100)
  89. {
  90. // We must keep the timer running forward :)
  91. LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
  92. mStartTime.QuadPart += adjust;
  93. newTime -= adjust;
  94. // Re-calculate milliseconds
  95. newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
  96. }
  97. // Record last time for adjust
  98. mLastTime = newTime;
  99. return newTicks;
  100. }
  101. unsigned long Timer::getStartMs() const
  102. {
  103. unsigned long newTicks = (unsigned long) (1000 * mStartTime.QuadPart / mFrequency.QuadPart);
  104. return newTicks;
  105. }
  106. //-------------------------------------------------------------------------
  107. unsigned long Timer::getMicroseconds()
  108. {
  109. LARGE_INTEGER curTime;
  110. HANDLE thread = GetCurrentThread();
  111. // Set affinity to the first core
  112. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
  113. // Query the timer
  114. QueryPerformanceCounter(&curTime);
  115. // Reset affinity
  116. SetThreadAffinityMask(thread, oldMask);
  117. LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
  118. // get milliseconds to check against GetTickCount
  119. unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
  120. // detect and compensate for performance counter leaps
  121. // (surprisingly common, see Microsoft KB: Q274323)
  122. unsigned long check = GetTickCount() - mStartTick;
  123. signed long msecOff = (signed long)(newTicks - check);
  124. if (msecOff < -100 || msecOff > 100)
  125. {
  126. // We must keep the timer running forward :)
  127. LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
  128. mStartTime.QuadPart += adjust;
  129. newTime -= adjust;
  130. }
  131. // Record last time for adjust
  132. mLastTime = newTime;
  133. // scale by 1000000 for microseconds
  134. unsigned long newMicro = (unsigned long) (1000000 * newTime / mFrequency.QuadPart);
  135. return newMicro;
  136. }
  137. //-------------------------------------------------------------------------
  138. unsigned long Timer::getMillisecondsCPU()
  139. {
  140. clock_t newClock = clock();
  141. return (unsigned long)( (float)( newClock - mZeroClock ) / ( (float)CLOCKS_PER_SEC / 1000.0 ) ) ;
  142. }
  143. //-------------------------------------------------------------------------
  144. unsigned long Timer::getMicrosecondsCPU()
  145. {
  146. clock_t newClock = clock();
  147. return (unsigned long)( (float)( newClock - mZeroClock ) / ( (float)CLOCKS_PER_SEC / 1000000.0 ) ) ;
  148. }