Skip to content

[https://nvbugs/6550275][fix] Bound V2 residency for non-droppable state pools - #17211

Open
trtllm-agent wants to merge 3 commits into
NVIDIA:mainfrom
tensorrt-cicd:repair-bot-bug6550275
Open

[https://nvbugs/6550275][fix] Bound V2 residency for non-droppable state pools#17211
trtllm-agent wants to merge 3 commits into
NVIDIA:mainfrom
tensorrt-cicd:repair-bot-bug6550275

Conversation

@trtllm-agent

@trtllm-agent trtllm-agent commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Regression and exact V1/V2 difference: PR [TRTLLM-11875][feat] BREAKING: MambaCacheManager based on KVCacheManagerV2 & agentic prefix caching #16598 enabled KV-cache manager V2 by default for Qwen3 Next. V1 honors the default GUARANTEED_NO_EVICT policy and reserves the blocks needed to finish a request before admitting it. V2 currently replaces every non-MAX_UTILIZATION policy with MAX_UTILIZATION, budgets only the next scheduling step, and relies on suspend/resume to recover from over-admission.
  • Root cause: the failing L40S workload admitted 485 requests although the limiting physical cache pool could keep only about 118 full-length sequences resident. Hybrid Mamba recurrent state is non-droppable and cannot be reconstructed from token IDs. With no effective host tier, over-admission eventually left every generation request suspended while no request could be evicted to free the pages needed for resume, producing the V2 no-progress deadlock.
  • Fix: derive a conservative resident-sequence bound from full per-sequence capacity (including extra KV, draft reserve, and base decode tokens), sum lifecycle costs that share a physical pool, and enforce the bound for both context and disaggregated-generation admission. Plain attention models keep the existing unbounded behavior.
  • Distributed safety: synchronize both the presence of non-droppable state and the minimum full-sequence capacity across ranks. Attention-only and zero-local-layer PP ranks therefore admit exactly the same request set as ranks that own Mamba state.
  • Automated fix initially generated by repair-bot and completed with review follow-ups.

Test plan

  • Existing direct capacity/rounding/coalesced-pool regressions (4 passed on the previous PR head)
  • Existing V2 scheduler regressions, including disaggregated transfer accounting (179 passed on the previous PR head)
  • Added attention-only, zero-capacity floor, attention-only PP-rank, and zero-local-layer PP-rank coverage
  • Relevant pre-commit hooks, including Ruff, Ruff format, codespell, DCO, and test-list validation
  • Standard CI rerun for ce537324a3 is in progress.

Links

…state pools

MAX_UTILIZATION admits new sequences up to max_batch_size and relies on
suspend/resume to survive over-subscription. That recovery needs some
resident sequence to still be evictable so its pages can be freed for a
suspended one to resume. A hybrid Mamba recurrent state is fixed-size per
sequence and cannot be recomputed from tokens, so such a sequence yields no
evictable pages; once every sequence is suspended the pool can no longer
drain and the scheduler stops making progress.

On L40S, qwen3.5_9b at 500-in/2000-out admitted 485 sequences while the
attention pool holds only ~118 at max_seq_len, then spun 8676 iterations
scheduling nothing before raising 'V2 scheduler deadlock'.

Add KVCacheManagerV2.max_resident_sequences(), derived from per-pool-group
page counts, and gate new-sequence admission on it. Returns None (unbounded,
unchanged behavior) for models without a non-droppable state pool.

Pin the return value on the scheduler test's manager double: a bare Mock() is
not None, so the new gate would otherwise compare an int against a child Mock
and raise TypeError in every test that schedules a first context chunk. Add
direct coverage for the cap, which had none.

Two config levers suggested by triage were measured and do not fix this:
avg_seq_len=2500 reproduces the failure identically, and
max_util_for_resume=1.0 replaces the raise with an unbounded livelock.

Signed-off-by: trtllm-agent <296075020+trtllm-agent@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

KVCacheManagerV2 centralizes sequence capacity calculation and computes resident-sequence limits from lifecycle pool storage. KVCacheV2Scheduler tracks resident requests and enforces limits for new first-context and disaggregated-initialization requests. Tests cover capacity calculation, distributed reduction, transfer residency, and capped scheduling.

Changes

Resident-sequence admission

Layer / File(s) Summary
Capacity calculation
tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py, tests/unittest/_torch/executor/test_kv_cache_manager_v2.py
KVCacheManagerV2 centralizes sequence capacity calculation. max_resident_sequences() aggregates physical pool costs, applies storage limits, synchronizes pipeline-rank results, and returns None for attention-only configurations. Tests cover rounding, token reservations, coalesced pools, minimum capacity, and distributed reductions.
Scheduler residency tracking
tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py
KVCacheV2Scheduler records the resident-sequence limit, caches transfer states, initializes resident request IDs, and detects residency from started requests, transfers, and active KV-cache entries.
Scheduler admission enforcement
tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py
New disaggregated-initialization and first-context requests are rejected when the cap is full. Already-resident requests continue scheduling. Admitted requests are added to the resident set.
Residency-cap test coverage
tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py
Tests validate unlimited admission, active-generation occupancy, transfer occupancy across iterations, continuing context chunks, and mixed disaggregated/context scheduling.

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

Suggested reviewers: liji-nv

🚥 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 follows the repository format and clearly identifies the fix for bounding V2 residency in non-droppable state pools.
Description check ✅ Passed The description explains the regression, root cause, fix, distributed behavior, tests, and bug link, but it omits the repository PR Checklist section.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 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: 3

🤖 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/kv_cache_manager_v2.py`:
- Around line 2177-2188: Update the capacity calculation around
max_blocks_per_seq so attention pools are charged using the full maximum
per-sequence allocation, including num_extra_kv_tokens,
_kv_reserve_draft_tokens, and the base decode token, matching max_seq_capacity
and max_blocks_per_seq. Preserve the fixed one-slot divisor for state pools, and
add a unit test where the extra allocation crosses a block boundary to verify
the scheduler cannot over-admit.

In `@tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py`:
- Around line 407-425: Extend resident-sequence accounting to the Phase 1
DISAGG_GENERATION_INIT path: initialize the count before Phase 1, reject or
defer new disaggregated requests when the cap is reached, and increment/account
only successful prepare_disagg_gen_init() admissions. Ensure already initialized
disaggregated requests are included in num_started on later scheduler
iterations, and add a regression test covering capped DISAGG_GENERATION_INIT
admission.

In `@tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py`:
- Around line 2229-2268: Extend TestResidencyCap with direct
KVCacheManagerV2.max_resident_sequences() tests covering storage statistics,
block-size rounding, and extra KV allocation, asserting the calculated residency
cap. Add a scheduler regression test for capped DISAGG_GENERATION_INIT
admission, verifying that generation initialization requests respect
max_resident_sequences while preserving existing admission behavior.
🪄 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: bd455d53-e826-4bbf-8e40-e075cea0e56c

📥 Commits

Reviewing files that changed from the base of the PR and between c5427c5 and ded67ab.

📒 Files selected for processing (3)
  • tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py
  • tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py
  • tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py

Comment thread tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py Outdated
Comment thread tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py Outdated
Comment thread tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py
Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
@VALLIS-NERIA

Copy link
Copy Markdown
Collaborator

/bot run

@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_kv_cache_manager_v2.py (1)

64-103: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add coverage for the None-return branch and the max(1, ...) floor.

The PR objective states that max_resident_sequences() "returns None, preserving existing behavior" for models without a non-droppable state pool. This test file only exercises the non-None branch (models with an "ssm" life cycle). Add a test with life_cycle_metadata containing only "attention" entries to confirm the None return path. Also consider a case where storage_stats[...].total // slots_per_sequence would compute to 0, to confirm the max(1, ...) floor is exercised.

Do you want me to generate these two additional test cases?

🤖 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_kv_cache_manager_v2.py` around lines 64 -
103, Add tests for max_resident_sequences() covering both missing non-droppable
pools and the minimum capacity floor: create an attention-only
life_cycle_metadata setup and assert the method returns None, then create a
setup where total available slots divided by slots_per_sequence is zero and
assert the result is 1. Reuse _make_residency_manager and the existing pool
configuration patterns.
🤖 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 `@tests/unittest/_torch/executor/test_kv_cache_manager_v2.py`:
- Around line 43-61: Extend max_resident_sequences() tests to cover the
all-"attention" lifecycle case returning None and the zero-capacity case
returning 1 via the max(1, ...) floor, using the existing
_make_residency_manager helper. Register
test_max_resident_sequences_uses_full_rounded_capacity and
test_max_resident_sequences_sums_coalesced_life_cycles in the appropriate
test-db and qa test list files under tests/integration/test_lists/.

---

Nitpick comments:
In `@tests/unittest/_torch/executor/test_kv_cache_manager_v2.py`:
- Around line 64-103: Add tests for max_resident_sequences() covering both
missing non-droppable pools and the minimum capacity floor: create an
attention-only life_cycle_metadata setup and assert the method returns None,
then create a setup where total available slots divided by slots_per_sequence is
zero and assert the result is 1. Reuse _make_residency_manager and the existing
pool configuration patterns.
🪄 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: bb066dec-2d10-4b51-8566-cf3a3f6e37de

📥 Commits

Reviewing files that changed from the base of the PR and between ded67ab and e0c11f9.

📒 Files selected for processing (4)
  • tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py
  • tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py
  • tests/unittest/_torch/executor/test_kv_cache_manager_v2.py
  • tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py
  • tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py
  • tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py

Comment on lines +43 to +61
def _make_residency_manager(
*,
max_seq_len: int,
tokens_per_block: int,
num_extra_kv_tokens: int,
reserve_draft_tokens: int,
life_cycle_metadata: dict[int, tuple[int, int | None, str]],
pool_group_totals: list[int],
) -> KVCacheManagerV2:
manager = object.__new__(KVCacheManagerV2)
manager.max_seq_len = max_seq_len
manager.tokens_per_block = tokens_per_block
manager.num_extra_kv_tokens = num_extra_kv_tokens
manager._kv_reserve_draft_tokens = reserve_draft_tokens
manager._stats_life_cycle_metadata = lambda: life_cycle_metadata
manager._get_storage_statistics = lambda _level: [
SimpleNamespace(total=total) for total in pool_group_totals
]
return manager

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Locate and inspect the _max_sequence_capacity implementation.
ast-grep run --pattern 'def _max_sequence_capacity($$$) {
  $$$
}' --lang python tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py

rg -n -B2 -A15 'def _max_sequence_capacity' tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 1569


🏁 Script executed:

# Inspect full max_resident_sequences method to check for None return and max(1,...) floor
rg -n -A30 'def max_resident_sequences' tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py

# Check for test registration in test lists
find tests/integration/test_lists -type f -name '*.txt' -o -name '*.yaml' -o -name '*.json' | head -20

# Check if test_kv_cache_manager_v2.py is referenced
grep -r 'test_kv_cache_manager_v2' tests/integration/test_lists/ 2>/dev/null || echo "Not found in test lists"

# Verify copyright header year in the test file
head -40 tests/unittest/_torch/executor/test_kv_cache_manager_v2.py | grep -i copyright

Repository: NVIDIA/TensorRT-LLM

Length of output: 2584


🏁 Script executed:

# Read the full test file to verify test functions and coverage
wc -l tests/unittest/_torch/executor/test_kv_cache_manager_v2.py

# Show test functions and their parameters
ast-grep outline tests/unittest/_torch/executor/test_kv_cache_manager_v2.py --view expanded

# Show lines 43-110 to see the helper and parametrized tests
sed -n '43,110p' tests/unittest/_torch/executor/test_kv_cache_manager_v2.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 5358


Add test coverage for None-return path and max(1, ...) floor in max_resident_sequences(); register new tests in test list files.

The arithmetic assumptions in both tests are correct: _max_sequence_capacity() returns max_seq_len + num_extra_kv_tokens + _kv_reserve_draft_tokens + 1, so test expectations (6 and 10) are valid. However, the test suite omits two branches:

  1. Attention-only path (line 2172-2173): When all lifecycle kinds are "attention", the method returns None. This branch is explicitly documented as preserving unbounded MAX_UTILIZATION behavior and should be tested.
  2. Floor at 1 (line 2183-2184): The max(1, ...) guard returns at least 1 resident sequence even if computed capacity would be 0. This edge case is not covered.

Additionally, per test-code guidelines, the two new test functions (test_max_resident_sequences_uses_full_rounded_capacity and test_max_resident_sequences_sums_coalesced_life_cycles) must be registered in the appropriate test list files under tests/integration/test_lists/ (test-db/ for CI, qa/ for manual QA). They are currently absent.

Test coverage verdict: Insufficient. Missing coverage for attention-only models and zero-capacity floor, and test registration incomplete.

🤖 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_kv_cache_manager_v2.py` around lines 43 -
61, Extend max_resident_sequences() tests to cover the all-"attention" lifecycle
case returning None and the zero-capacity case returning 1 via the max(1, ...)
floor, using the existing _make_residency_manager helper. Register
test_max_resident_sequences_uses_full_rounded_capacity and
test_max_resident_sequences_sums_coalesced_life_cycles in the appropriate
test-db and qa test list files under tests/integration/test_lists/.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63725 [ run ] triggered by Bot. Commit: e0c11f9 Link to invocation

@VALLIS-NERIA VALLIS-NERIA changed the title [https://nvbugs/6550275][fix] Add KVCacheManagerV2.max_resident_sequences() from per-pool-group page counts… [https://nvbugs/6550275][fix] Bound V2 residency for non-droppable state pools Aug 4, 2026
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63725 [ run ] completed with state SUCCESS. Commit: e0c11f9
/LLM/main/L0_MergeRequest_PR pipeline #51677 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

@nvpohanh

nvpohanh commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

[by Codex] @liji-nv Could you please review PR #17211 for the KV-cache manager changes? Thanks!

@nvpohanh

nvpohanh commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

similar to #17261

@yufeiwu-nv

Copy link
Copy Markdown
Collaborator

adjust test cases

@yufeiwu-nv yufeiwu-nv closed this Aug 7, 2026
@yufeiwu-nv yufeiwu-nv reopened this Aug 7, 2026
Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
@VALLIS-NERIA

Copy link
Copy Markdown
Collaborator

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64773 [ run ] triggered by Bot. Commit: ce53732 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64773 [ run ] completed with state FAILURE. Commit: ce53732
/LLM/main/L0_MergeRequest_PR pipeline #52617 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

@VALLIS-NERIA

Copy link
Copy Markdown
Collaborator

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65048 [ run ] triggered by Bot. Commit: ce53732 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65048 [ run ] completed with state SUCCESS. Commit: ce53732
/LLM/main/L0_MergeRequest_PR pipeline #52856 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

@VALLIS-NERIA

Copy link
Copy Markdown
Collaborator

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65066 [ run ] triggered by Bot. Commit: ce53732 Link to invocation

@VALLIS-NERIA

Copy link
Copy Markdown
Collaborator

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65066 [ run ] completed with state SUCCESS. Commit: ce53732
/LLM/main/L0_MergeRequest_PR pipeline #52871 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

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65102 [ run ] triggered by Bot. Commit: ce53732 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65102 [ run ] completed with state FAILURE. Commit: ce53732
/LLM/main/L0_MergeRequest_PR pipeline #52902 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

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.

6 participants