[None][perf] Address inter-iter idle times - #16875
Merged
pcicotti merged 10 commits intoJul 26, 2026
Merged
Conversation
get_block_ids_per_seq built one tensor per request and joined them with pad_sequence. That is a per-request Python loop, and pad_sequence returns pageable memory, so the copy that stages the result to the device blocks until the CUDA queue drains. At batch 128 the loop alone shows up as a 2.1 ms host-only gap in every decode step. Fill a single zero-filled pinned int32 tensor through a numpy view instead. The loop cost disappears and callers can stage the result with a non-blocking copy. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
build_kv_page_indices recovered each request's page ids by gathering the first slot of every page out of req_to_token on the device. That is five tiny kernels per request per step: at batch 128 it is one contiguous burst of 644 launches spanning 10.6 ms, during which the GPU starves. The work is redundant. Both callers use the manager's tokens_per_block as the page size, and req_to_token is built as block_id * tokens_per_block + offset, so req_to_token[b, p * page_size] // page_size is just block_ids[b, p] -- a value get_block_ids_per_seq already returned on the host. Build the table there instead and hand it back through the slot mapping, which now also exposes block_ids_cpu so no second manager query or device round trip is needed. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
out_cache_loc was built by reading req_to_token one new token at a time with .item(). At 6.6k context tokens that is a 17.4 ms window with no CUDA activity at all, and it scales with context length. It also forced a ~4.3 MB device-to-host copy of the whole req_to_token grid that existed only to feed the loop. The same slot ids follow from the host block ids by expanding the per-request lengths, so compute them there and stage the result with one asynchronous copy. Optimistic offsets can overhang the last allocated slot and a zero-length padding row lands at -1, so positions are clamped into the row; those slots are placeholders that on_update_kv_lens re-derives before any forward reads them. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
The per-request length mirrors and the query-row staging tensors were plain pageable allocations. Every copy_ that ships them to the device therefore ends in a cudaStreamSynchronize that drains the whole queue, which is what stops the host from running ahead of the GPU. Pin them where pinning helps and stage them non-blocking. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
sparse_fmha_plan moved its length inputs to the device with blocking copies and read total_q back through cu_seqlens_q[-1].item(). Planning sits on the critical path of input preparation, so each of those drains the CUDA queue. Stage the lengths to the device once, asynchronously, and take every scalar from the host copy instead. kv_segment_lens now stays on the host in the returned plan: only the page-table builder consumes it, and it reads per-request page counts on the host, while the kernels take their lengths from cu_seqlens_k and seqused_k. That subsumes _stage_sparse_plan_kv_lens_host, which patched the same field from the backend after the fact to dodge a per-layer D2H, so it is dropped. The MSA change ships as an additive update to the existing cumulative patch against submodule commit e2ebe76; the prior hunks are unchanged. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
_build_step_plans computed, on the host, whether an eager step selects no KV blocks at all, and run_indexer returned an all -1 selection when it did. The flag is derived from the optimistic lengths prepare() staged. The overlap scheduler then corrects kv_lens on device, and on_update_kv_lens cannot recompute a host bool without a device read, so the flag can be consulted after it has gone stale. Remove it. The staged per-token counts are clamped to at least one block, matching the decode path, and the kernel already masks each query to its own valid-block extent, so the empty case needs no special handling. The clamp is also what keeps a fully-masked row from producing a NaN. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
on_update_kv_lens rests on the correction only ever shrinking lengths: that is what lets the host-baked plan worklists and the page-table layout survive it. Nothing enforced that. A length that grew instead would drive the kernels past the extent prepare() planned for and read slots that were never mapped, silently. Snapshot the staged lens in prepare() and clamp the corrected lens against them. The snapshot is a device-to-device copy and the clamp is a torch.minimum, so the check costs no synchronization. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
Prefill and mixed steps handled the corrected lengths by copying kv_lens_cuda back to the host and re-running _build_msa_fields and _build_step_plans. The copy targets pageable memory, so it is a synchronizing 636-byte transfer that costs ~64 ms of host time per step, and the rebuild redoes work the correction cannot invalidate. Decode already patched the same state with device ops only. Extend that to every step: iterate whichever plan set is live, and patch each sub-plan's length rows in place from the corrected lengths. A mixed batch is split at the first long request, so each sub-plan covers its own request range and the row count says whether it is indexed per request or per query token. The token offsets come from a host-side tuple built in prepare(), so no device read is needed to slice a range. This also removes the corrected-host-lens override on msa_kv_lens_cpu, which existed only to feed the rebuild. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
The length mirroring wrote kv_segment_lens and qo_offset into every plan. For sparse plans that is wrong in both directions. kv_segment_lens is host-resident there -- only the page-table builder reads it, and it did so at plan time -- so writing a device tensor into it is a pointless copy that synchronizes the host, which is the stream sync left over after the D2H removal. Meanwhile seqused_k, the length sparse kernels actually mask with, was never patched and kept the optimistic value. Select the keys by plan flavour off the MM-SA-Nv tag instead of writing a fixed pair and letting a device check silently skip the host entries. seqused_k joins the graph-stable key set, since it is now a patch target and must keep a stable device buffer across replays. A missing mirror raises rather than being skipped: it means corrected lengths never reach the kernel, which is a silent accuracy bug. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
Two run_indexer tests raise AttributeError before reaching an assertion. The FP8 index-query test's fake predates head-major routing and never defines num_contexts or num_generations, which run_indexer now reads unconditionally to pick the output layout. It stands in for a two-request decode, so it gets 0 and 2. The head-major routing test's fake returns None from msa_idx_k_cache until msa_write_idx_k populates it, but run_indexer reads the cache before it writes, so the local is always None when the FP8 check dereferences it. The production cache always exists, so the fake holds a tensor from the start and the write copies into it. Also drops msa_eager_all_blocks_empty from that fake; nothing reads it. Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
requested review from
PerkzZheng,
pcicotti,
peihu-nv,
pengbowang-nv and
zheyuf
and removed request for
a team,
PerkzZheng and
pengbowang-nv
July 26, 2026 04:13
pcicotti
approved these changes
Jul 26, 2026
ZhanruiSunCh
pushed a commit
that referenced
this pull request
Jul 29, 2026
Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
This was referenced Aug 17, 2026
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 20, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 20, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 20, 2026
Input preparation for a MiniMax-M3 MSA step spent most of its host time in work that either blocked on the CUDA queue or launched a burst of tiny kernels, leaving the GPU idle between iterations: * get_block_ids_per_seq built one tensor per request and joined them with pad_sequence, a per-request Python loop landing in pageable memory. It now fills a single zero-filled pinned int32 tensor through a numpy view. * build_kv_page_indices recovered each request's page ids by gathering the first slot of every page out of req_to_token on the device, five tiny kernels per request per step. The work is redundant: req_to_token is built as block_id * tokens_per_block + offset, so req_to_token[b, p * page_size] // page_size is just block_ids[b, p], a value the host already has. The table is built there instead and the slot mapping hands the host block ids back so no second manager query or device round trip is needed. * out_cache_loc was built by reading req_to_token one new token at a time with .item(), a window that scales with context length. The same slot ids follow from the host block ids by expanding the per-request lengths, so they are computed there and staged with one asynchronous copy. * The per-request length mirrors are pinned and staged non-blocking, so their copies no longer end in a cudaStreamSynchronize. * sparse_fmha_plan staged its length inputs with blocking copies and read total_q back through cu_seqlens_q[-1].item(). It now stages once, asynchronously, and takes every scalar from the host copy. kv_segment_lens stays on the host in the returned plan: only the page-table builder consumes it, and it reads per-request page counts on the host, while the kernels take their lengths from cu_seqlens_k and seqused_k. That subsumes _stage_sparse_plan_kv_lens_host, which patched the same field from the backend after the fact, so it is dropped. Cherry-picked from NVIDIA#16875 on feat/m3_with_msa. The parts of that PR that turn on an MSA on_update_kv_lens override are dropped: main's MSA metadata has no such override, nor the device mirrors (msa_req_to_token, msa_q_batch_row, msa_q_intra, msa_qo_lens_dev) it patches through, so there is nothing here to make sync-free, clamp against a staged snapshot, or redirect from kv_segment_lens to seqused_k. The eager empty-block short-circuit that PR removes likewise does not exist on main, so its replacement clamp is left out and the eager valid-block counts keep main's unclamped staging. The two run_indexer test fakes it repairs cover head-major routing and the FP8 index-K producer, neither of which main carries. (cherry picked from commit a69907a) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 21, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 21, 2026
Input preparation for a MiniMax-M3 MSA step spent most of its host time in work that either blocked on the CUDA queue or launched a burst of tiny kernels, leaving the GPU idle between iterations: * get_block_ids_per_seq built one tensor per request and joined them with pad_sequence, a per-request Python loop landing in pageable memory. It now fills a single zero-filled pinned int32 tensor through a numpy view. * build_kv_page_indices recovered each request's page ids by gathering the first slot of every page out of req_to_token on the device, five tiny kernels per request per step. The work is redundant: req_to_token is built as block_id * tokens_per_block + offset, so req_to_token[b, p * page_size] // page_size is just block_ids[b, p], a value the host already has. The table is built there instead and the slot mapping hands the host block ids back so no second manager query or device round trip is needed. * out_cache_loc was built by reading req_to_token one new token at a time with .item(), a window that scales with context length. The same slot ids follow from the host block ids by expanding the per-request lengths, so they are computed there and staged with one asynchronous copy. * The per-request length mirrors are pinned and staged non-blocking, so their copies no longer end in a cudaStreamSynchronize. * sparse_fmha_plan staged its length inputs with blocking copies and read total_q back through cu_seqlens_q[-1].item(). It now stages once, asynchronously, and takes every scalar from the host copy. kv_segment_lens stays on the host in the returned plan: only the page-table builder consumes it, and it reads per-request page counts on the host, while the kernels take their lengths from cu_seqlens_k and seqused_k. That subsumes _stage_sparse_plan_kv_lens_host, which patched the same field from the backend after the fact, so it is dropped. Cherry-picked from NVIDIA#16875 on feat/m3_with_msa. The parts of that PR that turn on an MSA on_update_kv_lens override are dropped: main's MSA metadata has no such override, nor the device mirrors (msa_req_to_token, msa_q_batch_row, msa_q_intra, msa_qo_lens_dev) it patches through, so there is nothing here to make sync-free, clamp against a staged snapshot, or redirect from kv_segment_lens to seqused_k. The eager empty-block short-circuit that PR removes likewise does not exist on main, so its replacement clamp is left out and the eager valid-block counts keep main's unclamped staging. The two run_indexer test fakes it repairs cover head-major routing and the FP8 index-K producer, neither of which main carries. (cherry picked from commit a69907a) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 24, 2026
Input preparation for a MiniMax-M3 MSA step spent most of its host time in work that either blocked on the CUDA queue or launched a burst of tiny kernels, leaving the GPU idle between iterations: * get_block_ids_per_seq built one tensor per request and joined them with pad_sequence, a per-request Python loop landing in pageable memory. It now fills a single zero-filled pinned int32 tensor through a numpy view. * build_kv_page_indices recovered each request's page ids by gathering the first slot of every page out of req_to_token on the device, five tiny kernels per request per step. The work is redundant: req_to_token is built as block_id * tokens_per_block + offset, so req_to_token[b, p * page_size] // page_size is just block_ids[b, p], a value the host already has. The table is built there instead and the slot mapping hands the host block ids back so no second manager query or device round trip is needed. * out_cache_loc was built by reading req_to_token one new token at a time with .item(), a window that scales with context length. The same slot ids follow from the host block ids by expanding the per-request lengths, so they are computed there and staged with one asynchronous copy. * The per-request length mirrors are pinned and staged non-blocking, so their copies no longer end in a cudaStreamSynchronize. * sparse_fmha_plan staged its length inputs with blocking copies and read total_q back through cu_seqlens_q[-1].item(). It now stages once, asynchronously, and takes every scalar from the host copy. kv_segment_lens stays on the host in the returned plan: only the page-table builder consumes it, and it reads per-request page counts on the host, while the kernels take their lengths from cu_seqlens_k and seqused_k. That subsumes _stage_sparse_plan_kv_lens_host, which patched the same field from the backend after the fact, so it is dropped. Cherry-picked from NVIDIA#16875 on feat/m3_with_msa. The parts of that PR that turn on an MSA on_update_kv_lens override are dropped: main's MSA metadata has no such override, nor the device mirrors (msa_req_to_token, msa_q_batch_row, msa_q_intra, msa_qo_lens_dev) it patches through, so there is nothing here to make sync-free, clamp against a staged snapshot, or redirect from kv_segment_lens to seqused_k. The eager empty-block short-circuit that PR removes likewise does not exist on main, so its replacement clamp is left out and the eager valid-block counts keep main's unclamped staging. The two run_indexer test fakes it repairs cover head-major routing and the FP8 index-K producer, neither of which main carries. (cherry picked from commit a69907a) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 24, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 24, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 25, 2026
Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
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 MR does multiple perf optimizations to address inter-iter idle times:
out_cache_locare now built on the host from the block ids, replacing per-request device kernels and per-token.item()readson_update_kv_lenspatches plan lengths entirely on device for every step, dropping the prefill/mixed host copy-back and plan rebuild..item(), and sparse plans now patchseqused_k- the length their kernels actually mask with.kv_lensare clamped to the extent prepare()` planned for, and the stale host empty-block flag is gone.At TP=4, ISL=8192, OSL=128, c=320, request latency in ms.
Baseline
Feature
Test Coverage
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.