From 975aa4e2f2128b865ec5738c2704c8d37af6a7b9 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 15 May 2026 22:06:38 +0200 Subject: [common] remove ptr indirection on WallClock (#3864) also devirtualizes manually since compiler doesn't do it with LTO Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3864 Reviewed-by: crueter --- src/core/core_timing.cpp | 155 ++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 88 deletions(-) (limited to 'src/core/core_timing.cpp') diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index b216dc2094..6738a0d73d 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -57,15 +57,51 @@ void CoreTiming::Initialize(std::function&& on_thread_init_) { Reset(); on_thread_init = std::move(on_thread_init_); event_fifo_id = 0; - shutting_down = false; cpu_ticks = 0; if (is_multicore) { - timer_thread.emplace([](CoreTiming& instance) { + timer_thread = std::jthread([this](std::stop_token stop_token) { Common::SetCurrentThreadName("HostTiming"); Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - instance.on_thread_init(); - instance.ThreadLoop(); - }, std::ref(*this)); + on_thread_init(); + has_started = true; + while (!stop_token.stop_requested()) { + while (!paused && !stop_token.stop_requested()) { + paused_set = false; + if (auto const next_time = Advance(); next_time) { + // There are more events left in the queue, wait until the next event. + auto wait_time = *next_time - GetGlobalTimeNs().count(); + if (wait_time > 0) { +#ifdef _WIN32 + while (!paused && !event.IsSet() && wait_time > 0) { + wait_time = *next_time - GetGlobalTimeNs().count(); + if (wait_time >= timer_resolution_ns) { + Common::Windows::SleepForOneTick(); + } else { +#ifdef ARCHITECTURE_x86_64 + Common::X64::MicroSleep(); +#else + std::this_thread::yield(); +#endif + } + } + if (event.IsSet()) + event.Reset(); +#else + event.WaitFor(std::chrono::nanoseconds(wait_time)); +#endif + } + } else { + // Queue is empty, wait until another event is scheduled and signals us to + // continue. + wait_set = true; + event.Wait(); + } + wait_set = false; + } + paused_set = true; + pause_event.Wait(); + } + }); } } @@ -90,7 +126,7 @@ void CoreTiming::SyncPause(bool is_paused) { } Pause(is_paused); - if (timer_thread) { + if (timer_thread.joinable()) { if (!is_paused) { pause_event.Set(); } @@ -190,33 +226,22 @@ void CoreTiming::ResetTicks() { } u64 CoreTiming::GetClockTicks() const { - u64 fres; - if (is_multicore) [[likely]] { - fres = clock->GetCNTPCT(); - } else { - fres = Common::WallClock::CPUTickToCNTPCT(cpu_ticks); + u64 fres = is_multicore ? clock.GetCNTPCT() : Common::WallClock::CPUTickToCNTPCT(cpu_ticks); + if (auto const overclock = Settings::values.fast_cpu_time.GetValue(); overclock != Settings::CpuClock::Off) { + fres = u64(f64(fres) * (1.7 + 0.3 * u32(overclock))); } - - const auto overclock = Settings::values.fast_cpu_time.GetValue(); - - if (overclock != Settings::CpuClock::Off) { - fres = (u64) ((double) fres * (1.7 + 0.3 * u32(overclock))); - } - - if (Settings::values.sync_core_speed.GetValue()) { - const auto ticks = double(fres); - const auto speed_limit = double(Settings::SpeedLimit())*0.01; - return u64(ticks/speed_limit); - } else { - return fres; - } + if (::Settings::values.sync_core_speed.GetValue()) { + auto const ticks = f64(fres); + auto const speed_limit = f64(Settings::SpeedLimit()) * 0.01; + return u64(ticks / speed_limit); + } + return fres; } u64 CoreTiming::GetGPUTicks() const { - if (is_multicore) [[likely]] { - return clock->GetGPUTick(); - } - return Common::WallClock::CPUTickToGPUTick(cpu_ticks); + return is_multicore + ? clock.GetGPUTick() + : Common::WallClock::CPUTickToGPUTick(cpu_ticks); } std::optional CoreTiming::Advance() { @@ -278,75 +303,29 @@ std::optional CoreTiming::Advance() { } } -void CoreTiming::ThreadLoop() { - has_started = true; - while (!shutting_down) { - while (!paused) { - paused_set = false; - const auto next_time = Advance(); - if (next_time) { - // There are more events left in the queue, wait until the next event. - auto wait_time = *next_time - GetGlobalTimeNs().count(); - if (wait_time > 0) { -#ifdef _WIN32 - while (!paused && !event.IsSet() && wait_time > 0) { - wait_time = *next_time - GetGlobalTimeNs().count(); - if (wait_time >= timer_resolution_ns) { - Common::Windows::SleepForOneTick(); - } else { -#ifdef ARCHITECTURE_x86_64 - Common::X64::MicroSleep(); -#else - std::this_thread::yield(); -#endif - } - } - - if (event.IsSet()) { - event.Reset(); - } -#else - event.WaitFor(std::chrono::nanoseconds(wait_time)); -#endif - } - } else { - // Queue is empty, wait until another event is scheduled and signals us to - // continue. - wait_set = true; - event.Wait(); - } - wait_set = false; - } - - paused_set = true; - pause_event.Wait(); - } -} - void CoreTiming::Reset() { paused = true; - shutting_down = true; pause_event.Set(); event.Set(); - if (timer_thread) { - timer_thread->join(); + if (timer_thread.joinable()) { + timer_thread.request_stop(); + timer_thread.join(); } - timer_thread.reset(); has_started = false; } -std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { - if (is_multicore) [[likely]] { - return clock->GetTimeNS(); - } - return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)}; +/// @brief Returns current time in nanoseconds. +std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const noexcept { + return is_multicore + ? clock.GetTimeNS() + : std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)}; } -std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { - if (is_multicore) [[likely]] { - return clock->GetTimeUS(); - } - return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)}; +/// @brief Returns current time in microseconds. +std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const noexcept { + return is_multicore + ? clock.GetTimeUS() + : std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)}; } #ifdef _WIN32 -- cgit v1.2.3