Feat[DCP] Support decode context parallelism for DSA models with the flashmla_kv backend - #36990
Zhiy-Zhang wants to merge 2 commits into
Conversation
| if parallel.dcp_enabled: | ||
| # The indexer K cache is not sharded under DCP: every rank |
There was a problem hiding this comment.
The allocator can produce locations up to (size + page_size) * dcp_size - 1, but the indexer cache only covers size * dcp_size + page_size slots. Accessing the final widened page may cause an OOB GPU write. Please allocate the full (size + page_size) * dcp_size span.
| @@ -4520,6 +4473,12 @@ def __init__( | |||
| self.index_head_dim = index_head_dim | |||
| if index_buf_size is None: | |||
| index_buf_size = size | |||
| parallel = get_parallel() | |||
| if parallel.dcp_enabled: | |||
There was a problem hiding this comment.
This multiplies the actual indexer allocation by dcp_size, but the pool configurator still charges for one copy. Auto-calculated max_total_tokens may therefore overcommit memory and OOM during pool initialization. ref: _compute_dsa_indexer_cell_size
| parallel = get_parallel() | ||
| self.dcp_enabled = parallel.dcp_enabled | ||
| self.dcp_size = parallel.attn_dcp_size if self.dcp_enabled else 1 | ||
| self.dcp_rank = parallel.attn_dcp_rank if self.dcp_enabled else 0 |
There was a problem hiding this comment.
This bucket is based on the pre-gather local head count. For a 128-head model with TP8/DCP8, it selects 64 from 16 local heads, but FlashMLA receives 128 heads after Q all-gather, causing a shape mismatch and incorrect metadata. Please select the bucket per phase using the effective head count: local_heads * dcp_size for Q-gather paths and local_heads for CP-DCP global-KV prefill.
| if model_runner.server_args.enable_dp_attention: | ||
| # Keep each DCP group inside one attention-DP shard so the | ||
| # replicated indexer sees identical requests group-wide. | ||
| if parallel.attn_tp_size % self.dcp_size != 0: |
There was a problem hiding this comment.
Checking attn_tp_size alone rejects the standard DSA CP topology, which intentionally uses attn_tp_size=1 (e.g. TP8/CP8/DCP8 fails as 1 % 8 != 0). The requirement is that a DCP group must not cross an attention-DP shard, whose span is attn_tp_size * attn_cp_size. Please validate that span and its group alignment instead.
| dcp_meta = forward_batch.attn_dcp_metadata | ||
| if dcp_meta is None or dcp_meta.dcp_kv_buffer is None: | ||
| raise RuntimeError("DSA CP+DCP prefill requires a gathered KV buffer.") | ||
| dcp_page_table_1 = self._build_dcp_prefill_page_table( |
There was a problem hiding this comment.
indexer_seq_lens_cpu has already been filtered by bs_idx, while dcp_meta.dcp_kv_indptr still describes the original full batch. If a CP rank owns no tokens for some requests, this either fails the batch-size check or maps the remaining request to the wrong KV segment
| if gpu_mem is not None and gpu_mem > 60 * 1024: | ||
| reserved_mem = max(reserved_mem, 10 * 1024) | ||
| return reserved_mem | ||
| if self.dcp_size > 1 and is_cuda() and self.speculative_algorithm is not None: |
There was a problem hiding this comment.
This global guard breaks existing non-DSA configurations, including the registered Kimi K3 DCP8 + DSPARK path. Please scope this restriction to DSA with flashmla_kv, preferably in the DSA backend’s model-aware validation, rather than rejecting every CUDA DCP configuration.
There was a problem hiding this comment.
Under CP-v2 zigzag, materialize_full_mla_kv() writes the gathered KV into the cache and returns None, but this caller unconditionally unpacks a tuple, causing a TypeError.
There was a problem hiding this comment.
If every shard has LSE=-inf, all weights are zero and this computes 0 / 0, reintroducing NaNs even when the partial outputs were cleared beforehand. Please use a safe denominator and explicitly return zero output (and -inf global LSE) when weight_sum == 0
| quantize_k_cache_separate, | ||
| ) | ||
|
|
||
| current_nope, current_rope = quantize_k_cache_separate(k_nope, k_pe) |
There was a problem hiding this comment.
These rows are quantized here for the temporary gathered buffer, then the same k_nope/k_pe tensors are quantized again when writing the persistent KV cache.
…flashmla_kv backend Co-authored-by: Lai-JX <76830814+Lai-JX@users.noreply.github.com>
e11018e to
c6aeb8b
Compare
|
@huangzhilin-hzl Thank you very much for your review comments. Most of the boundary issues have been fixed. The only remaining issues are related to the DCP and MTP implementations, which will be addressed after #31785 is merged. |
|
@kpham-sgl Hi, I noticed #36507 has already been merged. Could you share some feedback on the implementation in this PR? |
co-author:https://github.com/Lai-JX
Motivation
Inspired by PR #31821, this PR builds on it to improve DCP support for NSA models.The main changes introduced in this PR are as follows:
Accuracy Tests
tp (baseline)
server command
accuracy result
cp-dcp
server command
accuracy result
tp-dcp
server command
accuracy result
Speed Tests and Profiling
The tests were conducted using an open-source agent workload dataset: Inferact/codex_swebenchpro_traces.
Here, Concurrency refers to the number of concurrent sessions, while Turns refers to the number of interaction rounds.
Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ciCI States
Latest PR Test (Base): ❌ Missing
run-cilabel -- add it to run CI tests.Latest PR Test (Extra): ❌ Blocked --
run-ciis required first.Latest PR Test (AMD ROCm 7.2): ➖ No AMD PR run found for this commit.