steady_clock.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #if defined(_WIN32)
  4. #include <windows.h>
  5. #else
  6. #include <time.h>
  7. #endif
  8. #include "common/steady_clock.h"
  9. namespace Common {
  10. #ifdef _WIN32
  11. static s64 WindowsQueryPerformanceFrequency() {
  12. LARGE_INTEGER frequency;
  13. QueryPerformanceFrequency(&frequency);
  14. return frequency.QuadPart;
  15. }
  16. static s64 WindowsQueryPerformanceCounter() {
  17. LARGE_INTEGER counter;
  18. QueryPerformanceCounter(&counter);
  19. return counter.QuadPart;
  20. }
  21. static s64 GetSystemTimeNS() {
  22. // GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
  23. static constexpr s64 Multiplier = 100;
  24. // Convert Windows epoch to Unix epoch.
  25. static constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL;
  26. FILETIME filetime;
  27. GetSystemTimePreciseAsFileTime(&filetime);
  28. return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) +
  29. static_cast<s64>(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
  30. }
  31. #endif
  32. SteadyClock::time_point SteadyClock::Now() noexcept {
  33. #if defined(_WIN32)
  34. static const auto freq = WindowsQueryPerformanceFrequency();
  35. const auto counter = WindowsQueryPerformanceCounter();
  36. // 10 MHz is a very common QPC frequency on modern PCs.
  37. // Optimizing for this specific frequency can double the performance of
  38. // this function by avoiding the expensive frequency conversion path.
  39. static constexpr s64 TenMHz = 10'000'000;
  40. if (freq == TenMHz) [[likely]] {
  41. static_assert(period::den % TenMHz == 0);
  42. static constexpr s64 Multiplier = period::den / TenMHz;
  43. return time_point{duration{counter * Multiplier}};
  44. }
  45. const auto whole = (counter / freq) * period::den;
  46. const auto part = (counter % freq) * period::den / freq;
  47. return time_point{duration{whole + part}};
  48. #elif defined(__APPLE__)
  49. return time_point{duration{clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)}};
  50. #else
  51. timespec ts;
  52. clock_gettime(CLOCK_MONOTONIC, &ts);
  53. return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
  54. #endif
  55. }
  56. RealTimeClock::time_point RealTimeClock::Now() noexcept {
  57. #if defined(_WIN32)
  58. return time_point{duration{GetSystemTimeNS()}};
  59. #elif defined(__APPLE__)
  60. return time_point{duration{clock_gettime_nsec_np(CLOCK_REALTIME)}};
  61. #else
  62. timespec ts;
  63. clock_gettime(CLOCK_REALTIME, &ts);
  64. return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
  65. #endif
  66. }
  67. }; // namespace Common