Repository navigation
[None][feat] Kimi K3 optimizations on Rubin - #19960
Conversation
1a6b257 to
1b1f238
Compare
|
A data point for the We run the same change on Kimi K3 + DSpark (7 drafts, 8-token verify) on SM107, 8 GPUs over 2 nodes, with the current
Since it is a self-contained, output-identical win that does not depend on the rest of the Rubin stack, would it make sense to split it out of this draft into a small PR so it can land earlier? I am happy to open one if you prefer. |
|
On the K3 MoE routing prologue: we worked on the other routing path, the scores path where For 5..8 tokens with more than 256 experts, that path uses Your PR moves K3 to a separate small-batch top-k plus the post-topK permutation (dyn-block at <= 12 tokens). Two questions, so we can decide where this should go:
cc @reasonsolo |
|
A data point for widening Same setup as my comment above (Kimi K3 + DSpark, 8-token verify, SM107, 8 GPUs over 2 nodes), only this gate changed, fresh server for each arm:
So about -6.7 to -6.9 ms per step at every length; acceptance is set by the drafter and the target, not by the verify kernel. Prefill goes through FLA in both arms. TTFT went up by 0.26 s (+2.1%) at 128K and 0.23 s (+0.5%) at 393K; part of that is the per-chunk replay-window write the fused verify adds to prefill (0.8-1.7 ms per chunk), the rest we could not separate from server-to-server variation. Outputs are not token-identical to the FLA path, as expected from a different kernel: the first generated token matched on 40/40 prompts, and the mean shared-prefix fraction of the greedy continuations against the FLA path was 0.658. The differences are deterministic (two cold starts of the fused path were token-identical on 40/40), and when I scored the divergence points with logprobs from a non-speculative reference run, none of the 18 scorable ones was a high-confidence divergence (largest |logit margin| 1.25 nats). Our accuracy checks did not change. So +1 for enabling 107 here. If this PR stays in draft for a while, would you be OK with me sending just the one-line gate change as a separate small PR? |
1b1f238 to
f09d991
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #78046 [ run ] triggered by Bot. Commit: |
f09d991 to
05904c1
Compare
|
PR_Github #78421 [ run ] completed with state
|
The DSpark attention_backend description changed in llm_args.py, so the checked-in serve and disaggregated schemas were stale. Regenerating with scripts/generate_trtllm_serve_schemas.py also picks up the kv_pool_rebalance_config and VisualGen tp_layout fields that the base branch added without regenerating, which test_checked_in_schemas_are_current reports together. Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
|
/bot run |
|
PR_Github #78474 [ run ] triggered by Bot. Commit: |
…nly batch Helix CP is decode-only, so the decoder runner skipped the autotuner warmup entirely on Helix CP workers: its context batch does not run there. Every tunable op then fell back to its default tactic, or tuned inside the serving loop. Run the autotuner warmup on Helix CP workers with generation_only=True: one batch of min(max_batch_size, max_num_tokens // (1 + max draft tokens)) generation requests, without the context batch. The other context warmups stay skipped on Helix CP. Tests: test_pytorch_model_engine_warmup.py checks the generation-only warmup batch on CPU, and that Helix CP warmup runs the autotuner followed by one empty_cache. Signed-off-by: Lanyu Liao <laliao@nvidia.com> Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
The Helix CP warmup test recorded that the autotuner warmup ran but not its arguments, so dropping generation_only=True would bring back the context warmup without failing it. Record each tracked call's arguments and assert the autotuner warmup receives the resource manager and generation_only=True. Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
Helix CP generation workers now run the autotuner warmup, but AutoTuner only treated TP ranks as a tuning group. A Helix generation worker with tp_size=1 and cp_size=8 therefore profiled the whole PARALLEL tactic space on every CP rank. For Kimi K3 the fine-grained MXFP8 Rubin GEMM has about 2,048 tactics per shape across 10 M buckets; on one rank a Helix CP8 generation server compiled 2,048 GEMM variants in 14 minutes and was still tuning at the 1800 s health timeout. Helix CP ranks run the same SPMD forward on the same token batch. Add them to the tuning group, so each rank profiles 1/(tp*cp) of the tactics. The existing tp_cp_allgather merge then keeps the fastest tactic per shape. Non-Helix CP keeps the TP-only group. Signed-off-by: Lizhi Zhou <1432185+reasonsolo@users.noreply.github.com>
|
/bot run |
|
PR_Github #78480 [ run ] triggered by Bot. Commit: |
|
PR_Github #78474 [ run ] completed with state |
|
PR_Github #78480 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #78510 [ run ] triggered by Bot. Commit: |
Barry-Delaney
left a comment
There was a problem hiding this comment.
Re-reviewed 029c8a2. Both previous blockers are resolved. The split-V pair now completes both CTAs cache reads before a cluster barrier, and only CTA 0 writes shared conv/replay caches; verified all ten cache reads precede the first cluster wait and all ten cache stores follow it under the single-writer guard. Draft counts above MAX_NUM_SPEC now disable replay-cache allocation through the shared executor/benchmark gate, retaining intermediate buffers and selecting sequential verification. Executed ten actual fallback-gate cases and both actual verify-dispatch branches. Reviewed the FP8 wide-head MLA carve-out, router gate tests, generation-only Helix warmup and TP/CP tuning partition. Eighteen actual partition groups and two cache-merge cases passed; Python parsing and git diff --check passed. No remaining blocking code finding. GPU race/numerical checks and native distributed tuning were not rerun locally.
|
PR_Github #78510 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #78589 [ run ] triggered by Bot. Commit: |
|
PR_Github #78589 [ run ] completed with state
|
|
/bot run |
|
PR_Github #78618 [ run ] triggered by Bot. Commit: |
|
PR_Github #78618 [ run ] completed with state
|
|
/bot run |
|
PR_Github #78626 [ run ] triggered by Bot. Commit: |
|
PR_Github #78626 [ run ] completed with state |
|
@reasonsolo @pengbowang-nv: since this merged, one case of It hit DGX_B200-PyTorch-4 and DGX_H100-PyTorch-5 on L0 #64787 (#20250, which doesn't touch attention). The test is host-only, so it fails the same way on any GPU. This is a semantic merge conflict between two PRs:
The other 9 parameter rows still pass. Which side is right is your call. Either the row should expect |
Dev Engineer Review
The inspected diff contains import-formatting changes in three Python files. It does not show runtime behavior, configuration, API, or test-list changes. The broader Kimi K3 and Rubin feature claims in the supplied objectives are not supported by this diff.
QA Engineer Review
No test changes.
Per-File QA Perspective
tensorrt_llm/_torch/custom_ops/cute_dsl_custom_ops.py: Import statements were reformatted. No observable behavior change appears in the inspected diff.tensorrt_llm/_torch/pyexecutor/_util.py: Import statements were reformatted. No observable behavior change appears in the inspected diff.tensorrt_llm/llmapi/llm_args.py: Import statements were reformatted, including moving the same Pydantic imports into a grouped import. No observable behavior change appears in the inspected diff.Description
Based on main
ff7ea92dfb.No longer stacked. #19959 has merged (
ff7ea92dfb); this branch now holds only its own 23 commits on top of main.Kimi K3 work for Rubin (SM107).
_Fp8BlockScaleWeightReadLinearpacks K32 R128c4 UE8M0 scales and runscute_dsl_mxfp8_gemm_rubinwith new K3 fine-grained low-M tuning buckets (fine_grained_m). SM100/SM103 keep DeepGEMM. Addsforward_prequantized.prime_inner_tactics), so the epilogue-keyed FC12 runner no longer raises TypeError in autotuner warmup. Kimi K3 acceptsmoe_config.backend: CUTEDSL_FC12.compact_packinginsubmit_dwdp.py. Needs [None][feat] Rubin merge-back: SM107 MoE, CFT release op, MegaMoE multi-node bootstrap, core runtime fixes #19183 for thedwdp/setup.pypart.TRTLLM_KDA_MTP_BF16_MATH=1, off by default). The replay caches becomekda_k_cache(bf16) +kda_g_cache(fp32) + bf16kda_v_cache/kda_beta_cache/ conv caches. bf16 and fp32 state pools are both accepted. SM107 is enabled for the optimized KDA kernels. The mixer now uses the kernel's fused attention-residual epilogue: packed token layout, gated RMSNorm in the epilogue (fuse_output_norm), and on SM107, for verify-only batches outside the breakable CUDA graph, an MXFP8 core with R128c4 scales that goes straight too_proj.forward_prequantized(Rubin CuTe MXFP8 GEMM). Without the output-gate section or finalized o_norm weights, the previous launch with the Python output gate is kept as the fallback.REPLAY_ONLY: the chunk is the accepted drafts, only the state is stored), andkda_mtp_commit_pending_drafts,commit_kda_pending_draftsand the V2 manager's_commit_kda_pending_draftsread the split caches. The verify after a resume starts a new WY-form chunk, so it matches an unsuspended run to the kernel's accuracy rather than bit for bit; the conv windows and replay caches stay bit-exact.ceil(H * S / 128)). Non-persistent only. The CUDA-graph workspace is sized once for every batch bucket, in 128-row tiles.TLLM_MOE_ASYNC_INPUT_QUANT).RMS_NORMgets MNNVL support without a residual. Other strategies fall back.trtllm::dsv3_router_latent_gemm_op), SM107, TP MEGAMOE_CUTEDSL.input_ready_eventthat ConfigurableMoE and the schedulers join at the first read ofx. The FC12 op zeroes its counters with one fill.AUTO). About 36% faster in the drafter region.TLLM_DRAFT_KV_GPU_BUDGET_GIBcaps the draft KV GPU budget on disaggregated generation workers and gives the excess to the target pool. It never goes below the draft's allocator floor and does nothing when unset.block_split_kvs; a request planned onto one split stores its output directly and the reducer skips its rows.test_kimi3.py::TestKimiK3::test_gsm8k_nvfp4_dep8with a gsm8k reference row. It runs withKIMI_K3_FP8_WEIGHT_READ_MOE_MLP=1(passed asenv_overrides): attention DP replicates the shared-expert and latentMoE MLPs, and in BF16 they leave DEP8 no KV-cache room. The reference was measured with this cast on.
Not included:
RMS_NORM_QUANT_FP8_BLOCKSCALE. Nothing uses it.fladependency. Main has both since [None][fix] Kimi K3 / KDA / MNNVL / DFlash: fixes for defects on main #19988 (_scratch_ct,fla-coreinrequirements.txt).ws_statsdouble buffer and slot-release__syncwarp. Main has them, pluscross-proxy fences, since [None][fix] Kimi K3 attn_res kernels: order the ws_stats reads and fence the slot releases #19829.
Test Coverage
tests/unittest/_torch/thop/parallel/test_kimi_k3_fp8_weight_read_linear.py(incl.test_checkpoint_pair_carries_cute_scale, Rubin)tests/unittest/_torch/moe/test_kimi_k3_situ_moe.py(incl.test_cutedsl_fc12_survives_autotune_warmup, SM107)tests/unittest/_torch/moe/test_moe_backend.py(incl.test_fc1_prologue_wait_preserves_exhaustion, SM107)tests/unittest/_torch/moe/test_kimi_k3_mlp.py:test_kimi_k3_shared_expert_parallel_constructiontest_kimi_k3_shared_allreduce_orderingtest_kimi_k3_latent_down_projection_overlaps_routingtests/unittest/_torch/thop/parallel/test_cute_dsl_moe.py: priming gate, FC12 warmup preparation, async input quantizationtests/unittest/_torch/thop/parallel/test_dsv3_router_gemm.py: 896 experts, top-k equality, fused router+latent optests/unittest/_torch/multi_gpu/test_mnnvl_allreduce.py::test_mnnvl_rms_norm_fusion_without_residualtests/unittest/_torch/attention/test_cute_dsl_mla.py: FP8 scales, split-KV sizing, MLA generation routing for FP8 wide-head verify groupstests/unittest/_torch/attention/test_cute_dsl_mla_split_plan.py: per-request split plantests/unittest/_torch/executor/kv_cache/test_kv_cache_budget_split.py: draft KV GPU budget cap, separate draft page sizetests/unittest/_torch/speculative/hw_agnostic/test_kimi_k3_dspark_semantics.py: DSpark drafter defaultstests/unittest/_torch/attention/test_cute_dsl_mla_helix.pytests/unittest/_torch/modules/kimi_kda/:test_kda_mtp_decode_cute_parity.py,test_kimi_kda_fused_verify_parity.py(epilogue arguments, unfused fallback, MXFP8 gating, SM107 MXFP8-vs-BF16),test_kimi_kda_bf16_state_pool.py; the replay-only commit intest_kda_mtp_decode_cute_parity.pytests/unittest/_torch/executor/kv_cache/test_mamba_cache_manager.pytests/unittest/_torch/speculative/hw_agnostic/test_sa.pytests/unittest/_torch/executor/test_pytorch_model_engine_warmup.py: Helix CP generation-only autotuner warmuptests/unittest/_torch/misc/test_autotuner.py: PARALLEL tactics split across the Helix TP×CP grouptests/integration/defs/accuracy/test_kimi3.py::TestKimiK3::test_gsm8k_nvfp4_dep8Validation results
K3 disaggregated DSpark, GSM8K (DEP16 context + DEP16 generation, FP8 KV cache, DSpark with 7 drafts)
cute_dsl_mla_decode_fp8.K3 disaggregated perf gate (SM107, Helix CP8 generation-only, concurrency 16, MTP5) at d5ca963: all 6 gates pass against the baseline.
test_helix_cp_runs_only_the_generation_autotuner_warmupand of the multi-rank Helix TP×CP tuning.PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.