Repository navigation
[TRTLLM-17033][feat] Qwen3.8-Flash-Next modeling_v2: CUTEDSL, MTP 1..7, video, FP8/NVFP4 KV, bf16 state, canonical QSA selection, breakable prefill graph, GB300 fast paths - #20276
Conversation
8d88898 to
c1812ac
Compare
1f44961 to
c8b05ad
Compare
02e2d7a to
bfa1ea6
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #78865 [ run ] triggered by Bot. Commit: |
…ecode kernel for every row count The fused block top-k + expansion compiled one CuTe kernel per distinct row count, since its operands were bound with static layouts. The eager prefill path calls it with each step's context-row count, so a new count paid a JIT compile on the serving path. The entry now compiles through the TVM-FFI path the target's other CuTe ops use: the score table is passed as a tensor and its layout rebuilt inside with the static width and row stride the 16-byte key loads need, the other operands as pointers, and the row count as a runtime argument. The cache key drops the row count; is_valid also checks the per-row operands are contiguous, which the pointer form relies on. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…FP4 KV cache only on SM100f Only the SM100-family FP8 context FMHA kernels read an NVFP4 KV cache, so other architectures keep failing AttentionOp's FP4 KV check instead of passing the FP8 FMHA gate. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…t copy only where its launches can happen Under trtllm-gen the trunk kept a CuteDSL-layout copy of the routed experts on every layer (about 63 GiB) for context launches of at least 4096 rows. It is now allocated and dispatched only when max_num_tokens can reach that size, and TRTLLM_MODELING_V2_MOE_PREFILL_COPY=0 drops it for memory-constrained deployments; every launch then runs on trtllm-gen. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…pendent of the KV head split The index and position planes were packed into QSA_SIDE_PLANES when a page coincided in size with a K/V or block-scale page on this rank, which depends on the KV heads the rank holds: with FP8 KV, two KV heads, head_dim 256 and 32 tokens per block, TP1 registered INDEX_KEY plus QSA_INDEX_POSITION while TP2 (one head a rank) registered the packed role, and NVFP4 flipped which side packed against ADP. Disaggregated peers then failed validate_peer_compatible. The candidate page sizes are now every size a layer's K/V or block-scale page can take at any split of its KV heads over ranks (one head a rank up to all of them), so the packing decision and the packed size are the same on TP, TP>1 and attention-DP layouts. With this target's geometry FP8 and NVFP4 pack on every layout and bf16 on none. The packed buffer grows in 16-byte steps. Adds a TP1/TP2/ADP2 regression test on real managers: equal logical roles, mapper kinds and side-view pages, with physical placement free to differ. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… to 11 The four pre-merge gates are unchanged. Post-merge keeps seven: three drafts over CuteDSL experts and a bf16 recurrent state in one engine (merging the two separate gates), the FP8 and NVFP4 KV pass keys, seven drafts over 3k-12k-token pass keys now on a bf16 state (merging the fp32 and bf16 versions), seven drafts all rejected, video, and the breakable prefill graph against eager. The thirteen cases no list ran are removed, with the acceptance-length keys only they read. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ope the target runs The target's op tests drove every certified cell of every op: 2687 cases over 90 files. Each op's CELLS now covers the shapes the target calls it at plus one cell per distinct path the forward reaches (dtype, pad slots, layouts, kernel-switch boundaries), at most about six per entry; each note lists the paths that are no longer certified. Repeated fan-outs (graph replays, reject lists, per-cell composition checks, cold-process runs) keep one case per path. The two hc_decode_mix test files are merged, duplicated vision and pool-contract checks are dropped, and the CPU-only weight-table test is marked cpu_only and listed in l0_cpu.yml. The bf16 decode rows form is now certified at 128 rows, the size the target runs it at. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ine running every check that fits One MTP1 engine runs gsm8k with its acceptance floor, MMMU and the videos; one CuteDSL + fp8 KV + bf16 state MTP3 engine runs gsm8k and the pass keys; MTP7 pass keys move to NVFP4 KV over the bf16 state. The forced-acceptance case is dropped. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…op, one property and one guard test Each op certifies the shapes and layouts its forward reaches in at most three cells (four where the forward reaches four compiled variants: hc decode first, inject norm, qk norm rope, bf16 gemv, cached replay), keeps one property test and one single-case guard, and drops the wrong-variant, composition and determinism tests. Every op note lists what stays certified and what does not. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…or the fp8 and NVFP4 KV engines Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…s next to main's KV retention check _validate_request reached the model's optional hook through self.model_engine. test_connector_retention_request_validation (NVIDIA#20086) builds its executor with object.__new__(PyExecutor) and sets only the members the other checks read, so it failed with AttributeError on model_engine. The hook is now looked up through getattr(self, "model_engine", None), as _kv_connector_moves_kv reads kv_connector_manager: an executor without a model engine has no hook to call. NVIDIA#20086 also made _validate_request read _is_kv_manager_v2, which this PR's admission tests' executor stub lacked; _fetch_and_activate_new_requests turned the AttributeError into a rejection of every request. The stub now carries it. Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
13c21f4 to
257d5f0
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #79774 [ run ] triggered by Bot. Commit: |
|
PR_Github #79774 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #79889 [ run ] triggered by Bot. Commit: |
|
PR_Github #79889 [ run ] completed with state
|
ZhanruiSunCh
left a comment
There was a problem hiding this comment.
LGTM for infra part
|
/bot run --disable-fail-fast |
|
PR_Github #80019 [ run ] triggered by Bot. Commit: |
|
PR_Github #80019 [ run ] completed with state Resource maintenance in LLM/main/L0_Test-x86_64-Multi-GPU #2983: B200 multi-GPU stages are paused to relieve the CI queue backlog (109 running / 459 pending on 2026-10-22). Owner: @sharabeshj-nvda. The CI team decides when to lift it.
|
|
/bot run --disable-fail-fast |
|
PR_Github #80081 [ run ] triggered by Bot. Commit: |
|
PR_Github #80081 [ run ] completed with state Resource maintenance in LLM/main/L0_Test-x86_64-Multi-GPU #3317: B200 multi-GPU stages are paused to relieve the CI queue backlog (109 running / 459 pending on 2026-10-22). Owner: @sharabeshj-nvda. The CI team decides when to lift it. |
Description
Completes the modeling_v2 target
qwen4_exp/qwen3_8_flash_next_nvfp4__sm_103__tp1(GB300 sm_103, TP1), on top of #20143 (merged), rebased on mainaf3e5eb257:Every new feature is off unless selected through engine configuration.
The commits are grouped by area for review; the commits between the feature head (
77f394148c) and59b0c08fe8add ops that59b0c08fe8wires in, the next six address the review comments and a CI failure,2cef6d6cc4follows main's move of the CuTe DSL helpers (#19275),53bdd2281ecompiles the fused block top-k once for every row count, the next three address the second round of review comments, the next five cut the target's tests down (26 accuracy cases to 6; the modeling_v2 unit run from 3,444 to 1,213 passed cases), and the last one keeps the admission tests passing next to main's KV cache retention check (#20086).109b161cd4feat5f4a2ac156feat77f394148ctest24c1ab6201perf• catalog entries for a low-M bf16 GEMM and FlashInfer's chunked gated delta rule
• PDL in the QSA index-score kernel
• QSA launch heuristics
d284f4a871perffef084ee3aperfc499e28702perfeb0808f923perf59b0c08fe8perfmodeling.py/weights.pyrun the fast pathsabd5b89871choreb1de32022ftest1141bb4781fix64c1e28466fix981b09a526fixzcoversxf19ae0bcaechoreroutegets theModelConfigand LLM args next to main'skv_cache_quant_algo; qwen4_exp derives its own engine choices26c282e864chorelow_m_bf16_mmandflashinfer_chunk_gated_delta_rulemove fromcatalog/to the target'sops/0186621e62test2cef6d6cc4choremake_ptrand the pipeline helpers fromtensorrt_llm/_torch/kernels/blackwell/, where #19275 moved them53bdd2281eperfqsa_topk_expand_decodecompiles one kernel for every row count: the row count is a runtime argument, so an eager step's context rows no longer pay a JIT compile for each new count456f198a1efix9aa0985bd7perfmax_num_tokenscan reach a 4096-row launch;TRTLLM_MODELING_V2_MOE_PREFILL_COPY=0drops itdcffd603d2fixcf90243a00,18f2de7752,ed32fa5db5test375b5f90e4,19521ac16dtest13c21f460bfixgetattr(self, "model_engine", None), as_kv_connector_moves_kvreads its connector, so #20086'sobject.__new__(PyExecutor)executor stub has no hook to call; this PR's admission tests' stub carries the_is_kv_manager_v2#20086 readsFeatures
moe_config.backend: CUTEDSL(TRTLLM/AUTOkeep trtllm-gen)• GDN cached replay
• QSA sparse attention in the draft layer
• IndexShare
• speculative rollback of the PLE and QSA side state
MTPDecodingConfig(the legacyTRTLLM_USE_GDN_REPLAY=0path stays at draft <= 3)kv_cache_config.dtype: fp8• uint8 e2m1 pages + e4m3 block scales
• QSA side planes packed so the data and scale pools keep one page-index scale
kv_cache_config.dtype: nvfp4kv_cache_config.mamba_ssm_cache_dtype: bfloat16(the engine'sautoresolves to bf16 for this checkpoint)prefill_cuda_graph_backend: breakableRouting declines what the target's constructor would refuse, from main's
kv_cache_quant_algo(#20267) and the engine choices qwen4_exp derives from theModelConfigand LLM args (EngineChoices):piecewiseprefill graph.So
modeling_v2="auto"falls back to the built-in model instead of failing mid-build.Performance
Setup:
modeling_v2: require.max_batch_size128,max_num_tokens16384, chunked prefill, CUDA graphs at batch 1..128,free_gpu_memory_fraction0.6.* Measured at an intermediate step of the perf work; the later steps targeted the mixed and con128 decode steps.
** 3 same-host rounds, TPOT 24.8 ms, TTFT 1.87 s. Measured before the last four perf steps, which were measured per kernel in place: 0.4 - 1.4 ms per mixed step each, and 55 us per decode step for the logits cast.
What runs on the fast paths:
The fast paths cover bf16 KV and an fp32 GDN state, the checkpoint's own storage. FP8 / NVFP4 KV and a bf16 state keep the feature commits' paths. At con128 they are slower: FP8 KV -20% and bf16 state -11.5% against bf16 KV / fp32 state, measured at an intermediate step.
Shared code touched (please review)
tensorrt_llm/_torch/pyexecutor/py_executor.py:_validate_requestcalls an optionalvalidate_request(request)on the model (found through the executor's model engine, if it has one), mirroringsampler.validate_request; no model in the tree defined one before. An oversize or inconsistent multimodal request now fails alone instead of ending the executor. The executor stub oftest_beam_search.py's admission test gains amodel_engine.tensorrt_llm/_torch/pyexecutor/engine/runners/decoder/inputs.py: the mRoPE position delta is carried through one-model MTP verify groups (DecoderInputPreparer._decode_mrope_position_delta;_pack_extend_requestsand_pack_generation_requestsshareHostInputs.has_gen_mrope_delta). This also changes verify-row rotary for built-in mRoPE models with a one-model drafter.tensorrt_llm/_torch/pyexecutor/model_loader.py,_experimental/modeling_v2/_router_index.py,tensorrt_llm/_torch/model_config.py:effective_mamba_ssm_cache_dtypeis factored out ofvalidate_and_set_mamba_ssm_cache_dtype;modeling_v2_resolvepassesmodel_configandllm_argsto every family'sroute(), after main'skv_cache_quant_algo: qwen4_exp derives itsEngineChoicesfrom them, gpt_oss and deepseek_v3 accept and ignore them;moe_backend_requestedkeeps the requested MoE backend.tensorrt_llm/_torch/attention/backends/sparse/qsa/:cache_manager.pypacks the index and position planes into one side buffer when their page size could equal a K/V or block-scale page at any split of the KV heads over ranks (FP8 and NVFP4 KV at this geometry, never bf16). The decision is the same on every TP / attention-DP layout, so disaggregated peers agree on the transfer roles. This fixes a trunkexact_divassert and a silent draft-layer misaddressing; the built-in path could not construct its manager with NVFP4 KV before.metadata.py: the draft block table andprepare_for_draft_forward.kernels.py:displace_oldestflag (default off);use_pdl/prefetch(both default off);cpp/tensorrt_llm/thop/attentionOp.cpp(in109b161cd4and456f198a1e, needs reviewer attention):mFP8ContextFMHAis also set for an FP4 KV cache when MLA is not enabled, on the SM100 family only. Only those FP8 context FMHA kernels read FP4 KV, and a bf16-output attention layer aborted ininitialize()before; other architectures still fail AttentionOp's FP4 KV check.mUseNvfp4MlaKvCache/mFP8ContextMLA. Reading the code, the expression is unchanged for them and for every non-FP4 call, but this is not measured on those models.attention/thop_attention.py: additive cells and constants (qwen4_exp FP8 / NVFP4 / MTP verify widths); the gpt_oss / deepseek cells and reference branches are unchanged;graph/eager_on_graph.py: the breakable prefill graph's break;attention/fused_qk_norm_rope.py: cells for this target's geometry.Decisions worth knowing
enable_heuristic_topk) is not included. Measured on GB300:max_num_tokens >= 4096, the smallest launch it serves; below that every launch stays on trtllm-gen and the memory stays in the KV pool.TRTLLM_MODELING_V2_MOE_PREFILL_COPY=0drops it for memory-constrained deployments (gsm8k 95.98 without it, 96.17 with it).generate(max_tokens=1)), eager -> BCG: 128 tokens 158 -> 30 ms, 512 tokens 104 -> 33 ms, 2048 tokens 104 -> 69 ms, 6000 tokens 204 -> 205 ms (MTP3: 123 -> 43, 124 -> 42, 124 -> 73, 212 -> 213).mamba_ssm_cache_dtype: autois now claimed by this target (it fell back to the built-in model before);fp16is refused.Known limitations / not verified
free_gpu_memory_fraction: 0.9did not boot; the perf configuration runs at 0.6.TRTLLM_MODELING_V2_MOE_PREFILL_COPY=0, ormax_num_tokens < 4096, gives the copy's memory back to the KV pool.route()cannot see those).tokens_per_block != 32;scripts/cbts: these tests were not run in the feature validation; one unix-socket test hangs in the container, unrelated to this diff.Test Coverage
GB300 (sm_103), TP1,
modeling_v2: require, full gsm8k (1319 samples).Final head (
13c21f460b, rebased on mainaf3e5eb257). The rebase applied every commit without conflicts; the sections below it were measured on the pre-rebase hashes.test_kv_connector_initialization.py,test_py_executor.py,test_beam_search.py -k vbws_rejects,disaggregated/test_chunked_transfer.py,test_trtllm_serve_config_schemas.pytest_checked_in_schemas_are_current, which main fails too since93b17dcdd9set the version to 1.4.0rc2 without regenerating the snapshots (waived)unittest/_torch/modeling_v2(not comm)l0_cpu.yml's modeling_v2 files,-m cpu_onlyscripts/run_mypy.sh)test_gsm8ktest_mtp1_gsm8k_mmmu_and_videotest_mtp3_long_context_passkeyTest slimming (
f29b8c6f3b, before the rebase):test_gsm8k(unchanged)test_mtp1_gsm8k_mmmu_and_videotest_mtp3_long_context_passkeytest_mtp3_cutedsl_fp8_kv_bf16_statetest_mtp7_long_context_passkey(NVFP4 KV, bf16 state)test_breakable_prefill_matches_eager(unchanged)unittest/_torch/modeling_v2(not comm)l0_cpu.yml's modeling_v2 files,-m cpu_onlyscripts/run_mypy.sh),pre-commitover the changed filesReview fixes (
6b039cb3c6):unittest/_torch/modeling_v2(not comm)test_cute_dsl_moe.py)71b2b3cf66(the top-k compile fix ond0b2d5dfa6):qsa_topk_expand_decodeand the target's other attention ops' unit tests, including one compiled kernel across 1 to 300 rowsd0b2d5dfa6)d0b2d5dfa6(on mainc14609482b):unittest/_torch/modeling_v2(not comm)l0_cpu.yml's modeling_v2 files,-m cpu_onlytest_beam_search.py -k vbws_rejectstest_pytorch_model_engine.py,test_py_executor.py,disaggregated/test_chunked_transfer.py, QSA,test_model_config.pypre-commitover the PR's files (mypy throughscripts/run_mypy.shin the container)Before the rebase (
dcff1146d0, on main72cd8b57a3):test_beam_search.py -k vbws_rejects(failed in CI onf22959cf9a)pre-commitover the changed filesBefore the review fixes (the same eleven patches as
f22959cf9a, on maina3766d68f9):unittest/_torch/executor-m cpu_onlywith no GPU visible: 2663 passedtest_model_configIn
unittest/_torch/executorthe only failures were:-m cpu_only;MpiPoolSessiontests, which cannot start workers in the test container (one timed out, two were deselected);test_overlap_scheduler.pytests, whoseQwen3-0.6Bcheckpoint this cluster does not have.All 26 qwen4_exp gates passed on the same eleven patches before the rebase onto #20134 (
02e2d7a7eaon main3163e66b2c):The other gates:
The acceptance lengths were read from the worker's iteration statistics. The test cluster cannot spawn MPI workers, so the LLM API worker runs in-process, and there
LLM.get_stats()returns nothing. The engine keeps the last 1000 iterations, so the values cover the end of each run. CI runs the gates unmodified.Earlier validation:
CI entries (
l0_b300.yml) are chosen for cost: every gate builds the full engine, and a gsm8k gate takes roughly 8-13 min on one GB300.test_qwen4_exp.pyholds six cases, each engine running every check that fits in it, and all six are listed:test_gsm8k;test_mtp1_gsm8k_mmmu_and_video: one MTP1 engine for gsm8k with the acceptance-length floor (the only gate that sees a miscomputed draft layer), MMMU and synthetic videos. It replaces main'stest_mtp1_gsm8k_and_acceptanceandtest_mtp1_mmmu;test_mtp3_long_context_passkey: IndexShare over bf16 KV, the only prompts long enough to run the sparse attention path.test_mtp3_cutedsl_fp8_kv_bf16_state: CuteDSL experts, FP8 KV and a bf16 state in one engine, gsm8k and then the pass keys;test_mtp7_long_context_passkey: seven drafts (the verify step's eight rows per request) over NVFP4 KV and a bf16 state;test_breakable_prefill_matches_eager.l0_cpu.ymladds the target's CPU tests: the multimodal splice and admission check on a stub tower, the KV pool contract, the KV storage derivation and the attention-call arguments.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.Dev Engineer Review
The inspected checkout shows formatting-only import changes in three source files. It shows no behavior, API, or default changes in those files. The supplied change inventory describes a much broader Qwen4-Exp implementation, but that scope is not present in the inspected diff and cannot be verified here.
No current review findings were supplied. Test results and completion status are unavailable.
QA Engineer Review
One test file changed, but only its imports were reformatted. No test functions, test IDs, selectors, or waivers changed. No integration test-list files changed. The modified unit test is not expected in the
test-db/orqa/integration lists. Coverage verdict: needs follow-up to reconcile the supplied change inventory with the inspected diff.Per-File QA Perspective
tensorrt_llm/_torch/model_config.py— Import formatting only; no observable behavior change to verify.tensorrt_llm/_torch/pyexecutor/model_loader.py— Import formatting only; no observable behavior change to verify.tensorrt_llm/_torch/pyexecutor/py_executor.py— Import formatting only; no observable behavior change to verify.tests/unittest/_torch/executor/test_pytorch_model_engine.py— Import formatting only; existing model-engine tests remain, with no new or changed test coverage. No integration-list entry applies.