From dcd13a7566340e80c042da7f626f9747ac71b8a7 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 4 Mar 2023 21:44:31 -0500 Subject: [PATCH 1/7] 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. --- src/common/x64/native_clock.cpp | 34 ++++++++++++++++++++++++++++----- src/common/x64/native_clock.h | 5 +++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index bc1a973b06..c11590291b 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -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 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( + std::chrono::duration_cast(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 diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index 38ae7a4625..03ca291d80 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h @@ -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 From 6f9918552c6a1d56a21fa544a7776cd1e5af7bc4 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 4 Mar 2023 22:59:04 -0500 Subject: [PATCH 2/7] steady_clock: Introduce a real time clock --- src/common/steady_clock.cpp | 25 +++++++++++++++++++++++++ src/common/steady_clock.h | 11 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/common/steady_clock.cpp b/src/common/steady_clock.cpp index 0d5908aa79..7828591960 100644 --- a/src/common/steady_clock.cpp +++ b/src/common/steady_clock.cpp @@ -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(filetime.dwHighDateTime) << 32) + + static_cast(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 diff --git a/src/common/steady_clock.h b/src/common/steady_clock.h index 9497cf865d..dbd0e25131 100644 --- a/src/common/steady_clock.h +++ b/src/common/steady_clock.h @@ -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; + + static constexpr bool is_steady = false; + + [[nodiscard]] static time_point Now() noexcept; +}; + } // namespace Common From c27a626b5bc1aa2ae593f44b0a7c10ae3c979291 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 5 Mar 2023 02:42:48 -0500 Subject: [PATCH 3/7] native_clock: Use RealTimeClock instead of SteadyClock We want to synchronize RDTSC to real time. --- src/common/x64/native_clock.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index c11590291b..3f90343a52 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -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( @@ -75,13 +75,13 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen // 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 auto start_time = Common::RealTimeClock::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 auto end_time = Common::RealTimeClock::Now(); const u64 tsc_end = FencedRDTSC(); // Calculate differences. const u64 timer_diff = static_cast( From d718eab351292e3c4d168738f9cd543044c335bc Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 5 Mar 2023 20:54:13 -0500 Subject: [PATCH 4/7] native_clock: Wait for 10 seconds instead of 30 It was experimentally determined to be sufficient. --- src/common/x64/native_clock.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 3f90343a52..76c66e7eed 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -72,13 +72,13 @@ 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 30 seconds has elapsed. + // 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 30 seconds. - if (!Common::StoppableTimedWait(token, std::chrono::seconds{30})) { + // Wait for 10 seconds. + if (!Common::StoppableTimedWait(token, std::chrono::seconds{10})) { return; } const auto end_time = Common::RealTimeClock::Now(); From 3053a6237525ae870791eff480812016a3d4ec1e Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 5 Mar 2023 22:27:03 -0500 Subject: [PATCH 5/7] core: Promote CPU/GPU threads to time critical And also demote Audren and CoreTiming to High thread priority. --- src/audio_core/renderer/adsp/audio_renderer.cpp | 2 +- src/core/core_timing.cpp | 2 +- src/core/cpu_manager.cpp | 2 +- src/video_core/gpu_thread.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index 78c15629bb..0e437e7799 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp @@ -135,7 +135,7 @@ void AudioRenderer::ThreadFunc() { static constexpr char name[]{"AudioRenderer"}; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); - Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); + Common::SetCurrentThreadPriority(Common::ThreadPriority::High); if (mailbox->ADSPWaitMessage() != RenderMessage::AudioRenderer_InitializeOK) { LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!"); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 742cfb9967..cd4df45228 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -53,7 +53,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) { static constexpr char name[] = "HostTiming"; MicroProfileOnThreadCreate(name); Common::SetCurrentThreadName(name); - Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); + Common::SetCurrentThreadPriority(Common::ThreadPriority::High); instance.on_thread_init(); instance.ThreadLoop(); MicroProfileOnThreadExit(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 04a11f4447..980bb97f95 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -192,7 +192,7 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) { } MicroProfileOnThreadCreate(name.c_str()); Common::SetCurrentThreadName(name.c_str()); - Common::SetCurrentThreadPriority(Common::ThreadPriority::High); + Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); auto& data = core_data[core]; data.host_context = Common::Fiber::ThreadToFiber(); diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 9c103c0d42..050b11874e 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -25,7 +25,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system, SCOPE_EXIT({ MicroProfileOnThreadExit(); }); Common::SetCurrentThreadName(name.c_str()); - Common::SetCurrentThreadPriority(Common::ThreadPriority::High); + Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); system.RegisterHostThread(); auto current_context = context.Acquire(); From 1073346c7f5541056b7ea88a701ad2e8e91a89b2 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Tue, 7 Mar 2023 19:24:13 -0500 Subject: [PATCH 6/7] hid: Use nanosecond timestamps instead of ticks --- src/core/hle/service/hid/controllers/stubbed.cpp | 2 +- src/core/hle/service/hid/controllers/touchscreen.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index df9ee0c3f4..9e2f3ab212 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -26,7 +26,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) { } CommonHeader header{}; - header.timestamp = core_timing.GetCPUTicks(); + header.timestamp = core_timing.GetGlobalTimeNs().count(); header.total_entry_count = 17; header.entry_count = 0; header.last_entry_index = 0; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index d90a4e732d..3ef91df4bc 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -32,7 +32,7 @@ void Controller_Touchscreen::OnInit() {} void Controller_Touchscreen::OnRelease() {} 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()) { 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 = static_cast(std::distance(active_fingers.begin(), end_iter)); - const u64 tick = core_timing.GetCPUTicks(); + const u64 timestamp = static_cast(core_timing.GetGlobalTimeNs().count()); const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state; 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_y = Settings::values.touchscreen.diameter_y; touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; - touch_entry.delta_time = tick - active_fingers[id].last_touch; - fingers[active_fingers[id].id].last_touch = tick; + touch_entry.delta_time = timestamp - active_fingers[id].last_touch; + fingers[active_fingers[id].id].last_touch = timestamp; touch_entry.finger = active_fingers[id].id; touch_entry.attribute.raw = active_fingers[id].attribute.raw; } else { From 67560296c697914f6bf809dca2ab555038b19aa2 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Tue, 7 Mar 2023 23:11:01 -0500 Subject: [PATCH 7/7] perf_stats: Check multicore first SpeedLimiting is SC only. Since MC is performance oriented we should check for it first to skip checking use_speed_limit. --- src/core/perf_stats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index f09c176f81..1231c0dc87 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -126,8 +126,8 @@ double PerfStats::GetLastFrameTimeScale() const { } void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) { - if (!Settings::values.use_speed_limit.GetValue() || - Settings::values.use_multi_core.GetValue()) { + if (Settings::values.use_multi_core.GetValue() || + !Settings::values.use_speed_limit.GetValue()) { return; }