diff options
| author | lizzie <lizzie@eden-emu.dev> | 2026-05-15 22:06:38 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-05-15 22:06:38 +0200 |
| commit | 975aa4e2f2128b865ec5738c2704c8d37af6a7b9 (patch) | |
| tree | feec00d92e12a8c8644ea1b18769d9b225a75c73 /src/common | |
| parent | a1f9e68f46c729a49eeaec1a81d9ac26145d2509 (diff) | |
[common] remove ptr indirection on WallClock (#3864)
also devirtualizes manually since compiler doesn't do it with LTO
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3864
Reviewed-by: crueter <crueter@eden-emu.dev>
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/common/arm64/native_clock.cpp | 87 | ||||
| -rw-r--r-- | src/common/arm64/native_clock.h | 45 | ||||
| -rw-r--r-- | src/common/wall_clock.cpp | 205 | ||||
| -rw-r--r-- | src/common/wall_clock.h | 45 | ||||
| -rw-r--r-- | src/common/x64/native_clock.cpp | 46 | ||||
| -rw-r--r-- | src/common/x64/native_clock.h | 38 |
7 files changed, 197 insertions, 275 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index fb2bdda146..e3b662e008 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -184,8 +184,6 @@ if(ARCHITECTURE_x86_64) x64/cpu_detect.h x64/cpu_wait.cpp x64/cpu_wait.h - x64/native_clock.cpp - x64/native_clock.h x64/rdtsc.cpp x64/rdtsc.h x64/xbyak_abi.h @@ -193,10 +191,6 @@ if(ARCHITECTURE_x86_64) target_link_libraries(common PRIVATE xbyak::xbyak) endif() -if(HAS_NCE) - target_sources(common PRIVATE arm64/native_clock.cpp arm64/native_clock.h) -endif() - if(MSVC) target_compile_definitions( common diff --git a/src/common/arm64/native_clock.cpp b/src/common/arm64/native_clock.cpp deleted file mode 100644 index 76ffb74bab..0000000000 --- a/src/common/arm64/native_clock.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#ifdef ANDROID -#include <sys/system_properties.h> -#endif -#include "common/arm64/native_clock.h" - -namespace Common::Arm64 { - -namespace { - -NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) { - return (static_cast<NativeClock::FactorType>(num) << 64) / den; -} - -u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) { - return static_cast<u64>((m * factor) >> 64); -} - -} // namespace - -NativeClock::NativeClock() { - const u64 host_cntfrq = GetHostCNTFRQ(); - ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq); - us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq); - ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq); - guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq); - gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); -} - -std::chrono::nanoseconds NativeClock::GetTimeNS() const { - return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)}; -} - -std::chrono::microseconds NativeClock::GetTimeUS() const { - return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)}; -} - -std::chrono::milliseconds NativeClock::GetTimeMS() const { - return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)}; -} - -s64 NativeClock::GetCNTPCT() const { - return MultiplyHigh(GetUptime(), guest_cntfrq_factor); -} - -s64 NativeClock::GetGPUTick() const { - return MultiplyHigh(GetUptime(), gputick_cntfrq_factor); -} - -s64 NativeClock::GetUptime() const { - s64 cntvct_el0 = 0; - asm volatile("dsb ish\n\t" - "mrs %[cntvct_el0], cntvct_el0\n\t" - "dsb ish\n\t" - : [cntvct_el0] "=r"(cntvct_el0)); - return cntvct_el0; -} - -bool NativeClock::IsNative() const { - return true; -} - -s64 NativeClock::GetHostCNTFRQ() { - u64 cntfrq_el0 = 0; - std::string_view board{""}; -#ifdef ANDROID - char buffer[PROP_VALUE_MAX]; - int len{__system_property_get("ro.product.board", buffer)}; - board = std::string_view(buffer, static_cast<size_t>(len)); -#endif - if (board == "s5e9925") { // Exynos 2200 - cntfrq_el0 = 25600000; - } else if (board == "exynos2100") { // Exynos 2100 - cntfrq_el0 = 26000000; - } else if (board == "exynos9810") { // Exynos 9810 - cntfrq_el0 = 26000000; - } else if (board == "s5e8825") { // Exynos 1280 - cntfrq_el0 = 26000000; - } else { - asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); - } - return cntfrq_el0; -} - -} // namespace Common::Arm64 diff --git a/src/common/arm64/native_clock.h b/src/common/arm64/native_clock.h deleted file mode 100644 index 94bc1882e0..0000000000 --- a/src/common/arm64/native_clock.h +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/wall_clock.h" - -namespace Common::Arm64 { - -class NativeClock final : public WallClock { -public: - explicit NativeClock(); - - std::chrono::nanoseconds GetTimeNS() const override; - - std::chrono::microseconds GetTimeUS() const override; - - std::chrono::milliseconds GetTimeMS() const override; - - s64 GetCNTPCT() const override; - - s64 GetGPUTick() const override; - - s64 GetUptime() const override; - - bool IsNative() const override; - - static s64 GetHostCNTFRQ(); - -public: - using FactorType = unsigned __int128; - - FactorType GetGuestCNTFRQFactor() const { - return guest_cntfrq_factor; - } - -private: - FactorType ns_cntfrq_factor; - FactorType us_cntfrq_factor; - FactorType ms_cntfrq_factor; - FactorType guest_cntfrq_factor; - FactorType gputick_cntfrq_factor; -}; - -} // namespace Common::Arm64 diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 4f9c240905..bff9e7b4f4 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -1,77 +1,196 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/steady_clock.h" +#include "common/uint128.h" #include "common/wall_clock.h" +#ifdef __ANDROID__ +#include <sys/system_properties.h> +#endif #ifdef ARCHITECTURE_x86_64 #include "common/x64/cpu_detect.h" -#include "common/x64/native_clock.h" #include "common/x64/rdtsc.h" #endif -#ifdef HAS_NCE -#include "common/arm64/native_clock.h" -#endif namespace Common { -class StandardWallClock final : public WallClock { -public: - explicit StandardWallClock() {} +#if defined(ARCHITECTURE_x86_64) +WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept + : invariant{invariant_} + , rdtsc_frequency{rdtsc_frequency_} + , ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_)} + , us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_)} + , ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_)} + , cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_)} + , gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_)} +{} - std::chrono::nanoseconds GetTimeNS() const override { - return std::chrono::duration_cast<std::chrono::nanoseconds>( - std::chrono::system_clock::now().time_since_epoch()); - } +std::chrono::nanoseconds WallClock::GetTimeNS() const { + if (invariant) + return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()); + return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)}; +} - std::chrono::microseconds GetTimeUS() const override { - return std::chrono::duration_cast<std::chrono::microseconds>( - std::chrono::system_clock::now().time_since_epoch()); - } +std::chrono::microseconds WallClock::GetTimeUS() const { + if (invariant) + return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()); + return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)}; +} - std::chrono::milliseconds GetTimeMS() const override { - return std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::system_clock::now().time_since_epoch()); - } +std::chrono::milliseconds WallClock::GetTimeMS() const { + if (invariant) + return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()); + return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)}; +} - s64 GetCNTPCT() const override { +s64 WallClock::GetCNTPCT() const { + if (invariant) return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; - } + return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor); +} - s64 GetGPUTick() const override { +s64 WallClock::GetGPUTick() const { + if (invariant) return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; - } + return MultiplyHigh(GetUptime(), gputick_rdtsc_factor); +} - s64 GetUptime() const override { - return std::chrono::duration_cast<std::chrono::nanoseconds>( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - } +s64 WallClock::GetUptime() const { + if (invariant) + return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); + return s64(Common::X64::FencedRDTSC()); +} - bool IsNative() const override { +bool WallClock::IsNative() const { + if (invariant) return false; - } -}; + return true; +} +#elif defined(HAS_NCE) +namespace { -std::unique_ptr<WallClock> CreateOptimalClock() { -#if defined(ARCHITECTURE_x86_64) - const auto& caps = GetCPUCaps(); +[[nodiscard]] WallClock::FactorType GetFixedPointFactor(u64 num, u64 den) noexcept { + return (WallClock::FactorType(num) << 64) / den; +} + +[[nodiscard]] u64 MultiplyHigh(u64 m, WallClock::FactorType factor) noexcept { + return static_cast<u64>((m * factor) >> 64); +} - if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) { - return std::make_unique<X64::NativeClock>(caps.tsc_frequency); +[[nodiscard]] s64 GetHostCNTFRQ() noexcept { + u64 cntfrq_el0 = 0; +#ifdef ANDROID + std::string_view board{""}; + char buffer[PROP_VALUE_MAX]; + int len{__system_property_get("ro.product.board", buffer)}; + board = std::string_view(buffer, static_cast<size_t>(len)); + if (board == "s5e9925") { // Exynos 2200 + cntfrq_el0 = 25600000; + } else if (board == "exynos2100") { // Exynos 2100 + cntfrq_el0 = 26000000; + } else if (board == "exynos9810") { // Exynos 9810 + cntfrq_el0 = 26000000; + } else if (board == "s5e8825") { // Exynos 1280 + cntfrq_el0 = 26000000; } else { - // Fallback to StandardWallClock if the hardware TSC - // - Is not invariant - // - Is not more precise than 1 GHz (1ns resolution) - return std::make_unique<StandardWallClock>(); + asm volatile("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); } + return cntfrq_el0; +#else + asm volatile("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); + return cntfrq_el0; +#endif +} + +} // namespace + +WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept { + const u64 host_cntfrq = std::max<u64>(GetHostCNTFRQ(), 1); + ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq); + us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq); + ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq); + guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq); + gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); +} + +std::chrono::nanoseconds WallClock::GetTimeNS() const { + return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)}; +} + +std::chrono::microseconds WallClock::GetTimeUS() const { + return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)}; +} + +std::chrono::milliseconds WallClock::GetTimeMS() const { + return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)}; +} + +s64 WallClock::GetCNTPCT() const { + return MultiplyHigh(GetUptime(), guest_cntfrq_factor); +} + +s64 WallClock::GetGPUTick() const { + return MultiplyHigh(GetUptime(), gputick_cntfrq_factor); +} + +s64 WallClock::GetUptime() const { + s64 cntvct_el0 = 0; + asm volatile( + "dsb ish\n\t" + "mrs %[cntvct_el0], cntvct_el0\n\t" + "dsb ish\n\t" + : [cntvct_el0] "=r"(cntvct_el0) + ); + return cntvct_el0; +} + +bool WallClock::IsNative() const { + return true; +} +#else +WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept {} + +std::chrono::nanoseconds WallClock::GetTimeNS() const { + return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()); +} + +std::chrono::microseconds WallClock::GetTimeUS() const { + return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()); +} + +std::chrono::milliseconds WallClock::GetTimeMS() const { + return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()); +} + +s64 WallClock::GetCNTPCT() const { + return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; +} + +s64 WallClock::GetGPUTick() const { + return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; +} + +s64 WallClock::GetUptime() const { + return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); +} + +bool WallClock::IsNative() const { + return false; +} +#endif + +WallClock CreateOptimalClock() noexcept { +#if defined(ARCHITECTURE_x86_64) + auto const& caps = GetCPUCaps(); + return WallClock(!(caps.invariant_tsc && caps.tsc_frequency >= std::nano::den), std::max<u64>(caps.tsc_frequency, 1)); #elif defined(HAS_NCE) - return std::make_unique<Arm64::NativeClock>(); + return WallClock(false, 1); #else - return std::make_unique<StandardWallClock>(); + return WallClock(true, 1); #endif } diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 7ad6536930..6a6d56a610 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project @@ -20,28 +20,28 @@ public: static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz static constexpr u64 CPUTickFreq = 1'020'000'000; // T210/4 A57 CPU Tick Frequency = 1020.0 MHz - virtual ~WallClock() = default; + explicit WallClock(bool invariant, u64 rdtsc_frequency_) noexcept; /// @returns The time in nanoseconds since the construction of this clock. - virtual std::chrono::nanoseconds GetTimeNS() const = 0; + std::chrono::nanoseconds GetTimeNS() const; /// @returns The time in microseconds since the construction of this clock. - virtual std::chrono::microseconds GetTimeUS() const = 0; + std::chrono::microseconds GetTimeUS() const; /// @returns The time in milliseconds since the construction of this clock. - virtual std::chrono::milliseconds GetTimeMS() const = 0; + std::chrono::milliseconds GetTimeMS() const; /// @returns The guest CNTPCT ticks since the construction of this clock. - virtual s64 GetCNTPCT() const = 0; + s64 GetCNTPCT() const; /// @returns The guest GPU ticks since the construction of this clock. - virtual s64 GetGPUTick() const = 0; + s64 GetGPUTick() const; /// @returns The raw host timer ticks since an indeterminate epoch. - virtual s64 GetUptime() const = 0; + s64 GetUptime() const; /// @returns Whether the clock directly uses the host's hardware clock. - virtual bool IsNative() const = 0; + bool IsNative() const; static inline u64 NSToCNTPCT(u64 ns) { return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; @@ -85,8 +85,33 @@ protected: using CPUTickToUsRatio = std::ratio<std::micro::den, CPUTickFreq>; using CPUTickToCNTPCTRatio = std::ratio<CNTFRQ, CPUTickFreq>; using CPUTickToGPUTickRatio = std::ratio<GPUTickFreq, CPUTickFreq>; + +#if defined(ARCHITECTURE_x86_64) + bool invariant; + u64 rdtsc_frequency; + u64 ns_rdtsc_factor; + u64 us_rdtsc_factor; + u64 ms_rdtsc_factor; + u64 cntpct_rdtsc_factor; + u64 gputick_rdtsc_factor; +#elif defined(HAS_NCE) +public: + using FactorType = unsigned __int128; + + FactorType GetGuestCNTFRQFactor() const { + return guest_cntfrq_factor; + } +protected: + FactorType ns_cntfrq_factor; + FactorType us_cntfrq_factor; + FactorType ms_cntfrq_factor; + FactorType guest_cntfrq_factor; + FactorType gputick_cntfrq_factor; +#else + +#endif }; -[[nodiscard]] std::unique_ptr<WallClock> CreateOptimalClock(); +[[nodiscard]] WallClock CreateOptimalClock() noexcept; } // namespace Common diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp deleted file mode 100644 index d2d27fafea..0000000000 --- a/src/common/x64/native_clock.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/uint128.h" -#include "common/x64/native_clock.h" -#include "common/x64/rdtsc.h" - -namespace Common::X64 { - -NativeClock::NativeClock(u64 rdtsc_frequency_) - : rdtsc_frequency{rdtsc_frequency_}, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, - rdtsc_frequency)}, - us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, - ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, - cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, - gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} - -std::chrono::nanoseconds NativeClock::GetTimeNS() const { - return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)}; -} - -std::chrono::microseconds NativeClock::GetTimeUS() const { - return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)}; -} - -std::chrono::milliseconds NativeClock::GetTimeMS() const { - return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)}; -} - -s64 NativeClock::GetCNTPCT() const { - return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor); -} - -s64 NativeClock::GetGPUTick() const { - return MultiplyHigh(GetUptime(), gputick_rdtsc_factor); -} - -s64 NativeClock::GetUptime() const { - return static_cast<s64>(FencedRDTSC()); -} - -bool NativeClock::IsNative() const { - return true; -} - -} // namespace Common::X64 diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h deleted file mode 100644 index b2629b0311..0000000000 --- a/src/common/x64/native_clock.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/wall_clock.h" - -namespace Common::X64 { - -class NativeClock final : public WallClock { -public: - explicit NativeClock(u64 rdtsc_frequency_); - - std::chrono::nanoseconds GetTimeNS() const override; - - std::chrono::microseconds GetTimeUS() const override; - - std::chrono::milliseconds GetTimeMS() const override; - - s64 GetCNTPCT() const override; - - s64 GetGPUTick() const override; - - s64 GetUptime() const override; - - bool IsNative() const override; - -private: - u64 rdtsc_frequency; - - u64 ns_rdtsc_factor; - u64 us_rdtsc_factor; - u64 ms_rdtsc_factor; - u64 cntpct_rdtsc_factor; - u64 gputick_rdtsc_factor; -}; - -} // namespace Common::X64 |
