Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Compiler allocation admission

Budgeted admission enforces both the raw compiler peak and the represented allocation storage on each device. For a complete record, the reservation is max(peak, argument + output - alias + temporary). Existing external retained residency is added afterward. Each record’s categories stay paired before device maxima are taken. compiler_peak_bytes and published peak_bytes remain raw compiler peaks.

The supported report contains nonnegative integral peak, argument, output, alias, and preallocated temporary counts, plus explicit host argument/output/alias/temporary counts. Aliases cannot exceed either their argument or output category. Missing, malformed, empty, inconsistent, and unpaired columnar reports refuse budgeted admission. The raw peak accessor retains its independent normalization contract, including columnar peaks. An absent allocation counter never becomes zero and a small raw peak cannot override represented temporary storage.

Nonzero host allocation counts refuse this default-memory reservation because the pinned peak calculation does not reliably separate memory spaces. Generated-code metadata is excluded from this allocation contract and alone causes no host-space refusal. The existing offload path moves arrays to an actual CPU device and compiles separate CPU assembly. Its host storage remains excluded from a GPU ceiling; selected CPU execution accounts for its own CPU storage. Unbudgeted execution is unchanged.

The reservation covers represented requirements. Generated code, omitted runtime workspace and constants, thread stacks, allocator overhead, and executable-cache storage remain outside a complete runtime bound. The CPU evidence below establishes this allocation contract on the captured executable. It establishes no GPU capacity claim.

Effective budget and headroom

The reservation this document bounds covers represented allocations only. Generated code, omitted runtime workspace, collective-communication buffers, library workspaces such as cuBLAS, the driver context, thread stacks, allocator overhead and fragmentation are all outside it, yet they occupy the same allocator pool. A budget set to the whole pool therefore admits plans the pool cannot host.

ExecutionConfig.device_memory_bytes is consequently a request, not the ceiling. The default "device" requests B_requested = min over selected devices d of L_d and resolves unbudgeted when no selected device reports a limit. The ceiling is resolved once, where a model binds its devices, as

B_effective = min(B_requested, min over selected devices d of (L_d - ceil(f * L_d)))

with L_d the device’s observed allocator pool limit (memory_stats()["bytes_limit"]) and f the ExecutionConfig.device_memory_headroom_fraction, which defaults to 0.15. A request of None stays unbudgeted and applies no pool-derived cap; public model construction still reads each visible device’s pool statistics once. A device whose backend reports no pool limit contributes no cap, and taking the minimum means a request already below the capped limit is never reduced a second time, so no margin is applied twice.

The fraction moves the ceiling and nothing else: every compiler reservation, residency figure and admission inequality is unchanged, and f = 0.0 reproduces admission against the whole pool. The default is a policy awaiting workload validation, not a measured requirement — no measurement establishes 15% as the required margin on any device.

The motivating case is a three-device A40 float32 production simulation on 2026-09-16 (Slurm job 27624359), which failed during backward induction when the BFC allocator refused a 39.82 GiB allocation against a 40.49 GiB pool limit. The caller had passed the entire pool as device_memory_bytes, so 98.3% of it was formally admissible while the unrepresented storage above made it unallocatable, and no deliberate margin stood between the admitted plan and the pool.

Captured CPU witness

The implementation base is 1f554a30c49ad6ddfaa8ead541ad40431e7d7235. The public witness uses two actions, two subjects, a sorting feasibility constraint, a 16,384-byte budget, Python 3.14.7, JAX/JAXLIB 0.11.1, CPU, and float64.

Captured counterBytes
Raw peak90
Arguments56
Outputs2
Aliases0
Preallocated temporary allocations131,072
Each host allocation counter0
Default and host generated-code counters0
Computed represented reservation131,130

The original regression failed when the admitted executable reached the numerical dispatch boundary. A guard intercepted that call before executing the feasibility producer. After the central change, the same regression passes with unchanged counters and no dispatch attempt. Both runs retain the complete scalar report, serialized buffer assignment, and HLO text at the compile seam.

The saved assignment contains 31 logical buffers, 30 allocations, and zero heap traces or events. Allocation 29 has size 131,072, color zero, and none of the entry-parameter, live-out, constant, or thread-local flags. Its logical buffers 44 and 45 share offset zero. Static charges reproduce 90 bytes exactly: 56 argument bytes, 2 output bytes, and 32 constant bytes. The temporary allocation receives no heap-event charge in this executable. The represented reservation removes sharing within the allocation through the compiler’s own allocation count.

The raw peak includes those 32 constant bytes; the allocation expression excludes them. Taking the maximum of the two reports leaves simultaneous coverage of the constants and temporary allocation unestablished. This is one concrete limit on the represented-buffer reservation’s scope.

The interpretation follows the wheel’s recorded JAX revision 2d66622450e2c8633cda2307688ef7aa294bd6eb and its pinned XLA revision dcf304bc5dca1932b99f740b911dbd73631a1a69:

The schema SHA-256 is ef83e18f357ef5e9f75948a64293988b166abf73ad5090af2f93e012ed760f2a. The captured assignment SHA-256 is 35c58cd22ea00baaacd553b47b9c57c295b1bf563d05169a09a31b95c6cfaf51. The bounded decoder encountered no unknown fields. Exact instruction-ID mapping remains limited by the absence of a serialized HLO module; the retained text contains the sorting operation.

Previously captured GPU record

The separately authorized IAME diagnostic captured a complete GPU report on source c710f9b522ec6041830211d9eaf2536f1c842826, fp64, JAX 0.11.1, and a Tesla V100. Its arguments, outputs, aliases, and temporary bytes were 7,093,116, 1,772,928, 0, and 5,803,032,504. Their allocation expression is 5,811,898,548 bytes; the raw peak is 5,811,906,304 bytes and remains the computed reservation. Host allocation counters were zero. Generated-code metadata was 31,512 bytes, which leaves the allocation contract unchanged.

That diagnostic failed a 5,803,032,576-byte contiguous allocation with a 4,294,967,296-byte largest reusable block and 5,620,367,360 bytes of remaining allocator-pool growth. A represented-buffer reservation does not establish contiguous allocation feasibility or resolve pool fragmentation. This reused record is arithmetic evidence from the prior diagnostic; no GPU execution of this repair was performed, and the original asynchronous failure site remains outside its conclusions.

Migration inventory

Budgeted consumerReservation and ownership behavior
execution/workspace_planning.pyComputes complete compiler records, ranks widths by reservation plus external residency, returns separate raw peak and reservation metadata.
solution/backward_induction.pyCaches complete reports by lowering, pairs each donation variant with its own residency, compares reservations in compilation waves and final selection, logs raw peaks under their existing label.
simulation/runtime.pyReads the exact executable’s complete report and rechecks call-owned original, placed, and compiler-eliminated arguments through the existing residency inventory.
simulation/host_operations.pyCaches complete accounting with executable code; preserves keep_unused=True and fresh physical-buffer residency for each call.
simulation/solution_copies.pyUses complete cached accounting while retaining original and earlier private copies.
simulation/process_grids.pyUses complete accounting for the supported uniform-grid and staged normal-support producers, including cumulative call-owned support and temporary buffers.
simulation/chunk_planning.pyAdds stage reservations to actual retained and future output storage; retains raw stage peaks separately and preserves separate CPU assembly.
Feasibility, action-grid, padding, and diagnostic operationsReach the central planner directly or through the profiled-operation owner, preserving refusal before dispatch.
Stochastic state-transition validationPlaces the concrete grid and scalar operands, compiles the complete Cartesian law producer, charges external residency, and dispatches only the admitted executable. Serial invalid-input replay admits its probability reduction through the same memory owner.

Compiler aliases only remove represented argument/output overlap. Existing physical buffer unioning and compiler-input metadata determine which caller-owned spans can be excluded from external residency. Eliminated inputs, uncovered source spans, and prior outputs stay charged. Source ownership and per-device transfer semantics are unchanged.

Executable controls

tests/execution/test_compiler_allocation_reservation.py covers temporary-dominant and peak-dominant reports, valid and invalid aliases, heterogeneous device records, complete counter requirements, explicit host-space refusal, generated-code metadata, cached lookups, external residency, and unbudgeted behavior.

tests/simulation/test_compiler_allocation_admission.py retains the original public refusal witness. Existing feasibility tests check sufficient-budget values, selected actions, caller arrays, and diagnostics. The two downstream diagnostic-pressure cases use cheap predicates so their intended gathers and per-constraint producers can be reached before refusal.

tests/simulation/test_state_transition_entry_admission.py records that a constrained simulation refuses before a stochastic state law finishes, exercises the admitted summary and serial invalid-input replay, and compares sufficient-budget simulation results and caller inputs with the unbudgeted route. The corresponding semantic certificate pins memory transport, input placement, external residency, compiler admission, readiness, temporary ownership, and the admitted diagnostic reduction. Regime-transition and joint-transition law producers remain separate inventory items.

The gather-pressure test still requires exactly two cohort gathers, for summary and serial replay, followed by refusal before the diagnostic-subset gather dispatches. The predicate-pressure test still requires exactly three gathers and refusal of the individual _batched_feasibility_check producer. Both retain their invalid-result predicate, original budgets, population size, and dispatch guards; the latter retains eight additional diagnostic predicates. Replacing only the sorting predicate with its existing parameter-only fixture lets these downstream assertions run under the stricter admission rule. The separate public witness retains the expensive sorting predicate.

The certificate preserves its seven existing populations totaling 538 controls. Fourteen separately named allocation_reservation: controls cover central arithmetic, malformed fields, host space, per-device reduction, raw metadata, cached operations, solve waves, donation variants, and chunk consumption. Production-source coverage remains 116 paths; test, certificate, and evidence binding manifests have a separate larger population.