diff options
author | Morph <39850852+Morph1984@users.noreply.github.com> | 2023-03-22 02:28:38 +0100 |
---|---|---|
committer | Morph <39850852+Morph1984@users.noreply.github.com> | 2023-03-27 23:45:22 +0200 |
commit | 27c33ab73fd03d659654c49967a081214daf6ac2 (patch) | |
tree | ce139e675dce91045a05fb3d5e44803af9931d0e /src/common/x64/cpu_wait.cpp | |
parent | x64: cpu_detect: Add detection of waitpkg instructions (diff) | |
download | yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.tar yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.tar.gz yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.tar.bz2 yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.tar.lz yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.tar.xz yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.tar.zst yuzu-27c33ab73fd03d659654c49967a081214daf6ac2.zip |
Diffstat (limited to 'src/common/x64/cpu_wait.cpp')
-rw-r--r-- | src/common/x64/cpu_wait.cpp | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp new file mode 100644 index 000000000..1fab0bfe8 --- /dev/null +++ b/src/common/x64/cpu_wait.cpp @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <thread> + +#ifdef _MSC_VER +#include <intrin.h> +#endif + +#include "common/x64/cpu_detect.h" +#include "common/x64/cpu_wait.h" + +namespace Common::X64 { + +#ifdef _MSC_VER +__forceinline static u64 FencedRDTSC() { + _mm_lfence(); + _ReadWriteBarrier(); + const u64 result = __rdtsc(); + _mm_lfence(); + _ReadWriteBarrier(); + return result; +} + +__forceinline static void TPAUSE() { + // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. + // For reference: + // At 1 GHz, 100K cycles is 100us + // At 2 GHz, 100K cycles is 50us + // At 4 GHz, 100K cycles is 25us + static constexpr auto PauseCycles = 100'000; + _tpause(0, FencedRDTSC() + PauseCycles); +} +#else +static u64 FencedRDTSC() { + u64 result; + asm volatile("lfence\n\t" + "rdtsc\n\t" + "shl $32, %%rdx\n\t" + "or %%rdx, %0\n\t" + "lfence" + : "=a"(result) + : + : "rdx", "memory", "cc"); + return result; +} + +static void TPAUSE() { + // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. + // For reference: + // At 1 GHz, 100K cycles is 100us + // At 2 GHz, 100K cycles is 50us + // At 4 GHz, 100K cycles is 25us + static constexpr auto PauseCycles = 100'000; + const auto tsc = FencedRDTSC() + PauseCycles; + const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); + const auto edx = static_cast<u32>(tsc >> 32); + asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax)); +} +#endif + +void MicroSleep() { + static const bool has_waitpkg = GetCPUCaps().waitpkg; + + if (has_waitpkg) { + TPAUSE(); + } else { + std::this_thread::yield(); + } +} + +} // namespace Common::X64 |