Skip to main content

Crate gdt_cpus

Crate gdt_cpus 

Source
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 Lp record per logical processor plus a first-class L3Domain table - 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.

WorkCoresPriority
Main / render threadbest Performance core (highest Lp::perf_hint, smt_index == 0)AboveNormal-Highest
Simulation / job workersone per remaining Performance core primary; keep cooperating sets inside ONE L3 domainNormal
Audio / haptics feederany Performance core - do NOT pin it onto the busiest oneTimeCritical (dedicate the thread; on macOS it permanently leaves the QoS system). For hard deadlines, promote_thread_to_realtime
Asset streaming / decompressionEfficiency cores if present - the mask CAN be empty, always fall back to PerformanceBelowNormal
Shader/PSO compilation, navmesh & lighting bakes, batch processingwherever there’s room - these want throughput, not latencyLowest
Telemetry, autosave compression, platform callbacksLpEfficiency island if present (trickle work only - these islands often have weak interconnects), else unpinnedBackground

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 with CpuInfo::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 Normal silently resolves to Normal. priority_capabilities predicts this up front; promote_thread_to_realtime is 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 with default-features = false.
  • serde: serialization for the CPU information structures.

Structs§

AffinityMask
A cross-platform CPU affinity mask representing a set of logical processors.
AppliedPriority
What a thread-priority request actually produced.
CacheInfo
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 detail string. value is interpreted per policy (see MechanismPolicy). Two bytes, no allocation; the Display impl renders the human form (e.g. nice -15, QoS UserInteractive, SCHED_RR 47).
PriorityCaps
What each ThreadPriority level will effectively deliver, as opaque ranks. Returned by priority_capabilities.

Enums§

BrokerError
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_error when reason is FallbackReason::BrokerRefused.
CoreKind
Classifies a CPU core by its performance/efficiency role.
Error
The error enum for all operations within the gdt-cpus crate.
FallbackReason
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.
MechanismPolicy
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::value when the policy is MechanismPolicy::Qos. A stable ordinal (NOT the raw darwin qos_class_t hex) so the C ABI and serialized conformance stay trivial.
ThreadPriority
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
true if 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 ThreadPriority level 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 Result type for gdt-cpus operations.