Repository navigation
[None][feat] Model-specific disaggregated KV transfer planners #20207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
WeiHaocheng
wants to merge
25
commits into
NVIDIA:main
Choose a base branch
from
WeiHaocheng:feat/deepseek-r1-dep4-transfer-planner
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+4,422
−949
Draft
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
3935380
[None][test] Gate the gpt_oss modeling_v2 target under disaggregated …
WeiHaocheng b4b6f27
[None][doc] Design spec for model-owned disaggregated KV transfer pla…
WeiHaocheng eb47a8b
[None][doc] Implementation plan for model-owned disaggregated transfe…
WeiHaocheng 9c4d45f
[None][refactor] Add the TransferPlanner seam for disaggregated KV tr…
WeiHaocheng 6ba0a92
[None][refactor] Carry planner_id and planner_blob on RankInfo
WeiHaocheng 9153ea9
[None][refactor] Move transfer planning out of PeerRegistrar into Def…
WeiHaocheng c8f15d8
[None][refactor] Sender builds KV write metadata from the planner's T…
WeiHaocheng bec115d
[None][refactor] Receiver dispatches through the planner; transfer.py…
WeiHaocheng 81bdecf
[None][feat] Let a model class supply its disaggregated TransferPlanner
WeiHaocheng 15b9efe
[None][fix] Keep the default planner's statics static, wrap every pee…
WeiHaocheng 265197f
[None][chore] Apply the repo formatters to the transfer-planner change
WeiHaocheng aad9ca5
[None][doc] Plan for the DeepSeek-R1 dep4 target-owned transfer planner
WeiHaocheng 6f4057a
[None][feat] DeepSeek-R1 dep4 target plans its own disaggregated KV t…
WeiHaocheng 0dab135
[None][test] Gate the DeepSeek-R1 dep4 target under disaggregated ser…
WeiHaocheng 341d260
[None][chore] Log which TransferPlanner a transfer worker runs
WeiHaocheng 159018c
[None][doc] Record the two-node DeepSeek-R1 dep4 planner gate results
WeiHaocheng d3a22f6
[None][refactor] Bind disaggregated KV planners to the targets they c…
WeiHaocheng da9b201
[None][doc] Record the two-node re-gate of the planner rebinding
WeiHaocheng 037c586
[None][refactor] Hand TransferPlanner the request descriptions whole
WeiHaocheng b7958a4
[None][refactor] Identify transfer-planner deployments by architectur…
WeiHaocheng d2df040
[None][refactor] Let each transfer planner judge its deployments with…
WeiHaocheng e0e8792
[None][feat] Select the KV transfer planner by name through TRTLLM_KV…
WeiHaocheng 9a47167
[None][doc] Document TRTLLM_KV_TRANSFER_PLANNER and bring the planner…
WeiHaocheng 2ce870a
[None][test] Build the context-only CSA2 transfer test on the planner…
WeiHaocheng 3472a11
[None][feat] Split the transfer planner into a cache describer and a …
WeiHaocheng File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
docs/superpowers/plans/2026-10-10-deepseek-r1-dep4-transfer-planner.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| # DeepSeek-R1 dep4 target-owned TransferPlanner — Phase 2 plan | ||
|
|
||
| > **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans. Steps use `- [ ]`. | ||
|
|
||
| **Goal:** The first modeling_v2 target that plans its own disaggregated KV transfer: the | ||
| `r1_0528_nvfp4__sm_103__dep4` target ships a `TransferPlanner` in its own directory, overrides | ||
| `build_transfer_planner`, and a ctx dep4 -> gen dep4 deployment across two 4-GPU nodes runs on it. | ||
|
|
||
| **Design (agreed in chat, 2026-10-10):** | ||
| - Under ADP dep4 every ctx rank pairs with exactly one gen rank (same dp_rank; flat rank == dp_rank | ||
| since pp=cp=1), MLA is one K buffer per layer (`kv_factor=1`), FP8 KV, one PAGED layer group over | ||
| one physical pool. The target planner therefore needs no pool matching, no policy, no mapper: | ||
| `targets` = `[peer_dp_rank]`, `plan` = ordinal pairing then `base + block*slot_stride`, merging | ||
| runs of blocks that are consecutive on both sides into one fragment (the default planner emits | ||
| one fragment per block). | ||
| - `check_peer` is the target declaring the only topology it supports: peer `dp_size == 4`, | ||
| `pp_size == cp_size == 1`, `enable_attention_dp`, one PAGED group with one pool, equal | ||
| `slot_bytes`, `tokens_per_block` and layer count. Anything else -> `PeerIncompatibleError`. | ||
| - `planner_id = "deepseek_r1_0528_nvfp4_sm103_dep4"`; `receiver_payload_bytes` = 0; `describe` = b"". | ||
| - Correctness proof is a CPU parity test against `DefaultTransferPlanner` on a synthesized R1 | ||
| page table: split the target planner's merged runs back to slot granularity and the fragment | ||
| multiset must equal the default planner's. | ||
| - GPU gate: two nodes (ctx on A, gen on B), NIXL over UCX tcp/eth0, `TRTLLM_MODELING_V2=require`, | ||
| GSM8K against the `deepseek-ai/DeepSeek-R1-0528` NVFP4/FP8 reference (94.24). The in-repo | ||
| accuracy test is the standard localhost 8-GPU form for CI; the two-node launcher is a dev script | ||
| outside the repo because the harness only knows localhost. | ||
|
|
||
| **Spec:** `docs/superpowers/specs/2026-10-10-disagg-transfer-planner-design.md` (Phase 2 section) | ||
| and the agreed design above. | ||
|
|
||
| ## Global Constraints | ||
| - NVIDIA header on new files; `git commit -s`; no AI attribution. | ||
| - Target isolation (`test_targets_do_not_share_files`): the planner file imports the catalog or | ||
| framework packages absolutely, never another target. | ||
| - Zero change to `native/` and to the default planner. | ||
|
|
||
| ## Review Focus | ||
| 1. Non-owning / empty pairing: a chunk whose ordinals the peer does not hold must yield | ||
| `TransferPlan.empty()` (pinned in the parity test with an all-holes dst table). | ||
| 2. Merged runs must stop at any discontinuity on *either* side (pinned: src consecutive, dst not). | ||
| 3. `dst_start_token` masking must match the default planner (pinned in parity). | ||
| 4. A peer with a second pool (e.g. MTP layer in its own pool) must be refused, not silently | ||
| half-transferred (pinned in `test_check_peer_refuses_*`). | ||
| 5. The target planner must never be selected for the gen side when the ctx side runs the default | ||
| planner: framework `planner_id` gate (already pinned in Phase 1). | ||
|
|
||
| --- | ||
|
|
||
| ### Task 1: planner + parity test | ||
| Files: Create `tensorrt_llm/_torch/_experimental/modeling_v2/models/deepseek_v3/r1_0528_nvfp4__sm_103__dep4/transfer.py`; | ||
| Modify `.../modeling.py` (override `build_transfer_planner`); | ||
| Test: `tests/unittest/_torch/modeling_v2/models/test_modeling_v2_deepseek_transfer_planner.py`. | ||
| Steps: write the parity + refusal tests, see them fail on import, implement, see them pass, commit. | ||
|
|
||
| ### Task 2: in-repo accuracy gate (8 GPUs, localhost form) | ||
| Files: `tests/integration/defs/accuracy/test_modeling_v2_deepseek_v3.py` += `test_gsm8k_disagg` | ||
| (ctx dep4 + gen dep4, NIXL PYTHON, require mode via extra_env, DuckLLM args patched with | ||
| `kv_cache_quant_algo=FP8` so the R1 reference entry matches). Not runnable on 4-GPU nodes; it is | ||
| the CI form of what Task 3 runs by hand. | ||
|
|
||
| ### Task 3: two-node dev launcher + GSM8K | ||
| Files (outside repo, `/scratch/.../users/fredw/mv2-disagg/twonode/`): `alloc2.sbatch` | ||
| (2 nodes x 4 GPUs, keepalive on both), `serve_ctx.sh`, `serve_gen.sh`, `disagg_server.sh`, | ||
| `client_gsm8k.py` (copy of the harness client closure around `run_accuracy_test`). | ||
| Verify: both workers log `planner_id=deepseek_r1_0528_nvfp4_sm103_dep4`... (grep "Resolved" + | ||
| transceiver logs), GSM8K within tolerance of 94.24, no `PeerIncompatibleError`. | ||
|
|
||
| ## Results (2026-10-10) | ||
|
|
||
| - Task 1: planner + parity test committed (9a9b56e485); 33 tests green including the modeling_v2 | ||
| claims and target-contract suites. | ||
| - Task 2: in-repo 8-GPU gate committed (048bd64c25); collected, not runnable on 4-GPU nodes. | ||
| - Task 3: two nodes (ctx dep4 on nvl72d202-T12, gen dep4 on nvl72d202-T16, NIXL over UCX tcp/eth0, | ||
| static worker URLs, `TRTLLM_MODELING_V2=require`). Both workers log | ||
| `KV transfer planned by DeepseekR1Dep4TransferPlanner`, no default-planner fallback, no | ||
| `PeerIncompatibleError`. GSM8K flexible-extract **95.22** against the 94.24 reference, PASSED; | ||
| 1319 requests in 6.5 min. Launcher findings (loopback-only HTTP discovery, `--server_role` | ||
| crash in static mode, `UCX_TLS=^ib` requirement) are recorded in the dev scripts and memory, | ||
| not in the repo. Logs: `/scratch/fsw/portfolios/coreai/projects/coreai_comparch_trtllm/users/fredw/mv2-disagg/twonode/logs/run_20261010T182505Z`. | ||
|
|
||
| ## Redesign of the binding (after review) | ||
|
|
||
| The target-overrides-`build_transfer_planner` binding was rejected in review: one planner | ||
| must be able to serve several targets, including pairs such as ctx dep4 -> gen dep8 and | ||
| targets from different cores. A `COVERS` matrix of target-id pairs, then of | ||
| architecture-plus-topology pairs, followed and was dropped in turn: it encoded a topology | ||
| nothing consumed and made coverage an enumeration. Implemented instead: | ||
|
|
||
| - Planner at `disaggregation/planners/deepseek_mla_latent.py` as | ||
| `DeepseekMlaLatentTransferPlanner`, `planner_id = "trtllm.deepseek_mla_latent"`, with | ||
| `supports_deployment(architecture, mapping)`: `DeepseekV3ForCausalLM`, attention DP, | ||
| pp = cp = 1, any width. `check_peer` keeps the layout checks (one pool, layer count, | ||
| `tokens_per_block`, `slot_bytes`) because the arithmetic depends on them; `describe()` is | ||
| the base class's empty blob. | ||
| - `disaggregation/planners/__init__.py`: `PLANNER_ENV_VAR = "TRTLLM_KV_TRANSFER_PLANNER"`, | ||
| `PLANNERS` (planner_id -> class), `bind_transfer_planner`. The user names the planner; the | ||
| framework never picks one. | ||
| - `AutoModelForCausalLM.from_config` binds after construction for every model; the target's | ||
| `modeling.py` has zero transfer-related lines. | ||
| - Tests: `tests/unittest/_torch/disaggregation/test_planner_binding.py` (supports_deployment, | ||
| PLANNERS keys, binding direction, unset/empty variable, named planner installed, unknown name, | ||
| unsupported deployment) and `test_deepseek_mla_latent_planner.py` (parity, merge, targets, | ||
| geometry refusal). | ||
|
|
||
| ## Interface hardening (after review) | ||
|
|
||
| Reviewing DeepSeek-V4.1 (PR #19727, merged 2026-10-11) against this branch showed | ||
| that `plan()` took a copy of `Chunk`'s field list as positional arguments. main | ||
| added `Chunk.excluded_pool_views` (remote-tail / bounded-replay SWA views the | ||
| generation side rebuilds locally) and filters on it inside the sender's pool | ||
| loop, which this branch moved into `DefaultTransferPlanner.plan`. With the old | ||
| signature that field could not reach the planner, and a textual rebase would | ||
| have merged cleanly while dropping the filter. | ||
|
|
||
| `plan(self_ri, peer_ri, chunk, req_info, prompt_len)` and | ||
| `receiver_payload_bytes(self_ri, peer_ri, req_info)` now receive the two request | ||
| descriptions whole. `RecvReqInfo` moved from `native/transfer.py` to | ||
| `base/backend.py` next to `Chunk`, since it is the wire protocol type the planner | ||
| contract depends on. The sender's `KVSendTask` is deliberately not passed: it | ||
| carries transfer progress, counters and timers. | ||
|
|
||
| Done at the rebase onto main: `DefaultTransferPlanner.plan` skips the | ||
| `chunk.excluded_pool_views` main added (the DeepSeek planner returns an empty plan | ||
| when its sole pool is excluded), and the `bounded_replay_on_generation` peer check | ||
| main added to `PeerRegistrar` lives in `DefaultTransferPlanner.check_peer`; both | ||
| sit on the planner, not on `transfer.py`. The disaggregated gates pass | ||
| `modeling_v2: require` through each server's config, since main made the switch | ||
| an `LLM` argument. | ||
|
|
||
| Verified: 292 unit tests green (planner, chunked transfer, ownership regressions, | ||
| unsubmitted session, peer, modeling_v2 transfers/claims/routing/target | ||
| contract/op bind). | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for curiosity. Is it on purpose to put the superpowers plans in the PR?