ovr_sdk

annotate 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
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_Timer.cpp
nuclear@0 4 Content : Provides static functions for precise timing
nuclear@0 5 Created : September 19, 2012
nuclear@0 6 Notes :
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 ************************************************************************************/
nuclear@0 26
nuclear@0 27 #include "OVR_Timer.h"
nuclear@0 28 #include "OVR_Log.h"
nuclear@0 29
nuclear@0 30 #if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
nuclear@0 31 #define WIN32_LEAN_AND_MEAN
nuclear@0 32 #include <windows.h>
nuclear@0 33 #include <MMSystem.h>
nuclear@0 34 #elif defined(OVR_OS_ANDROID)
nuclear@0 35 #include <time.h>
nuclear@0 36 #include <android/log.h>
nuclear@0 37 #elif defined(OVR_OS_MAC)
nuclear@0 38 #include <mach/mach_time.h>
nuclear@0 39 #else
nuclear@0 40 #include <time.h>
nuclear@0 41 #include <sys/time.h>
nuclear@0 42 #include <errno.h>
nuclear@0 43 #endif
nuclear@0 44
nuclear@0 45
nuclear@0 46 #if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
nuclear@0 47 #ifndef NTSTATUS
nuclear@0 48 #define NTSTATUS DWORD
nuclear@0 49 #endif
nuclear@0 50
nuclear@0 51 typedef NTSTATUS (NTAPI* NtQueryTimerResolutionType)(PULONG MaximumTime, PULONG MinimumTime, PULONG CurrentTime);
nuclear@0 52 NtQueryTimerResolutionType pNtQueryTimerResolution;
nuclear@0 53 #endif
nuclear@0 54
nuclear@0 55
nuclear@0 56
nuclear@0 57 #if defined(OVR_OS_MS) && !defined(OVR_OS_WIN32) // Non-desktop Microsoft platforms...
nuclear@0 58
nuclear@0 59 // Add this alias here because we're not going to include OVR_CAPI.cpp
nuclear@0 60 extern "C" {
nuclear@0 61 double ovr_GetTimeInSeconds()
nuclear@0 62 {
nuclear@0 63 return Timer::GetSeconds();
nuclear@0 64 }
nuclear@0 65 }
nuclear@0 66
nuclear@0 67 #endif
nuclear@0 68
nuclear@0 69
nuclear@0 70
nuclear@0 71
nuclear@0 72 namespace OVR {
nuclear@0 73
nuclear@0 74 // For recorded data playback
nuclear@0 75 bool Timer::useFakeSeconds = false;
nuclear@0 76 double Timer::FakeSeconds = 0;
nuclear@0 77
nuclear@0 78
nuclear@0 79
nuclear@0 80
nuclear@0 81 //------------------------------------------------------------------------
nuclear@0 82 // *** Android Specific Timer
nuclear@0 83
nuclear@0 84 #if defined(OVR_OS_ANDROID) // To consider: This implementation can also work on most Linux distributions
nuclear@0 85
nuclear@0 86 //------------------------------------------------------------------------
nuclear@0 87 // *** Timer - Platform Independent functions
nuclear@0 88
nuclear@0 89 // Returns global high-resolution application timer in seconds.
nuclear@0 90 double Timer::GetSeconds()
nuclear@0 91 {
nuclear@0 92 if(useFakeSeconds)
nuclear@0 93 return FakeSeconds;
nuclear@0 94
nuclear@0 95 // Choreographer vsync timestamp is based on.
nuclear@0 96 struct timespec tp;
nuclear@0 97 const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
nuclear@0 98
nuclear@0 99 #ifdef OVR_BUILD_DEBUG
nuclear@0 100 if (status != 0)
nuclear@0 101 {
nuclear@0 102 OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
nuclear@0 103 }
nuclear@0 104 #else
nuclear@0 105 OVR_UNUSED(status);
nuclear@0 106 #endif
nuclear@0 107
nuclear@0 108 return (double)tp.tv_sec;
nuclear@0 109 }
nuclear@0 110
nuclear@0 111
nuclear@0 112
nuclear@0 113 uint64_t Timer::GetTicksNanos()
nuclear@0 114 {
nuclear@0 115 if (useFakeSeconds)
nuclear@0 116 return (uint64_t) (FakeSeconds * NanosPerSecond);
nuclear@0 117
nuclear@0 118 // Choreographer vsync timestamp is based on.
nuclear@0 119 struct timespec tp;
nuclear@0 120 const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
nuclear@0 121
nuclear@0 122 #ifdef OVR_BUILD_DEBUG
nuclear@0 123 if (status != 0)
nuclear@0 124 {
nuclear@0 125 OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
nuclear@0 126 }
nuclear@0 127 #else
nuclear@0 128 OVR_UNUSED(status);
nuclear@0 129 #endif
nuclear@0 130
nuclear@0 131 const uint64_t result = (uint64_t)tp.tv_sec * (uint64_t)(1000 * 1000 * 1000) + uint64_t(tp.tv_nsec);
nuclear@0 132 return result;
nuclear@0 133 }
nuclear@0 134
nuclear@0 135
nuclear@0 136 void Timer::initializeTimerSystem()
nuclear@0 137 {
nuclear@0 138 // Empty for this platform.
nuclear@0 139 }
nuclear@0 140
nuclear@0 141 void Timer::shutdownTimerSystem()
nuclear@0 142 {
nuclear@0 143 // Empty for this platform.
nuclear@0 144 }
nuclear@0 145
nuclear@0 146
nuclear@0 147
nuclear@0 148
nuclear@0 149
nuclear@0 150 //------------------------------------------------------------------------
nuclear@0 151 // *** Win32 Specific Timer
nuclear@0 152
nuclear@0 153 #elif defined (OVR_OS_MS)
nuclear@0 154
nuclear@0 155
nuclear@0 156 // This helper class implements high-resolution wrapper that combines timeGetTime() output
nuclear@0 157 // with QueryPerformanceCounter. timeGetTime() is lower precision but drives the high bits,
nuclear@0 158 // as it's tied to the system clock.
nuclear@0 159 struct PerformanceTimer
nuclear@0 160 {
nuclear@0 161 PerformanceTimer()
nuclear@0 162 : UsingVistaOrLater(false),
nuclear@0 163 TimeCS(),
nuclear@0 164 OldMMTimeMs(0),
nuclear@0 165 MMTimeWrapCounter(0),
nuclear@0 166 PerfFrequency(0),
nuclear@0 167 PerfFrequencyInverse(0),
nuclear@0 168 PerfFrequencyInverseNanos(0),
nuclear@0 169 PerfMinusTicksDeltaNanos(0),
nuclear@0 170 LastResultNanos(0)
nuclear@0 171 { }
nuclear@0 172
nuclear@0 173 enum {
nuclear@0 174 MMTimerResolutionNanos = 1000000
nuclear@0 175 };
nuclear@0 176
nuclear@0 177 void Initialize();
nuclear@0 178 void Shutdown();
nuclear@0 179
nuclear@0 180 uint64_t GetTimeSeconds();
nuclear@0 181 double GetTimeSecondsDouble();
nuclear@0 182 uint64_t GetTimeNanos();
nuclear@0 183
nuclear@0 184 UINT64 getFrequency()
nuclear@0 185 {
nuclear@0 186 if (PerfFrequency == 0)
nuclear@0 187 {
nuclear@0 188 LARGE_INTEGER freq;
nuclear@0 189 QueryPerformanceFrequency(&freq);
nuclear@0 190 PerfFrequency = freq.QuadPart;
nuclear@0 191 PerfFrequencyInverse = 1.0 / (double)PerfFrequency;
nuclear@0 192 PerfFrequencyInverseNanos = 1000000000.0 / (double)PerfFrequency;
nuclear@0 193 }
nuclear@0 194 return PerfFrequency;
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 double GetFrequencyInverse()
nuclear@0 198 {
nuclear@0 199 OVR_ASSERT(PerfFrequencyInverse != 0.0); // Assert that the frequency has been initialized.
nuclear@0 200 return PerfFrequencyInverse;
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 bool UsingVistaOrLater;
nuclear@0 204
nuclear@0 205 CRITICAL_SECTION TimeCS;
nuclear@0 206 // timeGetTime() support with wrap.
nuclear@0 207 uint32_t OldMMTimeMs;
nuclear@0 208 uint32_t MMTimeWrapCounter;
nuclear@0 209 // Cached performance frequency result.
nuclear@0 210 uint64_t PerfFrequency; // cycles per second, typically a large value like 3000000, but usually not the same as the CPU clock rate.
nuclear@0 211 double PerfFrequencyInverse; // seconds per cycle (will be a small fractional value).
nuclear@0 212 double PerfFrequencyInverseNanos; // nanoseconds per cycle.
nuclear@0 213
nuclear@0 214 // Computed as (perfCounterNanos - ticksCounterNanos) initially,
nuclear@0 215 // and used to adjust timing.
nuclear@0 216 uint64_t PerfMinusTicksDeltaNanos;
nuclear@0 217 // Last returned value in nanoseconds, to ensure we don't back-step in time.
nuclear@0 218 uint64_t LastResultNanos;
nuclear@0 219 };
nuclear@0 220
nuclear@0 221 static PerformanceTimer Win32_PerfTimer;
nuclear@0 222
nuclear@0 223
nuclear@0 224 void PerformanceTimer::Initialize()
nuclear@0 225 {
nuclear@0 226 #if defined(OVR_OS_WIN32) // Desktop Windows only
nuclear@0 227 // The following has the effect of setting the NT timer resolution (NtSetTimerResolution) to 1 millisecond.
nuclear@0 228 MMRESULT mmr = timeBeginPeriod(1);
nuclear@0 229 OVR_ASSERT(TIMERR_NOERROR == mmr);
nuclear@0 230 OVR_UNUSED(mmr);
nuclear@0 231 #endif
nuclear@0 232
nuclear@0 233 InitializeCriticalSection(&TimeCS);
nuclear@0 234 MMTimeWrapCounter = 0;
nuclear@0 235 getFrequency();
nuclear@0 236
nuclear@0 237 #if defined(OVR_OS_WIN32) // Desktop Windows only
nuclear@0 238 // Set Vista flag. On Vista, we can just use QPC() without all the extra work
nuclear@0 239 OSVERSIONINFOEX ver;
nuclear@0 240 ZeroMemory(&ver, sizeof(OSVERSIONINFOEX));
nuclear@0 241 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
nuclear@0 242 ver.dwMajorVersion = 6; // Vista+
nuclear@0 243
nuclear@0 244 DWORDLONG condMask = 0;
nuclear@0 245 VER_SET_CONDITION(condMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
nuclear@0 246
nuclear@0 247 // VerifyVersionInfo returns true if the OS meets the conditions set above
nuclear@0 248 UsingVistaOrLater = VerifyVersionInfo(&ver, VER_MAJORVERSION, condMask) != 0;
nuclear@0 249 #else
nuclear@0 250 UsingVistaOrLater = true;
nuclear@0 251 #endif
nuclear@0 252
nuclear@0 253 OVR_DEBUG_LOG(("PerformanceTimer UsingVistaOrLater = %d", (int)UsingVistaOrLater));
nuclear@0 254
nuclear@0 255 #if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
nuclear@0 256 HMODULE hNtDll = LoadLibrary(L"NtDll.dll");
nuclear@0 257 if (hNtDll)
nuclear@0 258 {
nuclear@0 259 pNtQueryTimerResolution = (NtQueryTimerResolutionType)GetProcAddress(hNtDll, "NtQueryTimerResolution");
nuclear@0 260 //pNtSetTimerResolution = (NtSetTimerResolutionType)GetProcAddress(hNtDll, "NtSetTimerResolution");
nuclear@0 261
nuclear@0 262 if(pNtQueryTimerResolution)
nuclear@0 263 {
nuclear@0 264 ULONG MinimumResolution; // in 100-ns units
nuclear@0 265 ULONG MaximumResolution;
nuclear@0 266 ULONG ActualResolution;
nuclear@0 267 pNtQueryTimerResolution(&MinimumResolution, &MaximumResolution, &ActualResolution);
nuclear@0 268 OVR_DEBUG_LOG(("NtQueryTimerResolution = Min %ld us, Max %ld us, Current %ld us", MinimumResolution / 10, MaximumResolution / 10, ActualResolution / 10));
nuclear@0 269 }
nuclear@0 270
nuclear@0 271 FreeLibrary(hNtDll);
nuclear@0 272 }
nuclear@0 273 #endif
nuclear@0 274 }
nuclear@0 275
nuclear@0 276 void PerformanceTimer::Shutdown()
nuclear@0 277 {
nuclear@0 278 DeleteCriticalSection(&TimeCS);
nuclear@0 279
nuclear@0 280 #if defined(OVR_OS_WIN32) // Desktop Windows only
nuclear@0 281 MMRESULT mmr = timeEndPeriod(1);
nuclear@0 282 OVR_ASSERT(TIMERR_NOERROR == mmr);
nuclear@0 283 OVR_UNUSED(mmr);
nuclear@0 284 #endif
nuclear@0 285 }
nuclear@0 286
nuclear@0 287
nuclear@0 288 uint64_t PerformanceTimer::GetTimeSeconds()
nuclear@0 289 {
nuclear@0 290 if (UsingVistaOrLater)
nuclear@0 291 {
nuclear@0 292 LARGE_INTEGER li;
nuclear@0 293 QueryPerformanceCounter(&li);
nuclear@0 294 OVR_ASSERT(PerfFrequencyInverse != 0); // Initialize should have been called earlier.
nuclear@0 295 return (uint64_t)(li.QuadPart * PerfFrequencyInverse);
nuclear@0 296 }
nuclear@0 297
nuclear@0 298 return (uint64_t)(GetTimeNanos() * .0000000001);
nuclear@0 299 }
nuclear@0 300
nuclear@0 301
nuclear@0 302 double PerformanceTimer::GetTimeSecondsDouble()
nuclear@0 303 {
nuclear@0 304 if (UsingVistaOrLater)
nuclear@0 305 {
nuclear@0 306 LARGE_INTEGER li;
nuclear@0 307 QueryPerformanceCounter(&li);
nuclear@0 308 OVR_ASSERT(PerfFrequencyInverse != 0);
nuclear@0 309 return (li.QuadPart * PerfFrequencyInverse);
nuclear@0 310 }
nuclear@0 311
nuclear@0 312 return (GetTimeNanos() * .0000000001);
nuclear@0 313 }
nuclear@0 314
nuclear@0 315
nuclear@0 316 uint64_t PerformanceTimer::GetTimeNanos()
nuclear@0 317 {
nuclear@0 318 uint64_t resultNanos;
nuclear@0 319 LARGE_INTEGER li;
nuclear@0 320
nuclear@0 321 OVR_ASSERT(PerfFrequencyInverseNanos != 0); // Initialize should have been called earlier.
nuclear@0 322
nuclear@0 323 if (UsingVistaOrLater) // Includes non-desktop platforms
nuclear@0 324 {
nuclear@0 325 // Then we can use QPC() directly without all that extra work
nuclear@0 326 QueryPerformanceCounter(&li);
nuclear@0 327 resultNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
nuclear@0 328 }
nuclear@0 329 else
nuclear@0 330 {
nuclear@0 331 // On Win32 QueryPerformanceFrequency is unreliable due to SMP and
nuclear@0 332 // performance levels, so use this logic to detect wrapping and track
nuclear@0 333 // high bits.
nuclear@0 334 ::EnterCriticalSection(&TimeCS);
nuclear@0 335
nuclear@0 336 // Get raw value and perf counter "At the same time".
nuclear@0 337 QueryPerformanceCounter(&li);
nuclear@0 338
nuclear@0 339 DWORD mmTimeMs = timeGetTime();
nuclear@0 340 if (OldMMTimeMs > mmTimeMs)
nuclear@0 341 MMTimeWrapCounter++;
nuclear@0 342 OldMMTimeMs = mmTimeMs;
nuclear@0 343
nuclear@0 344 // Normalize to nanoseconds.
nuclear@0 345 uint64_t perfCounterNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
nuclear@0 346 uint64_t mmCounterNanos = ((uint64_t(MMTimeWrapCounter) << 32) | mmTimeMs) * 1000000;
nuclear@0 347 if (PerfMinusTicksDeltaNanos == 0)
nuclear@0 348 PerfMinusTicksDeltaNanos = perfCounterNanos - mmCounterNanos;
nuclear@0 349
nuclear@0 350 // Compute result before snapping.
nuclear@0 351 //
nuclear@0 352 // On first call, this evaluates to:
nuclear@0 353 // resultNanos = mmCounterNanos.
nuclear@0 354 // Next call, assuming no wrap:
nuclear@0 355 // resultNanos = prev_mmCounterNanos + (perfCounterNanos - prev_perfCounterNanos).
nuclear@0 356 // After wrap, this would be:
nuclear@0 357 // resultNanos = snapped(prev_mmCounterNanos +/- 1ms) + (perfCounterNanos - prev_perfCounterNanos).
nuclear@0 358 //
nuclear@0 359 resultNanos = perfCounterNanos - PerfMinusTicksDeltaNanos;
nuclear@0 360
nuclear@0 361 // Snap the range so that resultNanos never moves further apart then its target resolution.
nuclear@0 362 // It's better to allow more slack on the high side as timeGetTime() may be updated at sporadically
nuclear@0 363 // larger then 1 ms intervals even when 1 ms resolution is requested.
nuclear@0 364 if (resultNanos > (mmCounterNanos + MMTimerResolutionNanos*2))
nuclear@0 365 {
nuclear@0 366 resultNanos = mmCounterNanos + MMTimerResolutionNanos*2;
nuclear@0 367 if (resultNanos < LastResultNanos)
nuclear@0 368 resultNanos = LastResultNanos;
nuclear@0 369 PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
nuclear@0 370 }
nuclear@0 371 else if (resultNanos < (mmCounterNanos - MMTimerResolutionNanos))
nuclear@0 372 {
nuclear@0 373 resultNanos = mmCounterNanos - MMTimerResolutionNanos;
nuclear@0 374 if (resultNanos < LastResultNanos)
nuclear@0 375 resultNanos = LastResultNanos;
nuclear@0 376 PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
nuclear@0 377 }
nuclear@0 378
nuclear@0 379 LastResultNanos = resultNanos;
nuclear@0 380 ::LeaveCriticalSection(&TimeCS);
nuclear@0 381 }
nuclear@0 382
nuclear@0 383 //Tom's addition, to keep precision
nuclear@0 384 //static uint64_t initial_time = 0;
nuclear@0 385 //if (!initial_time) initial_time = resultNanos;
nuclear@0 386 //resultNanos -= initial_time;
nuclear@0 387 // FIXME: This cannot be used for cross-process timestamps
nuclear@0 388
nuclear@0 389 return resultNanos;
nuclear@0 390 }
nuclear@0 391
nuclear@0 392
nuclear@0 393 //------------------------------------------------------------------------
nuclear@0 394 // *** Timer - Platform Independent functions
nuclear@0 395
nuclear@0 396 // Returns global high-resolution application timer in seconds.
nuclear@0 397 double Timer::GetSeconds()
nuclear@0 398 {
nuclear@0 399 if(useFakeSeconds)
nuclear@0 400 return FakeSeconds;
nuclear@0 401
nuclear@0 402 return Win32_PerfTimer.GetTimeSecondsDouble();
nuclear@0 403 }
nuclear@0 404
nuclear@0 405
nuclear@0 406
nuclear@0 407 // Delegate to PerformanceTimer.
nuclear@0 408 uint64_t Timer::GetTicksNanos()
nuclear@0 409 {
nuclear@0 410 if (useFakeSeconds)
nuclear@0 411 return (uint64_t) (FakeSeconds * NanosPerSecond);
nuclear@0 412
nuclear@0 413 return Win32_PerfTimer.GetTimeNanos();
nuclear@0 414 }
nuclear@0 415 void Timer::initializeTimerSystem()
nuclear@0 416 {
nuclear@0 417 Win32_PerfTimer.Initialize();
nuclear@0 418 }
nuclear@0 419 void Timer::shutdownTimerSystem()
nuclear@0 420 {
nuclear@0 421 Win32_PerfTimer.Shutdown();
nuclear@0 422 }
nuclear@0 423
nuclear@0 424
nuclear@0 425
nuclear@0 426 #elif defined(OVR_OS_MAC)
nuclear@0 427
nuclear@0 428
nuclear@0 429 double Timer::TimeConvertFactorNanos = 0.0;
nuclear@0 430 double Timer::TimeConvertFactorSeconds = 0.0;
nuclear@0 431
nuclear@0 432
nuclear@0 433 //------------------------------------------------------------------------
nuclear@0 434 // *** Standard OS Timer
nuclear@0 435
nuclear@0 436 // Returns global high-resolution application timer in seconds.
nuclear@0 437 double Timer::GetSeconds()
nuclear@0 438 {
nuclear@0 439 if(useFakeSeconds)
nuclear@0 440 return FakeSeconds;
nuclear@0 441
nuclear@0 442 OVR_ASSERT(TimeConvertFactorNanos != 0.0);
nuclear@0 443 return (double)mach_absolute_time() * TimeConvertFactorNanos;
nuclear@0 444 }
nuclear@0 445
nuclear@0 446
nuclear@0 447 uint64_t Timer::GetTicksNanos()
nuclear@0 448 {
nuclear@0 449 if (useFakeSeconds)
nuclear@0 450 return (uint64_t) (FakeSeconds * NanosPerSecond);
nuclear@0 451
nuclear@0 452 OVR_ASSERT(TimeConvertFactorSeconds != 0.0);
nuclear@0 453 return (uint64_t)(mach_absolute_time() * TimeConvertFactorSeconds);
nuclear@0 454 }
nuclear@0 455
nuclear@0 456 void Timer::initializeTimerSystem()
nuclear@0 457 {
nuclear@0 458 mach_timebase_info_data_t timeBase;
nuclear@0 459 mach_timebase_info(&timeBase);
nuclear@0 460 TimeConvertFactorSeconds = ((double)timeBase.numer / (double)timeBase.denom);
nuclear@0 461 TimeConvertFactorNanos = TimeConvertFactorSeconds / 1000000000.0;
nuclear@0 462 }
nuclear@0 463
nuclear@0 464 void Timer::shutdownTimerSystem()
nuclear@0 465 {
nuclear@0 466 // Empty for this platform.
nuclear@0 467 }
nuclear@0 468
nuclear@0 469
nuclear@0 470 #else // Posix platforms (e.g. Linux, BSD Unix)
nuclear@0 471
nuclear@0 472
nuclear@0 473 bool Timer::MonotonicClockAvailable = false;
nuclear@0 474
nuclear@0 475
nuclear@0 476 // Returns global high-resolution application timer in seconds.
nuclear@0 477 double Timer::GetSeconds()
nuclear@0 478 {
nuclear@0 479 if(useFakeSeconds)
nuclear@0 480 return FakeSeconds;
nuclear@0 481
nuclear@0 482 // http://linux/die/netman3/clock_gettime
nuclear@0 483 #if defined(CLOCK_MONOTONIC) // If we can use clock_gettime, which has nanosecond precision...
nuclear@0 484 if(MonotonicClockAvailable)
nuclear@0 485 {
nuclear@0 486 timespec ts;
nuclear@0 487 clock_gettime(CLOCK_MONOTONIC, &ts); // Better to use CLOCK_MONOTONIC than CLOCK_REALTIME.
nuclear@0 488 return static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec) / 1E9;
nuclear@0 489 }
nuclear@0 490 #endif
nuclear@0 491
nuclear@0 492 // We cannot use rdtsc because its frequency changes at runtime.
nuclear@0 493 struct timeval tv;
nuclear@0 494 gettimeofday(&tv, 0);
nuclear@0 495
nuclear@0 496 return static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1E6;
nuclear@0 497 }
nuclear@0 498
nuclear@0 499
nuclear@0 500 uint64_t Timer::GetTicksNanos()
nuclear@0 501 {
nuclear@0 502 if (useFakeSeconds)
nuclear@0 503 return (uint64_t) (FakeSeconds * NanosPerSecond);
nuclear@0 504
nuclear@0 505 #if defined(CLOCK_MONOTONIC) // If we can use clock_gettime, which has nanosecond precision...
nuclear@0 506 if(MonotonicClockAvailable)
nuclear@0 507 {
nuclear@0 508 timespec ts;
nuclear@0 509 clock_gettime(CLOCK_MONOTONIC, &ts);
nuclear@0 510 return ((uint64_t)ts.tv_sec * 1000000000ULL) + (uint64_t)ts.tv_nsec;
nuclear@0 511 }
nuclear@0 512 #endif
nuclear@0 513
nuclear@0 514
nuclear@0 515 // We cannot use rdtsc because its frequency changes at runtime.
nuclear@0 516 uint64_t result;
nuclear@0 517
nuclear@0 518 // Return microseconds.
nuclear@0 519 struct timeval tv;
nuclear@0 520
nuclear@0 521 gettimeofday(&tv, 0);
nuclear@0 522
nuclear@0 523 result = (uint64_t)tv.tv_sec * 1000000;
nuclear@0 524 result += tv.tv_usec;
nuclear@0 525
nuclear@0 526 return result * 1000;
nuclear@0 527 }
nuclear@0 528
nuclear@0 529
nuclear@0 530 void Timer::initializeTimerSystem()
nuclear@0 531 {
nuclear@0 532 #if defined(CLOCK_MONOTONIC)
nuclear@0 533 timespec ts; // We could also check for the availability of CLOCK_MONOTONIC with sysconf(_SC_MONOTONIC_CLOCK)
nuclear@0 534 int result = clock_gettime(CLOCK_MONOTONIC, &ts);
nuclear@0 535 MonotonicClockAvailable = (result == 0);
nuclear@0 536 #endif
nuclear@0 537 }
nuclear@0 538
nuclear@0 539 void Timer::shutdownTimerSystem()
nuclear@0 540 {
nuclear@0 541 // Empty for this platform.
nuclear@0 542 }
nuclear@0 543
nuclear@0 544
nuclear@0 545
nuclear@0 546 #endif // OS-specific
nuclear@0 547
nuclear@0 548
nuclear@0 549
nuclear@0 550 } // OVR
nuclear@0 551