From fb0ff897319413852624035d750792ac39814fb8 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 20 Jun 2026 18:23:18 +0100 Subject: [PATCH] unitsync: link generic cpu_topology instead of per-platform detection unitsync wraps FileSystemInitializer::Initialize() in the thread pool so archive scanning/hashing parallelizes via for_mt, so it genuinely needs the pool. It does not, however, pin threads, so it does not need real CPU topology detection (P/E core masks, cache groups, pin policy). The topology dependency was incidental: CPUID::EnumerateCores() (called from the CPUID singleton ctor) eagerly calls cpu_topology::GetProcessorMasks() and GetProcessorCache(), and Threading::GetChosenThreadPinPolicy() calls cpu_topology::GetThreadPinPolicy(). These are link-time references in TUs unitsync compiles, so it had to link Platform/{Linux,Win,Mac}/CpuTopology.cpp even though it never pins. Provide a generic, platform-agnostic cpu_topology implementation (CpuTopologyGeneric.cpp) that reports every logical core as a single group of performance cores and requests no pinning, and link that into unitsync instead of the per-platform file. This removes the per-platform CpuTopology from unitsync on all platforms (notably Mac/CpuTopology.cpp), making the build consistent across Linux/Windows/macOS. The engine and dedicated server are untouched and keep linking the real per-platform topology for sim-worker pinning. --- rts/System/Platform/CpuTopologyGeneric.cpp | 45 ++++++++++++++++++++++ tools/unitsync/CMakeLists.txt | 14 +++++-- 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 rts/System/Platform/CpuTopologyGeneric.cpp diff --git a/rts/System/Platform/CpuTopologyGeneric.cpp b/rts/System/Platform/CpuTopologyGeneric.cpp new file mode 100644 index 00000000000..cfad9fe7faa --- /dev/null +++ b/rts/System/Platform/CpuTopologyGeneric.cpp @@ -0,0 +1,45 @@ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ + +// Generic, platform-agnostic cpu_topology implementation for tool builds +// (e.g. unitsync) that link the thread pool for parallel work but never pin +// threads. It reports every logical core as a single group of performance +// cores with no P/E split, no SMT/hyper-threading distinction and no cache +// grouping, and requests no thread pinning. This satisfies the three +// cpu_topology symbols pulled in by CpuID/Threading without dragging in the +// real per-platform topology detection (Platform/{Linux,Win,Mac}/CpuTopology.cpp). +// +// The engine and dedicated server do NOT use this; they link the real +// per-platform implementation for sim-worker pinning. + +#include "CpuTopology.h" + +#include +#include + +namespace cpu_topology { + +ThreadPinPolicy GetThreadPinPolicy() { + return THREAD_PIN_POLICY_NONE; +} + +ProcessorMasks GetProcessorMasks() { + ProcessorMasks processorMasks; + + // Masks are 32 bits wide; cap to match the real per-platform implementations + // (MAX_CPUS == 32). Treat every logical core as a performance core so that + // CPUID::EnumerateCores() derives a correct logical-core count for the pool. + const unsigned int logicalCores = std::min(32u, std::thread::hardware_concurrency()); + + processorMasks.performanceCoreMask = + (logicalCores >= 32u) ? ~0u : ((1u << logicalCores) - 1u); + + return processorMasks; +} + +ProcessorCaches GetProcessorCache() { + // No cache grouping: the only consumers (the affinity/pinning helpers in + // Threading.cpp) are never reached on the tool path. + return ProcessorCaches{}; +} + +} // namespace cpu_topology diff --git a/tools/unitsync/CMakeLists.txt b/tools/unitsync/CMakeLists.txt index 00f124f0a78..db456d8d365 100644 --- a/tools/unitsync/CMakeLists.txt +++ b/tools/unitsync/CMakeLists.txt @@ -82,6 +82,10 @@ set(main_files "${ENGINE_SRC_ROOT}/System/Misc/SpringTime.cpp" "${ENGINE_SRC_ROOT}/System/Platform/CpuID.cpp" "${ENGINE_SRC_ROOT}/System/Platform/CpuTopologyCommon.cpp" + ## unitsync needs the thread pool (for parallel archive scanning) but never + ## pins threads, so it links a generic cpu_topology instead of the real + ## per-platform Platform/{Linux,Win,Mac}/CpuTopology.cpp detection. + "${ENGINE_SRC_ROOT}/System/Platform/CpuTopologyGeneric.cpp" "${ENGINE_SRC_ROOT}/System/Platform/Misc.cpp" "${ENGINE_SRC_ROOT}/System/Platform/ScopedFileLock.cpp" "${ENGINE_SRC_ROOT}/System/Platform/Threading.cpp" @@ -102,20 +106,24 @@ set(main_files "${ENGINE_SRC_ROOT}/System/StringUtil.cpp" ) if (WIN32) - list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Win/CpuTopology.cpp") list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Win/Hardware.cpp") list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Win/WinVersion.cpp") list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/SharedLib.cpp") list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Win/DllLib.cpp") else (WIN32) - list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Linux/CpuTopology.cpp") list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Linux/Hardware.cpp") list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Linux/ThreadSupport.cpp") endif (WIN32) +# The shared engine threading source list pulls in the real per-platform +# Platform/{Linux,Win,Mac}/CpuTopology.cpp. unitsync links a generic +# cpu_topology instead (see main_files above), so strip the platform file here. +set(unitsync_threading_files ${sources_engine_System_Threading}) +list(FILTER unitsync_threading_files EXCLUDE REGEX "Platform/(Linux|Win|Mac)/CpuTopology\\.cpp$") + set(unitsync_files ${sources_engine_System_FileSystem} - ${sources_engine_System_Threading} + ${unitsync_threading_files} ${sources_engine_System_Log} ${sources_engine_System_Log_sinkFile} ${sources_engine_System_Log_sinkOutputDebugString}