Expand description
GDT-CPUs: Game Developer’s Toolkit for CPU Management
This crate provides detailed CPU information and thread management capabilities specifically designed for game developers: CPU topology (including hybrid P/E/LP-E core kinds and L3 cache domains), thread affinity and thread priority.
§Key Features
- Flat topology model: one
Lprecord per logical processor plus a first-classL3Domaintable - chiplet CPUs (multiple CCDs per socket) and hybrid designs are represented faithfully. - Core kinds:
CoreKind::Performance/CoreKind::Efficiency/CoreKind::LpEfficiency- modern silicon ships more than two kinds. - L3 cache domains: group cooperating threads by shared L3
(
CpuInfo::l3_domain_mask) - cross-domain latency is the real cliff. - Thread Affinity: pin threads to logical cores or sets of them.
- Thread Priority: 7 portable levels mapped to each OS’s scheduler.
- No global state:
CpuInfo::detect()returns a plain value you own.
§Getting Started
use gdt_cpus::CpuInfo;
fn main() -> Result<(), gdt_cpus::Error> {
let info = CpuInfo::detect()?;
println!("CPU: {} ({})", info.model_name, info.vendor);
println!("{} cores / {} threads", info.core_count, info.lps.len());
if info.is_hybrid() {
println!("hybrid: {}P + {}E + {}LP-E",
info.num_performance_cores(),
info.num_efficiency_cores(),
info.num_lp_efficiency_cores());
}
for (i, d) in info.l3_domains.iter().enumerate() {
println!("L3 domain {}: {} MiB, {} cores", i, d.size_bytes >> 20, d.core_count);
}
Ok(())
}§Thread placement: what goes where (rules of thumb)
Two independent levers exist on Linux/Windows: placement (affinity - WHERE a thread may run) and priority (WHO wins when threads compete). On macOS QoS fuses both (and Apple Silicon ignores pinning entirely), so treat affinity as best-effort and priority as the portable lever.
| Work | Cores | Priority |
|---|---|---|
| Main / render thread | best Performance core (highest Lp::perf_hint, smt_index == 0) | AboveNormal-Highest |
| Simulation / job workers | one per remaining Performance core primary; keep cooperating sets inside ONE L3 domain | Normal |
| Audio / haptics feeder | any Performance core - do NOT pin it onto the busiest one | TimeCritical (dedicate the thread; on macOS it permanently leaves the QoS system). For hard deadlines, promote_thread_to_realtime |
| Asset streaming / decompression | Efficiency cores if present - the mask CAN be empty, always fall back to Performance | BelowNormal |
| Shader/PSO compilation, navmesh & lighting bakes, batch processing | wherever there’s room - these want throughput, not latency | Lowest |
| Telemetry, autosave compression, platform callbacks | LpEfficiency island if present (trickle work only - these islands often have weak interconnects), else unpinned | Background |
Further rules:
- Don’t pin everything. Pinning removes the scheduler’s freedom; it
pays off only for threads with a real reason - latency (audio, render)
or cache locality (a cooperating producer/consumer set). Leave the
rest soft. On Windows prefer
set_thread_soft_affinity(CPU Sets) - the scheduler keeps an escape hatch. - One heavy thread per physical core: build worker pools from
CpuInfo::primary_thread_mask(smt_index == 0), not from all LPs - two heavy threads on SMT siblings share one core’s execution resources. Siblings are fine for light helpers. - Group by L3, not by core id: cross-L3-domain communication costs
multiples of in-domain (3.6× measured on a dual-CCD 5950X - run
examples/l3_domains.rs). Place cooperating threads withCpuInfo::l3_domain_mask; never assume core ids imply locality. - Within a kind, rank with
Lp::perf_hint- chips ship Performance tiers spanning several frequency bins (ARM prime-vs-mid, Intel favored cores). Compare it only within the same detected machine and kind; the source scale differs per OS. Equal hints = indistinguishable, don’t invent an order. - Kinds are classes, not guarantees: a machine may have NO
Efficiency cores (only P + LP-E), or nothing but Performance. Write
fallbacks:
efficiency_core_mask()empty -> use Performance at lower priority. - Check what priority can deliver: on a locked-down Linux box
(no rtkit, default rlimits) every level above
Normalsilently resolves toNormal.priority_capabilitiespredicts this up front;promote_thread_to_realtimeis the explicit escape hatch for the one thread with a hard deadline.
use gdt_cpus::{CoreKind, CpuInfo, ThreadPriority, pin_thread_to_core, set_thread_priority};
let info = CpuInfo::detect()?;
// Best Performance-core primaries first - render thread gets the top one.
let mut p_cores: Vec<_> = info.lps.iter()
.filter(|lp| lp.kind == CoreKind::Performance && lp.smt_index == 0)
.collect();
p_cores.sort_by_key(|lp| std::cmp::Reverse(lp.perf_hint));
if let Some(best) = p_cores.first() {
let _ = pin_thread_to_core(best.os_id as usize); // macOS: Unsupported - fine
let applied = set_thread_priority(ThreadPriority::Highest)?;
eprintln!("render priority: {applied}");
}
// Background telemetry: LP-E island when it exists, otherwise just priority.
let smol = info.kind_mask(CoreKind::LpEfficiency);
if !smol.is_empty() {
let _ = gdt_cpus::set_thread_affinity(&smol);
}
let _applied = set_thread_priority(ThreadPriority::Background)?;
§Cargo Features
rtkit(default): on Linux, negotiate priority through rtkit and the xdg realtime portal (hand-rolled minimal D-Bus client, no extra dependencies) when direct syscalls are denied. Opt out withdefault-features = false.serde: serialization for the CPU information structures.
Structs§
- Affinity
Mask - A cross-platform CPU affinity mask representing a set of logical processors.
- Applied
Priority - What a thread-priority request actually produced.
- Cache
Info - Size, line size and sharing degree of one cache instance.
- CpuFeatures
- Represents a set of CPU features and instruction set extensions available on an x86_64 architecture.
- CpuInfo
- The system’s CPU topology and identity - a flat, by-value description.
- L2Domain
- A set of cores sharing one L2 cache instance.
- L3Domain
- A set of cores sharing one L3 cache instance.
- Lp
- One record per ONLINE logical processor - the flat topology’s atom.
- Mechanism
- The concrete OS scheduling mechanism a priority request landed on – the typed
replacement for the old human
detailstring.valueis interpreted perpolicy(seeMechanismPolicy). Two bytes, no allocation; theDisplayimpl renders the human form (e.g.nice -15,QoS UserInteractive,SCHED_RR 47). - Priority
Caps - What each
ThreadPrioritylevel will effectively deliver, as opaque ranks. Returned bypriority_capabilities.
Enums§
- Broker
Error - The specific reason a privilege broker REFUSED a grant - the typed form of
the D-Bus error name it answered with, carried by
AppliedPriority::broker_errorwhenreasonisFallbackReason::BrokerRefused. - Core
Kind - Classifies a CPU core by its performance/efficiency role.
- Error
- The error enum for all operations within the
gdt-cpuscrate. - Fallback
Reason - Why a thread-priority request didn’t get a clean, direct grant of exactly what was asked.
- Grant
- How the OS satisfied a thread-priority request.
- Mechanism
Policy - Which OS scheduler API set a thread’s priority – the discriminant that says
how to read
Mechanism::value. - QosClass
- macOS Quality-of-Service class, stored as
Mechanism::valuewhen the policy isMechanismPolicy::Qos. A stable ordinal (NOT the raw darwinqos_class_thex) so the C ABI and serialized conformance stay trivial. - Thread
Priority - Represents different priority levels that can be assigned to a thread.
- Vendor
- The CPU’s manufacturer.
Functions§
- current_
affinity - Reads the current thread’s hard CPU affinity as an
AffinityMask. - demote_
thread_ from_ realtime - Returns the current thread from the real-time tier to normal scheduling.
- is_
hybrid trueif more than one core kind is present (P/E/LP-E).- num_
efficiency_ cores - Number of physical cores classified as Efficiency (0 on non-hybrid machines).
- num_
logical_ cores - Total number of logical processors (hardware threads).
- num_
lp_ efficiency_ cores - Number of physical cores classified as LpEfficiency (0 on non-hybrid machines).
- num_
performance_ cores - Number of physical cores classified as Performance.
- num_
physical_ cores - Total number of physical cores (SMT siblings counted once).
- pin_
thread_ to_ core - Pins the current thread to a single logical core (OS LP id).
- priority_
capabilities - Predicts what each
ThreadPrioritylevel will resolve to under this process’s current privileges. Touches no thread state. - promote_
thread_ to_ realtime - Promotes the current thread to the platform’s real-time tier.
- set_
thread_ affinity - Sets the current thread’s hard CPU affinity to
mask(OS LP ids). - set_
thread_ priority - Sets the current thread’s priority.
- set_
thread_ soft_ affinity - Sets the current thread’s SOFT affinity to
mask(OS LP ids) - Windows only.
Type Aliases§
- Result
- A specialized
Resulttype forgdt-cpusoperations.