windows-topology-sys
A refined view of the processor, cache, and memory topology Windows publishes.
Windows 11 / Windows Server 2025 and later. That floor is what is tested,
not the oldest version the APIs might work on: discover calls
GetSystemCpuSetInformation, which is documented only from Windows 10 /
Server 2016 and is imported statically, and nothing below Windows 11 is
exercised here. (Server 2025 is the server release built on the Windows 11
codebase; Server 2022 is not, despite the adjacent version numbers.)
Windows only. The crate does not build on other platforms, and is not
intended to: an earlier version of this line claimed it degraded to an empty
shell elsewhere, which was never true and was never built in CI (raised in
PR #56 review). That correction reached the prose but not the code -- two
modules stayed ungated, so the crate really did build for a Linux target and
hand back a two-type API -- and a compile_error! now enforces what this
paragraph says (raised in PR #61 review). Depend on it under
[target.'cfg(windows)'.dependencies].
Example
use MachineMemoryTopology;
let topology = discover?;
println!;
# Ok::
examples/print_topology.rs prints the host's
full topology as JSON (cargo run --example print_topology --features serde),
in the same shape a hand-written or fed-in description takes.
Why this crate exists
GetLogicalProcessorInformationEx is the Win32 entry point for topology, and
the windows crate exposes it as typed but still unsafe FFI: a raw output
pointer, two-call sizing, and records that must be walked by their own
self-reported Size rather than indexed as a slice. Several of the records
also declare a trailing array as length 1 (PROCESSOR_RELATIONSHIP::GroupMask: [GROUP_AFFINITY; 1]) while actually holding as many entries as GroupCount
reports -- reading past element 0 is exactly what correct use of the API
requires, and exactly what Rust calls undefined behavior if done through the
declared type. None of that is solved by a thin unsafe fn wrapper; it has to
be solved by walking the buffer correctly.
This crate does that walk once, safely, and hands back owned records.
What the model is
Observed connectivity, not a ladder of levels with optional rungs. The difference matters to a consumer: a level-shaped model has to invent a value for a rung the platform did not report, and the invented value is indistinguishable from a measured one.
- Relations are held as a set, and never reduced on insert. Windows
describes processors through two APIs --
GetLogicalProcessorInformationExandGetSystemCpuSetInformation-- and they are not the same API twice. Each relation carries anObservationnaming itsSource, so where the two disagree the disagreement survives rather than being silently resolved in favour of whichever was read last.MachineMemoryTopology::cpu_setsalso keeps the CPU-set view verbatim. Observed<T>distinguishes three facts that a plainOptioncollapses into two:Known,Absent("asked, and there is none"), andNotObserved("nobody asked"). With theserdefeature these are three distinct encodings, so a description round-trips the distinction instead of losing it.Granularityorders the domain kinds, andminimal_sharedis the meet -- so "how close are these two processors?" is answered over every kind and any cache depth, rather than over one nominated level.proximityderives the pairwise answer from an inclusion-ordered partitioning rather than restating the rule.MachineMemoryTopology::enumeration_anomaliesrecords what could not be decoded. Empty on every healthy machine. A malformed record is neither a panic nor a silent truncation, so a short list is distinguishable from a small machine.Provenancerecords how the object was obtained -- discovered, restored from a description, or hand-built -- which is a fact about the construction, orthogonal to which source reported any given relation.
Scope
What this is: safe enumeration (MachineMemoryTopology::discover), plus a plain-data
description (MachineMemoryTopology, Domain) that needs no Windows API call to
construct -- build one by hand, or (with the serde feature) deserialize one
from JSON written for a machine you do not have. (A machine you do not have,
not a platform you are not on.)
What this is not: a partitioning policy. It answers what the machine looks like, never which boundary you should shard on -- that depends on the workload, so it is the consumer's call. It is also not a device topology: no NVMe controller, NIC, or GPU is a participant here.
It does not go below the Win32 topology APIs. If Windows does not report a fact, this crate does not have it. That is a scope boundary rather than a judgement about the fact: ACPI carries SLIT distances, no Win32 API surfaces them, and reading firmware directly would be going below the boundary -- so there is no attributed-distance model, and none is planned here.
See DESIGN-NOTES.md for the full reasoning, including a cross-check against Linux's topology model, D-9's list of what was declined and why, D-20's scope ruling above, and D-8's note that the JSON schema is not covered by this crate's semver contract.
License
MIT. Copyright (c) Mike Grier.