Repository navigation
[None][feat] MiniMax-M3.1 DSpark: unified target and drafter KV cache in aggregated serving - #26
Merged
zheyuf merged 1 commit intoOct 29, 2026
Conversation
…'s manager in agg too Aggregated serving kept the DSpark drafter's KV in a separate pool paired with the target's block reuse, while disaggregated serving keeps it in the target's KVCacheManagerV2 as a windowed draft lifecycle. Use that layout in both, so one mechanism serves agg and disagg. What the paired pool did carries over: the drafter's window is reused only where it is complete, unwritten drafter pages are never published, and the draft lifecycle's share is window-sized for the same admissible sequences (the overlap scheduler's two per slot in agg). A model that ships the separate pool's window itself (F0a) keeps that pool in both modes. Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
zheyuf
force-pushed
the
zheyuf/brb-dspark-unified-agg-519-tfix
branch
from
October 29, 2026 07:55
12e9474 to
a3e252e
Compare
zheyuf
marked this pull request as ready for review
October 29, 2026 07:56
zheyuf
merged commit Oct 29, 2026
c09d042
into
brb-nv:user/brb/m3.1-flash-gb300-initial
4 of 6 checks passed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Description
This PR moves aggregated serving of MiniMax-M3.1-Flash with a standalone DSpark drafter to the unified KV layout that disaggregated serving uses, so one mechanism serves both. It is stacked on the unified-KV disagg PR (
zheyuf/brb-dspark-unified-disagg-519-v2); only its last commit is new. The section below describes the change, its results and its tests.Aggregated serving on the unified KV layout
On GB300, disaggregated serving keeps a standalone DSpark drafter's KV in the target's
KVCacheManagerV2, as explicit draft layer specs with a lifecycle of their own: BF16, 4096-token window, 128-token pages, and a window-sized share of the KV budget. Aggregated serving kept #22's separate draft pool, paired with the target's block reuse. It now uses the unified layout too:KvCacheCreator._should_unify_dflash_kv_cacheno longer requires disaggregated serving for a manager that hosts draft layers (MiniMaxM3KVCacheManagerV2).TRTLLM_DISAGG_SHARED_DRAFT_KV=0stays a disagg-only opt-out.Validating aggregated serving on the c44 regression config (TP2,
max_seq_len1M) found three costs of the unified layout, which hit disaggregated serving as well. Three commits of the disagg PR fix them:Results
Setup:
max_seq_len32K, or 131K with block reuse).tot-regression-c44-tp2-s6: TP2,per_conversationblock reuse, host cache, max batch 88,max_seq_len1M, ARIA env. Two deviations:indexer_kv_dtype: fp8(our image lacks the MiniMax MSA package) and an 89 GB host cache per rank (two TP2 servers per node, GPU pairs swapped between rounds).TRTLLM_MXFP8_GEMM_BACKEND=trtllm; otherwise the decode graphs' MXFP8 backend is re-profiled at every server start, which moves the step by about ±0.35 ms per server.AL, TP4/EP4. Golden = rejection sampling with block verification; default = rejection sampling off.
modeling_v2target, TP4 (4 passes)KV capacity per rank:
Decode step time, forced AL, device step (iteration-log median of steady generation steps), MXFP8 backend pinned, mean of two rounds:
Client TPOT p50 is at parity at every concurrency. These are fresh servers. After two agentic replays at natural AL, this PR's step is 0.1-0.2 ms longer at batch 1 and 0.2 ms (0.4%) longer at batch 64. Without the pinned backend, a single server's decode step moves by up to ±0.35 ms either way.
At natural AL (rejection sampling off), TP4/EP4 waves of 1024-token requests give output tok/s 0.998 at c16 and 1.003 at c64 (this PR / before, two rounds). TPOT p50 is 1.000 / 0.987 and TTFT p50 1.010 / 0.987.
Agentic replay, c44 config (MLPerf agentic v6, 531 requests, c44). Forced AL 3.04 except the last two rows; 12 replays before and 6 with this PR, with GPU pairs swapped between rounds:
Partial pages. The unified drafter's window is reused only where it is complete. Before the partial-endpoint commit, an OPTIONAL lifecycle was complete only at a page boundary. A prefix hit that ended inside a page therefore claimed up to the last full page and recomputed the rest, at most 127 tokens per hit; the paired pool copies the partial page instead. On the stack without that commit, every remaining difference above comes from this recompute:
Dropping the recompute without completing the window costs AL. Claiming the partial page, so that the drafter starts with no window after such a hit, gives an unforced agentic AL of 3.219 instead of 3.722. The partial-endpoint commit instead completes the window: an OPTIONAL lifecycle is checked at any endpoint with the REQUIRED coverage rule, and its partial page is copied as for REQUIRED lifecycles. With it (c44 config, MXFP8 backend pinned, two rounds plus unforced replays):
Two differences remain in the step pass. Its c1 requests are full-prompt hits, each sent right after a 1024-token request.
enable_iter_perf_stats: falseandprint_iter_log: false, c1 TTFT p50 is 42.9 vs 43.1 ms; the 3-4 ms between rounds follows the GPU pair. A fix belongs in the stats path.Prefix reuse, TP4/EP4 golden, block reuse on. Hit set (greedy, c1) and the agentic replay (531 requests, c48, unforced):
per_conversationper_conversationall_reusableall_reusableAgentX c44 (agentx-harness 1.0.12 on aiperf; the c44 recipe with the nvfp4 indexer; the partial-endpoint commit included). The warmup is 488 prefill-only requests with many subagent branch-offs. Prefilled tokens over the whole warmup:
kvCacheStats.cacheHitRateis not comparable across these layouts. KvCacheManagerV2 sums reuse and misses over all lifecycles, so in the unified layout the drafter lifecycle's page allocations count as misses: missed blocks are 2.1x the prefilled pages, against 1.0-1.2x with a separate pool. Compare prefilled tokens instead.Soak (TP4/EP4 golden, block reuse on): 2,611 requests in 13 minutes: SA, 3 x 320 mixed stress, the agentic replay, 3 x 320 stress, SA.
End to end: InferenceX AgentX on Balaram's recipes
agentx-harness 1.0.12 in full mode at synthetic AL 4.04, on Balaram's recipes verbatim. "good" is the branch without the four DSpark commits (it fails the SA AL gate at 0.74 of golden); "519" is the branch head. "this PR" includes #25. UF is this PR plus the DSpark agg perf PR (fused ancestral drafting + drafter slot lifetime). P90 tok/s/user is 1/P90(ITL).
Not covered
indexer_kv_dtype: nvfp4of the c44 config needs the MiniMax MSA package, which our image lacks; every run used fp8. The c44 config's host cache was halved per rank to fit two servers per node.Test coverage
tests/unittest/_torch/attention/sparse/msa/test_minimax_m3_unified_draft_kv.py: the unify gate (test_m3_unifies_a_dspark_drafter) and the window-sized share (test_window_sized_draft_ratio) are parametrized over aggregated and disaggregated serving.Unit runs on GB300 on the same wheel: this PR vs ff32d5d (the disagg PR before its host-sizing commit), so both commits are covered. No failure is new: every failure on this PR also fails on the base, with the same test ID.
test_dflash_host_ctx_alloc.py,test_minimax_m3_kv_transfer.pyNot run on either side:
test_hang_detector_kill.py(it SIGKILLs its process group),test_world_ranks_converge_on_hostless_fallback(it waits for an MPI world), andunittest/disaggregatedapart from the M3 KV-transfer file.Unit runs on a wheel built at the partial-endpoint commit: this PR vs that commit, with the same result. The MSA attention files give 137 vs 135 passed and 6 failed on both sides. The touched files plus
test_unified_draft_reuse.py,test_kvcm2_integration.pyandtest_dflash_unified_kv_gate.pygive 326 passed and 2 failed on both sides: the MPI-world test above, and one reuse-rule expectation that the partial-endpoint commit then updated.PR Checklist
🤖 Generated with Claude Code