Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix cpu detection #5

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 63 additions & 25 deletions Source/Base/Base/Util/CPUInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#ifdef _WIN32
#include <limits.h>
#include <intrin.h>
#include <windows.h>
#else
#include <stdio.h>
#include <stdint.h>
#endif

Expand All @@ -14,13 +16,13 @@ using namespace std;

class CPUID
{
u32 regs[4];
u32 regs[4] = { 0 };

public:
CPUID(u32 funcId, u32 subFuncId)
{
#ifdef _WIN32
__cpuidex((i32*)regs, (i32)funcId, (i32)subFuncId);
::__cpuidex((i32*)regs, (i32)funcId, (i32)subFuncId);
#else
asm volatile
("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
Expand Down Expand Up @@ -77,6 +79,43 @@ static inline void rtrim(std::string& s)
}).base(), s.end());
}

// source : https://github.com/time-killer-games/ween/blob/db69cafca2222c634a1d3a9e58262b5a2dc8d508/system.cpp#L1553
int CPUInfo::cpu_numcpus() {
if (_numThreads != -1) {
return _numThreads;
}
#if defined(_WIN32)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
_numThreads = sysinfo.dwNumberOfProcessors;
return _numThreads;
// #elif (defined(__APPLE__) && defined(__MACH__))
// int logical_cpus = -1;
// std::size_t len = sizeof(int);
// if (!sysctlbyname("machdep.cpu.thread_count", &logical_cpus, &len, nullptr, 0)) {
// numcpus = logical_cpus;
// }
// return numcpus;
// #elif defined(__linux__)
// char buf[1024];
// const char* result = nullptr;
// FILE* fp = popen("lscpu | grep 'CPU(s):' | uniq | cut -d' ' -f4- | awk 'NR==1{$1=$1;print}'", "r");
// if (fp) {
// if (fgets(buf, sizeof(buf), fp)) {
// buf[strlen(buf) - 1] = '\0';
// result = buf;
// }
// pclose(fp);
// static std::string str;
// str = (result && strlen(result)) ? result : "-1";
// _numThreads = (int)strtol(str.c_str(), nullptr, 10);
// }
// return _numThreads;
#else
return -1;
#endif
}

CPUInfo::CPUInfo()
{
// Get vendor name EAX=0
Expand All @@ -97,13 +136,17 @@ CPUInfo::CPUInfo()
// Get AVX2 instructions availability
CPUID cpuID7(7, 0);
features.isAVX2 = cpuID7.EBX() & AVX2_POS;
features.isAVX512F = cpuID7.EBX() & AVX512F_POS;

string upVId = _vendorId;
for_each(upVId.begin(), upVId.end(), [](char& in)
{
in = ::toupper(in);
});

_numThreadsPerCore = 0;
_numCores = 0;
_numThreads = cpu_numcpus();
// Get num of cores
if (upVId.find("INTEL") != std::string::npos)
{
Expand All @@ -116,12 +159,13 @@ CPUInfo::CPUInfo()

switch (currLevel)
{
case 0x01: _numThreadsPerCore = LVL_CORES & cpuID4.EBX(); break;
case 0x02: _numThreads = LVL_CORES & cpuID4.EBX(); break;
case 0x01: _numThreadsPerCore = LVL_CORES & cpuID4.EBX(); break; // EAX=0xB, ECX=0 - EBX is the number of logical processors (threads) per core
case 0x02: _numThreads = LVL_CORES & cpuID4.EBX(); break; // EAX=0xB, ECX=1 - EBX is the number of logical processors per processor package
default: break;
}
}
_numCores = _numThreads / _numThreadsPerCore;
features.isHTT = _numThreadsPerCore > 1;
}
else
{
Expand Down Expand Up @@ -149,30 +193,24 @@ CPUInfo::CPUInfo()
}
else if (upVId.find("AMD") != std::string::npos)
{
if (HFS >= 1)
{
_numThreads = (cpuID1.EBX() >> 16) & 0xFF;
if (CPUID(0x80000000, 0).EAX() >= 8)
{
_numCores = 1 + (CPUID(0x80000008, 0).ECX() & 0xFF);
}
_numThreadsPerCore = 1 + ((CPUID(0x8000001e, 0).EBX() >> 8) & 0xff);
if (_numThreads > 0 && _numThreadsPerCore > 0) {
_numCores = _numThreads / _numThreadsPerCore;
}
if (features.isHTT)
{
if (!(_numCores > 1))
{
_numCores = 1;
_numThreads = (_numThreads >= 2 ? _numThreads : 2);
else {
if (HFS >= 1) {
if (CPUID(0x80000000, 0).EAX() >= 8) {
_numCores = 1 + (CPUID(0x80000008, 0).ECX() & 0xFF);
}
}
else
{
_numThreadsPerCore = 2;
_numCores = _numThreads / _numThreadsPerCore;
if (features.isHTT) {
if (_numCores < 1) {
_numCores = 1;
}
}
else {
_numCores = 1;
}
}
else
{
_numCores = _numThreads = 1;
}
}
else
Expand Down
10 changes: 7 additions & 3 deletions Source/Base/Base/Util/CPUInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ class CPUInfo
bool IsSSE42() const { return features.isSSE42; }
bool IsAVX() const { return features.isAVX; }
bool IsAVX2() const { return features.isAVX2; }
bool isAVX512F() const { return features.isAVX512F; }
bool IsHyperThreaded() const { return features.isHTT; }

void Print(i32 detailLevel);

private:
CPUInfo();
i32 cpu_numcpus();

private:
static bool _initialized;
Expand All @@ -41,6 +43,7 @@ class CPUInfo
static const u32 SSE42_POS = 0x00100000;
static const u32 AVX_POS = 0x10000000;
static const u32 AVX2_POS = 0x00000020;
static const u32 AVX512F_POS = 1u << 15; // Bit 16
static const u32 LVL_NUM = 0x000000FF;
static const u32 LVL_TYPE = 0x0000FF00;
static const u32 LVL_CORES = 0x0000FFFF;
Expand All @@ -50,9 +53,9 @@ class CPUInfo
std::string _modelName;
std::string _prettyName;

i32 _numThreadsPerCore;
i32 _numCores;
i32 _numThreads;
i32 _numThreadsPerCore = 0;
i32 _numCores = 0;
i32 _numThreads = -1;

struct Features
{
Expand All @@ -64,6 +67,7 @@ class CPUInfo
u8 isSSE42 : 1;
u8 isAVX : 1;
u8 isAVX2 : 1;
u8 isAVX512F : 1;
};

Features features;
Expand Down