| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- /*
- -----------------------------------------------------------------------------
- This source file is part of OGRE
- (Object-oriented Graphics Rendering Engine)
- For the latest info, see http://www.ogre3d.org/
- Copyright (c) 2000-2011 Torus Knot Software Ltd
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- -----------------------------------------------------------------------------
- */
- #include "CmTimer.h"
- #include "CmBitwise.h"
- using namespace CamelotEngine;
- //-------------------------------------------------------------------------
- Timer::Timer()
- : mTimerMask( 0 )
- {
- reset();
- }
- //-------------------------------------------------------------------------
- Timer::~Timer()
- {
- }
- //-------------------------------------------------------------------------
- bool Timer::setOption( const String & key, const void * val )
- {
- if ( key == "QueryAffinityMask" )
- {
- // Telling timer what core to use for a timer read
- DWORD newTimerMask = * static_cast < const DWORD * > ( val );
- // Get the current process core mask
- DWORD_PTR procMask;
- DWORD_PTR sysMask;
- GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
- // If new mask is 0, then set to default behavior, otherwise check
- // to make sure new timer core mask overlaps with process core mask
- // and that new timer core mask is a power of 2 (i.e. a single core)
- if( ( newTimerMask == 0 ) ||
- ( ( ( newTimerMask & procMask ) != 0 ) && Bitwise::isPO2( newTimerMask ) ) )
- {
- mTimerMask = newTimerMask;
- return true;
- }
- }
- return false;
- }
- //-------------------------------------------------------------------------
- void Timer::reset()
- {
- // Get the current process core mask
- DWORD_PTR procMask;
- DWORD_PTR sysMask;
- GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
- // If procMask is 0, consider there is only one core available
- // (using 0 as procMask will cause an infinite loop below)
- if (procMask == 0)
- procMask = 1;
- // Find the lowest core that this process uses
- if( mTimerMask == 0 )
- {
- mTimerMask = 1;
- while( ( mTimerMask & procMask ) == 0 )
- {
- mTimerMask <<= 1;
- }
- }
- HANDLE thread = GetCurrentThread();
- // Set affinity to the first core
- DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
- // Get the constant frequency
- QueryPerformanceFrequency(&mFrequency);
- // Query the timer
- QueryPerformanceCounter(&mStartTime);
- mStartTick = GetTickCount();
- // Reset affinity
- SetThreadAffinityMask(thread, oldMask);
- mLastTime = 0;
- mZeroClock = clock();
- }
- //-------------------------------------------------------------------------
- unsigned long Timer::getMilliseconds()
- {
- LARGE_INTEGER curTime;
- HANDLE thread = GetCurrentThread();
- // Set affinity to the first core
- DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
- // Query the timer
- QueryPerformanceCounter(&curTime);
- // Reset affinity
- SetThreadAffinityMask(thread, oldMask);
- LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
-
- // scale by 1000 for milliseconds
- unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
- // detect and compensate for performance counter leaps
- // (surprisingly common, see Microsoft KB: Q274323)
- unsigned long check = GetTickCount() - mStartTick;
- signed long msecOff = (signed long)(newTicks - check);
- if (msecOff < -100 || msecOff > 100)
- {
- // We must keep the timer running forward :)
- LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
- mStartTime.QuadPart += adjust;
- newTime -= adjust;
- // Re-calculate milliseconds
- newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
- }
- // Record last time for adjust
- mLastTime = newTime;
- return newTicks;
- }
- //-------------------------------------------------------------------------
- unsigned long Timer::getMicroseconds()
- {
- LARGE_INTEGER curTime;
- HANDLE thread = GetCurrentThread();
- // Set affinity to the first core
- DWORD_PTR oldMask = SetThreadAffinityMask(thread, mTimerMask);
- // Query the timer
- QueryPerformanceCounter(&curTime);
- // Reset affinity
- SetThreadAffinityMask(thread, oldMask);
- LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;
-
- // get milliseconds to check against GetTickCount
- unsigned long newTicks = (unsigned long) (1000 * newTime / mFrequency.QuadPart);
-
- // detect and compensate for performance counter leaps
- // (surprisingly common, see Microsoft KB: Q274323)
- unsigned long check = GetTickCount() - mStartTick;
- signed long msecOff = (signed long)(newTicks - check);
- if (msecOff < -100 || msecOff > 100)
- {
- // We must keep the timer running forward :)
- LONGLONG adjust = (std::min)(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
- mStartTime.QuadPart += adjust;
- newTime -= adjust;
- }
- // Record last time for adjust
- mLastTime = newTime;
- // scale by 1000000 for microseconds
- unsigned long newMicro = (unsigned long) (1000000 * newTime / mFrequency.QuadPart);
- return newMicro;
- }
- //-------------------------------------------------------------------------
- unsigned long Timer::getMillisecondsCPU()
- {
- clock_t newClock = clock();
- return (unsigned long)( (float)( newClock - mZeroClock ) / ( (float)CLOCKS_PER_SEC / 1000.0 ) ) ;
- }
- //-------------------------------------------------------------------------
- unsigned long Timer::getMicrosecondsCPU()
- {
- clock_t newClock = clock();
- return (unsigned long)( (float)( newClock - mZeroClock ) / ( (float)CLOCKS_PER_SEC / 1000000.0 ) ) ;
- }
|