summaryrefslogtreecommitdiffstats
path: root/src/common/x64
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/x64')
-rw-r--r--src/common/x64/cpu_detect.cpp1
-rw-r--r--src/common/x64/cpu_detect.h1
-rw-r--r--src/common/x64/cpu_wait.cpp69
-rw-r--r--src/common/x64/cpu_wait.h10
-rw-r--r--src/common/x64/native_clock.cpp13
5 files changed, 86 insertions, 8 deletions
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index e54383a4a..72ed6e96c 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -144,6 +144,7 @@ static CPUCaps Detect() {
caps.bmi2 = Common::Bit<8>(cpu_id[1]);
caps.sha = Common::Bit<29>(cpu_id[1]);
+ caps.waitpkg = Common::Bit<5>(cpu_id[2]);
caps.gfni = Common::Bit<8>(cpu_id[2]);
__cpuidex(cpu_id, 0x00000007, 0x00000001);
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h
index ca8db19d6..8253944d6 100644
--- a/src/common/x64/cpu_detect.h
+++ b/src/common/x64/cpu_detect.h
@@ -67,6 +67,7 @@ struct CPUCaps {
bool pclmulqdq : 1;
bool popcnt : 1;
bool sha : 1;
+ bool waitpkg : 1;
};
/**
diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp
new file mode 100644
index 000000000..cfeef6a3d
--- /dev/null
+++ b/src/common/x64/cpu_wait.cpp
@@ -0,0 +1,69 @@
+// 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 eax;
+ u64 edx;
+ asm volatile("lfence\n\t"
+ "rdtsc\n\t"
+ "lfence\n\t"
+ : "=a"(eax), "=d"(edx));
+ return (edx << 32) | eax;
+}
+
+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
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 76c66e7ee..277b00662 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -27,16 +27,13 @@ __forceinline static u64 FencedRDTSC() {
}
#else
static u64 FencedRDTSC() {
- u64 result;
+ u64 eax;
+ u64 edx;
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;
+ "lfence\n\t"
+ : "=a"(eax), "=d"(edx));
+ return (edx << 32) | eax;
}
#endif