Skip to content

layer split: make the compute headroom overridable, and report what actually failed - #1911

Open
realhidden wants to merge 1 commit into
leejet:masterfrom
realhidden:layer-split-headroom
Open

layer split: make the compute headroom overridable, and report what actually failed#1911
realhidden wants to merge 1 commit into
leejet:masterfrom
realhidden:layer-split-headroom

Conversation

@realhidden

Copy link
Copy Markdown

What this changes

Two small things in graph_cut_layer_split_backend_capacities / partition_graph_cut_layer_split:

  1. compute_headroom_bytes (hardcoded 2 GiB) becomes overridable via SD_COMPUTE_HEADROOM_MB. Default unchanged.
  2. The "does not fit" error reports the segment's own size, what was already packed, the capacity and the shortfall — instead of one cumulative figure labelled as what the segment "needs".

No behaviour change unless the env var is set.

Why

Trying to run MiniMax-H3 ref2va Q4 at its trained 1344×768 canvas across an 8 GB + 12 GB pair (--backend "diffusion=cuda0&cuda1" --split-mode layer).

The params pass fills the 8 GB card to 5473 MB, leaving 2719 MB free. 2 GiB of that is then reserved as compute headroom, so the smaller card's capacity is ~0 — it can absorb no graph segments, everything piles onto the 12 GB card, and the plan is refused. The split silently degenerates to single-GPU:

graph-cut layer split: CUDA0 <- segments [0, 24), 265 tensors, 5473.0 MB
graph-cut layer split: CUDA1 <- segments [24, 51), 267 tensors, 5465.2 MB
ERROR: segment 14 needs 3582.3 MB on CUDA1, but only 3416.8 MB is available under current VRAM limits

Two things made this hard to diagnose from the outside:

--max-vram cannot help. The limit is applied with min(), so it can only ever lower the capacity. I tried cuda1=7.5, 11.0, 11.7 and got byte-identical output every time, because the free - headroom term always won. The message points at "current VRAM limits", which reads like --max-vram is the knob.

The reported figure is cumulative, not the segment. current_used + bytes is printed as what "segment N needs", which reads as one enormous segment — so the obvious move is to lower the resolution. That does nothing: I went 1344×768 → 1280×736 and the number did not move a single byte, because it is dominated by what was already packed. The actual segment was 210 MB and the shortfall 157 MB.

After the patch:

graph-cut layer split: segment 16 (210.1 MB) does not fit CUDA1: 3364.0 MB already packed
  + 210.1 MB > 3416.8 MB capacity (short by 157.3 MB). Capacity is min(free VRAM -
  compute headroom, --max-vram), so --max-vram cannot raise it; lower
  SD_COMPUTE_HEADROOM_MB (default 2048) or free VRAM on that device

which says immediately that the problem is the packing, not the segment.

On the override

To be clear about what it bought me: on this hardware, lowering the headroom does not rescue the job. At 512/256/0 MB the planner passes and then the allocation genuinely fails (cudaMalloc failed: out of memory, then a segfault) — the 2 GiB is load-bearing here, and the honest answer for this pair is that it does not have the VRAM.

But that is a useful thing to be able to establish in five minutes rather than by rebuilding, and on a less lopsided pair the headroom is exactly the knob you want. An env var seemed the least invasive way to expose it; happy to make it a CLI flag or a sd_ctx_params_t field instead if you'd prefer.

Testing

Built with -DSD_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=86 (2× RTX 3060) and exercised on MiniMax-H3 ref2va Q4 with reference images, single-GPU and split, at canvases from 832×480 to 1344×768. Default path unchanged: same output bytes and same 1.32 s/it as master on the single-GPU configuration.

…ally failed

The 2 GiB compute headroom held back on every device was hardcoded with no
override, and on an asymmetric multi-GPU pair that is what makes layer split
unusable. Measured on 8 GB + 12 GB with MiniMax-H3 ref2va Q4 at 1344x768: the
params pass fills the 8 GB card to 5473 MB, leaving 2719 MB free, and 2 GiB of
that is then reserved — so the small card absorbs no graph segments at all,
everything piles onto the 12 GB card, and the plan is refused by 165 MB.

--max-vram cannot rescue it: that limit is applied with min(), so it can only
ever lower the capacity, never raise it. Every value from 7.5 to 11.7 GB gave
byte-identical results because the free-VRAM term always won.

SD_COMPUTE_HEADROOM_MB makes the trade — refuse-to-plan versus risking a real
OOM — a per-host decision. Default unchanged at 2 GiB.

The error message also reported `current_used + bytes` as what the segment
"needs", which reads as one huge segment. It is cumulative, so it does not
shrink when you lower the resolution: I chased a smaller canvas from 1344x768
to 1280x736 and the number did not move a single byte. It now prints the
segment's own size, what was already packed, the capacity and the shortfall.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant