00001 /************************************************************************************ 00002 00003 Filename : OVR_Timer.cpp 00004 Content : Provides static functions for precise timing 00005 Created : September 19, 2012 00006 Notes : 00007 00008 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. 00009 00010 Use of this software is subject to the terms of the Oculus license 00011 agreement provided at the time of installation or download, or which 00012 otherwise accompanies this software in either electronic or hard copy form. 00013 00014 ************************************************************************************/ 00015 00016 #include "OVR_Timer.h" 00017 00018 #if defined (OVR_OS_WIN32) 00019 #include <windows.h> 00020 00021 #else 00022 #include <sys/time.h> 00023 #endif 00024 00025 namespace OVR { 00026 00027 //----------------------------------------------------------------------------------- 00028 // ***** Timer Class 00029 00030 UInt64 Timer::GetProfileTicks() 00031 { 00032 return (GetRawTicks() * MksPerSecond) / GetRawFrequency(); 00033 } 00034 double Timer::GetProfileSeconds() 00035 { 00036 static UInt64 StartTime = GetProfileTicks(); 00037 return TicksToSeconds(GetProfileTicks()-StartTime); 00038 } 00039 00040 00041 //------------------------------------------------------------------------ 00042 // *** Win32 Specific Timer 00043 00044 #if (defined (OVR_OS_WIN32)) 00045 00046 CRITICAL_SECTION WinAPI_GetTimeCS; 00047 volatile UInt32 WinAPI_OldTime = 0; 00048 volatile UInt32 WinAPI_WrapCounter = 0; 00049 00050 00051 UInt32 Timer::GetTicksMs() 00052 { 00053 return timeGetTime(); 00054 } 00055 00056 UInt64 Timer::GetTicks() 00057 { 00058 DWORD ticks = timeGetTime(); 00059 UInt64 result; 00060 00061 // On Win32 QueryPerformanceFrequency is unreliable due to SMP and 00062 // performance levels, so use this logic to detect wrapping and track 00063 // high bits. 00064 ::EnterCriticalSection(&WinAPI_GetTimeCS); 00065 00066 if (WinAPI_OldTime > ticks) 00067 WinAPI_WrapCounter++; 00068 WinAPI_OldTime = ticks; 00069 00070 result = (UInt64(WinAPI_WrapCounter) << 32) | ticks; 00071 ::LeaveCriticalSection(&WinAPI_GetTimeCS); 00072 00073 return result * MksPerMs; 00074 } 00075 00076 UInt64 Timer::GetRawTicks() 00077 { 00078 LARGE_INTEGER li; 00079 QueryPerformanceCounter(&li); 00080 return li.QuadPart; 00081 } 00082 00083 UInt64 Timer::GetRawFrequency() 00084 { 00085 static UInt64 perfFreq = 0; 00086 if (perfFreq == 0) 00087 { 00088 LARGE_INTEGER freq; 00089 QueryPerformanceFrequency(&freq); 00090 perfFreq = freq.QuadPart; 00091 } 00092 return perfFreq; 00093 } 00094 00095 void Timer::initializeTimerSystem() 00096 { 00097 timeBeginPeriod(1); 00098 InitializeCriticalSection(&WinAPI_GetTimeCS); 00099 00100 } 00101 void Timer::shutdownTimerSystem() 00102 { 00103 DeleteCriticalSection(&WinAPI_GetTimeCS); 00104 timeEndPeriod(1); 00105 } 00106 00107 #else // !OVR_OS_WIN32 00108 00109 00110 //------------------------------------------------------------------------ 00111 // *** Standard OS Timer 00112 00113 UInt32 Timer::GetTicksMs() 00114 { 00115 return (UInt32)(GetProfileTicks() / 1000); 00116 } 00117 // The profile ticks implementation is just fine for a normal timer. 00118 UInt64 Timer::GetTicks() 00119 { 00120 return GetProfileTicks(); 00121 } 00122 00123 void Timer::initializeTimerSystem() 00124 { 00125 } 00126 void Timer::shutdownTimerSystem() 00127 { 00128 } 00129 00130 UInt64 Timer::GetRawTicks() 00131 { 00132 // TODO: prefer rdtsc when available? 00133 00134 // Return microseconds. 00135 struct timeval tv; 00136 UInt64 result; 00137 00138 gettimeofday(&tv, 0); 00139 00140 result = (UInt64)tv.tv_sec * 1000000; 00141 result += tv.tv_usec; 00142 00143 return result; 00144 } 00145 00146 UInt64 Timer::GetRawFrequency() 00147 { 00148 return MksPerSecond; 00149 } 00150 00151 #endif // !OVR_OS_WIN32 00152 00153 00154 00155 } // OVR 00156