mirror of
https://git.suyu.dev/suyu/suyu
synced 2024-10-31 04:17:52 +00:00
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:
commit
021af4fd00
11 changed files with 83 additions and 18 deletions
|
@ -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!");
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue