native_clock: Re-adjust the RDTSC frequency
The RDTSC frequency reported by CPUID is not accurate to its true frequency. We will spawn a separate thread to calculate the true RDTSC frequency after a measurement period of 30 seconds has elapsed.
This commit is contained in:
		| @@ -72,13 +72,29 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||||||
|                          u64 rtsc_frequency_) |                          u64 rtsc_frequency_) | ||||||
|     : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ |     : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{ | ||||||
|                                                                                rtsc_frequency_} { |                                                                                rtsc_frequency_} { | ||||||
|  |     // Thread to re-adjust the RDTSC frequency after 30 seconds has elapsed. | ||||||
|  |     time_sync_thread = std::jthread{[this](std::stop_token token) { | ||||||
|  |         // Get the current time. | ||||||
|  |         const auto start_time = Common::SteadyClock::Now(); | ||||||
|  |         const u64 tsc_start = FencedRDTSC(); | ||||||
|  |         // Wait for 30 seconds. | ||||||
|  |         if (!Common::StoppableTimedWait(token, std::chrono::seconds{30})) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         const auto end_time = Common::SteadyClock::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.last_measure = FencedRDTSC(); | ||||||
|     time_point.inner.accumulated_ticks = 0U; |     time_point.inner.accumulated_ticks = 0U; | ||||||
|     ns_rtsc_factor = GetFixedPoint64Factor(NS_RATIO, rtsc_frequency); |     CalculateAndSetFactors(); | ||||||
|     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); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| u64 NativeClock::GetRTSC() { | u64 NativeClock::GetRTSC() { | ||||||
| @@ -138,6 +154,14 @@ u64 NativeClock::GetCPUCycles() { | |||||||
|     return MultiplyHigh(rtsc_value, cpu_rtsc_factor); |     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 X64 | ||||||
|  |  | ||||||
| } // namespace Common | } // namespace Common | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include "common/polyfill_thread.h" | ||||||
| #include "common/wall_clock.h" | #include "common/wall_clock.h" | ||||||
|  |  | ||||||
| namespace Common { | namespace Common { | ||||||
| @@ -28,6 +29,8 @@ public: | |||||||
| private: | private: | ||||||
|     u64 GetRTSC(); |     u64 GetRTSC(); | ||||||
|  |  | ||||||
|  |     void CalculateAndSetFactors(); | ||||||
|  |  | ||||||
|     union alignas(16) TimePoint { |     union alignas(16) TimePoint { | ||||||
|         TimePoint() : pack{} {} |         TimePoint() : pack{} {} | ||||||
|         u128 pack{}; |         u128 pack{}; | ||||||
| @@ -47,6 +50,8 @@ private: | |||||||
|     u64 ms_rtsc_factor{}; |     u64 ms_rtsc_factor{}; | ||||||
|  |  | ||||||
|     u64 rtsc_frequency; |     u64 rtsc_frequency; | ||||||
|  |  | ||||||
|  |     std::jthread time_sync_thread; | ||||||
| }; | }; | ||||||
| } // namespace X64 | } // namespace X64 | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user