|
|
|
@ -4,14 +4,27 @@
|
|
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include <string_view>
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include "common/bit_util.h"
|
|
|
|
|
#include "common/common_types.h"
|
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
|
#include "common/x64/cpu_detect.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
#include <intrin.h>
|
|
|
|
|
|
|
|
|
|
static inline u64 xgetbv(u32 index) {
|
|
|
|
|
return _xgetbv(index);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
|
|
|
@ -39,12 +52,11 @@ static inline void __cpuid(int info[4], u32 function_id) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define _XCR_XFEATURE_ENABLED_MASK 0
|
|
|
|
|
static inline u64 _xgetbv(u32 index) {
|
|
|
|
|
static inline u64 xgetbv(u32 index) {
|
|
|
|
|
u32 eax, edx;
|
|
|
|
|
__asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
|
|
|
|
|
return ((u64)edx << 32) | eax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // _MSC_VER
|
|
|
|
|
|
|
|
|
|
namespace Common {
|
|
|
|
@ -107,7 +119,7 @@ static CPUCaps Detect() {
|
|
|
|
|
// - Is the XSAVE bit set in CPUID?
|
|
|
|
|
// - XGETBV result has the XCR bit set.
|
|
|
|
|
if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) {
|
|
|
|
|
if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
|
|
|
|
|
if ((xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
|
|
|
|
|
caps.avx = true;
|
|
|
|
|
if (Common::Bit<12>(cpu_id[2]))
|
|
|
|
|
caps.fma = true;
|
|
|
|
@ -192,4 +204,45 @@ const CPUCaps& GetCPUCaps() {
|
|
|
|
|
return caps;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<int> GetProcessorCount() {
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
// Get the buffer length.
|
|
|
|
|
DWORD length = 0;
|
|
|
|
|
GetLogicalProcessorInformation(nullptr, &length);
|
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
|
LOG_ERROR(Frontend, "Failed to query core count.");
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(
|
|
|
|
|
length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
|
|
|
|
|
// Now query the core count.
|
|
|
|
|
if (!GetLogicalProcessorInformation(buffer.data(), &length)) {
|
|
|
|
|
LOG_ERROR(Frontend, "Failed to query core count.");
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
return static_cast<int>(
|
|
|
|
|
std::count_if(buffer.cbegin(), buffer.cend(), [](const auto& proc_info) {
|
|
|
|
|
return proc_info.Relationship == RelationProcessorCore;
|
|
|
|
|
}));
|
|
|
|
|
#elif defined(__unix__)
|
|
|
|
|
const int thread_count = std::thread::hardware_concurrency();
|
|
|
|
|
std::ifstream smt("/sys/devices/system/cpu/smt/active");
|
|
|
|
|
char state = '0';
|
|
|
|
|
if (smt) {
|
|
|
|
|
smt.read(&state, sizeof(state));
|
|
|
|
|
}
|
|
|
|
|
switch (state) {
|
|
|
|
|
case '0':
|
|
|
|
|
return thread_count;
|
|
|
|
|
case '1':
|
|
|
|
|
return thread_count / 2;
|
|
|
|
|
default:
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
// Shame on you
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Common
|
|
|
|
|