Extend cpu affinity mask to support up to 64 cores#286
Conversation
License Check Results🚀 The license check job ran with the Bazel command: bazel run --lockfile_mode=error //:license-checkStatus: Click to expand output |
|
Hey @NicolasFussberger 🙏 ready for review whenever you have a moment! |
Thanks! I requested @SimonKozik to do a review, he already had a closer look at this some time in the past. |
|
The created documentation from the pull request is available at: docu-html |
|
The qnx8 pipeline fails with I also could not find a reference to _NTO_TCTL_RUNMASK64_GET_AND_SET. But I think also the runmask support in qnx8 changed significantly with the introduction of cpu clusters. |
|
Thanks for catching this @NicolasFussberger 🙏 turns out |
3966871 to
195e81f
Compare
|
Hey @NicolasFussberger 🙏 reworked it to use |
The cpu_mask_ field in OsalConfig and the setaffinity() function used uint32_t, limiting process affinity to at most 32 cores. Systems with more than 32 cores would silently use only the lower 32 bits. Change the mask type to uint64_t throughout the affected chain: - OsalConfig::cpu_mask_ (iprocess.hpp) - setaffinity() signature (set_affinity.hpp and both platform impls) - kDefaultProcessorAffinityMask() return type (configuration_manager) - kDefaultNumCores cap raised from 32 to 64 (num_cores.hpp) On Linux the loop variable and shift literal are updated to uint64_t / 1ULL to avoid the undefined behaviour for i >= 32 noted in the original review discussion (PR eclipse-score#113). On QNX the 32-bit ThreadCtl(_NTO_TCTL_RUNMASK_GET_AND_SET) is replaced with _NTO_TCTL_RUNMASK64_GET_AND_SET which accepts a uint64_t mask. kDefaultProcessorAffinityMask() guards against the n == 64 edge case (where 1ULL << 64 would itself be UB) by returning UINT64_MAX instead. The XML configuration reader is updated to use std::stoull so the full 64-bit coremask value is parsed without truncation. Closes eclipse-score#122
_NTO_TCTL_RUNMASK_GET_AND_SET returns EINVAL on systems with more than 32 CPUs. Use _NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT instead, which accepts a struct _thread_runmask with RMSK_SIZE/RMSK_SET macros to support up to 64 CPUs across multiple CPU clusters. Issue: eclipse-score#122
Without setting inherit_mask, only the main thread of the launched process gets the CPU affinity from _NTO_TCTL_RUNMASK_GET_AND_SET_INHERIT. Any threads spawned by the child will run unconstrained. Setting inherit_mask mirrors the Linux sched_setaffinity behavior where the affinity applies to all threads. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3600d79 to
1f88553
Compare
The cpu_mask_ field in OsalConfig and the setaffinity() function used uint32_t, limiting process affinity to at most 32 cores. Systems with more than 32 cores would silently use only the lower 32 bits.
Change the mask type to uint64_t throughout the affected chain:
On Linux the loop variable and shift literal are updated to uint64_t / 1ULL to avoid the undefined behaviour for i >= 32 noted in the original review discussion (PR #113).
On QNX the 32-bit ThreadCtl(_NTO_TCTL_RUNMASK_GET_AND_SET) is replaced with _NTO_TCTL_RUNMASK64_GET_AND_SET which accepts a uint64_t mask.
kDefaultProcessorAffinityMask() guards against the n == 64 edge case (where 1ULL << 64 would itself be UB) by returning UINT64_MAX instead.
The XML configuration reader is updated to use std::stoull so the full 64-bit coremask value is parsed without truncation.
Closes #122