Skip to content

Commit

Permalink
x86: Use OS to detect core count.
Browse files Browse the repository at this point in the history
On Windows and Linux, at least.  This should be more reliable than what we
used before.
  • Loading branch information
unknownbrackets committed Sep 14, 2018
1 parent 6d0ed4a commit 9351146
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 2 deletions.
112 changes: 112 additions & 0 deletions Common/CPUDetect.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
#endif #endif


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


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


#if defined(_WIN32) && !defined(__MINGW32__) #if defined(_WIN32) && !defined(__MINGW32__)
Expand Down Expand Up @@ -97,6 +100,28 @@ CPUInfo::CPUInfo() {
Detect(); 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 // Detects the various cpu features
void CPUInfo::Detect() { void CPUInfo::Detect() {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
Expand Down Expand Up @@ -260,6 +285,93 @@ void CPUInfo::Detect() {
num_cores = (cpu_id[2] & 0xFF) + 1; 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;
#endif
} }


// Turn the cpu info into a string we can show // Turn the cpu info into a string we can show
Expand Down
7 changes: 5 additions & 2 deletions Common/FileUtil.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -106,11 +106,14 @@ std::string ResolvePath(const std::string &path) {
typedef DWORD (WINAPI *getFinalPathNameByHandleW_f)(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags); typedef DWORD (WINAPI *getFinalPathNameByHandleW_f)(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);
static getFinalPathNameByHandleW_f getFinalPathNameByHandleW = nullptr; static getFinalPathNameByHandleW_f getFinalPathNameByHandleW = nullptr;


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


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

0 comments on commit 9351146

Please sign in to comment.