summaryrefslogtreecommitdiff
path: root/src/common/x64/cpu_wait.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/x64/cpu_wait.cpp')
-rw-r--r--src/common/x64/cpu_wait.cpp72
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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <thread>
5
6#ifdef _MSC_VER
7#include <intrin.h>
8#endif
9
10#include "common/x64/cpu_detect.h"
11#include "common/x64/cpu_wait.h"
12
13namespace Common::X64 {
14
15#ifdef _MSC_VER
16__forceinline static u64 FencedRDTSC() {
17 _mm_lfence();
18 _ReadWriteBarrier();
19 const u64 result = __rdtsc();
20 _mm_lfence();
21 _ReadWriteBarrier();
22 return result;
23}
24
25__forceinline static void TPAUSE() {
26 // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
27 // For reference:
28 // At 1 GHz, 100K cycles is 100us
29 // At 2 GHz, 100K cycles is 50us
30 // At 4 GHz, 100K cycles is 25us
31 static constexpr auto PauseCycles = 100'000;
32 _tpause(0, FencedRDTSC() + PauseCycles);
33}
34#else
35static u64 FencedRDTSC() {
36 u64 result;
37 asm volatile("lfence\n\t"
38 "rdtsc\n\t"
39 "shl $32, %%rdx\n\t"
40 "or %%rdx, %0\n\t"
41 "lfence"
42 : "=a"(result)
43 :
44 : "rdx", "memory", "cc");
45 return result;
46}
47
48static void TPAUSE() {
49 // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
50 // For reference:
51 // At 1 GHz, 100K cycles is 100us
52 // At 2 GHz, 100K cycles is 50us
53 // At 4 GHz, 100K cycles is 25us
54 static constexpr auto PauseCycles = 100'000;
55 const auto tsc = FencedRDTSC() + PauseCycles;
56 const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
57 const auto edx = static_cast<u32>(tsc >> 32);
58 asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax));
59}
60#endif
61
62void MicroSleep() {
63 static const bool has_waitpkg = GetCPUCaps().waitpkg;
64
65 if (has_waitpkg) {
66 TPAUSE();
67 } else {
68 std::this_thread::yield();
69 }
70}
71
72} // namespace Common::X64