mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-14 07:00:43 +02:00
Merge pull request #5033 from Sonicadvance1/warkwark
CPUID: Fixes APICID for processor count calculation.
This commit is contained in:
2 files changed
+113
-8
No files matched your search
@@ -14,6 +14,7 @@ $end_info$
|
||||
#include <FEXCore/Core/CPUID.h>
|
||||
#include <FEXCore/Core/HostFeatures.h>
|
||||
#include <FEXCore/Utils/FileLoading.h>
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXHeaderUtils/Syscalls.h>
|
||||
|
||||
@@ -443,10 +444,10 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_01h(uint32_t Leaf) const {
|
||||
|
||||
Res.eax = FAMILY_IDENTIFIER;
|
||||
|
||||
Res.ebx = 0 | // Brand index
|
||||
(8 << 8) | // Cache line size in bytes
|
||||
(Cores << 16) | // Number of addressable IDs for the logical cores in the physical CPU
|
||||
(0 << 24); // Local APIC ID
|
||||
Res.ebx = 0 | // Brand index
|
||||
(8 << 8) | // Cache line size in bytes
|
||||
(Cores << 16) | // Number of addressable IDs for the logical cores in the physical CPU
|
||||
(GetCPUID() << 24); // Local APIC ID
|
||||
|
||||
Res.ecx = (1 << 0) | // SSE3
|
||||
(CTX->HostFeatures.SupportsPMULL_128Bit << 1) | // PCLMULQDQ
|
||||
@@ -509,7 +510,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_01h(uint32_t Leaf) const {
|
||||
(1 << 25) | // SSE
|
||||
(1 << 26) | // SSE2
|
||||
(0 << 27) | // Self Snoop
|
||||
(1 << 28) | // Max APIC IDs reserved field is valid
|
||||
(0 << 28) | // (HTT) Max APIC IDs reserved field is valid
|
||||
(1 << 29) | // Thermal monitor
|
||||
(0 << 30) | // Reserved
|
||||
(0 << 31); // Pending break enable
|
||||
@@ -1096,9 +1097,9 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0008h(uint32_t Leaf) con
|
||||
(CTX->HostFeatures.SupportsCLZERO << 0); // CLZERO support
|
||||
|
||||
uint32_t CoreCount = Cores - 1;
|
||||
Res.ecx = (0 << 16) | // PerfTscSize: Performance timestamp count size
|
||||
((uint32_t)std::log2(CoreCount + 1) << 12) | // ApicIdSize: Number of bits in ApicID
|
||||
(CoreCount << 0); // Count count subtract one
|
||||
Res.ecx = (0 << 16) | // PerfTscSize: Performance timestamp count size
|
||||
(std::bit_ceil(Cores) << 12) | // ApicIdSize: Number of bits in ApicID
|
||||
(CoreCount << 0); // Count count subtract one
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <cpuid.h>
|
||||
#include <optional>
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
|
||||
TEST_CASE("cpu count - libraries") {
|
||||
const auto hw_concurrency = std::thread::hardware_concurrency();
|
||||
CHECK(hw_concurrency == sysconf(_SC_NPROCESSORS_CONF));
|
||||
CHECK(hw_concurrency == sysconf(_SC_NPROCESSORS_ONLN));
|
||||
}
|
||||
|
||||
struct core_info {
|
||||
uint32_t local_apicid;
|
||||
uint32_t max_addressible_ids;
|
||||
uint32_t cores;
|
||||
uint32_t threads;
|
||||
bool HTT;
|
||||
};
|
||||
|
||||
struct cpuid_fn {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
};
|
||||
|
||||
cpuid_fn get_cpuid(uint32_t func, uint32_t leaf = 0) {
|
||||
cpuid_fn fn {};
|
||||
__cpuid_count(func, leaf, fn.eax, fn.ebx, fn.ecx, fn.edx);
|
||||
return fn;
|
||||
}
|
||||
|
||||
std::optional<core_info> cpuid_calculate_core_info() {
|
||||
core_info info {};
|
||||
|
||||
// Legacy path
|
||||
const auto cpuid_fn_0 = get_cpuid(0);
|
||||
if (cpuid_fn_0.eax < 1) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto cpuid_fn_1 = get_cpuid(1);
|
||||
|
||||
info.local_apicid = cpuid_fn_1.ebx >> 24;
|
||||
info.HTT = (cpuid_fn_1.edx >> 28) & 1;
|
||||
|
||||
const auto cpuid_fn_8000_0000 = get_cpuid(0x8000'0000U);
|
||||
|
||||
if (cpuid_fn_8000_0000.eax < 0x8000'0008) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto cpuid_fn_8000_0008 = get_cpuid(0x8000'0008U);
|
||||
const uint32_t apic_id_size = (cpuid_fn_8000_0008.ecx >> 12) & 0xF;
|
||||
|
||||
// E.5.2: MNLP (Maximum Number of Logical Processors)
|
||||
uint32_t MNLP {};
|
||||
|
||||
if (apic_id_size) {
|
||||
// Extended topology.
|
||||
MNLP = 1 << apic_id_size;
|
||||
} else {
|
||||
// Legacy path.
|
||||
MNLP = (cpuid_fn_8000_0008.ecx & 0xF) + 1;
|
||||
}
|
||||
|
||||
info.max_addressible_ids = MNLP;
|
||||
|
||||
const auto cpuid_fn_4 = get_cpuid(4);
|
||||
if (cpuid_fn_4.eax & 0xF) {
|
||||
// Intel exclusive cpuid function, AMD returns zero as unsupported.
|
||||
// `Maximum number of addressable IDs for processor cores in the physical package`
|
||||
info.cores = (cpuid_fn_4.eax >> 26) + 1;
|
||||
if (info.HTT) {
|
||||
// `A value of 1 for HTT indicates the value in CPUID.1.EBX[23:16] (the Maximum number of addressable IDs for logical processors in
|
||||
// this package) is valid for the package. `Maximum number of addressable IDs for logical processors in this physical package`
|
||||
info.threads = (cpuid_fn_1.ebx >> 16) & 0xFF;
|
||||
} else {
|
||||
info.threads = info.cores;
|
||||
}
|
||||
} else if (info.HTT) {
|
||||
info.cores = (cpuid_fn_1.ebx >> 16) & 0xFF;
|
||||
info.threads = info.cores * 2;
|
||||
} else {
|
||||
// Legacy path means cores/threads is equal to MNLP.
|
||||
info.cores = info.threads = MNLP;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
TEST_CASE("cpu count - cpuid") {
|
||||
const auto hw_concurrency = std::thread::hardware_concurrency();
|
||||
const auto core_info = cpuid_calculate_core_info();
|
||||
REQUIRE(core_info.has_value());
|
||||
CHECK(core_info->local_apicid < hw_concurrency);
|
||||
CHECK(core_info->local_apicid < core_info->max_addressible_ids);
|
||||
CHECK(core_info->max_addressible_ids >= hw_concurrency);
|
||||
if (core_info->HTT) {
|
||||
// May not be entirely correct on systems that mix HTT and non-HTT cpu cores.
|
||||
CHECK((core_info->cores * 2) == core_info->threads);
|
||||
} else {
|
||||
CHECK(core_info->cores == core_info->threads);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user