Skip to content

P72 profile-run cap couples qwen3_next GDN buffer size → runtime batch bounded by GENESIS_PROFILE_RUN_CAP_M, not --max-num-batched-tokens (Ada SM89, k8v4) #33

Description

@jsboige

Summary. On v7.72.5 the P72 profile-run cap (GENESIS_PROFILE_RUN_CAP_M) lets the engine boot at --max-num-batched-tokens > 4096, but it also sizes the qwen3_next (GatedDeltaNet) compiled buffers at the cap value. So the runtime batch is bounded by GENESIS_PROFILE_RUN_CAP_M, not by --max-num-batched-tokens: any single combined forward whose token count lands in (cap, max_num_batched_tokens] overflows the GDN buffer and kills the worker. With the cap at 4096, 4096 is the effective runtime ceiling. First — thank you for the patch tree; it's the only thing that makes TurboQuant k8v4 + hybrid Qwen3.6 work on our hardware at all.

Environment

  • Image: vllm-qwen36-genesis-tq:v7.72.5-vllm01d4d1ad3 (your tree on nightly 01d4d1ad3)
  • Hardware: 2× RTX 4090 (Ada, SM89), TP=2 + EP=2
  • Model: Qwen3.6-35B-A3B AWQ 4-bit, --kv-cache-dtype turboquant_k8v4, --max-model-len 262144, gpu-util 0.82
  • KV cache ~2.0M tokens, full CUDA graphs, vision on. Stable for 7+ days at --max-num-batched-tokens 4096.

What we tried. To lift throughput we set --max-num-batched-tokens 8192 with P72 (GENESIS_PROFILE_RUN_CAP_M=4096) + P74 (chunk-clamp). Two distinct failures, depending on the cap:

(A) Boot crash — P72 OFF, batch ramped to 32768. Dynamo fake-tensor mismatch in determine_available_memory()'s profiling forward:

mul(FakeTensor(..., 65536, 128), FakeTensor(..., 16*s59, 128))   # 65536 = 2 × max_num_batched_tokens

The TQ-k8v4 GQA/multi-query path (P40 / P67) can't specialize that symbolic shape at large batch → profiling forward never completes. This is why P72 exists.

(B) Runtime crash — P72 ON at 4096, batch 8192. Engine boots clean, a short bench passes, then ~1h25 into the deploy under real mixed traffic the worker dies:

RuntimeError: setStorage: sizes [5536, 16, 128], strides [2048, 128, 1], storage offset 0,
and itemsize 2 requiring a storage size of 22675456 are out of bounds for storage of size 16777216
                                                                    # qwen3_next.py:495

The math is decisive:

  • 16777216 = 4096 × 16 × 128 × 2 — GDN buffer sized for M = the P72 cap (4096)
  • 22675456 = 5536 × 16 × 128 × 2 — a real combined forward batch of 5536 tokens

5536 > 4096 → overflow, via the inductor / cuda-graph as_strided aliasing path (gen_alias_from_base).

Why our pre-deploy bench missed it (a caution for others). An 80K single-prefill "crash test" is P74-chunked to ≤4096 per forward, and N=16 concurrent decode is ~16 tokens/step — neither ever produces a single forward in (4096, 8192]. It takes co-scheduled long-context prefill + decode in the same step to sum one forward past the cap. A valid test must force a single forward strictly in (cap, max_num_batched_tokens] (e.g. several concurrent ~2-3K-token prefills landing in one step).

The coupling, stated plainly. GENESIS_PROFILE_RUN_CAP_M does double duty: it bounds the memory-profiling shape (good — dodges crash A) and it sizes the qwen3_next GDN compiled buffers (bad — bounds the safe runtime batch). Raising both the cap and forcing a fresh compile to 8192 would re-expose crash A, so it's not a workaround we're willing to run on prod.

Question / ask. Is there a path to decouple the GDN buffer sizing from the profile cap — i.e. size the qwen3_next compiled buffers from --max-num-batched-tokens (or max_num_seqs × something) while keeping the determine_available_memory() profiling shape capped to dodge crash A? Or, alternatively, a large-batch profile route that lets the TQ-k8v4 path specialize at the real batch so P72 isn't needed at all? If 4096 is fundamental to the k8v4 GDN geometry on this model, that's a useful thing to document too.

Happy to test a candidate patch on Ada SM89 in a prod-adjacent setup and report back with the same crash-reproducing traffic shape. I can also provide fuller logs / the compile_ranges and boot summary if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions