Skip to content

[TRTLLM-14138][fix] Pre-allocate CUDA graph padding dummy during warmup - #16072

Merged
liji-nv merged 5 commits into
NVIDIA:mainfrom
kaiyux:fix/cuda-graph-padding-prealloc-20260707
Aug 5, 2026
Merged

[TRTLLM-14138][fix] Pre-allocate CUDA graph padding dummy during warmup#16072
liji-nv merged 5 commits into
NVIDIA:mainfrom
kaiyux:fix/cuda-graph-padding-prealloc-20260707

Conversation

@kaiyux

@kaiyux kaiyux commented Jul 7, 2026

Copy link
Copy Markdown
Member

Description

The CUDA graph padding dummy request was allocated lazily at the first padded step. If the KV cache was already saturated by that point, the allocation failed — and kept failing on every subsequent step — so padded batches silently fell back to eager mode for the rest of the process lifetime, losing CUDA graph coverage exactly when the server is under load.

This PR:

  • Pre-allocates the padding dummies at the end of warmup, while the KV cache still has free blocks (CUDAGraphRunner.preallocate_padding_dummies() called from PyTorchModelEngine.warmup). One dummy is created per draft length of the captured graphs — exactly the set runtime padding can request (speculative engines pad with non-zero draft lengths, so unconditionally preallocating draft_len=0 would hold KV blocks and spec/hybrid slots the lazy path never uses).
  • Skips the preallocation when padding cannot occur at all for a draft length (_can_pad_any_batch, e.g. max_batch_size=1 with a captured graph for batch size 1), so infeasible configs don't retain KV blocks for nothing.
  • Skips the preallocation on the KV-cache-estimation executor: the estimation cache is sized with zero headroom, and a retained dummy can leave the estimation request unschedulable. KVCacheManager/KVCacheManagerV2 now retain the is_estimating_kv_cache flag they already receive as a constructor parameter so the runner can detect estimation-phase managers (MambaHybridCacheManager already did).
  • Refactors the dummy creation into _get_or_create_padding_dummy(), keeping the existing encoder-decoder handling, and drops the duplicated dynamic-draft-len enablement check at the round-up call sites: the dynamic mapping is only populated when the feature is active, so _round_up_batch_size_with_draft_len already reduces to plain batch-size rounding without it.
  • Logs a warning_once when CUDA graph padding falls back to eager, so the failure mode is visible instead of silent, and logs the preallocation outcome per draft length at warmup.

Trade-off: the final executor now permanently holds a few KV blocks per captured draft length — the same blocks the lazy path would have held from the first successfully padded step onward. The feasibility and estimation gates keep this from affecting configs that never pad.

Split out of #16033 (1 of 3, together with #16073 and #16074); this PR is independent of the other two.

Test Coverage

  • tests/unittest/_torch/executor/test_pytorch_model_engine.py:
    • test_warmup asserts the padding dummy exists after warmup and that no KV cache blocks leak beyond it.
    • test_warmup_skips_padding_dummy_when_padding_impossible asserts no dummy is retained when every reachable batch size already matches a captured graph.
    • test_warmup_skips_padding_dummy_during_estimation asserts no dummy is retained on estimation-phase KV cache managers.
    • test_preallocate_padding_dummies_uses_captured_draft_lens asserts dummies are created for the captured draft lengths, not draft_len=0 unconditionally.
  • Perf: measured standalone on top of main (045705139d) on 1x B200 (Gemma-4-31B-IT-NVFP4, ISL 1024 / OSL 128, 1024 prompts, concurrency 1024, trtllm-serve + benchmark_serving): 1319.0 vs 1331.8 tok/s output throughput (-1.0%, within run-to-run noise). Throughput-neutral is expected for this particular workload: at concurrency 1024 the steady-state decode batch size (~230) exceeds the CUDA graph max batch size, so the padded-batch path is not exercised at all. The change is a robustness fix for deployments where CUDA graph padding is active — there, KV-cache saturation before the first padded step previously caused a silent, permanent fallback to eager for every padded batch, and the pre-allocation preserves the CUDA graph coverage.

PR Checklist

  • 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-compatible or api-breaking. For api-breaking, include BREAKING in 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.

🤖 Generated with Claude Code

@kaiyux
kaiyux requested a review from a team as a code owner July 7, 2026 16:28
@kaiyux
kaiyux requested a review from lancelly July 7, 2026 16:28
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The CUDA graph padding dummy request allocation in CUDAGraphRunner is refactored into a new cached helper _get_or_create_padding_dummy, used by both _get_padded_batch and preallocate_padding_dummy. Warmup now preallocates the dummy earlier, before KV cache saturation, and a related test is updated to verify KV-block freeing.

Changes

Padding Dummy Allocation Refactor

Layer / File(s) Summary
Padding dummy helper and lazy allocation
tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py
New _get_or_create_padding_dummy method caches dummy requests per runtime_draft_len, handles encoder-decoder cross-KV allocation, and registers with the spec resource manager; _get_padded_batch now calls this helper and falls back to eager execution (returning 0) with a warning_once on allocation failure.
Early warmup preallocation and preallocate_padding_dummy update
tensorrt_llm/_torch/pyexecutor/model_engine.py, tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py
preallocate_padding_dummy now delegates to the new helper with logging on success/failure; PyTorchModelEngine.warmup invokes preallocation earlier, while the KV cache is still empty.
Warmup test validation update
tests/unittest/_torch/executor/test_pytorch_model_engine.py
test_warmup now asserts the cached dummy has draft_len=0, frees its KV blocks explicitly, and checks the free-block count returns to its pre-warmup value.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • NVIDIA/TensorRT-LLM#15637: Both PRs modify CUDA-graph padding dummy creation in CUDAGraphRunner for encoder-decoder models, touching the same _get_padded_batch code path.

Suggested reviewers: brb-nv, joyang-nv, JunyiXu-nv, shaharmor98, yuxianq

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the required ticket/type format and clearly summarizes the main warmup preallocation change.
Description check ✅ Passed The description includes the required Description, Test Coverage, and PR Checklist sections and explains the change clearly.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/unittest/_torch/executor/test_pytorch_model_engine.py (1)

340-349: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add coverage for the allocation-failure/fallback path.

test_warmup now verifies the happy path (preallocation succeeds and frees cleanly), but there's no test exercising the failure path this PR also touches: _get_padded_batch's new warning_once + return-0 fallback when _get_or_create_padding_dummy returns None (e.g., KV cache saturated by the time a padded batch is first requested), nor preallocate_padding_dummy's own warning-and-continue branch when preallocation itself fails at warmup.

Coverage is currently insufficient for the fallback branch introduced in cuda_graph_runner.py (_get_padded_batch lines 527-533, preallocate_padding_dummy lines 617-621). Suggest adding a test in this file that exhausts KV cache blocks (e.g., via dummy requests) before calling pad_batch/preallocate_padding_dummy, then asserts a 0 return / warning and that no exception is raised.

Based on path instructions for tests/**: "Act as a QA engineer reviewing test changes and coverage for TensorRT-LLM. Keep feedback actionable: suggest concrete list file names and whether coverage is sufficient, insufficient, or needs follow-up outside the PR."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_torch/executor/test_pytorch_model_engine.py` around lines 340
- 349, Coverage is insufficient for the new allocation-failure fallback in
cuda_graph_runner.py: add a test in test_pytorch_model_engine.py that forces KV
cache exhaustion before the first padded batch/preallocation attempt, then calls
pad_batch and preallocate_padding_dummy to verify the warning-once path, a 0
fallback from _get_padded_batch, and that preallocate_padding_dummy logs a
warning and continues without raising. Use the existing test_warmup setup plus
padding_dummy_requests and kv_cache_manager to locate the relevant flow.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py`:
- Around line 605-625: preallocate_padding_dummy() only allocates the padding
dummy for draft_len=0, but _get_padded_batch() can later request separate
dummies for each runtime draft length when dynamic draft-length scheduling is
enabled. Update preallocate_padding_dummy() to iterate over
self._dynamic_draft_len_mapping.values() and call
_get_or_create_padding_dummy(resource_manager, draft_len) for every reachable
draft length, while keeping the existing enabled/padding_enabled guard and
warning/logging behavior in CudaGraphRunner.

---

Nitpick comments:
In `@tests/unittest/_torch/executor/test_pytorch_model_engine.py`:
- Around line 340-349: Coverage is insufficient for the new allocation-failure
fallback in cuda_graph_runner.py: add a test in test_pytorch_model_engine.py
that forces KV cache exhaustion before the first padded batch/preallocation
attempt, then calls pad_batch and preallocate_padding_dummy to verify the
warning-once path, a 0 fallback from _get_padded_batch, and that
preallocate_padding_dummy logs a warning and continues without raising. Use the
existing test_warmup setup plus padding_dummy_requests and kv_cache_manager to
locate the relevant flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ab97c5a3-44a7-4595-846c-13afd6e6a70d

📥 Commits

Reviewing files that changed from the base of the PR and between 409b696 and 4e49bae.

📒 Files selected for processing (3)
  • tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tests/unittest/_torch/executor/test_pytorch_model_engine.py

Comment thread tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py Outdated
@kaiyux kaiyux changed the title [None][fix] Pre-allocate CUDA graph padding dummy during warmup [TRTLLM-14138][fix] Pre-allocate CUDA graph padding dummy during warmup Jul 8, 2026
@kaiyux

kaiyux commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58124 [ run ] triggered by Bot. Commit: 4e49bae Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58124 [ run ] completed with state SUCCESS. Commit: 4e49bae
/LLM/main/L0_MergeRequest_PR pipeline #46782 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@kaiyux
kaiyux force-pushed the fix/cuda-graph-padding-prealloc-20260707 branch from 4e49bae to c2fc7f3 Compare July 8, 2026 05:44
@kaiyux

kaiyux commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58164 [ run ] triggered by Bot. Commit: c2fc7f3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58164 [ run ] completed with state ABORTED. Commit: c2fc7f3
/LLM/main/L0_MergeRequest_PR pipeline #46814 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@kaiyux
kaiyux force-pushed the fix/cuda-graph-padding-prealloc-20260707 branch 2 times, most recently from 18142d5 to 81ba27b Compare July 9, 2026 09:30
@kaiyux

kaiyux commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58448 [ run ] triggered by Bot. Commit: 81ba27b Link to invocation

@kaiyux
kaiyux requested a review from a team as a code owner July 9, 2026 10:05
@kaiyux
kaiyux requested review from QiJune and yizhang-nv July 9, 2026 10:11
@kaiyux

kaiyux commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58451 [ run ] triggered by Bot. Commit: d10363b Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58448 [ run ] completed with state ABORTED. Commit: 81ba27b

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58451 [ run ] completed with state SUCCESS. Commit: d10363b
/LLM/main/L0_MergeRequest_PR pipeline #47063 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@kaiyux
kaiyux force-pushed the fix/cuda-graph-padding-prealloc-20260707 branch from d10363b to 4b853e1 Compare July 10, 2026 03:32
@kaiyux

kaiyux commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58578 [ run ] triggered by Bot. Commit: 4b853e1 Link to invocation

Signed-off-by: Jin Li <59594262+liji-nv@users.noreply.github.com>
@liji-nv
liji-nv requested review from a team as code owners July 30, 2026 07:45
@liji-nv

liji-nv commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62733 [ run ] triggered by Bot. Commit: e9a3dc3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62733 [ run ] completed with state SUCCESS. Commit: e9a3dc3
/LLM/main/L0_MergeRequest_PR pipeline #50867 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@kaiyux

kaiyux commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62904 [ run ] triggered by Bot. Commit: e9a3dc3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62904 [ run ] completed with state FAILURE. Commit: e9a3dc3
/LLM/main/L0_MergeRequest_PR pipeline #51027 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@kaiyux

kaiyux commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63339 [ run ] triggered by Bot. Commit: e9a3dc3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63339 [ run ] completed with state FAILURE. Commit: e9a3dc3
/LLM/main/L0_MergeRequest_PR pipeline #51331 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@liji-nv

liji-nv commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63373 [ run ] triggered by Bot. Commit: e9a3dc3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63373 [ run ] completed with state SUCCESS. Commit: e9a3dc3
/LLM/main/L0_MergeRequest_PR pipeline #51357 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@liji-nv

liji-nv commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63668 [ run ] triggered by Bot. Commit: e9a3dc3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63668 [ run ] completed with state SUCCESS. Commit: e9a3dc3
/LLM/main/L0_MergeRequest_PR pipeline #51623 completed with status: 'SUCCESS'

CI Report

Link to invocation

@liji-nv
liji-nv merged commit f1f773f into NVIDIA:main Aug 5, 2026
7 checks passed
@Shixiaowei02

Copy link
Copy Markdown
Collaborator

The preallocation has no ctx/gen role gate, and the feasibility check doesn't mirror the no-ctx-requests condition. A
dis-agg ctx server can never pad, so it now holds a dummy it will never use. cc @reasonsolo

@liji-nv

liji-nv commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

The preallocation has no ctx/gen role gate, and the feasibility check doesn't mirror the no-ctx-requests condition. A dis-agg ctx server can never pad, so it now holds a dummy it will never use. cc @reasonsolo

@Shixiaowei02 Would CTX disable cuda graph? If CTX disable the gen only cudagraph, the code just does not take effect by checking whether cuda graph is enabled at the beginning of preallocate_padding_dummies.

thorjohnsen added a commit to thorjohnsen/TensorRT-LLM that referenced this pull request Aug 10, 2026
…balance adjust()

CUDAGraphRunner retains one padding dummy request per captured draft
length, whose KVCacheManagerV2 cache stays ACTIVE across iterations but
never appears in PyExecutor.active_requests. The rebalance hook
therefore never suspends them, and the first live adjust() fails its
all-caches-suspended precondition, terminating the executor event loop
along with all in-flight requests.

Suspend the dummies alongside the active requests and resume them after
adjust(). Suspension is what the precondition actually asks for: it
tears down the cache's base-page-index buffers and releases its page
locks, which is what makes the pages safe to migrate. Those buffers are
written only when a page lock is taken and are never refreshed when a
page later migrates, so a cache left ACTIVE across adjust() can end up
addressing slots that now belong to other sequences.

The dummies are suspended rather than freed so that the warmup
pre-allocation added in NVIDIA#16072 survives a rebalance. Freeing them would
return to lazy re-creation against a KV cache that is under load --
rebalance only fires after 2000 sampled caches and a 120s cooldown --
and possibly just shrunk, which is exactly the case where allocation
fails and padded batches silently fall back to eager mode for the rest
of the process lifetime. A dummy that cannot be resumed is released and
dropped from the runner instead, because nothing reschedules a padding
dummy and _get_or_create_padding_dummy returns a cached dummy without
checking that its cache is live.

Reproduced on main with gemma-3-1b-it (VSWA, 2 pool groups) and
CudaGraphConfig(enable_padding=True) under
TLLM_KV_CACHE_MANAGER_V2_BACKEND=python, where the precondition is a
plain assert rather than the C++ backend's debug-gated TLLM_CHECK_DEBUG:
adjust() raised AssertionError and killed the executor loop. With this
change the same run completes and the GPU pool ratio moves from
0.500/0.500 to 0.667/0.333.

Signed-off-by: Thor Johnsen <41591019+thorjohnsen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants