Repository navigation
[ROCm][DSV4][Perf] Pack sparse-MLA ragged decode metadata into graph buffers - #58352
ZhengGong-amd wants to merge 1 commit into
Conversation
|
This pull request has merge conflicts that must be resolved before it can be |
a6b6cdb to
2bb84ad
Compare
130ec5d to
f00ec4c
Compare
tpopp
left a comment
There was a problem hiding this comment.
Thank you for carrying this on. I think effects would be better seen with lower concurrency benchmarks in this case.
| prefill_swa_ragged_indptr=prefill_ragged_indptr, | ||
| ) | ||
|
|
||
| def update_draft_decode_metadata( |
There was a problem hiding this comment.
I'm not really caught up on how the new model runner system should be structured. Do you know where common code could be shared? I think the _build_ragged_into_graph_buffers and update_draft_decode_metadata are exactly the same in deepseek_v4 and deepseek_v41.
There was a problem hiding this comment.
Done in ec746e9. _build_ragged_into_graph_buffers is now build_ragged_into_graph_buffers() in vllm/v1/attention/ops/rocm_aiter_mla_sparse.py, next to build_ragged_indices_from_dense_out(), which both modules already import. The draft-step body lives there as refresh_decode_swa_ragged(), so each ROCm SWA builder's update_draft_decode_metadata() is now super() plus one call. The draft-update unit test now runs on both the V4 and V4.1 builders, and its cases fail when refresh_decode_swa_ragged() is made a no-op.
| # Keep fused multi-step decode disabled until update_draft_decode_metadata() | ||
| # also refreshes the ROCm-specific ragged SWA indices and indptrs. | ||
| supports_draft_decode_metadata_update = False | ||
| supports_draft_decode_metadata_update = True |
There was a problem hiding this comment.
Am I mistaken that, based on the runs, setting this flag to true and update_draft_decode_metadata are dead code because 4.1 uses Dspark rather than MTP?
There was a problem hiding this comment.
When you wrote this, yes: V4.1 runs DSpark, and the flag only mattered for the MTP fused-AR draft path. #60692 (merged Oct 12) changed that. DSparkSpeculator subclasses DFlashSpeculator, which now checks supports_draft_decode_metadata_update on every draft attention group. If all of them support it, it records update_draft_decode_metadata() inside the FULL draft CUDA graph and skips the eager _build_uniform_attn_metadata() on replay.
The DSpark draft layers are SWA-only on both models: V4.1 treats layers past compress_ratios as ratio 0, and V4-Flash's entry at index 43 is 0. So their only builder is the ROCm SWA builder this PR enables, and on today's main the flag switches that path on for ROCm rather than being dead code.
That also raises the bar on validation. None of the Oct 1 numbers exercised this path, because they predate #60692. I'll rerun with DSpark before asking for another look.
There was a problem hiding this comment.
It is reached: since #60692 DSpark records update_draft_decode_metadata in its draft graph, so this removes the eager draft rebuild (948 of 950 draft steps on main) and the fallback log. It gives no measurable speedup on V4.1, though (flag off is within 0.5 % per verify step at concurrency 1, 4 and 64); the gain is from the build() packing.
|
This pull request has merge conflicts that must be resolved before it can be |
f00ec4c to
ceaa485
Compare
…buffers On ROCm the DeepSeek-V4/V4.1 decode builders pack the ragged sparse-MLA indices into freshly allocated scratch tensors and then copy them into the persistent buffers FULL decode graphs captured. Add build_ragged_indices_from_dense_out(), which runs the count/compact kernels straight into caller-owned buffers (counts are scanned in place in indptr[1:]), and make build_ragged_indices_from_dense() a thin allocating wrapper so both share one implementation of the -1 sentinel filtering. Use it on the V4 C128A/SWA and V4.1 SWA decode build() paths, dropping three allocations and two device copies per call, and in a new update_draft_decode_metadata() for the ROCm SWA builders so fused multi-step draft decode can be enabled there. The graph-buffer packing and the draft-step refresh live next to it in rocm_aiter_mla_sparse.py (build_ragged_into_graph_buffers, refresh_decode_swa_ragged), shared by the V4 and V4.1 builders. Generated-by: Hyperloom Co-authored-by: Tres Popp <tres.popp@amd.com> Co-authored-by: Claude Signed-off-by: ZhengGong-amd <zgong@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
ceaa485 to
ec746e9
Compare
|
Thanks for carrying #52628 over to this one. On lower concurrency: agreed. The The next round will cover:
The shared-helper refactor is in ec746e9, and the DSpark answer is in the inline thread. |
|
Reran on main
Could you take another look? |
Overview
On ROCm, every DeepSeek-V4 / V4.1 sparse-MLA decode
build()packs its ragged indices into scratch tensors and then copies them into the FULL decode graph buffers, and the ROCm SWA builders cannot refresh those buffers after a draft step; this PR packs straight into the graph buffers and adds the in-place draft refresh, so the ROCm SWA builders setsupports_draft_decode_metadata_update = True.build_ragged_indices_from_dense_out()runs the count → scan → compact kernels from #58058 into caller-owned buffers, writing counts intoindptr[1:]and scanning them in place;build_ragged_indices_from_dense()becomes an allocating wrapper, so the-1filtering has one implementation and prefill output is unchanged.build_ragged_into_graph_buffers()andrefresh_decode_swa_ragged()sit beside it inrocm_aiter_mla_sparse.pyand are shared by the V4 C128A/SWA and V4.1 SWA builders; each ROCm SWAupdate_draft_decode_metadata()issuper()plus one call. The gfx950 width narrowing is unchanged. The draft refresh comes from #52628 (Tres Popp, co-author), closed in favour of this PR.When every draft attention group can update in place, the MRV2 draft speculators record the update in their FULL draft graph instead of rebuilding the draft metadata eagerly on every draft step; since #60692 that includes DSpark, whose draft layers are SWA-only on V4 and V4.1.
Claims
hipMemcpyAsyncto 3 kernels, saving 14.2–14.6 µs (27 %) at every shape on MI355X.Attention backend(s) DEEPSEEK_SPARSE_SWA cannot update draft decode metadata in place; falling back to rebuilding attention metadata eagerly.log, but gives no measurable speedup: with the flag forced off, DSpark is within 0.5 % of the PR at every concurrency.Validation
Unit, MI355X (gfx950), main
5c4b94beec, main's and the PR'stests/against each tree: the PR's tests pass on the PR; main's tests fail on the PR only where they import the removed_copy_ragged_to_graph_buffers; forcing the flag off fails onlytest_rocm_swa_builder_enables_fused_draft_decode; a no-oprefresh_decode_swa_ragged()fails the four draft-update cases.Micro, MI355X, main
5c4b94beec, the production helpers at the e2e configs' V4.1 SWA shapes (1–384 rows × 128), 5 %-1sentinels, median of runs 2–4, sameindptrand indices on both arms: main 53.5–53.9 µs per call, PR 39.0–39.4 µs, −14.2 to −14.6 µs (27 %) at every shape.e2e, V4.1-Flash, TP=2, MI355X, main
5c4b94beec,--kv-cache-dtype fp8,VLLM_ROCM_USE_AITER=1, DSpark as{"method": "dspark"}.vllm bench serve, random 1031 in / 509 out, 32 × concurrency prompts, one server on the host at a time, fresh server per run, median (range) of runs 2–4. "Flag off" is this PR withsupports_draft_decode_metadata_update = False. With DSpark the metric is ms per verify step, mean TPOT × mean acceptance length: on random prompts acceptance moves between 1.64 and 1.94 from run to run, and raw TPOT and throughput follow it.GSM8K 5-shot strict-match, greedy,
seed=1234, same setup:Per sample, the PR matches main's verdict on 1265 of 1319 with DSpark (repeat 1259) and 1250 without (repeat 1257). V4 was last measured on main
72e7874fa6, before #60692: at concurrency 61, TP=1 and MTP × 3, the arms' ranges overlapped and GSM8K matched main as closely as a repeat.Details
With
--monokernel(off by default), V4.1 decode batches of up to 32 rows get their SWA metadata fromswa_decode_meta, on gfx942 since #60731 and on gfx950 since #63885, which also writes into the graph buffers; this PR covers the default configuration, larger V4.1 batches, and V4. #57860 fuses indptr into a different V4.1 pack kernel and composes with this.Found by Hyperloom; reviewed and measured by hand.