fix(driver/cuda): size attention float workspace from prefill split-KV bound#421
Conversation
…V bound flashinfer's PrefillPlan carves the split-KV partial outputs out of the float workspace as tmp_v = num_qo_heads * padded_batch_size * cta_tile_q * head_dim_vo * 4 tmp_s = num_qo_heads * padded_batch_size * cta_tile_q * 4 where padded_batch_size is bounded by max_batch_size_if_split and the plan hardcodes num_blocks_per_sm = 2, giving per rank max_batch_size_if_split = ceil(2 * num_sm / num_kv_heads_local) and cta_tile_q tops out at 128 (64 for head_dim >= 256). This scales with SM count and head config, so a fixed buffer overflows on larger GPUs / low-KV-head models with "0 bytes available in AlignedAllocator". attention_float_workspace_bytes() already received a cudaDeviceProp but ignored it, sizing instead from a decode-shaped heuristic (cta_tile_q=16, padded_batch keyed off max_requests) that only happened to over-provision when max_requests was large, and early-returned the base for GQA ratios outside the decode fast-path, sliding-window, and TP>1 — all of which still hit the prefill kernel. Compute the actual prefill split-KV bound from prop.multiProcessorCount and the per-rank head config, sized unconditionally for every arch that reaches the prefill kernel. The estimate matches flashinfer v0.6.9 (the pinned version), v0.6.12, and main, which are byte-identical in this path. The bound is tp-invariant; base remains a floor. Fixes #414
|
Caution Review failedPull request was closed or merged during review Walkthrough
ChangesDynamic float workspace sizing
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Fixes #414 — the intermittent
batch_prefill_tmp_s ... only 0 bytes available in AlignedAllocator. Increase the workspace buffer size.warning during prefill on larger GPUs / certain head configs.flashinfer's
PrefillPlancarves the split-KV partial outputs out of the float workspace as:padded_batch_sizeis bounded bymax_batch_size_if_split, and the plan hardcodesnum_blocks_per_sm = 2, giving per rankmax_batch_size_if_split = ceil(2 * num_sm / num_kv_heads_local);cta_tile_qtops out at 128 (64 forhead_dim >= 256). The requirement therefore scales with SM count and head config, neither of which a fixed buffer can track.Root cause in our code
attention_float_workspace_bytes()already received acudaDevicePropbut ignored it, sizing instead from a decode-shaped heuristic (cta_tile_q = 16,padded_batchkeyed offmax_requests). That only over-provisioned by accident whenmax_requestswas large, and it early-returned the base for GQA ratios outside the decode fast-path, sliding-window layouts, and TP>1 — all of which still hit the prefill kernel (force_prefill_pathis set precisely when GQA isn't decode-supported).Change
Compute the actual prefill split-KV bound from
prop.multiProcessorCountand the per-rank head config, sized unconditionally for every arch that reaches the prefill kernel. The bound is tp-invariant (qo_headsshrinks asnum_kv_headsshrinks);base(80 MiB, 128 MiB for Qwen hybrids) remains a floor.Resulting sizes:
Validation
main— that sizing block is byte-identical across all three, so this is not coupled to a transient implementation detail.tests/inferlets/test_async_lm.py --driver cuda_nativeon an affected GPU (e.g. L40S) to confirm the warning is gone.Notes / follow-ups
parity_harness.cppstill callsAttentionWorkspace::allocate()with the 80 MiB default (it doesn't go through the planner); left as-is since it's a dev-only path.PrefillPlancall sites (catch the bump-allocator failure / compare computed-vs-available bytes) would be the only thing fully robust to a future flashinfer change to the sizing constants; out of scope here.Summary by CodeRabbit