Skip to content

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

Open
trtllm-agent wants to merge 2 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 2 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

  • Root cause: V2's MAX_UTILIZATION admits sequences up to max_batch_size (485) with no bound on resident KV capacity (~118), and a hybrid Mamba recurrent state is non-droppable, so once all sequences suspend nothing is evictable and the pool can never drain.
  • Fix: Bound resident sequences from full per-sequence capacity (including extra KV, draft reserve, and base decode tokens), sum all lifecycle costs sharing a physical pool, and enforce the bound for both context and disaggregated-generation admission. Attention-only models still return None and keep existing behavior.
  • Automated fix generated by repair-bot

Test plan

  • Verify fix on the same GPU type as the original failure
  • Check for regressions in related tests
  • Direct capacity/rounding/coalesced-pool regressions (4 passed)
  • V2 scheduler regressions, including disaggregated transfer accounting (179 passed)

Links

Dev Engineer Review

  • Added KVCacheManagerV2.max_resident_sequences().
  • The method returns None for attention-only models.
  • The scheduler enforces the resident-sequence limit during admission.
  • Resident requests remain admitted.
  • Continuing context chunks do not consume additional resident slots.
  • The change prevents over-admission when MAX_UTILIZATION exceeds resident KV capacity.
  • No configuration or test-list changes were identified.
  • The API and error handling match the described behavior.

QA Engineer Review

  • Modified tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py.
  • Modified tests/unittest/_torch/executor/test_kv_cache_manager_v2.py.
  • Added coverage for:
    • Unlimited admission.
    • Newly started sequence limits.
    • Active generation occupancy.
    • Continuing context chunks.
    • Disaggregated-generation residency.
    • Mixed disaggregated and context scheduling.
    • Capacity rounding with extra and draft tokens.
    • Coalesced life cycles sharing a physical pool group.
  • No corresponding entries in tests/integration/test_lists/ were identified.
  • Verdict: needs follow-up.

…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 now centralizes sequence capacity calculation and exposes a public method that computes resident-sequence limits based on physical pool storage. KVCacheV2Scheduler records this limit, tracks resident requests through transfer states and active cache entries, and enforces admission gates for new first-context and disaggregated-initialization requests. Tests validate capacity calculation under different token reservations, disaggregated-transfer residency occupancy, and context-chunk scheduling with the cap enabled.

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._max_sequence_capacity() centralizes token and block size computation. max_resident_sequences() groups lifecycle pools by physical pool group, charges attention variants by full-sequence page cost, and non-attention variants by one slot per sequence, returning the minimum capacity or None for attention-only models. Tests verify capacity calculations with token reservations and coalesced lifecycles.
Scheduler residency tracking
tensorrt_llm/_torch/pyexecutor/scheduler/scheduler_v2.py
KVCacheV2Scheduler records the capacity limit, caches disaggregated-transfer state values, initializes the resident request set from pre-resident requests, and detects resident requests through started requests, in-progress 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 residency cap is full. Already-resident requests bypass the cap. Admitted requests are added to the resident set for future iterations.
Residency-cap test coverage
tests/unittest/_torch/executor/test_kv_cache_v2_scheduler.py
Tests configure the manager mock with optional residency limits, validate scheduler behavior under full residency including disaggregated-transfer occupancy, verify continuing context chunks do not consume residency, and confirm admission gates on new requests.

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

Possibly related PRs

Suggested reviewers: liji-nv, tongyuantongyu

🚥 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 uses the required NVBugs/type format and clearly describes the fix that bounds V2 residency for non-droppable state pools.
Description check ✅ Passed The description explains the root cause and fix, identifies affected admission paths, and lists targeted regression and capacity tests.
✨ 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: 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

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.

4 participants