aboutsummaryrefslogtreecommitdiff
path: root/src/common/steady_clock.cpp
blob: c516a12d65e2eb4611cd5817a589fac447a6134b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#if defined(_WIN32)
#include <windows.h>
#else
#include <time.h>
#endif

#include "common/steady_clock.h"

namespace Common {

#ifdef _WIN32
static s64 WindowsQueryPerformanceFrequency() {
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);
    return frequency.QuadPart;
}

static s64 WindowsQueryPerformanceCounter() {
    LARGE_INTEGER counter;
    QueryPerformanceCounter(&counter);
    return counter.QuadPart;
}

static s64 GetSystemTimeNS() {
    static auto pf = (decltype(&GetSystemTimePreciseAsFileTime))(void*)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "GetSystemTimePreciseAsFileTime"); // Windows 8+
    if (pf) {
        // GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
        constexpr s64 Multiplier = 100;
        // Convert Windows epoch to Unix epoch.
        constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL;
        FILETIME filetime;
        pf(&filetime);
        return Multiplier * ((s64(filetime.dwHighDateTime) << 32) + s64(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
    } else {
        // Only Windows XP and below error out here
        LARGE_INTEGER ticks;
        QueryPerformanceCounter(&ticks);
        return ticks.QuadPart;
    }
}
#endif

SteadyClock::time_point SteadyClock::Now() noexcept {
#if defined(_WIN32)
    static const auto timer_freq = WindowsQueryPerformanceFrequency();
    const auto counter = WindowsQueryPerformanceCounter();
    const auto whole = (counter / timer_freq) * period::den;
    const auto part = (counter % timer_freq) * period::den / timer_freq;
    return time_point{duration{whole + part}};
#elif defined(__APPLE__)
    return time_point{duration{clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)}};
#else
    timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
#endif
}

RealTimeClock::time_point RealTimeClock::Now() noexcept {
#if defined(_WIN32)
    return time_point{duration{GetSystemTimeNS()}};
#elif defined(__APPLE__)
    return time_point{duration{clock_gettime_nsec_np(CLOCK_REALTIME)}};
#else
    timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
#endif
}

}; // namespace Common