Machine-model files for vxc --machine <file> program.vx (#281). Each file declares one SKU's
memory hierarchy and its transfer topology, and nothing else: no functions, no program logic. The
admission program is written once and admitted against each SKU by swapping the flag, which is the
claim the MLSys fleet-admission paper rests on.
The files here are machine models: accelerators, passed with --machine. A host — the
machine an accelerator hangs off — is a different thing, passed with --host, and declares
Memory::CPU_DRAM and nothing else (host-x86-e5-2666v3.vx). Neither is assumed, and a program
staging through host memory against a machine model must name a host or be refused (E6014).
A host declares no capacity: host memory is virtual, so a hard limit would reject programs that
page rather than fail. See docs/lang/hosts_and_machines.md.
Every SKU declares the same space names, so one program text can reference them:
| Space | What it is | Scope |
|---|---|---|
HBM |
device-global memory (HBM2e/HBM3/HBM3e) | device |
L2 |
last-level on-die cache / Infinity Cache | device |
SMEM |
per-SM/CU shared memory (scratchpad) | sm |
A program that places a tile in Memory::HBM therefore means "this SKU's device memory", and the
capacity check resolves that to whichever number the selected machine file declares. Adding a SKU
means adding a file with these spaces, not touching any program.
A SKU declares a space only if the hardware has one. The vocabulary is shared so that programs
are portable, not so that every file is the same length, and a machine file is a description of
hardware before it is a row in a table. xeon-e5-2666v3.vx declares no SMEM, because x86 has no
software-managed scratchpad: the nearest thing is a per-core cache, and a tile is resident there
only while the hardware has no better use for the lines.
Declaring it anyway would make a program that places a tile in Memory::SMEM admitted against
that machine, on a capacity number that does not mean what it means on every other SKU. Omitting it
makes the compiler say what is true:
Error: Cannot transfer from CPUDRAM to Custom("SMEM"): no hardware path exists
A program that needs a scratchpad cannot run on a machine without one, and finds that out at compile time. That is the claim this directory exists to support, and it is not worth weakening to keep a table rectangular.
cortex-m7.vx is where the roles pay for themselves, because the hardware behind them looks like
nothing else here. It is an STM32H743 microcontroller: HBM is 512 KiB of AXI SRAM, L2 is the
Cortex-M7's 16 KiB L1 data cache, and SMEM is the 128 KiB DTCM. The tightly-coupled memory really
is the same kind of space as a GPU's shared memory — you put something there on purpose, it stays
there, and it is fast because it is not a cache — so the same capacity check decides both, six
orders of magnitude apart. Vx emits no code for the part; the placement and capacity checks run in
the frontend and need no backend.
To turn an admission verdict into an engine launch command, see
utils/vllm/map_admission.py. It reads the --diagnostics-json record, not these
files — the mapping lives outside fleet/ because it changes with vLLM's flag surface, not with
SKU data.
node-8gpu.vx is different in kind: it models one 8-GPU node, adding the interconnect spaces
and edges (NVLink, PCIe, InfiniBand) that a multi-GPU placement crosses. It is composed with a SKU
file rather than replacing it — but note that the --machine flag currently takes a single file
(#281), so the node file re-declares the SKU spaces it needs. Declaration import (#224) would let
these compose properly; see the note in that file.
dtypes: on a topology states which element types the hardware can natively represent and compute
on. A placement outside the list is E6026. A topology that omits the field constrains nothing, so a
machine file written before the field existed keeps its meaning.
The list is the union of the part's matrix-unit types and its general scalar types — a machine that
holds an i32 array is not required to have an i32 matrix instruction. Types Vx has no
ElementType for are simply absent: TF32 (all three vendors have it) and FP6 (Blackwell) are
not listed anywhere, and a machine file naming an element type the compiler does not know is a parse
error rather than a silently ignored word.
| SKU | Source |
|---|---|
| a100-40, a100-80 | NVIDIA A100 Tensor Core GPU Architecture whitepaper v1.0 — "A100 Tensor Cores Support All DL Data Types" (p.26), Table 2 (p.23), Figure 7 (p.22) |
| h100-sxm, h200 | NVIDIA, "NVIDIA Hopper Architecture In-Depth" — "The FP8, FP16, BF16, TF32, FP64, and INT8 MMA data types are supported." |
| b200 | NVIDIA RTX Blackwell PRO GPU Architecture whitepaper v1.0 — "Blackwell 5th Generation Tensor Cores" |
| mi300x | AMD ROCm documentation, "AMD Instinct MI300 series microarchitecture" — per-datatype table |
| m4-uma | Apple, Metal Shading Language Specification — "Scalar Data Types", Table 2.1 |
| cortex-m7 | STMicroelectronics, STM32H742xI/G STM32H743xI/G datasheet (DS12110) |
What the declarations then say, which is the point of writing them down:
| fp8 | fp4 | int4 | f64 | |
|---|---|---|---|---|
| a100-80 | no | no | yes | yes |
| h100-sxm | yes | no | no | yes |
| b200 | yes | yes | no | yes |
| mi300x | yes | no | no | yes |
| m4-uma | no | no | no | no |
Note the int4 column. It is not a version number that only grows: Ampere's Tensor Cores take INT4,
Hopper's do not — it was deprecated after Ampere and is emulated over int8 MMA on sm_90 and sm_100.
A rule of the form "newer hardware supports more" gets that backwards, which is why the vocabulary is
declared per part rather than derived from a generation.
The host files (xeon-e5-2666v3, host-x86-e5-2666v3) declare no dtypes:. A CPU's element
vocabulary is set by the ISA extensions the code is built for rather than by the part alone, so
stating one here would claim more than the file knows.
Every capacity, bandwidth, and link figure carries a spec: comment naming its source. The
paper's capacity numbers are only as credible as their provenance, so a number without a citation
is a bug, not a detail.
GB is 10^9; GiB is 2^30. Both spellings parse (src/units.rs), conversion is exact integer
arithmetic, and a figure that is not a whole number of bytes is rejected rather than rounded.
The rule exists because breaking it cost 9%. TB was previously read as 2^40 while every spec:
line here cites a vendor figure in decimal — NVIDIA's "3.35 TB/s" is 3.35e12 B/s, from a
5120-bit bus at 3.2 Gbps. The compiler therefore treated every link as ~10% faster than its own
citation claimed and understated every predicted transfer time by 9.05%. In a calibration study
that residual would have been charged to the hardware.
Which to write:
| Field | Convention | Why |
|---|---|---|
bandwidth: |
SI (3.35 TB/s, 2039 GB/s) |
vendors quote memory bandwidth decimal |
capacity:, granule: |
IEC (80 GiB, 228 KiB, 1 KiB) |
HBM stacks, caches and SMEM are genuinely powers of two |
Copy the digits from the spec sheet and pick the spelling that matches what the sheet meant — do not pre-convert, since a hand-converted figure no longer matches its citation.
Note that whether a quoted capacity is decimal or binary is itself contested per SKU (the
192-vs-180 GiB gap below), and settling it by measurement is an open experiment (utils/memalg). The spellings here record current belief, not a verified
fact; spec: says where the belief came from. If a figure transcribed as GiB was in fact
quoted decimal, that capacity is ~7% smaller than modelled — inside the margins in the current
matrix, but enough to flip a marginal cell.
| Figure class | Status |
|---|---|
HBM capacity and bandwidth (A100 40/80, H100, H200, MI300X) |
verified 2026-08-03 — quoted from per-GPU vendor spec tables |
HBM capacity (B200) |
measured on hardware — nvidia-smi reports 183,359 MiB (192.3 GB, 179.06 GiB), #1204. Vendor materials say 180 GB, most likely a usable-after-reservation figure |
HBM bandwidth (B200) |
contested — 7.7 TB/s (Lenovo per-GPU table) vs 8.0 TB/s (NVIDIA DGX aggregate ÷ 8). 7.7 used; see b200.vx |
L2 capacity and bandwidth |
unverified — transcribed from architecture whitepapers from memory |
SMEM capacity |
unverified — per-SM/CU configurable maximum |
| cortex-m7 capacities (AXI SRAM, DTCM, L1 D-cache) | verified 2026-09-17 — quoted from the ST datasheet (DS12110) |
| cortex-m7 bandwidths | unverified — derived from bus width x clock (64-bit AXI at 240 MHz; 64-bit TCM at the 480 MHz core clock), not quoted |
Interconnect figures in node-8gpu.vx |
unverified |
dtypes lists |
verified 2026-09-03 — each quoted from a vendor document; see "Element type vocabularies" below |
Transfer costs (: N on an edge) |
not physical — relative latencies for path selection |
The first verification pass found four wrong figures, all in the direction of understating the machine, which is worth recording as evidence that transcribing from memory is not adequate here:
-
H100 bandwidth was written as
3 TB/s; the spec is 3.35 TB/s (10% low). -
H200 bandwidth was written as
4 TB/s; the spec is 4.8 TB/s (17% low). -
MI300X bandwidth was written as
5 TB/s; the spec is 5.3 TB/s. -
B200 was written as
192 GBat8 TB/s. HGX B200 — the part a neocloud rents — is 180 GB at 7.7 TB/s.192 GBis a pre-release figure still repeated by secondary sources;8 TB/sbelongs to the 186 GB GB200 NVL part. Modelling 192 GB would admit configurations that do not fit a rented B200 (a false accept, the class this campaign exists to catch), and pairing 180 GB with 8 TB/s would understate every transfer cost on that SKU.This one took four passes, which is the useful lesson. Memory said 192 GB. Dividing a DGX system aggregate gave 180 GB @ 8 TB/s — capacity right, but derived rather than quoted. A per-GPU spec table gave 180 GB @ 7.7 TB/s. Checking a secondary source that claimed 192 GB @ 8 TB/s then showed the bandwidth is genuinely contested between two reputable sources, not settled as the third pass had asserted.
Two distinct lessons. First: a figure that is plausible and self-consistent can still be a mix of two SKUs — nothing about
180 GB @ 8 TB/slooks wrong. Second, and easier to miss: the correction can overclaim too. Pass three explained the discrepancy with a tidy story ("8 TB/s is the GB200 NVL part") that the evidence did not support. A resolved-sounding narrative is not the same as a resolved question, and the write-up should say which one it has.
A rounded bandwidth is not cosmetic: bandwidth: drives the derived roofline cost, so an
understated figure inflates every transfer cost on that SKU.
These files declare what the hardware has. They do not declare how much of it a deployment may use, and those are different numbers — by more than the errors this document has been tracking.
A serving engine cannot allocate 100% of device memory: framework overhead, fragmentation, and the
CUDA context all take a share. vLLM's gpu_memory_utilization defaults to 0.9. So on a 192 GiB
B200 the usable budget is roughly 173 GiB, and a configuration in the ~173–192 GiB band is
admitted by the current capacity check and will still OOM in practice.
This is a false accept of the same class as the B200 capacity error, but it is not a mistake in any
figure — every number can be right and the verdict still wrong, because the check is comparing
against the wrong bound. The correct bound is capacity x utilization, and nothing in the model
expresses the second factor yet.
Two consequences worth stating before results are collected:
- A verdict near a SKU's ceiling means "fits the device", not "fits a serving deployment on the device". Cells close to the boundary should be treated as unresolved until this is modelled.
- This is what makes #285's
gpu_memory_utilizationfield load-bearing rather than a convenience: it is the factor that turns a capacity verdict into an admission verdict. Deriving it is not optional polish.
The alternative — baking the headroom into capacity: — is rejected deliberately. It would
make the machine files describe a policy rather than a machine, hide the assumption where no
reviewer would find it, and silently change every verdict if a deployment tuned the knob.
⚠ Still to verify before submission. The unverified rows above. Each
spec:line must be confirmed against the cited document, and this notice narrowed as rows are cleared.
Known roundings and judgment calls:
- Per-SM shared memory is the configurable maximum per SM, not the default carve-out. Vx models a single SM's budget, since that is what a tile placement has to fit.
L2on NVIDIA parts andInfinity Cacheon MI300X are modelled under one name (L2) because they play the same role in a placement decision, despite differing in architecture.- Interconnect bandwidths are quoted unidirectional where vendors publish a bidirectional aggregate; halved figures are marked in the comment.
- Transfer costs (the unitless
: Non an edge) are relative latencies, not measured numbers. They no longer decide routing on their own: route selection minimises predicted cost — the per-byte time frombandwidth:or from a link's own: N GB/s— and falls back to: Nonly between spaces whose cost nothing can derive. A route the model can price always beats one it cannot, so an edge with only a: Nis a gap to close rather than a tuning knob. The bandwidth-derived roofline (bandwidth:) is what carries physical meaning.