Skip to content

0045. Enforced GPU co-residency, not whole-card ownership

  • Status: accepted
  • Date: 2026-07-20
  • Deciders: lusoris
  • Supersedes: ADR-0044 — governance-plane split retained, whole-card ownership reversed
  • Related: ADR-0030, ADR-0041, BUG-45

Context

ADR-0044 concluded that whole-card ownership is the allocation unit, and that sharedDevNum should drop to 1 so each Arc card serves exactly one workload. That conclusion was wrong, and it inverted the actual requirement: the point of this work is to make consumer hardware serve multiple workloads reliably, not to give up and hand each card to one tenant.

The supporting argument was that co-tenancy caused BUG-45's wedged B580. The bug record says otherwise. Pre-fault telemetry showed ~8.6 GB of 12 GB in use (~7.1 GB for the 8B model, 1.43 GB for the reranker) with zero spill, and the bug is explicitly classified as "a kernel/device fault rather than ordinary capacity exhaustion." Co-residency was working when the device faulted. The wedge is a driver-level failure to recover from an engine reset, which exclusivity would not have prevented.

The two workloads also do not contend for the same silicon in the way the argument assumed. Jellyfin's VA-API transcode drives the fixed-function media engines; inference drives the compute EUs. They coexist physically. What they genuinely share is VRAM and memory bandwidth — and VRAM is the resource that, left unbounded, lets one tenant starve the other.

Decision

Co-residency is the intended state. Bound it rather than forbid it.

1. sharedDevNum stays above 1. It expresses how many tenants may share a card. ADR-0044 was right that it is not an enforcement mechanism, and wrong to conclude it should therefore be 1. It is the admission count; enforcement is a separate layer, added below.

2. VRAM is enforced per container via the dmem cgroup. apps/infra/xe-dmem-nri injects dmem.max at CreateContainer, giving each Arc tenant a hard residency ceiling the kernel enforces through TTM eviction. This is the enforcement Intel's own resourceManager no longer provides after its removal in device-plugin 0.34. Every workload sharing a card carries an explicit VRAM budget, and the budgets on a card must sum to less than its physical VRAM.

3. Budgets are set from measurement, not fear. BUG-45's telemetry is the model: read actual resident VRAM under load, then set the ceiling above the observed working set with headroom. Ceilings pulled from caution rather than measurement waste the card, which is the failure this ADR exists to avoid.

4. Compute contention is accepted and observed, not prevented. Nothing available on Arc serialises compute or media engines between containers. Under simultaneous load, transcode and inference will each slow. That is the correct trade for a shared card, and it is bounded because neither can evict the other's memory. Latency effects are monitored rather than designed away.

5. Device-fault recovery is tracked as its own problem. BUG-45 is a driver recovery failure, independent of sharing. It needs detection and automatic recovery, and must not be conflated with capacity policy again.

Consequences

Both cards keep serving multiple tenants. The B60 continues to host llama-swap and qwen3-embed-predictor; the B580 continues to host jellyfin and qwen3-8b-b580-predictor. No consolidation, no model relocation, no service loses its accelerator.

xe-dmem-nri moves from experimental to the enforcement path, so its fail-open contract becomes load-bearing: a plugin that errors must never block container creation, which TestFailOpen asserts across fifteen paths. Enabling it requires verifying that the allocated render device appears in the NRI CreateContainer device list.

Per-card VRAM budgets must be assigned before enabling enforcement. An unbudgeted container is unbounded, so partial rollout leaves the gap it is meant to close.

Retained from ADR-0044 without change: the split between an achievable governance plane and unachievable datacenter-grade isolation; that Kueue governs Jobs and JobSets but not Deployments or InferenceServices; that the workstation 4090 is reached by a queue-worker rather than a synthetic Node; and that preemption waits on a checkpoint contract.

Alternatives considered

Whole-card ownership (ADR-0044's position). Rejected. It reads a driver fault as a capacity problem, discards working co-residency, and delivers the opposite of the requirement.

Move the 8B model to the B60 and give jellyfin the B580 alone. This was the recommendation that followed from the same misreading. It costs no VRAM, which made it look free, but it removes a working tenant from a card with 3.4 GB of headroom.

Leave co-residency unbounded, as today. Rejected. It works until one tenant grows, and nothing prevents that.

References

  • BUG-45 — pre-fault telemetry, ~8.6 GB resident of 12 GB with zero spill, classified as device fault not capacity exhaustion
  • .workingdir2/cache/ck-arbiter-design.md — establishes that jellyfin cannot be proxied by a userspace arbiter, since its FFmpeg opens /dev/dri/renderD128 directly
  • .workingdir2/cache/cr-xe-cgroup-enforcement.md — dmem cgroup as the enforceable VRAM ceiling on Arc
  • apps/infra/xe-dmem-nri/README.md — plugin contract and fail-open semantics