nuclear@1: /************************************************************************************ nuclear@1: nuclear@1: Filename : OVR_Timer.cpp nuclear@1: Content : Provides static functions for precise timing nuclear@1: Created : September 19, 2012 nuclear@1: Notes : nuclear@1: nuclear@1: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@1: nuclear@1: Use of this software is subject to the terms of the Oculus license nuclear@1: agreement provided at the time of installation or download, or which nuclear@1: otherwise accompanies this software in either electronic or hard copy form. nuclear@1: nuclear@1: ************************************************************************************/ nuclear@1: nuclear@1: #include "OVR_Timer.h" nuclear@1: nuclear@1: #if defined (OVR_OS_WIN32) nuclear@1: #include nuclear@1: nuclear@1: #else nuclear@1: #include nuclear@1: #endif nuclear@1: nuclear@1: namespace OVR { nuclear@1: nuclear@1: //----------------------------------------------------------------------------------- nuclear@1: // ***** Timer Class nuclear@1: nuclear@1: UInt64 Timer::GetProfileTicks() nuclear@1: { nuclear@1: return (GetRawTicks() * MksPerSecond) / GetRawFrequency(); nuclear@1: } nuclear@1: double Timer::GetProfileSeconds() nuclear@1: { nuclear@1: static UInt64 StartTime = GetProfileTicks(); nuclear@1: return TicksToSeconds(GetProfileTicks()-StartTime); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: //------------------------------------------------------------------------ nuclear@1: // *** Win32 Specific Timer nuclear@1: nuclear@1: #if (defined (OVR_OS_WIN32)) nuclear@1: nuclear@1: CRITICAL_SECTION WinAPI_GetTimeCS; nuclear@1: volatile UInt32 WinAPI_OldTime = 0; nuclear@1: volatile UInt32 WinAPI_WrapCounter = 0; nuclear@1: nuclear@1: nuclear@1: UInt32 Timer::GetTicksMs() nuclear@1: { nuclear@1: return timeGetTime(); nuclear@1: } nuclear@1: nuclear@1: UInt64 Timer::GetTicks() nuclear@1: { nuclear@1: DWORD ticks = timeGetTime(); nuclear@1: UInt64 result; nuclear@1: nuclear@1: // On Win32 QueryPerformanceFrequency is unreliable due to SMP and nuclear@1: // performance levels, so use this logic to detect wrapping and track nuclear@1: // high bits. nuclear@1: ::EnterCriticalSection(&WinAPI_GetTimeCS); nuclear@1: nuclear@1: if (WinAPI_OldTime > ticks) nuclear@1: WinAPI_WrapCounter++; nuclear@1: WinAPI_OldTime = ticks; nuclear@1: nuclear@1: result = (UInt64(WinAPI_WrapCounter) << 32) | ticks; nuclear@1: ::LeaveCriticalSection(&WinAPI_GetTimeCS); nuclear@1: nuclear@1: return result * MksPerMs; nuclear@1: } nuclear@1: nuclear@1: UInt64 Timer::GetRawTicks() nuclear@1: { nuclear@1: LARGE_INTEGER li; nuclear@1: QueryPerformanceCounter(&li); nuclear@1: return li.QuadPart; nuclear@1: } nuclear@1: nuclear@1: UInt64 Timer::GetRawFrequency() nuclear@1: { nuclear@1: static UInt64 perfFreq = 0; nuclear@1: if (perfFreq == 0) nuclear@1: { nuclear@1: LARGE_INTEGER freq; nuclear@1: QueryPerformanceFrequency(&freq); nuclear@1: perfFreq = freq.QuadPart; nuclear@1: } nuclear@1: return perfFreq; nuclear@1: } nuclear@1: nuclear@1: void Timer::initializeTimerSystem() nuclear@1: { nuclear@1: timeBeginPeriod(1); nuclear@1: InitializeCriticalSection(&WinAPI_GetTimeCS); nuclear@1: nuclear@1: } nuclear@1: void Timer::shutdownTimerSystem() nuclear@1: { nuclear@1: DeleteCriticalSection(&WinAPI_GetTimeCS); nuclear@1: timeEndPeriod(1); nuclear@1: } nuclear@1: nuclear@1: #else // !OVR_OS_WIN32 nuclear@1: nuclear@1: nuclear@1: //------------------------------------------------------------------------ nuclear@1: // *** Standard OS Timer nuclear@1: nuclear@1: UInt32 Timer::GetTicksMs() nuclear@1: { nuclear@1: return (UInt32)(GetProfileTicks() / 1000); nuclear@1: } nuclear@1: // The profile ticks implementation is just fine for a normal timer. nuclear@1: UInt64 Timer::GetTicks() nuclear@1: { nuclear@1: return GetProfileTicks(); nuclear@1: } nuclear@1: nuclear@1: void Timer::initializeTimerSystem() nuclear@1: { nuclear@1: } nuclear@1: void Timer::shutdownTimerSystem() nuclear@1: { nuclear@1: } nuclear@1: nuclear@1: UInt64 Timer::GetRawTicks() nuclear@1: { nuclear@1: // TODO: prefer rdtsc when available? nuclear@1: nuclear@1: // Return microseconds. nuclear@1: struct timeval tv; nuclear@1: UInt64 result; nuclear@1: nuclear@1: gettimeofday(&tv, 0); nuclear@1: nuclear@1: result = (UInt64)tv.tv_sec * 1000000; nuclear@1: result += tv.tv_usec; nuclear@1: nuclear@1: return result; nuclear@1: } nuclear@1: nuclear@1: UInt64 Timer::GetRawFrequency() nuclear@1: { nuclear@1: return MksPerSecond; nuclear@1: } nuclear@1: nuclear@1: #endif // !OVR_OS_WIN32 nuclear@1: nuclear@1: nuclear@1: nuclear@1: } // OVR nuclear@1: