Skip to content

macOS: build the unitsync target on Apple Silicon#3042

Open
tomjn wants to merge 2 commits into
beyond-all-reason:masterfrom
tomjn:macos/unitsync-build
Open

macOS: build the unitsync target on Apple Silicon#3042
tomjn wants to merge 2 commits into
beyond-all-reason:masterfrom
tomjn:macos/unitsync-build

Conversation

@tomjn

@tomjn tomjn commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What

Adds the platform pieces unitsync needs to build on macOS:

  • System/Platform/Mac/CpuTopology.cpp — implements the cpu_topology API on macOS via sysctl. Splits performance vs efficiency cores using hw.perflevel0/1.physicalcpu on Apple Silicon (falls back to a homogeneous core count on Intel / older kernels), and returns THREAD_PIN_POLICY_NONE because macOS has no affinity-pinning API (scheduling locality is expressed as a QoS hint instead).
  • tools/unitsync/CMakeLists.txt — an elseif (APPLE) branch in the per-platform source selection: pulls in the Mac CpuTopology plus the shared Linux Hardware/SharedLib/SoLib sources (the Linux ThreadSupport doesn't build on macOS).

Result

libunitsync.dylib builds as a native arm64 library under Homebrew GCC — verified locally (file reports Mach-O 64-bit dynamically linked shared library arm64, C API exports like GetSpringVersion/GetMapCount present).

Notes

  • Part of the macOS bring-up. To configure and compile cleanly it relies on the companion PRs (macOS CMake configure fixes, macOS threading: affinity/ThreadSupport, FindSevenZip 7zz, MemPoolTypes thread-id). Each is independently correct; together they make the unitsync target build on Apple Silicon.
  • No effect on Linux/Windows (additive APPLE branch + a new Mac-only file).
  • The CpuTopology P/E split uses hw.perflevel0/perflevel1 per earlier review feedback on the macOS PR.
  • "Builds" is verified; runtime correctness (reading a real game install, archive hash parity with the Linux build) is the next validation step and not yet done.

@sprunk

sprunk commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

unitsync doesn't do anything remotely related to CPU topology AFAIK so I think the proper thing to do would be to find how exactly this dependency is created and drop it instead.

Add the platform pieces unitsync needs on macOS:

- System/Platform/Mac/CpuTopology.cpp: implements the cpu_topology API
  on macOS via sysctl. Uses hw.perflevel0/1.physicalcpu to split
  performance vs efficiency cores on Apple Silicon (falling back to a
  homogeneous core count on Intel / older kernels), and reports
  THREAD_PIN_POLICY_NONE since macOS has no affinity pinning (scheduling
  locality is a QoS hint instead).

- tools/unitsync/CMakeLists.txt: an APPLE branch in the per-platform
  source selection, pulling in the Mac CpuTopology plus the shared
  Linux Hardware/SharedLib/SoLib sources (the Linux ThreadSupport does
  not build on macOS).

With this, libunitsync.dylib builds as a native arm64 library under
Homebrew GCC. Part of the macOS bring-up; depends on the macOS
threading and CMake-configure changes in the related PRs to compile and
configure cleanly. No effect on Linux/Windows.
@tomjn tomjn force-pushed the macos/unitsync-build branch from aa9a440 to b68a43d Compare June 20, 2026 15:10
@tomjn

tomjn commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

unitsync doesn't do anything remotely related to CPU topology AFAIK so I think the proper thing to do would be to find how exactly this dependency is created and drop it instead.

unitsync.cpp calls ThreadPool::SetThreadCount(), and ThreadPool -> Threading's affinity code → cpu_topology (16 refs in Threading.cpp). Linux unitsync already links Platform/Linux/CpuTopology.cpp in the existing else() branch; this PR just adds the macOS counterpart.

@tomjn

tomjn commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

@sprunk dropping that dependency would require a refactor of the thread pool, which I'm not sure is worth it right now. Affinity setting is triggered by the Thread pool implementation so we'd need to separate it out or make it optional

@tomjn

tomjn commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

@sprunk given that unitsync does use threading, but doesn't require affinity, the closest it gets is counting cores, perhaps making CPUID::EnumerateCores not eagerly call cpu_topology for code that only wants a core count would solve this?

@tomjn

tomjn commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

@sprunk I've dug into this more and the only options I've seen might work involve spreading a tonne of UNITSYNC ifdef's through shared files to avoid the affinity changes coming in, or a wide ranging refactor.

Specifically, a generic CPU topology for tools rts/System/Platform/CpuTopologyGeneric.cpp, raising this in a fresh PR

@sprunk sprunk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the explicit multithreading is there for the initial VFS scan, keeping that is reasonable so the fix is conceptually alright. I have no clue around the topic of cpu topology though so it's probably something for @lostsquirrel1.

Comment thread rts/System/Platform/Mac/CpuTopology.cpp Outdated
@sprunk sprunk added the big mac Part of the big push to support Mac. label Jun 22, 2026
Move the local BitsForCount helper out of Mac/CpuTopology.cpp into a
generic spring::LowBitsMask in System/BitUtils.h, per review feedback.
It saturates at the type width to avoid the 1<<width shift UB.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

big mac Part of the big push to support Mac.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants