win-numa-sys 0.1.1

Memory-safe Rust over the Windows NUMA APIs: a VirtualAllocExNuma-backed buffer, a NumaNode newtype, and the node queries a caller needs to decide what to pass. Thin over Win32, with no policy about which node anything should use.
Documentation

win-numa-sys

Memory-safe Rust over the Windows NUMA APIs.

Windows provides some NUMA concepts; this crate builds library notions on top of them. Whether a client uses them is up to the client.

What is here

  • NumaNode -- a node number, as Windows numbers them. A newtype because a node number and a count of nodes are both small integers and are trivially swapped at a call site.
  • NumaBuffer -- an owned allocation made with VirtualAllocExNuma and released with VirtualFree, so a buffer can be placed on a chosen node rather than wherever the default allocator lands it.
  • highest_numa_node() and volume_numa_node(handle) -- the two questions Windows will answer about nodes, wrapped so a caller can find a node to pass without writing the FFI.

What is not here, and will not be

Any opinion about which node anything should use. This crate reports what Windows says and allocates where it is told. It does not map a file to a node, does not shard anything, and does not choose a node on a caller's behalf.

The -sys suffix is that promise. In this workspace the suffix means thin over Win32, memory-safe, adding no policy -- see the repository's DESIGN-NOTES.md, where a sibling crate drops the suffix for failing exactly that test.

The name

The first crate here to take win- rather than windows-. windows is Microsoft's namespace, and a crate published as windows-numa-sys today is a name they may reasonably want tomorrow; see DESIGN-NOTES.md. Existing crates keep their names for now.

A node argument is a preference, not an instruction

VirtualAllocExNuma's parameter is nndPreferred, and the name is the contract. A successful allocation is not evidence that the pages landed on the node that was asked for. Two things follow, both of which have already caught someone in this workspace:

  • Committed pages are demand-zero, so until something writes to them no physical page has been drawn from the preferred node at all. Measuring placement means faulting the pages in first.
  • An invalid node is refused -- but u32::MAX is not a test of that, because it is the API's own no-preference sentinel and is accepted by design. A measurement that asks for u32::MAX and sees it succeed has measured the sentinel, not a range check.

Observing where pages actually landed needs QueryWorkingSetEx, which lives in windows-placement-probe today; whether it moves here is CHECKLIST.md N-1.2.

Buffer traits

NumaBuffer implements io-buffers' IoBuf and IoBufMut, so a ring takes it as a buffer as it is. This crate defines no buffer trait of its own: the traits belong to io-buffers, which is portable and so cannot depend on a Windows allocator, and the orphan rule lets only the crate that owns the trait or the type implement it, which is why the implementations are here.

A crate that owns a buffer trait of its own implements it for NumaBuffer the same way, over the inherent as_ptr, as_mut_ptr and len. See DESIGN-NOTES.md N-D-2.