CmTimer.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org/
  6. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. #include "CmTimer.h"
  25. #include "CmBitwise.h"
  26. using namespace CamelotEngine;
  27. //-------------------------------------------------------------------------
  28. Timer::Timer()
  29. : mTimerMask( 0 )
  30. {
  31. reset();
  32. }
  33. //-------------------------------------------------------------------------
  34. Timer::~Timer()
  35. {
  36. }
  37. //-------------------------------------------------------------------------
  38. bool Timer::setOption( const String & key, const void * val )
  39. {
  40. if ( key == "QueryAffinityMask" )
  41. {
  42. // Telling timer what core to use for a timer read
  43. DWORD newTimerMask = * static_cast < const DWORD * > ( val );
  44. // Get the current process core mask
  45. DWORD_PTR procMask;
  46. DWORD_PTR sysMask;
  47. GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
  48. // If new mask is 0, then set to default behavior, otherwise check
  49. // to make sure new timer core mask overlaps with process core mask
  50. // and that new timer core mask is a power of 2 (i.e. a single core)
  51. if( ( newTimerMask == 0 ) ||
  52. ( ( ( newTimerMask & procMask ) != 0 ) && Bitwise::isPO2( newTimerMask ) ) )
  53. {
  54. mTimerMask = newTimerMask;
  55. return true;
  56. }
  57. }
  58. return false;
  59. }
  60. //-------------------------------------------------------------------------
  61. void Timer::reset()
  62. {
  63. // Get the current process core mask
  64. DWORD_PTR procMask;
  65. DWORD_PTR sysMask;
  66. GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
  67. // If procMask is 0, consider there is only one core available
  68. // (using 0 as procMask will cause an infinite loop below)
  69. if (procMask == 0)
  70. procMask = 1;
  71. // Find the lowest core that this process uses
  72. if( mTimerMask == 0 )
  73. {
  74. mTimerMask = 1;
  75. while( ( mTimerMask & procMask ) == 0 )
  76. {
  77. mTimerMask <<= 1;
  78. }
  79. }
  80. HANDLE thread = GetCurrentThread();
  81. // Set affinity to the first core
  82. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
  83. // Get the constant frequency
  84. QueryPerformanceFrequency(&mFrequency);
  85. // Query the timer
  86. QueryPerformanceCounter(&mStartTime);
  87. mStartTick = GetTickCount();
  88. // Reset affinity
  89. SetThreadAffinityMask(thread, oldMask);
  90. mLastTime = 0;
  91. mZeroClock = clock();
  92. }
  93. //-------------------------------------------------------------------------
  94. unsigned long Timer::getMilliseconds()
  95. {
  96. LARGE_INTEGER curTime;
  97. HANDLE thread = GetCurrentThread();
  98. // Set affinity to the first core
  99. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
  100. // Query the timer
  101. QueryPerformanceCounter(&curTime);
  102. // Reset affinity
  103. SetThreadAffinityMask(thread, oldMask);
  104. LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
  105. // scale by 1000 for milliseconds
  106. unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
  107. // detect and compensate for performance counter leaps
  108. // (surprisingly common, see Microsoft KB: Q274323)
  109. unsigned long check = GetTickCount() - mStartTick;
  110. signed long msecOff = (signed long)(newTicks - check);
  111. if (msecOff < -100 || msecOff > 100)
  112. {
  113. // We must keep the timer running forward :)
  114. LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
  115. mStartTime.QuadPart += adjust;
  116. newTime -= adjust;
  117. // Re-calculate milliseconds
  118. newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
  119. }
  120. // Record last time for adjust
  121. mLastTime = newTime;
  122. return newTicks;
  123. }
  124. //-------------------------------------------------------------------------
  125. unsigned long Timer::getMicroseconds()
  126. {
  127. LARGE_INTEGER curTime;
  128. HANDLE thread = GetCurrentThread();
  129. // Set affinity to the first core
  130. DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
  131. // Query the timer
  132. QueryPerformanceCounter(&curTime);
  133. // Reset affinity
  134. SetThreadAffinityMask(thread, oldMask);
  135. LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
  136. // get milliseconds to check against GetTickCount
  137. unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
  138. // detect and compensate for performance counter leaps
  139. // (surprisingly common, see Microsoft KB: Q274323)
  140. unsigned long check = GetTickCount() - mStartTick;
  141. signed long msecOff = (signed long)(newTicks - check);
  142. if (msecOff < -100 || msecOff > 100)
  143. {
  144. // We must keep the timer running forward :)
  145. LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
  146. mStartTime.QuadPart += adjust;
  147. newTime -= adjust;
  148. }
  149. // Record last time for adjust
  150. mLastTime = newTime;
  151. // scale by 1000000 for microseconds
  152. unsigned long newMicro = (unsigned long) (1000000 * newTime / mFrequency.QuadPart);
  153. return newMicro;
  154. }
  155. //-------------------------------------------------------------------------
  156. unsigned long Timer::getMillisecondsCPU()
  157. {
  158. clock_t newClock = clock();
  159. return (unsigned long)( (float)( newClock - mZeroClock ) / ( (float)CLOCKS_PER_SEC / 1000.0 ) ) ;
  160. }
  161. //-------------------------------------------------------------------------
  162. unsigned long Timer::getMicrosecondsCPU()
  163. {
  164. clock_t newClock = clock();
  165. return (unsigned long)( (float)( newClock - mZeroClock ) / ( (float)CLOCKS_PER_SEC / 1000000.0 ) ) ;
  166. }