summaryrefslogtreecommitdiff
path: root/src/common/x64/cpu_wait.cpp
diff options
context:
space:
mode:
authorGravatar liamwhite2023-03-28 09:09:35 -0400
committerGravatar GitHub2023-03-28 09:09:35 -0400
commit40efd2ab56c2296da4524085a133021f7731e67f (patch)
treea43b51a4056ad7664346a63f145c889da1f59d16 /src/common/x64/cpu_wait.cpp
parentMerge pull request #10002 from german77/log (diff)
parenttelemetry: Add waitpkg instruction (diff)
downloadyuzu-40efd2ab56c2296da4524085a133021f7731e67f.tar.gz
yuzu-40efd2ab56c2296da4524085a133021f7731e67f.tar.xz
yuzu-40efd2ab56c2296da4524085a133021f7731e67f.zip
Merge pull request #9982 from Morph1984/tpause
x64: Make use of waitpkg instructions for power efficient sleeps
Diffstat (limited to 'src/common/x64/cpu_wait.cpp')
-rw-r--r--src/common/x64/cpu_wait.cpp69
1 files changed, 69 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..cfeef6a3d
--- /dev/null
+++ b/src/common/x64/cpu_wait.cpp
@@ -0,0 +1,69 @@
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 eax;
37 u64 edx;
38 asm volatile("lfence\n\t"
39 "rdtsc\n\t"
40 "lfence\n\t"
41 : "=a"(eax), "=d"(edx));
42 return (edx << 32) | eax;
43}
44
45static void TPAUSE() {
46 // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
47 // For reference:
48 // At 1 GHz, 100K cycles is 100us
49 // At 2 GHz, 100K cycles is 50us
50 // At 4 GHz, 100K cycles is 25us
51 static constexpr auto PauseCycles = 100'000;
52 const auto tsc = FencedRDTSC() + PauseCycles;
53 const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
54 const auto edx = static_cast<u32>(tsc >> 32);
55 asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax));
56}
57#endif
58
59void MicroSleep() {
60 static const bool has_waitpkg = GetCPUCaps().waitpkg;
61
62 if (has_waitpkg) {
63 TPAUSE();
64 } else {
65 std::this_thread::yield();
66 }
67}
68
69} // namespace Common::X64