ovr_sdk

diff LibOVR/Src/Kernel/OVR_Timer.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/LibOVR/Src/Kernel/OVR_Timer.cpp	Wed Jan 14 06:51:16 2015 +0200
     1.3 @@ -0,0 +1,551 @@
     1.4 +/************************************************************************************
     1.5 +
     1.6 +Filename    :   OVR_Timer.cpp
     1.7 +Content     :   Provides static functions for precise timing
     1.8 +Created     :   September 19, 2012
     1.9 +Notes       : 
    1.10 +
    1.11 +Copyright   :   Copyright 2014 Oculus VR, LLC All Rights reserved.
    1.12 +
    1.13 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 
    1.14 +you may not use the Oculus VR Rift SDK except in compliance with the License, 
    1.15 +which is provided at the time of installation or download, or which 
    1.16 +otherwise accompanies this software in either electronic or hard copy form.
    1.17 +
    1.18 +You may obtain a copy of the License at
    1.19 +
    1.20 +http://www.oculusvr.com/licenses/LICENSE-3.2 
    1.21 +
    1.22 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 
    1.23 +distributed under the License is distributed on an "AS IS" BASIS,
    1.24 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.25 +See the License for the specific language governing permissions and
    1.26 +limitations under the License.
    1.27 +
    1.28 +************************************************************************************/
    1.29 +
    1.30 +#include "OVR_Timer.h"
    1.31 +#include "OVR_Log.h"
    1.32 +
    1.33 +#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
    1.34 +#define WIN32_LEAN_AND_MEAN
    1.35 +#include <windows.h>
    1.36 +#include <MMSystem.h>
    1.37 +#elif defined(OVR_OS_ANDROID)
    1.38 +#include <time.h>
    1.39 +#include <android/log.h>
    1.40 +#elif defined(OVR_OS_MAC)
    1.41 +#include <mach/mach_time.h>
    1.42 +#else
    1.43 +#include <time.h>
    1.44 +#include <sys/time.h>
    1.45 +#include <errno.h>
    1.46 +#endif
    1.47 +
    1.48 +
    1.49 +#if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
    1.50 +    #ifndef NTSTATUS
    1.51 +        #define NTSTATUS DWORD
    1.52 +    #endif
    1.53 +
    1.54 +    typedef NTSTATUS (NTAPI* NtQueryTimerResolutionType)(PULONG MaximumTime, PULONG MinimumTime, PULONG CurrentTime);
    1.55 +    NtQueryTimerResolutionType pNtQueryTimerResolution;
    1.56 +#endif
    1.57 +
    1.58 +
    1.59 +
    1.60 +#if defined(OVR_OS_MS) && !defined(OVR_OS_WIN32) // Non-desktop Microsoft platforms...
    1.61 +
    1.62 +// Add this alias here because we're not going to include OVR_CAPI.cpp
    1.63 +extern "C" {
    1.64 +    double ovr_GetTimeInSeconds()
    1.65 +    {
    1.66 +        return Timer::GetSeconds();
    1.67 +    }
    1.68 +}
    1.69 +
    1.70 +#endif
    1.71 +
    1.72 +
    1.73 +
    1.74 +
    1.75 +namespace OVR {
    1.76 +
    1.77 +// For recorded data playback
    1.78 +bool   Timer::useFakeSeconds = false;
    1.79 +double Timer::FakeSeconds    = 0;
    1.80 +
    1.81 +
    1.82 +
    1.83 +
    1.84 +//------------------------------------------------------------------------
    1.85 +// *** Android Specific Timer
    1.86 +
    1.87 +#if defined(OVR_OS_ANDROID) // To consider: This implementation can also work on most Linux distributions
    1.88 +
    1.89 +//------------------------------------------------------------------------
    1.90 +// *** Timer - Platform Independent functions
    1.91 +
    1.92 +// Returns global high-resolution application timer in seconds.
    1.93 +double Timer::GetSeconds()
    1.94 +{
    1.95 +	if(useFakeSeconds)
    1.96 +		return FakeSeconds;
    1.97 +
    1.98 +    // Choreographer vsync timestamp is based on.
    1.99 +    struct timespec tp;
   1.100 +    const int       status = clock_gettime(CLOCK_MONOTONIC, &tp);
   1.101 +
   1.102 +#ifdef OVR_BUILD_DEBUG
   1.103 +    if (status != 0)
   1.104 +    {
   1.105 +        OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
   1.106 +    }
   1.107 +#else
   1.108 +    OVR_UNUSED(status);
   1.109 +#endif
   1.110 +
   1.111 +    return (double)tp.tv_sec;
   1.112 +}
   1.113 +
   1.114 +
   1.115 +
   1.116 +uint64_t Timer::GetTicksNanos()
   1.117 +{
   1.118 +    if (useFakeSeconds)
   1.119 +        return (uint64_t) (FakeSeconds * NanosPerSecond);
   1.120 +
   1.121 +    // Choreographer vsync timestamp is based on.
   1.122 +    struct timespec tp;
   1.123 +    const int       status = clock_gettime(CLOCK_MONOTONIC, &tp);
   1.124 +
   1.125 +#ifdef OVR_BUILD_DEBUG
   1.126 +    if (status != 0)
   1.127 +    {
   1.128 +        OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
   1.129 +    }
   1.130 +#else
   1.131 +    OVR_UNUSED(status);
   1.132 +#endif
   1.133 +
   1.134 +    const uint64_t result = (uint64_t)tp.tv_sec * (uint64_t)(1000 * 1000 * 1000) + uint64_t(tp.tv_nsec);
   1.135 +    return result;
   1.136 +}
   1.137 +
   1.138 +
   1.139 +void Timer::initializeTimerSystem()
   1.140 +{
   1.141 +    // Empty for this platform.
   1.142 +}
   1.143 +
   1.144 +void Timer::shutdownTimerSystem()
   1.145 +{
   1.146 +    // Empty for this platform.
   1.147 +}
   1.148 +
   1.149 +
   1.150 +
   1.151 +
   1.152 +
   1.153 +//------------------------------------------------------------------------
   1.154 +// *** Win32 Specific Timer
   1.155 +
   1.156 +#elif defined (OVR_OS_MS)
   1.157 +
   1.158 +
   1.159 +// This helper class implements high-resolution wrapper that combines timeGetTime() output
   1.160 +// with QueryPerformanceCounter.  timeGetTime() is lower precision but drives the high bits,
   1.161 +// as it's tied to the system clock.
   1.162 +struct PerformanceTimer
   1.163 +{
   1.164 +    PerformanceTimer()
   1.165 +        : UsingVistaOrLater(false),
   1.166 +          TimeCS(),
   1.167 +          OldMMTimeMs(0), 
   1.168 +          MMTimeWrapCounter(0), 
   1.169 +          PerfFrequency(0),
   1.170 +          PerfFrequencyInverse(0),
   1.171 +          PerfFrequencyInverseNanos(0),
   1.172 +          PerfMinusTicksDeltaNanos(0),
   1.173 +          LastResultNanos(0)
   1.174 +    { }
   1.175 +    
   1.176 +    enum {
   1.177 +        MMTimerResolutionNanos = 1000000
   1.178 +    };
   1.179 +   
   1.180 +    void    Initialize();
   1.181 +    void    Shutdown();
   1.182 +
   1.183 +    uint64_t  GetTimeSeconds();
   1.184 +    double    GetTimeSecondsDouble();
   1.185 +    uint64_t  GetTimeNanos();
   1.186 +
   1.187 +    UINT64 getFrequency()
   1.188 +    {
   1.189 +        if (PerfFrequency == 0)
   1.190 +        {
   1.191 +            LARGE_INTEGER freq;
   1.192 +            QueryPerformanceFrequency(&freq);
   1.193 +            PerfFrequency = freq.QuadPart;
   1.194 +            PerfFrequencyInverse = 1.0 / (double)PerfFrequency;
   1.195 +            PerfFrequencyInverseNanos = 1000000000.0 / (double)PerfFrequency;
   1.196 +        }        
   1.197 +        return PerfFrequency;
   1.198 +    }
   1.199 +    
   1.200 +    double GetFrequencyInverse()
   1.201 +    {
   1.202 +        OVR_ASSERT(PerfFrequencyInverse != 0.0); // Assert that the frequency has been initialized.
   1.203 +        return PerfFrequencyInverse;
   1.204 +    }
   1.205 +
   1.206 +	bool            UsingVistaOrLater;
   1.207 +
   1.208 +    CRITICAL_SECTION TimeCS;
   1.209 +    // timeGetTime() support with wrap.
   1.210 +    uint32_t        OldMMTimeMs;
   1.211 +    uint32_t        MMTimeWrapCounter;
   1.212 +    // Cached performance frequency result.
   1.213 +    uint64_t        PerfFrequency;              // cycles per second, typically a large value like 3000000, but usually not the same as the CPU clock rate.
   1.214 +    double          PerfFrequencyInverse;       // seconds per cycle (will be a small fractional value).
   1.215 +    double          PerfFrequencyInverseNanos;  // nanoseconds per cycle.
   1.216 +    
   1.217 +    // Computed as (perfCounterNanos - ticksCounterNanos) initially,
   1.218 +    // and used to adjust timing.
   1.219 +    uint64_t        PerfMinusTicksDeltaNanos;
   1.220 +    // Last returned value in nanoseconds, to ensure we don't back-step in time.
   1.221 +    uint64_t        LastResultNanos;
   1.222 +};
   1.223 +
   1.224 +static PerformanceTimer Win32_PerfTimer;
   1.225 +
   1.226 +
   1.227 +void PerformanceTimer::Initialize()
   1.228 +{
   1.229 +    #if defined(OVR_OS_WIN32) // Desktop Windows only
   1.230 +        // The following has the effect of setting the NT timer resolution (NtSetTimerResolution) to 1 millisecond.
   1.231 +        MMRESULT mmr = timeBeginPeriod(1);
   1.232 +        OVR_ASSERT(TIMERR_NOERROR == mmr);
   1.233 +        OVR_UNUSED(mmr);
   1.234 +    #endif
   1.235 +
   1.236 +    InitializeCriticalSection(&TimeCS);
   1.237 +    MMTimeWrapCounter = 0;
   1.238 +    getFrequency();
   1.239 +
   1.240 +    #if defined(OVR_OS_WIN32) // Desktop Windows only
   1.241 +	    // Set Vista flag.  On Vista, we can just use QPC() without all the extra work
   1.242 +        OSVERSIONINFOEX ver;
   1.243 +	    ZeroMemory(&ver, sizeof(OSVERSIONINFOEX));
   1.244 +	    ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
   1.245 +	    ver.dwMajorVersion = 6; // Vista+
   1.246 +
   1.247 +        DWORDLONG condMask = 0;
   1.248 +        VER_SET_CONDITION(condMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
   1.249 +
   1.250 +	    // VerifyVersionInfo returns true if the OS meets the conditions set above
   1.251 +	    UsingVistaOrLater = VerifyVersionInfo(&ver, VER_MAJORVERSION, condMask) != 0;
   1.252 +    #else
   1.253 +        UsingVistaOrLater = true;
   1.254 +    #endif
   1.255 +
   1.256 +	OVR_DEBUG_LOG(("PerformanceTimer UsingVistaOrLater = %d", (int)UsingVistaOrLater));
   1.257 +
   1.258 +    #if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
   1.259 +        HMODULE hNtDll = LoadLibrary(L"NtDll.dll");
   1.260 +        if (hNtDll)
   1.261 +        {
   1.262 +            pNtQueryTimerResolution = (NtQueryTimerResolutionType)GetProcAddress(hNtDll, "NtQueryTimerResolution");
   1.263 +          //pNtSetTimerResolution = (NtSetTimerResolutionType)GetProcAddress(hNtDll, "NtSetTimerResolution");
   1.264 +
   1.265 +            if(pNtQueryTimerResolution)
   1.266 +            {
   1.267 +                ULONG MinimumResolution; // in 100-ns units
   1.268 +                ULONG MaximumResolution;
   1.269 +                ULONG ActualResolution;
   1.270 +                pNtQueryTimerResolution(&MinimumResolution, &MaximumResolution, &ActualResolution);
   1.271 +	            OVR_DEBUG_LOG(("NtQueryTimerResolution = Min %ld us, Max %ld us, Current %ld us", MinimumResolution / 10, MaximumResolution / 10, ActualResolution / 10));
   1.272 +            }
   1.273 +
   1.274 +            FreeLibrary(hNtDll);
   1.275 +        }
   1.276 +    #endif
   1.277 +}
   1.278 +
   1.279 +void PerformanceTimer::Shutdown()
   1.280 +{
   1.281 +    DeleteCriticalSection(&TimeCS);
   1.282 +
   1.283 +    #if defined(OVR_OS_WIN32) // Desktop Windows only
   1.284 +        MMRESULT mmr = timeEndPeriod(1);
   1.285 +        OVR_ASSERT(TIMERR_NOERROR == mmr);
   1.286 +        OVR_UNUSED(mmr);
   1.287 +    #endif
   1.288 +}
   1.289 +
   1.290 +
   1.291 +uint64_t PerformanceTimer::GetTimeSeconds()
   1.292 +{
   1.293 +	if (UsingVistaOrLater)
   1.294 +	{
   1.295 +        LARGE_INTEGER li;
   1.296 +		QueryPerformanceCounter(&li);
   1.297 +        OVR_ASSERT(PerfFrequencyInverse != 0); // Initialize should have been called earlier.
   1.298 +        return (uint64_t)(li.QuadPart * PerfFrequencyInverse);
   1.299 +    }
   1.300 +
   1.301 +    return (uint64_t)(GetTimeNanos() * .0000000001);
   1.302 +}
   1.303 +
   1.304 +
   1.305 +double PerformanceTimer::GetTimeSecondsDouble()
   1.306 +{
   1.307 +	if (UsingVistaOrLater)
   1.308 +	{
   1.309 +        LARGE_INTEGER li;
   1.310 +		QueryPerformanceCounter(&li);
   1.311 +        OVR_ASSERT(PerfFrequencyInverse != 0);
   1.312 +        return (li.QuadPart * PerfFrequencyInverse);
   1.313 +    }
   1.314 +
   1.315 +    return (GetTimeNanos() * .0000000001);
   1.316 +}
   1.317 +
   1.318 +
   1.319 +uint64_t PerformanceTimer::GetTimeNanos()
   1.320 +{
   1.321 +    uint64_t      resultNanos;
   1.322 +    LARGE_INTEGER li;
   1.323 +
   1.324 +    OVR_ASSERT(PerfFrequencyInverseNanos != 0); // Initialize should have been called earlier.
   1.325 +
   1.326 +    if (UsingVistaOrLater) // Includes non-desktop platforms
   1.327 +	{
   1.328 +		// Then we can use QPC() directly without all that extra work
   1.329 +		QueryPerformanceCounter(&li);
   1.330 +        resultNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
   1.331 +	}
   1.332 +	else
   1.333 +	{
   1.334 +        // On Win32 QueryPerformanceFrequency is unreliable due to SMP and
   1.335 +        // performance levels, so use this logic to detect wrapping and track
   1.336 +        // high bits.
   1.337 +        ::EnterCriticalSection(&TimeCS);
   1.338 +
   1.339 +        // Get raw value and perf counter "At the same time".
   1.340 +        QueryPerformanceCounter(&li);
   1.341 +
   1.342 +        DWORD mmTimeMs = timeGetTime();
   1.343 +        if (OldMMTimeMs > mmTimeMs)
   1.344 +            MMTimeWrapCounter++;
   1.345 +        OldMMTimeMs = mmTimeMs;
   1.346 +
   1.347 +        // Normalize to nanoseconds.
   1.348 +        uint64_t  perfCounterNanos   = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
   1.349 +        uint64_t  mmCounterNanos     = ((uint64_t(MMTimeWrapCounter) << 32) | mmTimeMs) * 1000000;
   1.350 +        if (PerfMinusTicksDeltaNanos == 0)
   1.351 +            PerfMinusTicksDeltaNanos = perfCounterNanos - mmCounterNanos;
   1.352 + 
   1.353 +        // Compute result before snapping. 
   1.354 +        //
   1.355 +        // On first call, this evaluates to:
   1.356 +        //          resultNanos = mmCounterNanos.    
   1.357 +        // Next call, assuming no wrap:
   1.358 +        //          resultNanos = prev_mmCounterNanos + (perfCounterNanos - prev_perfCounterNanos).        
   1.359 +        // After wrap, this would be:
   1.360 +        //          resultNanos = snapped(prev_mmCounterNanos +/- 1ms) + (perfCounterNanos - prev_perfCounterNanos).
   1.361 +        //
   1.362 +        resultNanos = perfCounterNanos - PerfMinusTicksDeltaNanos;    
   1.363 +
   1.364 +        // Snap the range so that resultNanos never moves further apart then its target resolution.
   1.365 +        // It's better to allow more slack on the high side as timeGetTime() may be updated at sporadically 
   1.366 +        // larger then 1 ms intervals even when 1 ms resolution is requested.
   1.367 +        if (resultNanos > (mmCounterNanos + MMTimerResolutionNanos*2))
   1.368 +        {
   1.369 +            resultNanos = mmCounterNanos + MMTimerResolutionNanos*2;
   1.370 +            if (resultNanos < LastResultNanos)
   1.371 +                resultNanos = LastResultNanos;
   1.372 +            PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
   1.373 +        }
   1.374 +        else if (resultNanos < (mmCounterNanos - MMTimerResolutionNanos))
   1.375 +        {
   1.376 +            resultNanos = mmCounterNanos - MMTimerResolutionNanos;
   1.377 +            if (resultNanos < LastResultNanos)
   1.378 +                resultNanos = LastResultNanos;
   1.379 +            PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
   1.380 +        }
   1.381 +
   1.382 +        LastResultNanos = resultNanos;
   1.383 +        ::LeaveCriticalSection(&TimeCS);
   1.384 +	}
   1.385 +
   1.386 +	//Tom's addition, to keep precision
   1.387 +	//static uint64_t    initial_time = 0;
   1.388 +	//if (!initial_time) initial_time = resultNanos;
   1.389 +	//resultNanos -= initial_time;
   1.390 +	// FIXME: This cannot be used for cross-process timestamps
   1.391 +
   1.392 +    return resultNanos;
   1.393 +}
   1.394 +
   1.395 +
   1.396 +//------------------------------------------------------------------------
   1.397 +// *** Timer - Platform Independent functions
   1.398 +
   1.399 +// Returns global high-resolution application timer in seconds.
   1.400 +double Timer::GetSeconds()
   1.401 +{
   1.402 +	if(useFakeSeconds)
   1.403 +		return FakeSeconds;
   1.404 +
   1.405 +    return Win32_PerfTimer.GetTimeSecondsDouble();
   1.406 +}
   1.407 +
   1.408 +
   1.409 +
   1.410 +// Delegate to PerformanceTimer.
   1.411 +uint64_t Timer::GetTicksNanos()
   1.412 +{
   1.413 +    if (useFakeSeconds)
   1.414 +        return (uint64_t) (FakeSeconds * NanosPerSecond);
   1.415 +
   1.416 +    return Win32_PerfTimer.GetTimeNanos();
   1.417 +}
   1.418 +void Timer::initializeTimerSystem()
   1.419 +{
   1.420 +    Win32_PerfTimer.Initialize();
   1.421 +}
   1.422 +void Timer::shutdownTimerSystem()
   1.423 +{
   1.424 +    Win32_PerfTimer.Shutdown();
   1.425 +}
   1.426 +
   1.427 +
   1.428 +
   1.429 +#elif defined(OVR_OS_MAC)
   1.430 +
   1.431 +
   1.432 +double Timer::TimeConvertFactorNanos   = 0.0;
   1.433 +double Timer::TimeConvertFactorSeconds = 0.0;
   1.434 +
   1.435 +
   1.436 +//------------------------------------------------------------------------
   1.437 +// *** Standard OS Timer     
   1.438 +
   1.439 +// Returns global high-resolution application timer in seconds.
   1.440 +double Timer::GetSeconds()
   1.441 +{
   1.442 +	if(useFakeSeconds)
   1.443 +		return FakeSeconds;
   1.444 +    
   1.445 +    OVR_ASSERT(TimeConvertFactorNanos != 0.0);
   1.446 +    return (double)mach_absolute_time() * TimeConvertFactorNanos;
   1.447 +}
   1.448 +
   1.449 +
   1.450 +uint64_t Timer::GetTicksNanos()
   1.451 +{
   1.452 +    if (useFakeSeconds)
   1.453 +        return (uint64_t) (FakeSeconds * NanosPerSecond);
   1.454 +    
   1.455 +    OVR_ASSERT(TimeConvertFactorSeconds != 0.0);
   1.456 +    return (uint64_t)(mach_absolute_time() * TimeConvertFactorSeconds);
   1.457 +}
   1.458 +
   1.459 +void Timer::initializeTimerSystem()
   1.460 +{
   1.461 +    mach_timebase_info_data_t timeBase;
   1.462 +    mach_timebase_info(&timeBase);
   1.463 +    TimeConvertFactorSeconds = ((double)timeBase.numer / (double)timeBase.denom);
   1.464 +    TimeConvertFactorNanos   = TimeConvertFactorSeconds / 1000000000.0;
   1.465 +}
   1.466 +
   1.467 +void Timer::shutdownTimerSystem()
   1.468 +{
   1.469 +    // Empty for this platform.
   1.470 +}
   1.471 +
   1.472 +
   1.473 +#else // Posix platforms (e.g. Linux, BSD Unix)
   1.474 +
   1.475 +
   1.476 +bool Timer::MonotonicClockAvailable = false;
   1.477 +
   1.478 +
   1.479 +// Returns global high-resolution application timer in seconds.
   1.480 +double Timer::GetSeconds()
   1.481 +{
   1.482 +	if(useFakeSeconds)
   1.483 +		return FakeSeconds;
   1.484 +
   1.485 +    // http://linux/die/netman3/clock_gettime
   1.486 +    #if defined(CLOCK_MONOTONIC) // If we can use clock_gettime, which has nanosecond precision...
   1.487 +        if(MonotonicClockAvailable)
   1.488 +        {
   1.489 +            timespec ts;
   1.490 +            clock_gettime(CLOCK_MONOTONIC, &ts); // Better to use CLOCK_MONOTONIC than CLOCK_REALTIME.
   1.491 +            return static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec) / 1E9;
   1.492 +        }
   1.493 +    #endif
   1.494 +
   1.495 +    // We cannot use rdtsc because its frequency changes at runtime.
   1.496 +    struct timeval tv;
   1.497 +    gettimeofday(&tv, 0);
   1.498 +
   1.499 +    return static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1E6;
   1.500 +}
   1.501 +
   1.502 +
   1.503 +uint64_t Timer::GetTicksNanos()
   1.504 +{
   1.505 +    if (useFakeSeconds)
   1.506 +        return (uint64_t) (FakeSeconds * NanosPerSecond);
   1.507 +
   1.508 +    #if defined(CLOCK_MONOTONIC) // If we can use clock_gettime, which has nanosecond precision...
   1.509 +        if(MonotonicClockAvailable)
   1.510 +        {
   1.511 +            timespec ts;
   1.512 +            clock_gettime(CLOCK_MONOTONIC, &ts);
   1.513 +            return ((uint64_t)ts.tv_sec * 1000000000ULL) + (uint64_t)ts.tv_nsec;
   1.514 +        }
   1.515 +    #endif
   1.516 +
   1.517 +
   1.518 +    // We cannot use rdtsc because its frequency changes at runtime.
   1.519 +	uint64_t result;
   1.520 +
   1.521 +    // Return microseconds.
   1.522 +    struct timeval tv;
   1.523 +
   1.524 +    gettimeofday(&tv, 0);
   1.525 +
   1.526 +    result = (uint64_t)tv.tv_sec * 1000000;
   1.527 +    result += tv.tv_usec;
   1.528 +
   1.529 +    return result * 1000;
   1.530 +}
   1.531 +
   1.532 +
   1.533 +void Timer::initializeTimerSystem()
   1.534 +{
   1.535 +    #if defined(CLOCK_MONOTONIC)
   1.536 +        timespec ts; // We could also check for the availability of CLOCK_MONOTONIC with sysconf(_SC_MONOTONIC_CLOCK)
   1.537 +        int result = clock_gettime(CLOCK_MONOTONIC, &ts);
   1.538 +        MonotonicClockAvailable = (result == 0);
   1.539 +    #endif
   1.540 +}
   1.541 +
   1.542 +void Timer::shutdownTimerSystem()
   1.543 +{
   1.544 +    // Empty for this platform.
   1.545 +}
   1.546 +
   1.547 +
   1.548 +
   1.549 +#endif  // OS-specific
   1.550 +
   1.551 +
   1.552 +
   1.553 +} // OVR
   1.554 +