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

@ -135,7 +135,7 @@ void AudioRenderer::ThreadFunc() {
static constexpr char name[]{"AudioRenderer"}; static constexpr char name[]{"AudioRenderer"};
MicroProfileOnThreadCreate(name); MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name); Common::SetCurrentThreadName(name);
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
if (mailbox->ADSPWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) { if (mailbox->ADSPWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) {
LOG_ERROR(Service_Audio, LOG_ERROR(Service_Audio,
"ADSP Audio Renderer -- Failed to receive initialize message from host!"); "ADSP Audio Renderer -- Failed to receive initialize message from host!");

View file

@ -23,6 +23,19 @@ static s64 WindowsQueryPerformanceCounter() {
QueryPerformanceCounter(&counter); QueryPerformanceCounter(&counter);
return counter.QuadPart; 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 #endif
SteadyClock::time_point SteadyClock::Now() noexcept { SteadyClock::time_point SteadyClock::Now() noexcept {
@ -53,4 +66,16 @@ SteadyClock::time_point SteadyClock::Now() noexcept {
#endif #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 }; // namespace Common

View file

@ -20,4 +20,15 @@ struct SteadyClock {
[[nodiscard]] static time_point Now() noexcept; [[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 } // namespace Common

View file

@ -53,11 +53,11 @@ u64 EstimateRDTSCFrequency() {
FencedRDTSC(); FencedRDTSC();
// Get the current time. // Get the current time.
const auto start_time = Common::SteadyClock::Now(); const auto start_time = Common::RealTimeClock::Now();
const u64 tsc_start = FencedRDTSC(); const u64 tsc_start = FencedRDTSC();
// Wait for 250 milliseconds. // Wait for 250 milliseconds.
std::this_thread::sleep_for(std::chrono::milliseconds{250}); 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(); const u64 tsc_end = FencedRDTSC();
// Calculate differences. // Calculate differences.
const u64 timer_diff = static_cast<u64>( const u64 timer_diff = static_cast<u64>(
@ -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 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.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

View file

@ -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

View file

@ -53,7 +53,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) {
static constexpr char name[] = "HostTiming"; static constexpr char name[] = "HostTiming";
MicroProfileOnThreadCreate(name); MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name); Common::SetCurrentThreadName(name);
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
instance.on_thread_init(); instance.on_thread_init();
instance.ThreadLoop(); instance.ThreadLoop();
MicroProfileOnThreadExit(); MicroProfileOnThreadExit();

View file

@ -192,7 +192,7 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
} }
MicroProfileOnThreadCreate(name.c_str()); MicroProfileOnThreadCreate(name.c_str());
Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadName(name.c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::High); Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
auto& data = core_data[core]; auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber(); data.host_context = Common::Fiber::ThreadToFiber();

View file

@ -26,7 +26,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
} }
CommonHeader header{}; CommonHeader header{};
header.timestamp = core_timing.GetCPUTicks(); header.timestamp = core_timing.GetGlobalTimeNs().count();
header.total_entry_count = 17; header.total_entry_count = 17;
header.entry_count = 0; header.entry_count = 0;
header.last_entry_index = 0; header.last_entry_index = 0;

View file

@ -32,7 +32,7 @@ void Controller_Touchscreen::OnInit() {}
void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnRelease() {}
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory->touch_screen_lifo.buffer_count = 0; shared_memory->touch_screen_lifo.buffer_count = 0;
@ -85,7 +85,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
const auto active_fingers_count = const auto active_fingers_count =
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 tick = core_timing.GetCPUTicks(); const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state; const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1; next_state.sampling_number = last_entry.sampling_number + 1;
@ -102,8 +102,8 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
touch_entry.delta_time = tick - active_fingers[id].last_touch; touch_entry.delta_time = timestamp - active_fingers[id].last_touch;
fingers[active_fingers[id].id].last_touch = tick; fingers[active_fingers[id].id].last_touch = timestamp;
touch_entry.finger = active_fingers[id].id; touch_entry.finger = active_fingers[id].id;
touch_entry.attribute.raw = active_fingers[id].attribute.raw; touch_entry.attribute.raw = active_fingers[id].attribute.raw;
} else { } else {

View file

@ -126,8 +126,8 @@ double PerfStats::GetLastFrameTimeScale() const {
} }
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) { void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
if (!Settings::values.use_speed_limit.GetValue() || if (Settings::values.use_multi_core.GetValue() ||
Settings::values.use_multi_core.GetValue()) { !Settings::values.use_speed_limit.GetValue()) {
return; return;
} }

View file

@ -25,7 +25,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
SCOPE_EXIT({ MicroProfileOnThreadExit(); }); SCOPE_EXIT({ MicroProfileOnThreadExit(); });
Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadName(name.c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::High); Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
system.RegisterHostThread(); system.RegisterHostThread();
auto current_context = context.Acquire(); auto current_context = context.Acquire();