Skip to content

[AMD][PD] enable mori transfer for PD decode DCP - #37358

Merged
ShangmingCai merged 17 commits into
sgl-project:mainfrom
inkcherry:feat/mori-pd-dcp
Oct 13, 2026
Merged

ShangmingCai merged 17 commits into
sgl-project:mainfrom
inkcherry:feat/mori-pd-dcp

Conversation

@inkcherry

@inkcherry inkcherry commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

PD decode with DCP currently rejects the Mori transfer backend because Mori does not implement the token relayout required by round-robin DCP KV shards.

Changes

  • Add DCP rank and layer metadata to Mori peer registration.
  • Transfer MLA KV at token granularity into each decode rank's DCP shard.
  • Map PP-local KV and Mamba state tensors by global layer ID.
  • Handle TP mismatch for replicated latent KV and reject unsupported head-sharded layouts.
  • Skip cached-prefix early send when DCP relayout is required.
  • Allow Mori in the PD decode DCP backend validation.

Validation

  • Mori DCP unit tests: 6/6 passed.
  • ServerArgs DCP tests: 6/6 passed.
  • Kimi-K3 PP8/TP1 prefill + TP8/DCP8 decode: both servers healthy, with no KV transfer errors.
  • 31K long-context retrieval and arithmetic: 8/8 passed, with no errors or truncation.
  • GSM8K: 39/40 (97.5%), with no errors or truncation.
  • 32K input, 1 output token, concurrency 16, 128 requests: 16,699 input tok/s and 31.11s median TTFT.
  • Pre-commit and lint checks passed.

The Kimi-K3 E2E validation used an AITER DCP-enabled stack; this PR only changes the Mori transfer path.


CI States

Latest PR Test (Base): ✅ Run #38288271653
Latest PR Test (Extra): ❌ Run #38288270583
Latest PR Test (AMD ROCm 10): ❌ Run #38288271415

@inkcherry
inkcherry marked this pull request as ready for review September 1, 2026 06:05
@Duyi-Wang Duyi-Wang added amd run-mori-pd Run mori pd related ci workflow labels Sep 3, 2026
Duyi-Wang and others added 3 commits September 3, 2026 15:53
Signed-off-by: inkcherry <mingzhi.liu@amd.com>

# Conflicts:
#	python/sglang/srt/disaggregation/mori/conn.py
Signed-off-by: inkcherry <mingzhi.liu@amd.com>
Comment on lines +1237 to +1242
requires_dcp_relayout = getattr(
req.disagg_kv_sender, "requires_dcp_relayout", None
)
if requires_dcp_relayout is not None and requires_dcp_relayout():
return

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QQ: Does only Mori need this? If so, I think this introduces another code path divergence. Also, I think we should avoid using getattr. And the code here is confusing.

@inkcherry inkcherry Sep 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, yes, writing it that way does introduce some confusion.

#32837 — this PR supports further optimization of DCP. But it only covers Mooncake and NIXL.

  • The current PR first supports the basic functionality of DCP for mori. Now I modified it here with an API supports_cached_prefix_early_send to bypass ·. No changes for nixl and mooncake.

  • In subsequent separate PRs, we will try to leverage feat: support Kimi Linear PD disaggregation with DCP #32837 and the validated optimizations. If it works, we can remove this bypass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-verified on Kimi3 E2E.

@ShangmingCai ShangmingCai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No other comment, others look good. But before we merge, we need to discuss about the diff in prefill.py.

@inkcherry

inkcherry commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor Author

No other comment, others look good. But before we merge, we need to discuss about the diff in prefill.py.

Thank you, I have replied with the reason and revised the code. Do you think we should directly support the mori layout-related work through this PR? I am inclined to separate it.

Signed-off-by: inkcherry <mingzhi.liu@amd.com>
Signed-off-by: inkcherry <mingzhi.liu@amd.com>
@inkcherry

inkcherry commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

@ShangmingCai Applied the DCP KV layout optimization to Mori without introducing backend-specific control-flow divergence now.
re-verified on Kimi3 E2E.

@ShangmingCai ShangmingCai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ShangmingCai

Copy link
Copy Markdown
Collaborator

/tag-and-reurn-ci

@github-actions

Copy link
Copy Markdown
Contributor

⛔ /tag-and-reurn-ci isn't a recognized CI command. Did you mean /tag-and-rerun-ci?

See the command reference.

@HaiShaw

HaiShaw commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

/tag-and-rerun-ci

@github-actions github-actions Bot added the run-ci CI: run the baseline test suite on this PR label Sep 24, 2026
@HaiShaw

HaiShaw commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

@Lzy17 please have a review.

@Lzy17

Lzy17 commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

@inkcherry @HaiShaw

The port itself looks right -- every helper this calls (build_dcp_token_transfer_plan, requires_dcp_relayout, prepare_dcp_token_item_lens, resolve_dcp_dst_entry_indices) is already on main and already used by nixl and mooncake, so mori is just the third caller. pr-test-amd-mori passed on this head: 4 unit tests and 2 PD e2e tests.

One gap: nothing in CI executes the new path. test_mori_backend_basic.py is fully mocked, and test_mori_transfer_engine_e2e.py -- the one that runs on GPUs -- uses the default small model with no --dcp-size. Since requires_dcp_relayout only returns True for MLA with dcp_size 1 -> N, send_kvcache_dcp is never reached. Could you add a case with a small MLA model, prefill --dcp-size 1 and decode --dcp-size 2, on the existing linux-mi35x-gpu-8.fabric runner? If it is easier for you, we are happy to add it ourselves -- just let us know which topology you had in mind.

Two smaller things:

  • _build_tp_slice_config switching to compute_head_slice_params changes the ordinary TP-mismatch path, which is unrelated to DCP. The TPMismatch e2e test does cover it, so this is not a blocker, but it would be cleaner as its own PR -- and the function-local import hides the dependency.
  • test_server_args.py repoints the rejection case from mori to ascend, which is correct now that mori is allowed, but nothing asserts mori is accepted. One extra case would close that.

@inkcherry
inkcherry requested a review from Lzy17 as a code owner October 8, 2026 03:15
@inkcherry

Copy link
Copy Markdown
Contributor Author

@inkcherry @HaiShaw

The port itself looks right -- every helper this calls (build_dcp_token_transfer_plan, requires_dcp_relayout, prepare_dcp_token_item_lens, resolve_dcp_dst_entry_indices) is already on main and already used by nixl and mooncake, so mori is just the third caller. pr-test-amd-mori passed on this head: 4 unit tests and 2 PD e2e tests.

One gap: nothing in CI executes the new path. test_mori_backend_basic.py is fully mocked, and test_mori_transfer_engine_e2e.py -- the one that runs on GPUs -- uses the default small model with no --dcp-size. Since requires_dcp_relayout only returns True for MLA with dcp_size 1 -> N, send_kvcache_dcp is never reached. Could you add a case with a small MLA model, prefill --dcp-size 1 and decode --dcp-size 2, on the existing linux-mi35x-gpu-8.fabric runner? If it is easier for you, we are happy to add it ourselves -- just let us know which topology you had in mind.

Two smaller things:

  • _build_tp_slice_config switching to compute_head_slice_params changes the ordinary TP-mismatch path, which is unrelated to DCP. The TPMismatch e2e test does cover it, so this is not a blocker, but it would be cleaner as its own PR -- and the function-local import hides the dependency.
  • test_server_args.py repoints the rejection case from mori to ascend, which is correct now that mori is allowed, but nothing asserts mori is accepted. One extra case would close that.

modified.

@Lzy17 Lzy17 left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. Items:

  1. Add the DCP e2e (small MLA model, prefill dcp1 / decode dcp2) and a test that mori is accepted, per my earlier comment. Neither is in the current head.
  2. State in the description, or split out, that this also changes non-DCP paths (layer-id PP mapping, mamba TP-slice), which only mocked tests cover.
  3. Bounds-check state_conv_shard_groups[i] / state_slice_outer_counts[i] in send_state, as is done for src_dims.
  4. Surface requires_dcp_relayout errors from _add_remote_peer as a request failure. The caller only logs, so the request waits for its timeout.
  5. Coordinate with #41769 (same _send_swa_dsa_state loop; dst-length lookups must use j) and #41140 (registration message needs the four new fields).

@ShangmingCai ShangmingCai added the bypass-fail-fast CI: a failing job no longer aborts its siblings (lint still gates) label Oct 10, 2026
@ShangmingCai

Copy link
Copy Markdown
Collaborator

/rerun-failed-ci

@ShangmingCai
ShangmingCai merged commit 50a1440 into sgl-project:main Oct 13, 2026
232 of 259 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

amd bypass-fail-fast CI: a failing job no longer aborts its siblings (lint still gates) run-ci CI: run the baseline test suite on this PR run-mori-pd Run mori pd related ci workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants