Merge pull request #9917 from Morph1984/the-real-time

native_clock: Re-adjust the RDTSC frequency to its real frequency
This commit is contained in:
liamwhite 2023-03-10 13:55:11 -05:00 committed by GitHub
commit 021af4fd00
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 83 additions and 18 deletions

View file

@ -23,6 +23,19 @@ static s64 WindowsQueryPerformanceCounter() {
QueryPerformanceCounter(&counter);
return counter.QuadPart;
}
static s64 GetSystemTimeNS() {
// GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
static constexpr s64 Multiplier = 100;
// Convert Windows epoch to Unix epoch.
static constexpr s64 WindowsEpochToUnixEpochNS = 0x19DB1DED53E8000LL;
FILETIME filetime;
GetSystemTimePreciseAsFileTime(&filetime);
return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) +
static_cast<s64>(filetime.dwLowDateTime)) -
WindowsEpochToUnixEpochNS;
}
#endif
SteadyClock::time_point SteadyClock::Now() noexcept {
@ -53,4 +66,16 @@ SteadyClock::time_point SteadyClock::Now() noexcept {
#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

View file

@ -20,4 +20,15 @@ struct SteadyClock {
[[nodiscard]] static time_point Now() noexcept;
};
struct RealTimeClock {
using rep = s64;
using period = std::nano;
using duration = std::chrono::nanoseconds;
using time_point = std::chrono::time_point<RealTimeClock>;
static constexpr bool is_steady = false;
[[nodiscard]] static time_point Now() noexcept;
};
} // namespace Common

View file

@ -53,11 +53,11 @@ u64 EstimateRDTSCFrequency() {
FencedRDTSC();
// Get the current time.
const auto start_time = Common::SteadyClock::Now();
const auto start_time = Common::RealTimeClock::Now();
const u64 tsc_start = FencedRDTSC();
// Wait for 250 milliseconds.
std::this_thread::sleep_for(std::chrono::milliseconds{250});
const auto end_time = Common::SteadyClock::Now();
const auto end_time = Common::RealTimeClock::Now();
const u64 tsc_end = FencedRDTSC();
// Calculate differences.
const u64 timer_diff = static_cast<u64>(
@ -72,13 +72,29 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen
u64 rtsc_frequency_)
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
rtsc_frequency_} {
// Thread to re-adjust the RDTSC frequency after 10 seconds has elapsed.
time_sync_thread = std::jthread{[this](std::stop_token token) {
// Get the current time.
const auto start_time = Common::RealTimeClock::Now();
const u64 tsc_start = FencedRDTSC();
// Wait for 10 seconds.
if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) {
return;
}
const auto end_time = Common::RealTimeClock::Now();
const u64 tsc_end = FencedRDTSC();
// Calculate differences.
const u64 timer_diff = static_cast<u64>(
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
const u64 tsc_diff = tsc_end - tsc_start;
const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
rtsc_frequency = tsc_freq;
CalculateAndSetFactors();
}};
time_point.inner.last_measure = FencedRDTSC();
time_point.inner.accumulated_ticks = 0U;
ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency);
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
CalculateAndSetFactors();
}
u64 NativeClock::GetRTSC() {
@ -138,6 +154,14 @@ u64 NativeClock::GetCPUCycles() {
return MultiplyHigh(rtsc_value, cpu_rtsc_factor);
}
void NativeClock::CalculateAndSetFactors() {
ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency);
us_rtsc_factor = GetFixedPoint64Factor(US_RATIO, rtsc_frequency);
ms_rtsc_factor = GetFixedPoint64Factor(MS_RATIO, rtsc_frequency);
clock_rtsc_factor = GetFixedPoint64Factor(emulated_clock_frequency, rtsc_frequency);
cpu_rtsc_factor = GetFixedPoint64Factor(emulated_cpu_frequency, rtsc_frequency);
}
} // namespace X64
} // namespace Common

View file

@ -3,6 +3,7 @@
#pragma once
#include "common/polyfill_thread.h"
#include "common/wall_clock.h"
namespace Common {
@ -28,6 +29,8 @@ public:
private:
u64 GetRTSC();
void CalculateAndSetFactors();
union alignas(16) TimePoint {
TimePoint() : pack{} {}
u128 pack{};
@ -47,6 +50,8 @@ private:
u64 ms_rtsc_factor{};
u64 rtsc_frequency;
std::jthread time_sync_thread;
};
} // namespace X64