Skip to content

[None][fix] Restore KVCacheManagerV2 mypyc compilability - #15990

Open
thorjohnsen wants to merge 1 commit into
NVIDIA:mainfrom
thorjohnsen:fix/kv-cache-v2-mypyc-build-main
Open

[None][fix] Restore KVCacheManagerV2 mypyc compilability#15990
thorjohnsen wants to merge 1 commit into
NVIDIA:mainfrom
thorjohnsen:fix/kv-cache-v2-mypyc-build-main

Conversation

@thorjohnsen

@thorjohnsen thorjohnsen commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Description

KVCacheManagerV2 is designed to be compilable with mypyc for production performance (see its AGENTS.md and setup_mypyc.py), but the build (make -C kv_cache_manager_v2 all) fails on current main with the pinned mypy==1.19.1. This PR fixes every pre-existing issue needed to get a green, regression-clean build:

Typing fixes (annotation-only): missing return/parameter annotations, bare generic casts (TypedIndexList, array.array, rawref.ref), loop variables reusing a name with a conflicting narrowed type, Self on _stats.copy(), # type: ignore comment placement (mypy only honors it as the first comment), import-untyped ignores for cuda/tensorrt_llm imports, and int() wraps for helpers whose defining module is outside the compiled set.

Semantic fixes for mypyc backend behavior (behavior-neutral in interpreted mode, verified by the regression suite):

  • HalfOpenRange is no longer a tuple subclass: mypyc lowers len(), bool() and in on tuple-typed values to raw tuple operations, silently bypassing the class's overrides — an empty range reported len() == 2 and was truthy, which corrupted scratch-slot accounting when compiled. It is now a plain slotted class implementing the same protocol (indexing, unpacking, value-equality with 2-tuples).
  • LayerConfig.type ClassVars became properties: compiled dataclasses count a leading defaulted ClassVar as an __init__ field (TypeError: non-default argument 'layer_id' follows default argument at import).
  • KVCacheDesc/BatchDesc get explicit __deepcopy__: the compiled frozen dataclass's generated __setstate__ assigns via plain setattr and trips its own frozen __setattr__ (KVCacheManager.__init__ deepcopies its config).
  • DeltaScratchSlots moved to module level (mypyc cannot compile class definitions nested in a class body).

Known remaining mypyc issues (excluded from compilation in setup_mypyc.py with comments, so the default build is green):

  • compiling _core/_kv_cache.py leaks strong page references invisible to gc introspection (committed pages survive clear_reusable_blocks() with zero visible referrers, breaking block reuse and pool shrink at shutdown);
  • compiling _block_radix_tree.py strands pages in eviction queues on resize_quota teardown, with an occasional segfault in the subsequent __del__ cascade.

Both reproduce deterministically via TestNoBatching::test_cache_reuse_0 / TestResizeQuota::test_resize_quota when the respective module is added back to the compile list; they appear to be mypyc codegen issues (refcount or tp_traverse) and are left for follow-up.

Test Coverage

tests/unittest/kv_cache_manager_v2_tests/test_kv_cache_manager_v2.py, run on H100:

  • interpreted (default mode): 61 passed / 12 skipped — identical to main's baseline;
  • mypyc-compiled (20 modules): 61 passed / 12 skipped — identical to the interpreted baseline (on main the compiled suite cannot run at all since the build fails).

PR Checklist

  • PR title and description follow the contribution guidelines
  • Tests pass locally (see above)
  • No user-facing API change

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved stability in KV cache handling, including event hashing, eviction, copy behavior, and cache traversal.
    • Fixed several deep-copy and state-handling edge cases to better preserve cache data during runtime operations.
    • Made memory and range utilities more consistent, including GPU memory queries and range comparisons.
  • Refactor

    • Tightened type annotations across runtime components for clearer, more reliable behavior.
    • Simplified several internal utility classes and data structures for better consistency.

…g issues)

The package's mypyc build (make -C kv_cache_manager_v2 all) fails on
current main. This fixes every pre-existing issue needed to get a
green build with the pinned mypy==1.19.1:

- typing: missing return/parameter annotations, bare generic casts
  (TypedIndexList, array.array, rawref.ref), shadowed loop variables
  with conflicting narrowed types, Self on _stats.copy(), import-
  untyped ignores for cuda/tensorrt_llm imports, int() wraps for
  helpers whose defining module is outside the compiled set;
- HalfOpenRange is no longer a tuple subclass: mypyc lowers len(),
  bool() and 'in' on tuple-typed values to raw tuple operations,
  silently bypassing the overrides (an empty range reported len 2 and
  was truthy, corrupting scratch-slot accounting);
- LayerConfig.type ClassVars became properties: compiled dataclasses
  count a leading defaulted ClassVar as an init field;
- KVCacheDesc/BatchDesc get explicit __deepcopy__: the compiled frozen
  dataclass's generated __setstate__ assigns via plain setattr and
  trips its own frozen __setattr__ (KVCacheManager.__init__ deepcopies
  its config);
- DeltaScratchSlots moved to module level (nested class definitions
  are not compilable);
- setup_mypyc.py excludes _core/_kv_cache.py and _block_radix_tree.py
  for now: compiling the former leaks gc-invisible strong page
  references (breaks block reuse) and the latter strands pages in
  eviction queues on resize_quota teardown; both need root-causing in
  mypyc codegen before they can be re-enabled.

With this, the hybrid build (20/22 modules compiled) passes the full
v2 regression suite identically to the interpreted baseline
(61 passed / 12 skipped).

Signed-off-by: thorjohnsen <41591019+thorjohnsen@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR applies typing-focused cleanup across kv_cache_manager_v2: adds explicit type annotations, casts, and type-ignore comments to imports; converts layer-type ClassVars to properties; adds deepcopy overrides; rewrites HalfOpenRange as a non-tuple class; and removes two modules from mypyc compilation. No functional logic changes.

Changes

Type annotation and typing-behavior cleanup

Layer / File(s) Summary
Config layer-type properties and deepcopy
_config.py
AttentionLayerConfig.type/SsmLayerConfig.type change from ClassVar to instance properties; KVCacheDesc.__deepcopy__ and BatchDesc.__deepcopy__ overrides added.
HalfOpenRange rewrite and utils typing
_utils.py
HalfOpenRange becomes a slotted Generic[Idx] class instead of a tuple subclass with custom equality/containment; typed CUDA imports, decorator/DynamicBitset/__exit__/HolderT/GPU-memory-query typing tweaks added.
KV cache core typing and DeltaScratchSlots refactor
_core/_kv_cache.py
IndexSeq narrowed; DeltaScratchSlots moved to module-level NamedTuple; _blocks/commit()/resume()/_commit_block()/_lock_held_blocks()/_check_sanity() get typing/formatting adjustments.
Block radix tree typed traversal
_block_radix_tree.py
try_get_tree and Block.unset_page gain explicit local variable typing without logic changes.
Copy engine return types and address casts
_copy_engine.py
CUDA import type-ignores, -> None return types on copy helpers, cast(...) for MemAddress/DiskAddress, typed StagingBuffer.__exit__.
Event manager hashing casts and eviction controller typing
_event_manager.py, _eviction_controller/_eviction_controller.py
Import type-ignores, timeout_ms is not None guard, int(...) wraps on hash results, EvictablePage casts, TypedIndexList parameterization, -> None return type.
Remaining typing annotations across modules
_core/_moving_average.py, _core/_pending_stats.py, _cuda_virt_mem.py, _exceptions.py, _page.py, _stats.py, _storage/_config.py, _storage_manager.py, rawref/__init__.pyi, setup_mypyc.py
Return type annotations, bool(...) wrap, import type-ignores, typed casts, and mypyc module list trims applied.

Estimated code review effort: 2 (Simple) | ~15 minutes

Suggested reviewers: joyang-nv, arysef, bo-nv, hyukn

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, specific, and matches the PR's main goal of restoring KVCacheManagerV2 mypyc compilability.
Description check ✅ Passed The description fills the required sections with a clear problem statement, solution summary, test coverage, and checklist items.
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.
✨ 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tensorrt_llm/runtime/kv_cache_manager_v2/_storage/_config.py (1)

152-158: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid sharing the same list object here.

[[]] * self.num_life_cycles aliases every inner list. Since this function returns nested mutable lists, that can cross-contaminate life-cycle entries if one is mutated later. Build the outer list with a comprehension instead.

Suggested fix
-        ret: list[list[int]] = [[]] * self.num_life_cycles
+        ret: list[list[int]] = [[] for _ in range(int(self.num_life_cycles))]
🤖 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 `@tensorrt_llm/runtime/kv_cache_manager_v2/_storage/_config.py` around lines
152 - 158, The slot_to_page_indices method is creating aliased inner lists by
initializing ret with [[]] * self.num_life_cycles, which can cause life_cycle
entries to share mutable state. Update slot_to_page_indices in _config.py to
build ret with a comprehension so each life_cycle gets its own independent list,
while keeping the rest of the loop over slot_desc_list and
slot.coalesced_buffers unchanged.
🧹 Nitpick comments (2)
tensorrt_llm/runtime/kv_cache_manager_v2/_utils.py (2)

67-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use overloads for _unwrap instead of Any.

_unwrap has fixed arity-based outcomes (None, T, or tuple[T, U]), so Any leaks type information into the CUDA query and copy helpers. Overloads keep those call sites typed without changing runtime behavior.

🤖 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 `@tensorrt_llm/runtime/kv_cache_manager_v2/_utils.py` around lines 67 - 74, The
_unwrap helper currently returns Any even though its behavior is fixed by tuple
arity, so replace the broad annotation with overloads on _unwrap to preserve
typing for the CUDA query and copy helpers. Add distinct overload signatures for
the CUresult-only case, the single-value tuple case, and the two-value tuple
case, while keeping the existing runtime implementation unchanged and using the
_unwrap symbol to guide the edit.

Source: Coding guidelines


237-250: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use ParamSpec for these decorators. noexcept and not_implemented currently erase wrapped signatures with Callable[..., T] and Any; switching to Callable[P, T] / *args: P.args, **kwargs: P.kwargs keeps the decorators type-safe with minimal churn.

🤖 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 `@tensorrt_llm/runtime/kv_cache_manager_v2/_utils.py` around lines 237 - 250,
Update the noexcept and not_implemented decorators to preserve wrapped function
signatures by introducing ParamSpec and using Callable[P, T] instead of
Callable[..., T]. Adjust the inner wrappers in _utils.py to accept *args: P.args
and **kwargs: P.kwargs, and remove the broad Any-based signature so the
decorators remain type-safe while keeping behavior unchanged.

Source: Coding guidelines

🤖 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/runtime/kv_cache_manager_v2/_stats.py`:
- Line 17: The import in the module-level setup uses typing.Self, which is not
available on Python 3.10. Update the _stats.py import to pull Self from
typing_extensions instead, and keep the rest of the type annotations in the file
unchanged so the class and method signatures that reference Self continue to
work on all supported versions.

---

Outside diff comments:
In `@tensorrt_llm/runtime/kv_cache_manager_v2/_storage/_config.py`:
- Around line 152-158: The slot_to_page_indices method is creating aliased inner
lists by initializing ret with [[]] * self.num_life_cycles, which can cause
life_cycle entries to share mutable state. Update slot_to_page_indices in
_config.py to build ret with a comprehension so each life_cycle gets its own
independent list, while keeping the rest of the loop over slot_desc_list and
slot.coalesced_buffers unchanged.

---

Nitpick comments:
In `@tensorrt_llm/runtime/kv_cache_manager_v2/_utils.py`:
- Around line 67-74: The _unwrap helper currently returns Any even though its
behavior is fixed by tuple arity, so replace the broad annotation with overloads
on _unwrap to preserve typing for the CUDA query and copy helpers. Add distinct
overload signatures for the CUresult-only case, the single-value tuple case, and
the two-value tuple case, while keeping the existing runtime implementation
unchanged and using the _unwrap symbol to guide the edit.
- Around line 237-250: Update the noexcept and not_implemented decorators to
preserve wrapped function signatures by introducing ParamSpec and using
Callable[P, T] instead of Callable[..., T]. Adjust the inner wrappers in
_utils.py to accept *args: P.args and **kwargs: P.kwargs, and remove the broad
Any-based signature so the decorators remain type-safe while keeping behavior
unchanged.
🪄 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: 63ce790e-ca73-4925-991d-9eee91168e12

📥 Commits

Reviewing files that changed from the base of the PR and between 011e849 and 0c84bd3.

📒 Files selected for processing (17)
  • tensorrt_llm/runtime/kv_cache_manager_v2/_block_radix_tree.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_config.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_copy_engine.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_core/_kv_cache.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_core/_moving_average.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_core/_pending_stats.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_cuda_virt_mem.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_event_manager.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_eviction_controller/_eviction_controller.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_exceptions.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_page.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_stats.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_storage/_config.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_storage_manager.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/_utils.py
  • tensorrt_llm/runtime/kv_cache_manager_v2/rawref/__init__.pyi
  • tensorrt_llm/runtime/kv_cache_manager_v2/setup_mypyc.py
💤 Files with no reviewable changes (1)
  • tensorrt_llm/runtime/kv_cache_manager_v2/setup_mypyc.py

# limitations under the License.

from dataclasses import dataclass, fields
from typing import Self

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '## File\n'
cat -n tensorrt_llm/runtime/kv_cache_manager_v2/_stats.py | sed -n '1,120p'

printf '\n## Python version declarations\n'
rg -n --hidden --glob '!**/.git/**' -e 'python_requires|requires-python|3\.10|3\.11|3\.12|3\.13' pyproject.toml setup.py setup.cfg tox.ini noxfile.py requirements*.txt .github/workflows AGENTS.md CLAUDE.md legacy-files.txt tensorrt_llm -g '!**/node_modules/**' || true

Repository: NVIDIA/TensorRT-LLM

Length of output: 4992


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('tensorrt_llm/runtime/kv_cache_manager_v2/_stats.py')
print(p.read_text())
PY

printf '\n## Python version declarations\n'
rg -n --hidden --glob '!**/.git/**' -e 'python_requires|requires-python|3\.10|3\.11|3\.12|3\.13' pyproject.toml setup.py setup.cfg tox.ini noxfile.py requirements*.txt .github/workflows AGENTS.md CLAUDE.md legacy-files.txt tensorrt_llm || true

Repository: NVIDIA/TensorRT-LLM

Length of output: 4467


🏁 Script executed:

#!/bin/bash
set -euo pipefail
pwd
git ls-files tensorrt_llm/runtime/kv_cache_manager_v2/_stats.py pyproject.toml setup.py setup.cfg | sed -n '1,20p'

Repository: NVIDIA/TensorRT-LLM

Length of output: 251


🏁 Script executed:

#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
print(Path('pyproject.toml').read_text())
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- pyproject.toml ---'
sed -n '1,120p' pyproject.toml

echo
echo '--- Search for requires-python / python versions ---'
rg -n 'requires-python|python_requires|3\.10|3\.11|3\.12|3\.13' pyproject.toml setup.py setup.cfg tox.ini noxfile.py .github/workflows AGENTS.md CLAUDE.md tensorrt_llm | head -n 200 || true

Repository: NVIDIA/TensorRT-LLM

Length of output: 7664


Import Self from typing_extensions. Python 3.10 is still a supported target, so typing.Self will fail at import time here.

🤖 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 `@tensorrt_llm/runtime/kv_cache_manager_v2/_stats.py` at line 17, The import in
the module-level setup uses typing.Self, which is not available on Python 3.10.
Update the _stats.py import to pull Self from typing_extensions instead, and
keep the rest of the type annotations in the file unchanged so the class and
method signatures that reference Self continue to work on all supported
versions.

Sources: Coding guidelines, Learnings

@thorjohnsen

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57839 [ run ] triggered by Bot. Commit: 0c84bd3 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57839 [ run ] completed with state SUCCESS. Commit: 0c84bd3
/LLM/main/L0_MergeRequest_PR pipeline #46535 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.

2 participants