Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions rts/System/BitUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */

#pragma once

#include <cstdint>
#include <climits>

namespace spring {

// Returns a mask with the low `n` bits set. Saturates at the width of T to
// avoid the undefined behavior of shifting by >= the type's bit width.
template<class T = uint32_t>
constexpr T LowBitsMask(unsigned int n) {
if (n == 0)
return T(0);
if (n >= sizeof(T) * CHAR_BIT)
return ~T(0);
return (T(1) << n) - T(1);
}

} // namespace spring
88 changes: 88 additions & 0 deletions rts/System/Platform/Mac/CpuTopology.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */

#include "System/Platform/CpuTopology.h"
#include "System/BitUtils.h"
#include <sys/sysctl.h>
#include <thread>

namespace cpu_topology {

namespace {

// Read an unsigned sysctl value by name. Returns 0 if the key is unavailable
// (e.g. perflevel keys on Intel Macs or pre-Apple-Silicon kernels).
unsigned int ReadSysctlUInt(const char* name) {
int value = 0;
size_t valueSize = sizeof(value);
if (sysctlbyname(name, &value, &valueSize, nullptr, 0) != 0)
return 0;
return (value > 0) ? static_cast<unsigned int>(value) : 0;
}

} // namespace

ThreadPinPolicy GetThreadPinPolicy() {
// macOS has no pthread_setaffinity_np equivalent. Scheduling locality is
// instead expressed via QOS classes; see Platform/Mac/ThreadSupport.cpp.
return THREAD_PIN_POLICY_NONE;
}

ProcessorMasks GetProcessorMasks() {
ProcessorMasks masks{};

// Apple Silicon exposes per-perflevel core counts. perflevel0 is the
// high-performance (P) cluster; perflevel1, when present, is the
// efficiency (E) cluster. Intel Macs and older kernels do not expose
// these keys; fall back to treating every core as a P-core there.
const unsigned int numPCores = ReadSysctlUInt("hw.perflevel0.physicalcpu");
const unsigned int numECores = ReadSysctlUInt("hw.perflevel1.physicalcpu");

if (numPCores > 0) {
masks.performanceCoreMask = spring::LowBitsMask(numPCores);
// E-cores occupy the bits above the P-cores in the combined mask.
const unsigned int totalCores = numPCores + numECores;
const unsigned int allMask = spring::LowBitsMask(totalCores);
masks.efficiencyCoreMask = allMask & ~masks.performanceCoreMask;
} else {
// Intel Mac / unknown topology: treat the visible core count as
// homogeneous P-cores. Matches prior behavior on those targets.
unsigned int numCores = std::thread::hardware_concurrency();
if (numCores == 0) numCores = 4;
masks.performanceCoreMask = spring::LowBitsMask(numCores);
masks.efficiencyCoreMask = 0;
}

// macOS does not expose SMT/HT details; report all visible cores as
// hyper-thread-low so callers consuming those masks stay consistent.
masks.hyperThreadLowMask = masks.performanceCoreMask | masks.efficiencyCoreMask;
masks.hyperThreadHighMask = 0;

return masks;
}

ProcessorCaches GetProcessorCache() {
ProcessorCaches caches;

ProcessorGroupCaches group;
unsigned int numCores = std::thread::hardware_concurrency();
if (numCores == 0) numCores = 4;
group.groupMask = spring::LowBitsMask(numCores);

// Try to get cache sizes via sysctl
size_t size = sizeof(uint64_t);
uint64_t cacheSize = 0;

if (sysctlbyname("hw.l1dcachesize", &cacheSize, &size, nullptr, 0) == 0)
group.cacheSizes[0] = static_cast<uint32_t>(cacheSize);

if (sysctlbyname("hw.l2cachesize", &cacheSize, &size, nullptr, 0) == 0)
group.cacheSizes[1] = static_cast<uint32_t>(cacheSize);

if (sysctlbyname("hw.l3cachesize", &cacheSize, &size, nullptr, 0) == 0)
group.cacheSizes[2] = static_cast<uint32_t>(cacheSize);

caches.groupCaches.push_back(group);
return caches;
}

} // namespace cpu_topology
9 changes: 7 additions & 2 deletions tools/unitsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,16 @@ if (WIN32)
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)
elseif (APPLE)
list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Mac/CpuTopology.cpp")
list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Linux/Hardware.cpp")
list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/SharedLib.cpp")
list(APPEND main_files "${ENGINE_SRC_ROOT}/System/Platform/Linux/SoLib.cpp")
else ()
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)
endif ()

set(unitsync_files
${sources_engine_System_FileSystem}
Expand Down
Loading