From eb5a65aeb08d787d595044299a41b0226d73b569 Mon Sep 17 00:00:00 2001 From: Timothy Herchen Date: Sat, 10 Jan 2026 10:18:48 -0800 Subject: [PATCH] Fix RelationCache on Windows 10 compiles Windows 10 is missing the GroupMasks and GroupCount members, this breaks compiles on Windows 10. Windows 11 builds, including the official ones, run fine on Windows 10/11. To support developers/testers on Windows 10, fallback conditionally to the Windows 10 struct definition. closes https://github.com/official-stockfish/Stockfish/pull/6538 No functional change --- src/numa.h | 64 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/src/numa.h b/src/numa.h index df11f0286..b3d1c34d9 100644 --- a/src/numa.h +++ b/src/numa.h @@ -371,6 +371,50 @@ inline WindowsAffinity get_process_affinity() { return affinity; } +// Type machinery used to emulate Cache->GroupCount + +template +struct HasGroupCount: std::false_type {}; + +template +struct HasGroupCount().Cache.GroupCount)>>: std::true_type { +}; + +template::value, bool> = true> +std::set readCacheMembers(const T* info, Pred&& is_cpu_allowed) { + std::set cpus; + // On Windows 10 this will read a 0 because GroupCount doesn't exist + int groupCount = std::max(info->Cache.GroupCount, WORD(1)); + for (WORD procGroup = 0; procGroup < groupCount; ++procGroup) + { + for (BYTE number = 0; number < WIN_PROCESSOR_GROUP_SIZE; ++number) + { + WORD groupNumber = info->Cache.GroupMasks[procGroup].Group; + const CpuIndex c = static_cast(groupNumber) * WIN_PROCESSOR_GROUP_SIZE + + static_cast(number); + if (!(info->Cache.GroupMasks[procGroup].Mask & (1ULL << number)) || !is_cpu_allowed(c)) + continue; + cpus.insert(c); + } + } + return cpus; +} + +template::value, bool> = true> +std::set readCacheMembers(const T* info, Pred&& is_cpu_allowed) { + std::set cpus; + for (BYTE number = 0; number < WIN_PROCESSOR_GROUP_SIZE; ++number) + { + WORD groupNumber = info->Cache.GroupMask.Group; + const CpuIndex c = static_cast(groupNumber) * WIN_PROCESSOR_GROUP_SIZE + + static_cast(number); + if (!(info->Cache.GroupMask.Mask & (1ULL << number)) || !is_cpu_allowed(c)) + continue; + cpus.insert(c); + } + return cpus; +} + #endif #if defined(__linux__) && !defined(__ANDROID__) @@ -1174,29 +1218,17 @@ class NumaConfig { if (info->Relationship == RelationCache && info->Cache.Level == 3) { L3Domain domain{}; - for (WORD procGroup = 0; procGroup < info->Cache.GroupCount; ++procGroup) - { - for (BYTE number = 0; number < WIN_PROCESSOR_GROUP_SIZE; ++number) - { - WORD groupNumber = info->Cache.GroupMasks[procGroup].Group; - const CpuIndex c = - static_cast(groupNumber) * WIN_PROCESSOR_GROUP_SIZE - + static_cast(number); - if (!(info->Cache.GroupMasks[procGroup].Mask & (1ULL << number)) - || !is_cpu_allowed(c)) - continue; - domain.systemNumaIndex = systemConfig.nodeByCpu.at(c); - domain.cpus.insert(c); - } - } + domain.cpus = readCacheMembers(info, is_cpu_allowed); if (!domain.cpus.empty()) + { + domain.systemNumaIndex = systemConfig.nodeByCpu.at(*domain.cpus.begin()); l3Domains.push_back(std::move(domain)); + } } // Variable length data structure, advance to next info = reinterpret_cast( reinterpret_cast(info) + info->Size); } - #endif if (!l3Domains.empty())