summaryrefslogtreecommitdiffstats
path: root/src/common/x64
diff options
context:
space:
mode:
authorMorph <39850852+Morph1984@users.noreply.github.com>2023-03-22 02:28:38 +0100
committerMorph <39850852+Morph1984@users.noreply.github.com>2023-03-27 23:45:22 +0200
commit27c33ab73fd03d659654c49967a081214daf6ac2 (patch)
treece139e675dce91045a05fb3d5e44803af9931d0e /src/common/x64
parentx64: cpu_detect: Add detection of waitpkg instructions (diff)
downloadyuzu-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')
-rw-r--r--src/common/x64/cpu_wait.cpp72
-rw-r--r--src/common/x64/cpu_wait.h10
2 files changed, 82 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
diff --git a/src/common/x64/cpu_wait.h b/src/common/x64/cpu_wait.h
new file mode 100644
index 000000000..99d3757a7
--- /dev/null
+++ b/src/common/x64/cpu_wait.h
@@ -0,0 +1,10 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+namespace Common::X64 {
+
+void MicroSleep();
+
+} // namespace Common::X64