Skip to content
Permalink
Browse files

Merge pull request #11388 from unknownbrackets/cpuinfo

Use OS to detect core count
  • Loading branch information...
hrydgard committed Sep 14, 2018
2 parents 6d0ed4a + 36f298d commit a1e33fd9f5d0f1f3e1816cc264bae002772ea919
Showing with 130 additions and 2 deletions.
  1. +125 −0 Common/CPUDetect.cpp
  2. +5 −2 Common/FileUtil.cpp
@@ -17,17 +17,23 @@

#if defined(_M_IX86) || defined(_M_X64)

#include "ppsspp_config.h"
#ifdef __ANDROID__
#include <sys/stat.h>
#include <fcntl.h>
#elif PPSSPP_PLATFORM(MAC)
#include <sys/sysctl.h>
#endif

#include <memory.h>
#include <set>
#include "base/logging.h"
#include "base/basictypes.h"
#include "file/file_util.h"

#include "Common.h"
#include "CPUDetect.h"
#include "FileUtil.h"
#include "StringUtils.h"

#if defined(_WIN32) && !defined(__MINGW32__)
@@ -97,6 +103,28 @@ CPUInfo::CPUInfo() {
Detect();
}

static std::vector<int> ParseCPUList(const std::string &filename) {
std::string data;
std::vector<int> results;

if (readFileToString(true, filename.c_str(), data)) {
std::vector<std::string> ranges;
SplitString(data, ',', ranges);
for (auto range : ranges) {
int low = 0, high = 0;
int parts = sscanf(range.c_str(), "%d-%d", &low, &high);
if (parts == 1) {
high = low;
}
for (int i = low; i <= high; ++i) {
results.push_back(i);
}
}
}

return results;
}

// Detects the various cpu features
void CPUInfo::Detect() {
memset(this, 0, sizeof(*this));
@@ -260,6 +288,103 @@ void CPUInfo::Detect() {
num_cores = (cpu_id[2] & 0xFF) + 1;
}
}

// The above only gets valid info for the active processor.
// Let's rely on OS APIs for accurate information, if available, below.

#if PPSSPP_PLATFORM(WINDOWS)
#if !PPSSPP_PLATFORM(UWP)
typedef BOOL (WINAPI *getLogicalProcessorInformationEx_f)(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer, PDWORD ReturnedLength);
auto getLogicalProcessorInformationEx = (getLogicalProcessorInformationEx_f)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetLogicalProcessorInformationEx");
#else
void *getLogicalProcessorInformationEx = nullptr;
#endif

if (getLogicalProcessorInformationEx) {
#if !PPSSPP_PLATFORM(UWP)
DWORD len = 0;
getLogicalProcessorInformationEx(RelationAll, nullptr, &len);
auto processors = new uint8_t[len];
if (getLogicalProcessorInformationEx(RelationAll, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)processors, &len)) {
num_cores = 0;
logical_cpu_count = 0;
auto p = processors;
while (p < processors + len) {
const auto &processor = *(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)p;
if (processor.Relationship == RelationProcessorCore) {
num_cores++;
for (int j = 0; j < processor.Processor.GroupCount; ++j) {
const auto &mask = processor.Processor.GroupMask[j].Mask;
for (int i = 0; i < sizeof(mask) * 8; ++i) {
logical_cpu_count += (mask >> i) & 1;
}
}
}
p += processor.Size;
}
}
delete [] processors;
#endif
} else {
DWORD len = 0;
const DWORD sz = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
GetLogicalProcessorInformation(nullptr, &len);
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> processors;
processors.resize((len + sz - 1) / sz);
if (GetLogicalProcessorInformation(&processors[0], &len)) {
num_cores = 0;
logical_cpu_count = 0;
for (auto processor : processors) {
if (processor.Relationship == RelationProcessorCore) {
num_cores++;
for (int i = 0; i < sizeof(processor.ProcessorMask) * 8; ++i) {
logical_cpu_count += (processor.ProcessorMask >> i) & 1;
}
}
}
}
}

// This seems to be the count per core. Hopefully all cores are the same, but we counted each above.
logical_cpu_count /= num_cores;
#elif PPSSPP_PLATFORM(LINUX)
if (File::Exists("/sys/devices/system/cpu/present")) {
// This may not count unplugged cores, but at least it's a best guess.
// Also, this assumes the CPU cores are heterogeneous (e.g. all cores could be active simultaneously.)
num_cores = 0;
logical_cpu_count = 0;

std::set<int> counted_cores;
auto present = ParseCPUList("/sys/devices/system/cpu/present");
for (int id : present) {
logical_cpu_count++;

if (counted_cores.count(id) == 0) {
num_cores++;
counted_cores.insert(id);

// Also count any thread siblings as counted.
auto threads = ParseCPUList(StringFromFormat("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", id));
for (int mark_id : threads) {
counted_cores.insert(mark_id);
}
}
}
}

// This seems to be the count per core. Hopefully all cores are the same, but we counted each above.
logical_cpu_count /= num_cores;
#elif PPSSPP_PLATFORM(MAC)
int num = 0;
size_t sz = sizeof(num);
if (sysctlbyname("hw.physicalcpu_max", &num, &sz, nullptr, 0) == 0) {
num_cores = num;
sz = sizeof(num);
if (sysctlbyname("hw.logicalcpu_max", &num, &sz, nullptr, 0) == 0) {
logical_cpu_count = num / num_cores;
}
}
#endif
}

// Turn the cpu info into a string we can show
@@ -106,11 +106,14 @@ std::string ResolvePath(const std::string &path) {
typedef DWORD (WINAPI *getFinalPathNameByHandleW_f)(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
static getFinalPathNameByHandleW_f getFinalPathNameByHandleW = nullptr;

#if PPSSPP_PLATFORM(UWP)
getFinalPathNameByHandleW = &GetFinalPathNameByHandleW;
#else
if (!getFinalPathNameByHandleW) {
// We leak this, but that's okay since the process should hold onto this DLL for the entire lifetime anyway.
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
getFinalPathNameByHandleW = (getFinalPathNameByHandleW_f)GetProcAddress(kernel32, "GetFinalPathNameByHandleW");
}
#endif

static const int BUF_SIZE = 32768;
wchar_t *buf = new wchar_t[BUF_SIZE];

0 comments on commit a1e33fd

Please sign in to comment.
You can’t perform that action at this time.