summaryrefslogtreecommitdiff
path: root/src/common/x64/cpu_detect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/x64/cpu_detect.cpp')
-rw-r--r--src/common/x64/cpu_detect.cpp59
1 files changed, 56 insertions, 3 deletions
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp
index 1a27532d4..e54383a4a 100644
--- a/src/common/x64/cpu_detect.cpp
+++ b/src/common/x64/cpu_detect.cpp
@@ -4,14 +4,27 @@
4 4
5#include <array> 5#include <array>
6#include <cstring> 6#include <cstring>
7#include <fstream>
7#include <iterator> 8#include <iterator>
9#include <optional>
8#include <string_view> 10#include <string_view>
11#include <thread>
12#include <vector>
9#include "common/bit_util.h" 13#include "common/bit_util.h"
10#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/logging/log.h"
11#include "common/x64/cpu_detect.h" 16#include "common/x64/cpu_detect.h"
12 17
18#ifdef _WIN32
19#include <windows.h>
20#endif
21
13#ifdef _MSC_VER 22#ifdef _MSC_VER
14#include <intrin.h> 23#include <intrin.h>
24
25static inline u64 xgetbv(u32 index) {
26 return _xgetbv(index);
27}
15#else 28#else
16 29
17#if defined(__DragonFly__) || defined(__FreeBSD__) 30#if defined(__DragonFly__) || defined(__FreeBSD__)
@@ -39,12 +52,11 @@ static inline void __cpuid(int info[4], u32 function_id) {
39} 52}
40 53
41#define _XCR_XFEATURE_ENABLED_MASK 0 54#define _XCR_XFEATURE_ENABLED_MASK 0
42static inline u64 _xgetbv(u32 index) { 55static inline u64 xgetbv(u32 index) {
43 u32 eax, edx; 56 u32 eax, edx;
44 __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); 57 __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
45 return ((u64)edx << 32) | eax; 58 return ((u64)edx << 32) | eax;
46} 59}
47
48#endif // _MSC_VER 60#endif // _MSC_VER
49 61
50namespace Common { 62namespace Common {
@@ -107,7 +119,7 @@ static CPUCaps Detect() {
107 // - Is the XSAVE bit set in CPUID? 119 // - Is the XSAVE bit set in CPUID?
108 // - XGETBV result has the XCR bit set. 120 // - XGETBV result has the XCR bit set.
109 if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) { 121 if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) {
110 if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { 122 if ((xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
111 caps.avx = true; 123 caps.avx = true;
112 if (Common::Bit<12>(cpu_id[2])) 124 if (Common::Bit<12>(cpu_id[2]))
113 caps.fma = true; 125 caps.fma = true;
@@ -192,4 +204,45 @@ const CPUCaps& GetCPUCaps() {
192 return caps; 204 return caps;
193} 205}
194 206
207std::optional<int> GetProcessorCount() {
208#if defined(_WIN32)
209 // Get the buffer length.
210 DWORD length = 0;
211 GetLogicalProcessorInformation(nullptr, &length);
212 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
213 LOG_ERROR(Frontend, "Failed to query core count.");
214 return std::nullopt;
215 }
216 std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(
217 length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
218 // Now query the core count.
219 if (!GetLogicalProcessorInformation(buffer.data(), &length)) {
220 LOG_ERROR(Frontend, "Failed to query core count.");
221 return std::nullopt;
222 }
223 return static_cast<int>(
224 std::count_if(buffer.cbegin(), buffer.cend(), [](const auto& proc_info) {
225 return proc_info.Relationship == RelationProcessorCore;
226 }));
227#elif defined(__unix__)
228 const int thread_count = std::thread::hardware_concurrency();
229 std::ifstream smt("/sys/devices/system/cpu/smt/active");
230 char state = '0';
231 if (smt) {
232 smt.read(&state, sizeof(state));
233 }
234 switch (state) {
235 case '0':
236 return thread_count;
237 case '1':
238 return thread_count / 2;
239 default:
240 return std::nullopt;
241 }
242#else
243 // Shame on you
244 return std::nullopt;
245#endif
246}
247
195} // namespace Common 248} // namespace Common