diff options
Diffstat (limited to 'src/common/x64/cpu_detect.cpp')
| -rw-r--r-- | src/common/x64/cpu_detect.cpp | 59 |
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 | |||
| 25 | static 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 |
| 42 | static inline u64 _xgetbv(u32 index) { | 55 | static 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 | ||
| 50 | namespace Common { | 62 | namespace 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 | ||
| 207 | std::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 |