Skip to content

feat: use rtp-kernel fused rope kvcache ops#824

Merged
JackTan25 merged 2 commits intomainfrom
feat/replace_fused_rope
Apr 2, 2026
Merged

feat: use rtp-kernel fused rope kvcache ops#824
JackTan25 merged 2 commits intomainfrom
feat/replace_fused_rope

Conversation

@moui0
Copy link
Copy Markdown
Collaborator

@moui0 moui0 commented Mar 23, 2026

@moui0 moui0 requested a review from LLLLKKKK as a code owner March 23, 2026 12:39
@moui0 moui0 requested review from Bruce-Lee-LY and Copilot and removed request for Copilot March 23, 2026 12:39
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #824 — feat: use rtp-kernel fused rope kvcache ops

概述

This PR replaces the C++ pybind-based FusedRopeKVCache{Prefill,Decode}Op with Python wrappers around rtp_kernel. On CUDA, the ops are now pure-Python calling rtp_kernel.fused_rope_kvcache; on PPU, a compatibility wrapper delegates to the old pybind classes; ROCm is unchanged. A new max_seq_len parameter is threaded through all FMHA impl constructors.

优点

  • Clean separation of fused RoPE+KVCache ops from C++ pybind to Python+rtp_kernel
  • Thorough and consistent max_seq_len threading through all FMHA impl constructors (CUDA, ROCm, CP)
  • PPU compatibility wrapper is a nice pattern to bridge old/new APIs
  • arch.py simplification is a welcome cleanup

建议改进

P1 - 重要

  1. Module-level device query in compute_ops.py is import-order fragile
    is_cuda() / is_ppu() are called at module import time, which requires the C++ device singleton to already be initialized. If any code path imports compute_ops before init_device(), this will crash. Consider lazy import (function-level) or try/except ImportError fallback.

  2. Missing test coverage for decode path and QKVOut prefill path
    The new 230-line fused_rope_kvcache_op.py only has the QOut prefill path exercised by the existing test. FusedRopeKVCacheDecodeOp and FusedRopeKVCachePrefillOpQKVOut have no test coverage. The PPU compatibility wrapper is also untested.

P2 - 建议

  1. Hardcoded get_sm() == (9, 0) in trt.py — Only matches sm90 exactly. Future Hopper variants may be missed. Consider get_sm()[0] >= 9 if the intent is "Hopper and above".

  2. ROCm/CUDA pybind asymmetry — CUDA removes KVBlockArray from pybind registration and .pyi stub, while ROCm still registers it via registerFusedRopeKVCacheOp. Confirm no shared Python code imports KVBlockArray from rtp_llm_ops on CUDA.

P3 - Nits

  1. FusedRopeAttnParams.attn_type: torch.dtype — name is misleading (sounds like MHA/MLA type). Consider scalar_type or dtype.
  2. PPU wrapper sets __qualname__ = base_class.__name__ — should be base_class.__qualname__ for consistency.

总结

REQUEST_CHANGES — The module-level device query creates an import-order dependency risk, and the new Python implementation lacks test coverage for 2 of 3 op variants. The core refactoring logic is sound and the max_seq_len threading is thorough.

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

Code Review: PR #824 - feat: use rtp-kernel fused rope kvcache ops

Author: moui0 | Reviewer: Claude

Summary

Replaces C++ pybind FusedRopeKVCache ops with Python rtp_kernel-based implementations on CUDA. PPU falls back to pybind wrappers with compatibility shim. 16 files, +355/-84.

Findings

[P1] ROCm has no FusedRopeKVCache import — NameError if any ROCm path uses it
compute_ops.py: On non-CUDA, non-PPU platforms, the FusedRopeKVCache* names are never defined. Currently safe (ROCm aiter.py has its own rope logic), but fragile. Add explicit ROCm branch with stub or clear error.

[P1] KVBlockArray removed from .pyi but pybind registration still exists
rtp_llm_ops.pyi removes KVBlockArray class, but FusedRopeKVCacheOp.cc still registers it. Type-checked code will get errors.

[P2] input_lengths.max().item() device-to-host sync in prepare()
Acceptable for non-graph mode but would break CUDA graph capture.

[P2] assert params.kv_cache_offset is not None in decode forward
assert is stripped with -O. Use if...raise RuntimeError for kernel segfault guard.

Verdict: COMMENT

No blockers. ROCm import gap and .pyi inconsistency should be addressed.

Copilot AI review requested due to automatic review settings March 24, 2026 08:07
@moui0 moui0 force-pushed the feat/replace_fused_rope branch from 3125026 to 0756e79 Compare March 24, 2026 08:07
@moui0 moui0 review requested due to automatic review settings March 24, 2026 08:09
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

AI Code Review -- PR #824 — feat: use rtp-kernel fused rope kvcache ops (Incremental v2)

Overview

Replaces C++ pybind FusedRopeKVCache ops with pure Python wrappers around rtp_kernel on CUDA. Ops now live in a dedicated cuda_impl/fused_rope_kvcache_op.py module. C++ pybind registrations for FusedRopeKVCache* are removed; only TRTAttn binding is retained. BUILD adds ARM CUDA deps. 14 files changed.

Previous P1 Issues — Resolved

  • ROCm import gap: resolved — ops now in cuda_impl/ directory, ROCm paths don't import them
  • KVBlockArray .pyi inconsistency: resolved — registerFusedRopeKVCacheOp() no longer called, so KVBlockArray correctly unregistered from pybind

Suggestions

P1 - Important

  1. SM check get_sm() == (9, 0) is too narrow (trt.py line 143)
    if get_sm() == (9, 0) only matches H100 exactly. SM 8.9 (L40S), SM 10.0 (Blackwell) all miss this check. If the intent is "Hopper and later need host-side offset", this should be >= (9, 0). If truly SM90-only, please add a comment explaining why.

P2 - Suggestions

  1. Dead C++ code: registerFusedRopeKVCacheOp() and all C++ FusedRopeKVCache classes are now unreachable* (FusedRopeKVCacheOp.cc)
    The function is no longer called from registerAttnOpBindings(). The entire body plus C++ class implementations are dead code. Recommend cleanup in this PR or a follow-up.

  2. input_lengths.max().item() triggers CUDA sync (fused_rope_kvcache_op.py lines 192-193)
    Two device-to-host syncs in prepare(). Acceptable for non-graph mode but would break CUDA graph capture if prepare() is ever called during capture.

  3. assert guards in decode path stripped with -O (fused_rope_kvcache_op.py lines 308, 343-345)
    assert params.kv_cache_offset is not None guards against kernel segfaults. Should use if ... raise RuntimeError(...) for production safety.

Summary

Previous P1 issues are resolved. One new P1: the SM version check in trt.py is too narrow and may skip the kv_cache_offset_h CPU copy on future architectures. Dead C++ code cleanup recommended. Overall the migration from C++ pybind to Python rtp_kernel wrappers is clean.

@moui0 moui0 force-pushed the feat/replace_fused_rope branch from 0756e79 to 66b4949 Compare March 25, 2026 06:35
@moui0 moui0 requested review from Copilot and removed request for Copilot March 25, 2026 06:35
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #824 v3 (feat: use rtp-kernel fused rope kvcache ops)

概述

v3 将 FusedRopeKVCache ops 从 C++ pybind 迁移到 Python wrapper(基于 rtp_kernel.fused_rope_kvcache)。新增 fused_rope_kvcache_op.py(242 行),compute_ops.py 条件导入,C++ pybind 精简,ARM 平台支持。

建议改进

P1

  1. compute_ops.py 导入无 fallback — Python 实现覆盖 C++ 导入,但如果 rtp_kernel 未安装,from .fused_rope_kvcache_op import ... 会失败,导致整个 compute_ops 模块崩溃(影响所有功能)。建议用 try/except ImportError 包裹。

  2. FusedRopeAttnParamsTRTAttn 接口兼容性 — Python 实现返回 FusedRopeAttnParams dataclass,C++ 返回 TRTAttn。需确认 common.copy_kv_cache_offsetcommon.update_trt_params 等消费者兼容两种类型。

P2

  1. prepare().max().item() 触发两次 CUDA synchronize,建议合并
  2. registerFusedRopeKVCacheOp 函数不再被调用但未删除

结论

REQUEST CHANGES — P1: 需要 try/except fallback + 接口兼容性确认。

Review by Claude | Commit: 66b4949

Copilot AI review requested due to automatic review settings March 27, 2026 03:40
@moui0 moui0 force-pushed the feat/replace_fused_rope branch from 66b4949 to b5f9154 Compare March 27, 2026 03:40
@moui0 moui0 review requested due to automatic review settings March 27, 2026 03:40
@moui0 moui0 force-pushed the feat/replace_fused_rope branch from b5f9154 to f37d6ea Compare March 27, 2026 03:45
@moui0 moui0 requested review from Copilot and removed request for Copilot March 27, 2026 03:45
@moui0
Copy link
Copy Markdown
Collaborator Author

moui0 commented Mar 27, 2026

P1-1: rtp-kernel 在CUDA环境总是可用
P1-2: 根据 registerTRTAttn 定义,python只能读写 kv_cache_offset 字段,FusedRopeAttnParams 包含该字段且类型一致
P2-3: 与 C++ 实现保持一致
P2-4: PPU仍需调用C++实现

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #824

PR 概述

Title: feat: use rtp-kernel fused rope kvcache ops
Author: moui0
规模: 7(GitHub) + 1(内源) files, +277/-57

核心目标

将 FusedRopeKVCache 系列 op(Prefill QKVOut / QOut / Decode)从 C++ pybind 实现迁移到 Python 实现,底层调用 rtp_kernel.fused_rope_kvcache 包。同时将 TRTAttn 的 pybind 注册拆分为独立函数,并为 ARM CUDA 12 平台启用 rtp_kernel 和 flashattn 依赖。


改动逻辑拆解

GitHub 开源仓库变更(主要代码)

1. 新增 Python 实现 — rtp_llm/ops/fused_rope_kvcache_op.py(+242)

核心新增文件。定义了 FusedRopeAttnParams dataclass 和三个 op 类:

  • FusedRopeKVCachePrefillOpBase / FusedRopeKVCachePrefillOpQKVOut / FusedRopeKVCachePrefillOpQOut:prefill 路径,调用 rtp_kernel.fused_rope_kvcache.prefill_fused_rope_kvcache
  • FusedRopeKVCacheDecodeOp:decode 路径,调用 rtp_kernel.fused_rope_kvcache.decode_fused_rope_kvcache

接口与原 C++ pybind 类保持一致(__init__(attn_configs), prepare(attn_inputs), forward(qkv, kv_cache, params)),确保上层调用方无需修改。

2. 条件导入 — rtp_llm/ops/compute_ops.py(+15)

在 CUDA 设备上用 Python 实现覆盖 C++ 版本:

if is_cuda():
    from .fused_rope_kvcache_op import (...)
else:
    logging.info("Fallback to default implementation...")

非 CUDA 设备(ROCm)仍使用 librtp_compute_ops 中的 C++ 实现。

3. C++ pybind 重构 — FusedRopeKVCacheOp.cc/h, RegisterAttnOpBindings.hpp

  • TRTAttn 的 pybind 注册从 registerFusedRopeKVCacheOp 中拆出为独立的 registerTRTAttn 函数
  • RegisterAttnOpBindings.hpp 中用 registerTRTAttn 替换 registerFusedRopeKVCacheOp,不再注册 C++ 版 FusedRopeKVCache* op 和 KVBlockArray

4. sm90 kv_cache_offset_h 处理 — trt.py(+3/-1)

TRTPagedMHAImpl.__init__ 中新增:

if get_sm() == (9, 0) and self.rope_params.kv_cache_offset is not None:
    self.rope_params.kv_cache_offset_h = self.rope_params.kv_cache_offset.cpu()

为 H100/H800 (sm90) 提供 host 端 kv_cache_offset 副本。

5. BUILD 文件 — ARM 平台支持(+2)

using_cuda12_arm 条件添加 rtp_kernelflashattn 依赖。

6. .pyi 类型存根更新(+2/-48)

rtp_llm_ops.pyi 中移除 FusedRopeKVCacheDecodeOpFusedRopeKVCachePrefillOpQKVOutFusedRopeKVCachePrefillOpQOutKVBlockArray 的类型定义和 __all__ 条目。

内源仓库变更

1. PPU 注册

在 PPU 路径中添加 registerTRTAttn 调用,确保 PPU 平台仍能使用 TRTAttn。


Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ 每个类职责单一
OCP ✅ 通过条件导入扩展,未修改核心逻辑
LSP ✅ Python 实现保持与 C++ 版相同接口契约
ISP
DIP ✅ 上层依赖抽象接口(prepare/forward),不依赖具体实现
DRY ✅ prefill 基类提取了公共 _forward 逻辑
KISS
YAGNI

架构审视

检查项 结果
抽象边界 ✅ Python 实现放在 rtp_llm/ops/ 层,与 C++ 版同层
依赖方向
状态完整性 ❌ sm90 kv_cache_offset_h 在 CUDA Graph replay 时未更新(见 P1-1)
错误语义 ✅ decode 路径有 assert 校验
可观测性 ✅ 有 logging.info 标识使用哪个实现
可演进性
可运维性 ✅ 非 CUDA 设备自动 fallback

测试

检查项 结果
新功能有对应测试 ❌ 无新增测试验证 Python 实现与 C++ 实现的等价性(见 P2-1)
删除的测试有等价替代 ✅ 未删除测试
边界 case 覆盖 ❌ 缺少 kv_cache_offset 为 None 时的 decode 路径测试
分布式改动有多卡测试 N/A

代码质量与文档

检查项 结果
无关改动分离
mega-PR 拆分 ✅ PR 聚焦单一功能
Commit 原子性 ✅ commit 1 为主功能,commit 2 为 rebase 修复
Commit message 准确性
PR description 说明动机和设计 ❌ PR description 过于简略,仅一句话指向源文件,未说明迁移动机和预期收益
日志频率控制 ✅ logging.info 仅在模块加载时执行一次

领域检查

A. 兼容性与配置 — 全部 ✅

B. 正确性与逻辑

检查项 结果
逻辑错误 ❌ sm90 CUDA Graph replay 时 kv_cache_offset_h 过期(见 P1-1)
边界 case
死代码
状态标志生命周期

C. 线程安全与并发 — 全部 ✅

D. 性能

检查项 结果
hot path per-forward 内存分配 prepare().max().item() 触发设备同步(见 P2-2)
设备同步在关键路径 ❌ 同上
CUDA Graph replay 参数过期 kv_cache_offset_h 未在 replay 时更新(见 P1-1)

E. 分布式 — 全部 ✅

F. 跨平台(ROCm/ARM)

检查项 结果
CUDA/ROCm binding 对称清理 ✅ ROCm 侧 registerFusedRopeKVCacheOp 未被修改,保持独立

G. 语言与框架特有 — 全部 ✅

H. 测试与 CI

检查项 结果
测试覆盖充分 ❌ 缺少 Python 实现的等价性测试(见 P2-1)

I. 代码质量 — 全部 ✅


Review 意见

问题

  1. sm90 CUDA Graph replay 时 kv_cache_offset_h 过期 [P1]

    trt.pyTRTPagedMHAImpl.__init__ 中新增了 sm90 特殊处理:

    if get_sm() == (9, 0) and self.rope_params.kv_cache_offset is not None:
        self.rope_params.kv_cache_offset_h = self.rope_params.kv_cache_offset.cpu()

    common.update_trt_params() 在 CUDA Graph replay 路径(prepare_cuda_graph)中只更新 rope_params.kv_cache_offset(device tensor),不更新 kv_cache_offset_h(host tensor)。

    触发条件:H100/H800 (sm90) + CUDA Graph 启用 + TRTPagedMHAImpl 路径
    风险后果:replay 时 kernel 使用 capture 时的 host offset,导致 KV cache 读写位置错误,产生错误的推理结果
    代码位置rtp_llm/models_py/modules/factory/attention/common.py:108-135update_trt_params 缺少 kv_cache_offset_h 更新)
    建议:在 update_trt_params 中增加 kv_cache_offset_h 的更新逻辑,或在 TRTPagedMHAImpl.prepare_cuda_graph 中补充:

    if get_sm() == (9, 0) and self.rope_params.kv_cache_offset is not None:
        self.rope_params.kv_cache_offset_h = self.rope_params.kv_cache_offset.cpu()
  2. 缺少 Python 实现等价性测试 [P2]

    将 FusedRopeKVCache 从 C++ 迁移到 Python 是行为变更,但未新增测试验证两者输出一致。现有测试(如 test_mha_rotary_emb.py)会间接覆盖,但缺少显式的 regression test。
    建议:至少添加一个对比测试,验证 Python 实现与 C++ 实现在相同输入下输出一致(可参考 test_mha_rotary_emb.py 的模式)。

  3. prepare().max().item() 触发隐式设备同步 [P2]

    FusedRopeKVCachePrefillOpBase.prepare() 中:

    attn_inputs.input_lengths.max().item(),
    attn_inputs.prefix_lengths.max().item(),

    .item() 会触发 CUDA 设备同步,在 per-layer 调用时可能影响性能。原 C++ 实现在 C++ 侧完成此计算,不会触发 Python 层的设备同步。
    代码位置rtp_llm/ops/fused_rope_kvcache_op.py:90-91
    建议:确认 prepare() 是否在 per-layer 热路径上调用。如果是,考虑将 max 值从上层传入或缓存。如果 prepare() 仅在初始化时调用一次,则影响可忽略。

小问题

  • P3: FusedRopeAttnParams.attn_type 类型标注为 torch.dtype,但 get_scalar_type() 返回的是 scalar type enum,建议修正标注。
  • P3: PR description 过于简略(仅一句话),建议补充迁移动机(性能?可维护性?)和预期收益。

整体评价

PR 将 FusedRopeKVCache op 从 C++ pybind 迁移到 Python + rtp_kernel 调用,架构清晰,接口兼容性好,条件导入机制保证了非 CUDA 平台的 fallback。主要风险在于 sm90 CUDA Graph 路径下 kv_cache_offset_h 未随 replay 更新,可能导致 H100/H800 上的正确性问题,建议修复后合入。

存在阻塞/重要问题(P1 x 1)

@moui0 moui0 force-pushed the feat/replace_fused_rope branch from f37d6ea to 6a92cde Compare March 27, 2026 15:10
Copilot AI review requested due to automatic review settings March 27, 2026 15:10

This comment was marked as abuse.

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #824

PR 概述

Title: feat: use rtp-kernel fused rope kvcache ops
Author: moui0
规模: 7(GitHub) files, +272/-56
Review 类型: 检测到 force push/rebase,本次为 PR 全量 review(第 2 次 review)

核心目标

将 FusedRopeKVCache 系列 op(Prefill/Decode)从 C++ pybind 实现迁移到 Python 实现,底层调用 rtp_kernel 包的 fused rope kvcache 函数。C++ 侧仅保留 TRTAttnKVBlockArray 的 pybind 注册,不再注册 FusedRope op 类。


改动逻辑拆解

GitHub 开源仓库变更(主要代码)

1. C++ Binding 拆分(FusedRopeKVCacheOp.cc/h, RegisterAttnOpBindings.hpp)

  • registerFusedRopeKVCacheOp() 中提取 TRTAttn 的 pybind 注册为独立函数 registerTRTAttn()
  • RegisterAttnOpBindings.hpp 中将 registerFusedRopeKVCacheOp 替换为 registerTRTAttn
  • KVBlockArray 的 pybind 注册保留在 registerFusedRopeKVCacheOp() 中(PPU 路径仍调用)

2. Python 替代实现(fused_rope_kvcache_op.py,新增 242 行)

  • FusedRopeAttnParams dataclass 替代 C++ TRTAttn 作为 prepare/forward 间的参数传递对象
  • FusedRopeKVCachePrefillOpBase / QKVOut / QOut 替代 C++ prefill op
  • FusedRopeKVCacheDecodeOp 替代 C++ decode op
  • 底层调用 rtp_kernel.fused_rope_kvcache

3. 条件导入(compute_ops.py)

  • CUDA 设备上从 Python 模块导入 FusedRope ops,非 CUDA 设备 fallback

4. 构建配置(BUILD)

  • using_cuda12_arm 平台添加 rtp_kernelflashattn 依赖

5. 类型存根(rtp_llm_ops.pyi)

  • 移除 C++ FusedRopeKVCache* 和 KVBlockArray 的类型存根

Review 意见

问题

  1. Prefill 与 Decode 使用不同的 block_id 字段名 [P0]

    FusedRopeKVCachePrefillOpBase.prepare() 使用 attn_inputs.kv_cache_kernel_block_id_hostattn_inputs.kv_cache_kernel_block_id_device

    # fused_rope_kvcache_op.py L145-149
    if (
        attn_inputs.kv_cache_kernel_block_id_host is not None
        and attn_inputs.kv_cache_kernel_block_id_host.numel() > 0
    ):
        kv_cache_offset = convert_offset_to_block_array(
            attn_inputs.kv_cache_kernel_block_id_device
        )

    FusedRopeKVCacheDecodeOp.prepare() 使用 attn_inputs.kv_cache_block_id_device

    # fused_rope_kvcache_op.py L324-325
    kv_cache_offset = convert_offset_to_block_array(
        attn_inputs.kv_cache_block_id_device
    )

    但 decode 的 guard 条件仍然检查 kv_cache_kernel_block_id_host

    存在两个问题:

    • 字段名不一致:prefill 用 kv_cache_kernel_block_id_device,decode 用 kv_cache_block_id_device,但 guard 条件都用 kv_cache_kernel_block_id_host。C++ 原始实现中两个路径都使用 kv_cache_block_id_host / kv_cache_block_id_device(见 FusedRopeKVCacheOp.cc L107-109 和 L215-217),字段名完全一致。
    • 如果 kv_cache_kernel_block_id_host 不存在于 PyAttentionInputs 上,运行时会 AttributeError。

    建议:统一为同一个字段名,与 OpDefs.h 中的定义保持一致(kv_cache_block_id_host / kv_cache_block_id_device)。

  2. CUDA Graph replay 时 kv_cache_offset 更新语义变化 [P1]

    C++ 版本的 prepare() 返回 TRTAttn(C++ 对象),CUDA Graph replay 时通过 common.copy_kv_cache_offset() 原地更新 offset 数据。

    Python 版本的 prepare() 每次返回新的 FusedRopeAttnParams dataclass,其中 kv_cache_offsetconvert_offset_to_block_array() 返回的新 tensor。CUDA Graph replay 路径中 common.copy_kv_cache_offset(old_offset, new_offset) 会将新 tensor 数据 copy 到旧 tensor。

    这依赖于 convert_offset_to_block_array() 返回的 tensor 与 C++ KVBlockArraykv_cache_offset 具有相同的 shape 和语义。如果 shape 不匹配,copy_kv_cache_offset 会走 slice 路径,可能导致数据截断。

    此外,kv_cache_offset_h 始终为 None。上次 review 指出 C++ 版本中 kv_cache_offset_h(host 端 offset)在 CUDA Graph replay 时未更新。Python 版本直接将其设为 None,需要确认 rtp_kerneldecode_fused_rope_kvcachekv_cache_offset_h=None 时是否有正确的 fallback 逻辑。

    建议:(1) 添加注释说明 kv_cache_offset_h=None 的设计意图;(2) 在 CUDA Graph 测试中验证 decode 路径的正确性。

  3. 新增 242 行 Python 实现无测试覆盖 [P1]

    fused_rope_kvcache_op.py 是核心 attention 路径的替代实现,涉及 RoPE + KV Cache 写入,但没有任何单元测试或集成测试。

    建议:至少添加 Python prefill/decode op 与 C++ 版本的数值一致性测试,以及 CUDA Graph capture/replay 路径的端到端测试。

小问题

  1. Prefill prepare 中两次设备同步 [P2]
    attn_inputs.input_lengths.max().item()attn_inputs.prefix_lengths.max().item() 各触发一次 GPU→CPU 同步。C++ 版本也有同样的调用,不是回退,但后续可考虑合并。

  2. 非 CUDA 设备 fallback 行为 [P2]
    非 CUDA 设备上不导入 Python FusedRope ops,ROCm 仍使用 C++ 实现。建议添加注释说明。

  3. FusedRopeAttnParams.attn_type 类型注解 [P3]
    声明为 torch.dtype,但 get_scalar_type() 返回值可能不是 torch.dtype。建议确认并更新注解。

整体评价

架构方向合理,将 FusedRopeKVCache ops 从 C++ pybind 迁移到 Python + rtp_kernel 可降低编译依赖。主要风险在于 prefill/decode 路径使用了不一致的字段名(P0),以及缺少测试覆盖(P1)。CUDA Graph replay 路径的语义变化也需要验证。

存在阻塞/重要问题,不建议合入

@moui0 moui0 force-pushed the feat/replace_fused_rope branch from 6a92cde to 68157ab Compare March 27, 2026 15:46
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #824

PR 概述

Title: feat: use rtp-kernel fused rope kvcache ops
Author: moui0
规模: 7(GitHub) files, +274/-56
Review 类型: 检测到 force push/rebase,本次为 PR 全量 review(第 3 次 review)
上次 P0 修复状态: 未修复(详见 P0-1)

核心目标

将 FusedRopeKVCache 系列 op(Prefill/Decode)从 C++ pybind 实现迁移到 Python 实现,底层调用 rtp_kernel 包的 fused rope kvcache 函数。C++ 侧仅保留 TRTAttnKVBlockArray 的 pybind 注册,不再注册 FusedRope op 类。


Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ 每个类职责单一
OCP ✅ 通过条件导入扩展
LSP ✅ 保持 prepare/forward 接口契约
ISP
DIP ✅ 通过 compute_ops 统一入口
DRY ✅ prefill 共用 _forward 基类方法
KISS
YAGNI

架构审视

检查项 结果
抽象边界
依赖方向
状态完整性 ❌ 见 P1-1
错误语义
可观测性
可演进性
可运维性

测试

检查项 结果
新功能有对应测试 ❌ 见 P1-2
边界 case 覆盖 ❌ 无测试

代码质量与文档 — 全部 ✅

领域检查

  • A. 兼容与配置 — 全部 ✅
  • B. 正确性与逻辑 — ❌ 见 P0-1
  • C. 线程安全与并发 — 全部 ✅
  • D. 性能 — ❌ 见 P1-1, P2-1
  • E. 分布式 — 全部 ✅
  • F. 跨平台 — 全部 ✅
  • G. 语言与框架 — 全部 ✅
  • H. 测试与 CI — ❌ 见 P1-2
  • I. 代码质量 — 全部 ✅

Review 意见

问题

  1. Prefill 和 Decode 均使用不存在的字段名 kv_cache_kernel_block_id_* [P0]

    上次 P0 跟踪: 上次 review 指出 prefill 用 kv_cache_kernel_block_id_device、decode 用 kv_cache_block_id_device,字段名不一致。本次 rebase 后第二个 commit(68157ab "fix: update KVCache types and field names after rebase")将 decode 也改为 kv_cache_kernel_block_id_*,使两个路径一致了——但统一到了一个不存在的字段名

    PyAttentionInputs 的定义在 OpDefs.h L90-91:

    torch::Tensor kv_cache_block_id_host;
    torch::Tensor kv_cache_block_id_device;

    整个代码库中所有消费者(flash_infer.pytrtllm_gen.pyxqa.pypy_flashinfer_mha.pyindexer_op.pyauto_model.py、所有测试文件)均使用 kv_cache_block_id_host / kv_cache_block_id_device。全局搜索 kv_cache_kernel_block_id 返回 0 个匹配(仅存在于本 PR 新增的 fused_rope_kvcache_op.py 中)。

    C++ 原始实现(FusedRopeKVCacheOp.cc L107-109, L215-217)也使用 kv_cache_block_id_host / kv_cache_block_id_device

    影响: 运行时 attn_inputs.kv_cache_kernel_block_id_host 会触发 AttributeError,prefill 和 decode 路径均无法工作。

    修复:fused_rope_kvcache_op.py 中所有 kv_cache_kernel_block_id_host 替换为 kv_cache_block_id_hostkv_cache_kernel_block_id_device 替换为 kv_cache_block_id_device。具体位置:

    • L144-146(prefill prepare guard)
    • L148-149(prefill prepare convert)
    • L320-322(decode prepare assert)
    • L324-325(decode prepare convert)
  2. CUDA Graph replay 时 kv_cache_offset 更新语义变化 [P1]

    C++ 版本的 prepare() 返回 TRTAttn(含 KVBlockArray C++ 对象)。Python 版本每次返回新 FusedRopeAttnParams dataclass,kv_cache_offsetconvert_offset_to_block_array() 返回的新 tensor。

    CUDA Graph replay 路径(flash_infer.py L138-141、trtllm_gen.py L362-365/424-427/486-489)中 copy_kv_cache_offset(old, new) 依赖 shape 匹配。如果 convert_offset_to_block_array() 返回的 tensor 与 C++ KVBlockArraykv_cache_offset shape 不同,会走 slice 路径导致数据截断。

    此外 kv_cache_offset_h 始终为 None,需确认 rtp_kerneldecode_fused_rope_kvcachekv_cache_offset_h=None 时有正确 fallback。

  3. 新增 242 行 Python 实现无测试覆盖 [P1]

    fused_rope_kvcache_op.py 是核心 attention 路径的替代实现,涉及 RoPE + KV Cache 写入,但没有任何测试。建议至少添加 Python/C++ 数值一致性测试和 CUDA Graph 端到端测试。

小问题

  1. Prefill prepare 中两次设备同步 [P2] — .max().item() 触发 GPU→CPU 同步,与 C++ 版本一致,非回退。
  2. FusedRopeAttnParams.attn_type 类型注解 [P3] — 声明 torch.dtype 但实际可能不是,建议确认。

整体评价

架构方向合理,但上次 P0(字段名不一致)的修复将两个路径统一到了不存在的字段名 kv_cache_kernel_block_id_*,运行时会直接 AttributeError。这是连续第 3 次 review 存在 P0 级问题。

存在阻塞/重要问题,不建议合入

Copilot AI review requested due to automatic review settings March 29, 2026 13:42
@moui0 moui0 force-pushed the feat/replace_fused_rope branch from 68157ab to 5abfd07 Compare March 29, 2026 13:42

This comment was marked as abuse.

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #824

PR 概述

Title: feat: use rtp-kernel fused rope kvcache ops
Author: moui0
规模: 7(GitHub) files, +275/-56
Review 类型: 检测到 force push/rebase(68157ab5abfd07),本次为 PR 全量 review(第 4 次 review)
上次 P0 修复状态: 未修复 — 上次指出 kv_cache_kernel_block_id_* 字段不存在于 PyAttentionInputs,本次 rebase 后该问题仍然存在

核心目标

将 FusedRopeKVCache 系列 op(Prefill/Decode)从 C++ pybind 实现迁移到 Python 实现,底层调用 rtp_kernel 包的 fused rope kvcache 函数。C++ 侧仅保留 TRTAttnKVBlockArray 的 pybind 注册,不再注册 FusedRope op 类。


Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ 每个类职责单一
OCP ✅ 通过条件导入扩展
LSP ✅ Python 实现保持与 C++ 版本相同的 prepare/forward 接口契约
ISP
DIP ✅ 调用方通过 compute_ops 统一入口
DRY ✅ prefill 共用 _forward 基类方法
KISS
YAGNI

架构审视

检查项 结果
抽象边界
依赖方向
状态完整性 ❌ 见 P1-1
错误语义
可观测性
可演进性
可运维性

测试

检查项 结果
新功能有对应测试 ❌ 见 P1-2
边界 case 覆盖 ❌ 无测试

代码质量与文档 — 全部 ✅

领域检查

A. 兼容与配置 — 全部 ✅

B. 正确性与逻辑

检查项 结果
逻辑错误 ❌ 见 P0-1
边界 case

C. 线程安全与并发 — 全部 ✅

D. 性能

检查项 结果
CUDA Graph replay 参数过期 ❌ 见 P1-1
设备同步 ❌ 见 P2-1

E-G — 全部 ✅

H. 测试与 CI — ❌ 见 P1-2

I. 代码质量 — 全部 ✅


Review 意见

问题

  1. Prefill 和 Decode 均使用不存在的字段名 kv_cache_kernel_block_id_* [P0]

    连续 P0 跟踪(第 4 次 review): 前 3 次 review 均指出此问题。本次 rebase(5abfd07)未修复,代码完全相同。

    PyAttentionInputs 的定义在 OpDefs.h L90-91:

    torch::Tensor kv_cache_block_id_host;
    torch::Tensor kv_cache_block_id_device;

    pybind 注册在 OpDefs.cc L76-77:

    .def_readwrite("kv_cache_block_id_host", &PyAttentionInputs::kv_cache_block_id_host)
    .def_readwrite("kv_cache_block_id_device", &PyAttentionInputs::kv_cache_block_id_device)

    整个代码库中所有消费者均使用 kv_cache_block_id_host / kv_cache_block_id_device。全局搜索 kv_cache_kernel_block_id 返回 0 个匹配(仅存在于本 PR 新增的 fused_rope_kvcache_op.py 中)。

    影响: 运行时 attn_inputs.kv_cache_kernel_block_id_host 会触发 AttributeError,prefill 和 decode 路径均无法工作。

    修复:fused_rope_kvcache_op.py 中所有 kv_cache_kernel_block_id_host 替换为 kv_cache_block_id_hostkv_cache_kernel_block_id_device 替换为 kv_cache_block_id_device。具体位置:

    • L144-146(prefill prepare guard)
    • L148-149(prefill prepare convert)
    • L320-322(decode prepare assert)
    • L324-325(decode prepare convert)
  2. CUDA Graph replay 时 kv_cache_offset 更新语义需验证 [P1]

    Python 版本的 prepare() 每次返回新的 FusedRopeAttnParams dataclass,其中 kv_cache_offsetconvert_offset_to_block_array() 返回的新 tensor。在 CUDA Graph replay 路径中,copy_kv_cache_offset(old_offset, new_offset) 依赖 shape 一致性。如果 shape 不匹配会走 slice 路径,可能导致数据截断。

    此外 kv_cache_offset_h 始终为 None,需确认 rtp_kerneldecode_fused_rope_kvcache 在此情况下有正确 fallback。

  3. 新增 243 行 Python 实现无测试覆盖 [P1]

    fused_rope_kvcache_op.py 是核心 attention 路径的替代实现,涉及 RoPE + KV Cache 写入,但没有任何单元测试或集成测试。建议至少添加数值一致性测试和 CUDA Graph 端到端测试。

小问题

  1. Prefill prepare 中两次设备同步 [P2] — .max().item() 触发 GPU→CPU 同步(L169-170),后续可优化。
  2. FusedRopeAttnParams.attn_type 类型注解 [P3] — 声明 torch.dtype 但实际赋值为 get_scalar_type() 返回值。
  3. pyi 存根移除了 KVBlockArray [P3] — C++ 侧仍注册(PPU 路径),存根与实际导出不一致。

整体评价

架构方向合理,但连续第 4 次 review 仍存在同一个 P0kv_cache_kernel_block_id_* 字段不存在于 PyAttentionInputs,运行时会直接 AttributeError。修复方法:将 6 处 kv_cache_kernel_block_id_host/device 替换为 kv_cache_block_id_host/device

存在阻塞/重要问题,不建议合入

@moui0
Copy link
Copy Markdown
Collaborator Author

moui0 commented Mar 30, 2026

P0-1: 为支持 kernel_block_size,应使用 #820 引入的 kv_cache_kernel_block_id_host, kv_cache_kernel_block_id_device

torch::Tensor kv_cache_kernel_block_id_host;
torch::Tensor kv_cache_kernel_block_id_device;

P1-2: 根据rtp-kernel中定义,convert_offset_to_block_array 输出 shape 为 [batch_size, 1, 2, max_blocks_per_batch]

@JackTan25 JackTan25 enabled auto-merge (rebase) April 2, 2026 06:19
@JackTan25 JackTan25 requested a review from Copilot April 2, 2026 06:19
@JackTan25 JackTan25 requested review from Copilot and removed request for Bruce-Lee-LY and Copilot April 2, 2026 06:25
@JackTan25 JackTan25 disabled auto-merge April 2, 2026 06:28
@JackTan25 JackTan25 enabled auto-merge (rebase) April 2, 2026 06:28
@JackTan25 JackTan25 merged commit b680437 into main Apr 2, 2026
18 checks passed
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