common: Implement a high resolution steady clock
This implementation provides a consistent, high performance, and high resolution clock where/when std::chrono::steady_clock does not provide sufficient precision.
This commit is contained in:
parent
ce8f4da638
commit
bd09c82521
|
@ -113,6 +113,8 @@ add_library(common STATIC
|
||||||
socket_types.h
|
socket_types.h
|
||||||
spin_lock.cpp
|
spin_lock.cpp
|
||||||
spin_lock.h
|
spin_lock.h
|
||||||
|
steady_clock.cpp
|
||||||
|
steady_clock.h
|
||||||
stream.cpp
|
stream.cpp
|
||||||
stream.h
|
stream.h
|
||||||
string_util.cpp
|
string_util.cpp
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SteadyClock::time_point SteadyClock::Now() noexcept {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
static const auto freq = WindowsQueryPerformanceFrequency();
|
||||||
|
const auto counter = WindowsQueryPerformanceCounter();
|
||||||
|
|
||||||
|
// 10 MHz is a very common QPC frequency on modern PCs.
|
||||||
|
// Optimizing for this specific frequency can double the performance of
|
||||||
|
// this function by avoiding the expensive frequency conversion path.
|
||||||
|
static constexpr s64 TenMHz = 10'000'000;
|
||||||
|
|
||||||
|
if (freq == TenMHz) [[likely]] {
|
||||||
|
static_assert(period::den % TenMHz == 0);
|
||||||
|
static constexpr s64 Multiplier = period::den / TenMHz;
|
||||||
|
return time_point{duration{counter * Multiplier}};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto whole = (counter / freq) * period::den;
|
||||||
|
const auto part = (counter % freq) * period::den / 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace Common
|
|
@ -0,0 +1,23 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
struct SteadyClock {
|
||||||
|
using rep = s64;
|
||||||
|
using period = std::nano;
|
||||||
|
using duration = std::chrono::nanoseconds;
|
||||||
|
using time_point = std::chrono::time_point<SteadyClock>;
|
||||||
|
|
||||||
|
static constexpr bool is_steady = true;
|
||||||
|
|
||||||
|
[[nodiscard]] static time_point Now() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Common
|
Reference in New Issue