Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
CPUAffinity.h File Reference
#include "Stroika/Foundation/StroikaPreComp.h"
#include <optional>
#include "Stroika/Foundation/Common/Common.h"
#include "Stroika/Foundation/Containers/Set.h"
#include "CPUAffinity.inl"

Go to the source code of this file.

Namespaces

namespace  Stroika::Foundation
 
namespace  Stroika::Foundation::Execution
 

Typedefs

using Stroika::Foundation::Execution::LogicalCPUCoreSet = Containers::Set< unsigned int >
 A set of 0-based logical CPU core numbers, as used by Get/SetCPUAffinity.
 

Functions

optional< LogicalCPUCoreSetStroika::Foundation::Execution::GetCPUAffinity ()
 Which logical CPU cores this process may currently run on; nullopt if not knowable.
 
void Stroika::Foundation::Execution::SetCPUAffinity (const LogicalCPUCoreSet &cores)
 Restrict this process to the given logical CPU cores.
 
bool Stroika::Foundation::Execution::SetCPUAffinityQuietly (const LogicalCPUCoreSet &cores) noexcept
 Like SetCPUAffinity (), but returns false rather than throwing.
 
optional< unsigned int > Stroika::Foundation::Execution::PinToOneLogicalCPUCoreQuietly () noexcept
 Pin to a single logical CPU core chosen from those currently permitted; returns which, or nullopt.
 

Variables

constexpr bool Stroika::Foundation::Execution::kCPUAffinitySupported
 Can CPU affinity be controlled on this platform at all?
 

Detailed Description

Control which logical CPU cores THIS PROCESS is permitted to run on.

Companion to Common/SystemConfiguration.h, which DESCRIBES the machine (how many sockets, how many logical cores, model names). This header does not describe anything - it constrains where the caller runs. Core numbering here is the same 0-based logical core numbering the OS uses, and the count comes from there, not from here.

See also
Common::GetNumberOfLogicalCPUCores - how many logical cores exist (cheap, mildly stale)
Common::GetSystemConfiguration_CPU - fuller topology, sockets and per-core details

The motivating use is measurement. A benchmark that migrates between cores mid-run measures the migration as well as the code: pinning Tests/52 to one core took its run-to-run spread from 8.3% median (39% worst) to 2.6% (17% worst) - about 3x tighter - while moving the scores themselves not at all (median ratio 0.992x across 34 tests). So this buys precision, not speed. Pinning ordinary application code is usually a pessimization, since it denies the scheduler every other core.

Note
PROCESS SCOPE - and that means subtly different things per platform. A real platform difference, not an implementation gap: o Windows: SetProcessAffinityMask () is genuinely process-wide - it applies to every thread, including ones already running. o Linux: there is no process-wide call. sched_setaffinity (0, ...) sets the CALLING THREAD. Threads created later inherit the mask; threads already running keep the old one. Changing those would mean walking /proc/self/task, which this does not do. For the intended use - pin early, from a still-single-threaded program - the two coincide.
NOT AVAILABLE EVERYWHERE - see kCPUAffinitySupported. macOS has no equivalent of sched_setaffinity: thread_policy_set (THREAD_AFFINITY_POLICY) is an advisory hint about which threads want to share a cache, not a pinning primitive, and does nothing whatever on Apple Silicon. Reported honestly here rather than faked.

TODO:

Why wait: SetThreadPriority () copes with being called BEFORE Start () by stashing fRep_->fInitialPriority_ and applying it at launch, because that is a common sequence. Affinity has the same usage pattern, so a member that silently did nothing before Start () would be a trap manufactured by matching that precedent only halfway - and honoring it properly needs a new field on the Thread rep plus a hook at thread start. Worth doing when some caller actually needs to pin another thread; until then this process-scope API covers the measurement use, and is also where the portable GETTER has to live regardless.

Definition in file CPUAffinity.h.