/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ #include "ogremath/OgreTimer.h" #include "ogremath/OgreBitwise.h" using namespace Ogre; //------------------------------------------------------------------------- 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 procMask; DWORD sysMask; #if _MSC_VER >= 1400 && defined (_M_X64) GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask); #else GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask); #endif // 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 procMask; DWORD sysMask; #if _MSC_VER >= 1400 && defined (_M_X64) GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask); #else GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask); #endif // 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 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 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 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 ) ) ; }