Skip to content

Optimize kernel launch#832

Merged
Vinkle-hzt merged 4 commits into
alibaba:mainfrom
Vinkle-hzt:opt_launch
Apr 23, 2026
Merged

Optimize kernel launch#832
Vinkle-hzt merged 4 commits into
alibaba:mainfrom
Vinkle-hzt:opt_launch

Conversation

@Vinkle-hzt
Copy link
Copy Markdown
Collaborator

@Vinkle-hzt Vinkle-hzt commented Mar 26, 2026

fuse d2d & d2d stride copy

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 15(GitHub) files, ~+3600/-100

核心目标

优化 kernel launch 开销:将多个小 H2D copy 合并为单次 fused copy kernel,使用 pinned memory + fused copy 替代逐个 tensor.to(kCUDA)


Review 意见

  1. MAX_FUSED_D2D_COPIES = 16 硬编码 [P2]
    超过 16 个 tensor 时 assert 触发。建议添加 fallback。

  2. PR description 为空 [P2]

整体评价

有效的性能优化,pinned memory 使用正确,fused copy 减少 kernel launch 次数。

LGTM ready to ci

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

LLLLKKKK commented Apr 9, 2026

🤖 AI Code Review (incremental) — PR #832
Head SHA: 7d3e72023d17 | Previous: b948f4a6f668 | Verdict: P2

Changes since last review

Squash-rebased with 7d3e72023d17 ("refactor: implement fused copy operations"). This is a substantial rewrite:

  • New fused D2D copy kernel batching multiple copies into single launch
  • Strided fused copy kernel replacing copySmallerIntoLarger
  • Pinned memory throughout (PyWrappedModel, MtpExecutor, FlashInfer, CudaGraphRunner)
  • cu_seqlens split into host + device; new input_lengths_d / prefix_lengths_d
  • tensorHoldHostAndToCuda refactored to collect copies for single fused launch
  • Logits matmul changed from FP32 to model-dtype precision
  • FlashInfer prefill CUDA graph support (cuda_graph_plan, prepare_cuda_graph)

Findings

[P1] kv_cache_layer_to_group copy removed without replacement
The old code copied kv_cache_layer_to_group in prepareInputs(). This is completely removed. If this tensor can change between CUDA graph replays, this is a correctness bug. If it's guaranteed static after capture, a comment explaining why would be valuable.

[P2] Logits dtype change may affect numerical results

// Before: torch::mm(last_hidden.to(kFloat32), kernel.to(kFloat32).t())
// After:  torch::mm(last_hidden, kernel.t()).to(kFloat32)

Matmul now runs in BF16/FP16 instead of FP32. May cause smoke test golden mismatches for large vocab sizes.

[P2] Fused copy kernel — no error checking after launch
invokeFusedCopy/invokeFusedStridedCopy never check cudaGetLastError(). The assert in add() is debug-only; overflowing MAX_FUSED_D2D_COPIES=16 silently corrupts in release.

[P2] prefix_lengths init sign flip (-+)
Subtle change from max_seq_len_ - num_tokens_per_bs_ to max_seq_len_ + num_tokens_per_bs_. Likely intentional but needs a comment.

[Nit] util.h missing newline at EOF. FlashInfer version hard-pinned to == "0.6.0" is fragile.

Upgrading from LGTM to P2 overall. The removed kv_cache_layer_to_group copy is the most concerning item.

@Vinkle-hzt Vinkle-hzt marked this pull request as ready for review April 14, 2026 07:33
@Vinkle-hzt Vinkle-hzt requested a review from LLLLKKKK as a code owner April 14, 2026 07:33
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

Code Review: PR #832 — Optimize Kernel Launch

审查者: Claude Opus 4.6 (自动 Review) | 日期: 2026-04-14 | CI: 功能测试 FAILED

变更概述

通过 fused D2D copy kernel 合并多个独立 memcpy 为单次 kernel launch,减少 CUDA Graph 路径和 PyWrappedModel forward 路径的 launch 开销。同时统一 pinned memory 分配,拆分 cu_seqlens 为 host/device 独立 tensor。

问题汇总

级别 ID 问题 文件
P0 P0-1 kv_cache_block_id_device/host 拷贝被删除,cache store 在 CUDA Graph 下失效 cuda_graph_runner.cc
P1 P1-1 prefix_lengths 初始化值 -+,可能导致 attention 越界 cuda_graph_runner.cc
P1 P1-2 kv_cache_kernel_block_id_device 在 prefill 模式下未拷贝 cuda_graph_runner.cc
P1 P1-3 prepare_cuda_graph 调用时序变更,decode 路径 D2D 异步未完成时可能被读取 cuda_graph_runner.cc
P1 P1-4 fuse_copy_util.h 缺少文件末尾换行符 fuse_copy_util.h
P1 P1-5 MAX_FUSED_D2D_COPIES=16 用 assert 检查,Release 下静默越界 fuse_copy_util.h
P1 P1-6 缺少测试覆盖(fused copy kernel + CUDA Graph 回归)
P2 P2-1 pinned_check_remaining_ 在 forward/forwardMicroBatched 中重复递减 PyWrappedModel.cc
P2 P2-2 stridedCopyHost contiguous 时可单次 memcpy cuda_graph_runner.cc
P2 P2-4 cuda_graph_copy_kernel.cu 移除参数校验,无效参数导致 GPU UB cuda_graph_copy_kernel.cu
P2 P2-6 rtp_llm/cpp/kernels/BUILD 引用不存在的源文件 BUILD

详细说明

P0-1: kv_cache_block_id 拷贝丢失

原始代码中 prepareInputskv_cache_block_id_devicekv_cache_block_id_host 执行了 copySmallerIntoLarger,新代码中这两个拷贝被完全移除。这些是 cache store 专用的物理 block ID 表,与 kv_cache_kernel_block_id 不同。缺失拷贝会导致 cache store 在 CUDA Graph 路径下写入全零 block 地址。

P1-1: prefix_lengths 初始化值符号变更

// 原始: max_seq_len_ - num_tokens_per_bs_
// 新代码: max_seq_len_ + num_tokens_per_bs_

capture 时 prefix_lengths 表示已有 KV cache 长度上限,加号会使值超过实际最大序列长度。请确认是否为笔误。

P1-5: assert 在 Release 下被移除

FusedD2DCopyParams::add()FusedStridedCopyParams::add() 使用 assert(num_copies < MAX) 检查越界。Release 构建中 assert 被编译移除,超过 16 个 copy 时会静默越界写入栈上数组。建议改为 RTP_LLM_CHECK_WITH_INFO 或添加 fallback。


完整报告见内源 .ci_analysis/pr_832/code_review/cr_2026-04-14.md

Generated by Claude Opus 4.6 automated review

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

Code Review v2: PR #832 — Optimize Kernel Launch

审查者: Claude Opus 4.6 (自动 Review) | 日期: 2026-04-15 | Head SHA: cf388328c99d

v1 问题修复跟踪 (7 项)

编号 描述 状态
P0-1 kv_cache_block_id_device/host 拷贝被删除 降级 P1,需确认(作者注释称 kernel 不使用)
P1-1 prefix_lengths 初始值符号翻转 (- -> +) 已修复
P1-2 prefill 模式下 kv_cache_kernel_block_id_device 未拷贝 已修复
P1-3 prepare_cuda_graph 调用时序变更 可接受(统一末尾调用)
P1-4 fuse_copy_util.h 缺少文件末尾换行符 已修复
P1-5 assert-only bounds check 已修复(改为 throw std::runtime_error
P1-6 缺少测试覆盖 未修复

新发现

P1-NEW-1: capturePrefillkv_host 未使用 pinned memory,与其他 tensor 风格不一致,未来改 non_blocking=true 时会产生 race condition。

  • 文件: rtp_llm/cpp/cuda_graph/cuda_graph_prefill.cc (约 line 106-112)

P1-NEW-2: tryAddStridedD2DCopy 静默跳过 1D tensor(src.dim() < 2 直接 return),kv_cache_kernel_block_id_device 在单 block 场景下可能是 1D,导致 block ID 全为 0。

  • 文件: rtp_llm/cpp/cuda_graph/cuda_graph_runner.cc (prepareInputs 内 lambda)

P2-NEW-1: initCapture 中对 CUDA device tensor 使用 operator[] 赋值,触发隐式同步 round-trip。

  • 文件: rtp_llm/cpp/cuda_graph/cuda_graph_runner.cc (initCapture, 约 line 579-582)

P2-NEW-2: copyParamsAssert 在头文件中定义为 static,应改为 inline 避免代码膨胀。

  • 文件: rtp_llm/models_py/bindings/common/kernels/fuse_copy_util.h

当前阻塞项

  1. 需作者确认 kv_cache_block_id 在 CUDA Graph 路径下确实不需要拷贝
  2. tryAddStridedD2DCopy 静默跳过 1D tensor 可能导致 block ID 丢失
  3. 缺少测试覆盖(fused copy kernel + CUDA Graph prepareInputs 回归测试)

CI 当前 build pending。

详细报告: cr_2026-04-15.md

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

Code Review v3 — Optimize Kernel Launch (PR #832)

审查者: Claude Opus 4.6 (自动 Review v3) | SHA: fa7b6f4d439a | 日期: 2026-04-15

增量说明

v3 再次 force-push(squash),代码量从 v2 的 +456/-174 增长到 +554/-176。主要新增为 input_lengths_dprefix_lengths_d 两个 device tensor 字段的管理逻辑,与已有的 host/device 拆分模式一致,逻辑正确。

v2 遗留问题跟踪

编号 描述 v3 状态
P1(原P0-1) kv_cache_block_id 拷贝删除,需确认 cache store 路径 未修复,待确认
P1-6 缺少测试覆盖 未修复
P1-NEW-1 kv_host 未使用 pinned memory 降级 P2(风格问题)
P1-NEW-2 tryAddStridedD2DCopy 静默跳过 1D tensor 未修复
P2-NEW-1 initCapture device tensor 下标赋值 未修复,v3 新增 input_lengths_d[0]
P2-NEW-2 copyParamsAssert 应为 inlinestatic 未修复

v3 新发现

  • P2-NEW-3: input_lengths_d / prefix_lengths_d 在 C++ 侧广泛使用,但未在 OpDefs.h 中声明或 OpDefs.cc 中注册 pybind。如果是新增字段需补充声明。

总结

级别 数量
P0 0
P1 3
P2 4

阻塞项:

  1. P1(原P0-1): 需作者确认 kv_cache_block_id 在 CUDA Graph 路径下确实不需要拷贝
  2. P1-NEW-2: tryAddStridedD2DCopy / stridedCopyHost 静默跳过 1D tensor 可能导致 block ID 丢失
  3. P1-6: 缺少测试覆盖(fused copy kernel + CUDA Graph prepareInputs 回归测试)

CI 当前 build pending。

完整报告: .ci_analysis/pr_832/code_review/cr_2026-04-15_v3.md
🤖 Auto Review v3 by Claude Opus 4.6

@wht21
Copy link
Copy Markdown
Collaborator

wht21 commented Apr 16, 2026

internal source has been updated, please review the changes!

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 26(GitHub) files, +569/-179
Head SHA: 2ccb65ea42059f82132f89e7df5b62b9e5a11252
Review 版本: v4(检测到 force push/rebase,本次为 PR 全量 review)

核心目标

通过引入 fused D2D copy kernel,将 CUDA Graph prepareInputs 中的多次独立 memcpy/kernel launch 合并为两次 fused kernel launch(contiguous + strided),减少 kernel launch 开销。同时将 PyWrappedModel::tensorHoldHostAndToCuda 中的逐个 H2D 拷贝也合并为单次 fused copy。此外,将多个 host tensor 统一改为 pinned memory 以支持异步传输。


v3 遗留问题跟踪

编号 描述 v3 级别 v4 状态
原 P0-1 kv_cache_block_id 拷贝删除 P1 ✅ 降级 P2,作者添加了充分的架构注释说明 cache store 在 CUDA Graph 外读取原始 inputs
P1-6 缺少测试覆盖 P1 ❌ 未修复
P1-NEW-2 tryAddStridedD2DCopy 静默跳过 1D tensor P1 ✅ 已修复,1D tensor fallback 到 contiguous copy
P2(原P1-NEW-1) capturePrefill kv_host 非 pinned P2 ✅ 已修复,不再使用独立 kv_host
P2-NEW-1 initCapture device tensor 下标赋值 P2 ❌ 未修复,保持 P2
P2-NEW-2 copyParamsAssert static → inline P2 ❌ 未修复,保持 P2
P2-NEW-3 input_lengths_d/prefix_lengths_d pybind P2 ✅ 非问题,字段已在 base 代码中声明

Review 意见

问题

  1. 缺少测试覆盖 [P1]

    fused copy kernel(fusedCopyKernelfusedStridedCopyKernel)是新增的 CUDA kernel,没有任何单元测试。prepareInputscopySmallerIntoLarger + 逐个 optimizedCopyAsync 重构为 fused copy 路径,行为等价性也没有测试验证。

    建议至少添加:

    • fused copy kernel 的基础正确性测试(对齐/非对齐、不同 size、边界值)
    • 1D tensor fallback 路径测试
    • MAX_FUSED_D2D_COPIES 边界测试(恰好 16 个、超过 16 个)

小问题

P2:

  1. kv_cache_block_id 拷贝删除:架构说明已充分,建议在 prepareWriteCacheParams 添加注释确认读取原始 inputs。
  2. initCapture device tensor 下标赋值(x3):可合并为一次 fused copy 或 H2D memcpy,但仅初始化时执行,非阻塞。
  3. copyParamsAssert 应为 inlinefuse_copy_util.h):static 函数在头文件中会在每个翻译单元生成独立副本,改为 inline 更合适。

P3:

  1. PR title typo: "kerenel" → "kernel"

整体评价

v4 相比 v3 修复了两个关键问题(1D tensor 静默跳过、capturePrefill kv_host 非 pinned),代码质量明显提升。fused copy 架构设计合理,D2D 收集 → 单次 flush 的模式清晰。tryAddStridedD2DCopy 的 1D fallback 修复消除了之前最严重的正确性风险。

当前唯一的 P1 是缺少测试覆盖。建议补充 fused copy kernel 的基础测试后合入。

存在重要问题(P1 x1: 缺少测试),不建议合入

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832 (增量 review v5, 1 个新 commit)

PR 概述

Title: Optimize kernel launch
Author: Vinkle-hzt (隐智)
新 head SHA: 465f334f4e08
增量: 27 files, +488/-183

新 commit: refactor: implement fused copy operations

将 fused copy 逻辑从 cuda_graph_runner.cc 解耦为独立 FusedCopyOp,新增 fuse_copy_kernel.cu/hfuse_copy_util.h


v4 问题修复状态

v4 问题 状态 说明
P1: 缺少 fused copy kernel 测试 ❌ 未修复 新增 4 个文件仍无测试

Review 意见

  1. 仍缺少 fused copy kernel 测试 [P1]

    v5 新增 4 个文件实现 fused copy,但仍无单元测试。fused copy 是 CUDA Graph 路径关键组件。建议补充基本 copy 正确性、strided copy、边界 case 测试。

整体评价

架构重构方向正确,fused copy 解耦为独立 op 后代码组织更清晰。唯一 P1(缺少测试)从 v4 延续至今。

P0x0, P1x1 — 建议补充测试后合入

@wht21
Copy link
Copy Markdown
Collaborator

wht21 commented Apr 16, 2026

internal source has been updated, please review the changes!

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832 (v5)

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 27(GitHub) files, +577/-185
Review 版本: v5(检测到 force push/rebase,本次为 PR 全量 review)

核心目标

通过引入 fused D2D copy kernel,将 CUDA Graph prepareInputs 中的多次独立 memcpy/kernel launch 合并为两次 fused kernel launch(contiguous + strided),减少 kernel launch 开销。同时将 PyWrappedModel::tensorHoldHostAndToCuda 中的逐个 H2D 拷贝也合并为单次 fused copy。此外,将多个 host tensor 统一改为 pinned memory 以支持异步传输。

v4 → v5 变更摘要

本次 force push 与 v4 差异极小(+8/-6 行,新增 1 个文件):

  • 新增 rtp_llm/models_py/bindings/cuda/BUILD 变更:添加 profiling_scope 依赖
  • 其余文件微调(对齐、格式)

v4 遗留的所有问题均未修复。


v4 遗留问题跟踪

P1-6: 缺少测试覆盖 → 仍未修复,保持 P1

v5 diff 仍未包含任何新增测试文件。fused copy kernel 正确性(fusedCopyKernelfusedStridedCopyKernel)、1D fallback 路径、prepareInputs 行为等价性仍缺乏测试验证。

连续 5 轮 review 均指出此问题。

P2(原 P0-1): kv_cache_block_id 拷贝删除 → 保持 P2,接受

架构说明已充分。建议在 prepareWriteCacheParams 中添加注释确认读取原始 inputs。

P2-NEW-1: initCapture 中 device tensor 下标赋值 → 未修复,保持 P2

仅初始化时执行一次,性能影响可忽略。

P2-NEW-2: copyParamsAssertstatic 函数在头文件中 → 未修复,保持 P2

应改为 inline

P3-1: PR title typo → 未修复,保持 P3

"Optimize kerenel launch" → "Optimize kernel launch"


Review 意见

问题

  1. 缺少测试覆盖 [P1] — 连续 5 轮未修复

    fused copy kernel(fusedCopyKernelfusedStridedCopyKernel)是新增的 CUDA kernel,没有任何单元测试。prepareInputscopySmallerIntoLarger + 逐个 optimizedCopyAsync 重构为 fused copy 路径,行为等价性也没有测试验证。

    建议至少添加:

    • fused copy kernel 的基础正确性测试(对齐/非对齐、不同 size、边界值)
    • 1D tensor fallback 路径测试
    • MAX_FUSED_D2D_COPIES 边界测试(恰好 16 个、超过 16 个)

小问题

P2:

  1. kv_cache_block_id 拷贝删除:架构说明已充分,建议在 prepareWriteCacheParams 添加注释确认读取原始 inputs。
  2. initCapture device tensor 下标赋值(x3):可合并为一次 fused copy 或 H2D memcpy,但仅初始化时执行,非阻塞。
  3. copyParamsAssert 应为 inlinestatic 函数在头文件中会在每个翻译单元生成独立副本,改为 inline 更合适。

P3:

  1. PR title typo: "kerenel" → "kernel"

整体评价

v5 与 v4 几乎无实质差异(+8/-6 行,新增 1 个 BUILD 依赖)。代码架构和实现质量在 v4 已经达到较好水平:fused copy 设计合理,D2D 收集 → 单次 flush 模式清晰,1D fallback 正确处理,pinned memory 统一到位。

唯一的 P1 仍然是缺少测试覆盖,已连续 5 轮 review 指出。如果 CI smoke/功能测试已覆盖 CUDA Graph 路径的端到端正确性,可考虑将此 P1 降级为 P2 并在后续 PR 补充单元测试。但从工程规范角度,新增 CUDA kernel 应有对应测试。

存在重要问题(P1 x1: 缺少测试),不建议合入

@Vinkle-hzt
Copy link
Copy Markdown
Collaborator Author

Re: P1-6 缺少测试覆盖

Fused copy 路径已被现有 smoke 测试充分覆盖,无需新增专门的回归测试。具体来说:

所有 CUDA Graph 路径的 smoke 测试都会走 fused copy:prepareInputs 中的 fusedCopy / fusedStridedCopy 是 CUDA Graph replay 的唯一 D2D copy 路径(替换了原来的 optimizedCopyAsync + copySmallerIntoLarger),不存在 fallback 到旧路径的情况。因此任何走 CUDA Graph 的 smoke case(decode / embedding prefill / speculative scoring)都在测试 fused copy kernel。

tensorHoldHostAndToCuda 中的 fused copy 同理:PyWrappedModel::forward 和 forwardMicroBatched 每次 forward 都会调用 fusedCopy(d2d_copies_),所有非 CUDA Graph 的 forward smoke 测试也覆盖了这条路径。

回归风险已由 CI smoke 兜底:如果 fused copy kernel 有 correctness 问题,模型输出会直接 diff,smoke golden 比对会立即捕获。

综上,现有 smoke 测试集已构成对 fused copy kernel 和 CUDA Graph prepareInputs 的端到端回归覆盖,新增 unit test 的增量收益有限。

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832 (增量 review v6, force push)

v5 问题修复状态

v5 问题 状态 说明
P1: 缺少 fused copy kernel 测试 ❌ 未修复(第 6 轮) 仅修改已有测试 1 行,未新增 fused copy 测试

增量极小(+1/-1 在 cuda_graph_decode_padding.py),无新问题。

P0x0, P1x1 — 建议补充测试后合入

@wht21
Copy link
Copy Markdown
Collaborator

wht21 commented Apr 16, 2026

internal source has been updated, please review the changes!

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832 (v6, full review after force push)

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 28(GitHub) files, +578/-186
Review 类型: 增量 review v6(检测到 force push/rebase,本次为 PR 全量 review)

核心目标

将 CUDA graph prepareInputs 和 PyWrappedModel forward 中的多次独立 D2D memcpy 合并为单次 fused kernel launch,减少 kernel launch 开销。同时将多个 host tensor 改为 pinned memory 以支持异步 H2D 传输,并为 cu_seqlens 等字段引入 host/device 双副本架构。


改动逻辑拆解

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

1. 新增 Fused Copy Kernel 基础设施

  • fuse_copy_util.h: 定义 FusedD2DCopyParamsFusedStridedCopyParams 结构体,固定数组上限 16
  • fuse_copy_kernel.cu: 实现 fusedCopyKernel(支持 int4 向量化快速路径 + byte fallback)和 fusedStridedCopyKernel(2D strided copy)
  • FusedCopyOp.cc: 封装 CUDA/ROCm stream 获取,注册为 ExecOps 接口

2. CudaGraphRunner::prepareInputs 重构

  • 删除 copySmallerIntoLarger() 方法,替换为 lambda 收集 + 一次性 fused kernel 发射
  • H2H copy 在 D2D 之后执行,让 GPU 尽早开始工作
  • 不再清零 kv_cache_block_id_{host,device}(注释说明这些字段不被 CUDA graph replay 中的 attention kernel 消费)

3. Host/Device 双副本架构

  • cu_seqlens 从 pinned CPU tensor 改为 CUDA device tensor,新增 cu_seqlens_host 作为 pinned CPU 镜像
  • input_lengths_dprefix_lengths_d 作为 device 侧副本

4. PyWrappedModel 批量 H2D

  • tensorHoldHostAndToCuda() 不再直接 .to(kCUDA),改为收集到 d2d_copies_,统一 fusedCopy() 发射
  • 新增 pinned_check_remaining_ 计数器,前 3 次 forward 检查 is_pinned()

5. Pinned Memory 全面推广

  • EmbeddingExecutorMtpBatchStreamProcessorMtpExecutorCudaFlashInferOpDefsUtils 中多处 tensor 改用 pinned memory

6. CUDA Graph Copy Kernel 修复

  • grid size 从动态计算改为固定 dim3(1024),修复 CUDA graph replay 时 grid 参数过期问题

Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP
OCP
DRY ✅ 将重复 copy 逻辑统一为 fused kernel
KISS / YAGNI

架构审视

检查项 结果
抽象边界 ✅ fuse_copy_util.h 纯数据结构,kernel 和 op 分层清晰
状态完整性 ✅ d2d_copies_ 每次 forward 开头 clear()
可观测性 ✅ 新增多处 RTP_LLM_PROFILE_SCOPE

测试

检查项 结果
新功能有对应测试 ❌ 新增 fused copy kernel 无单元测试(P1-1)
边界 case 覆盖 ❌ 未覆盖 kernel 边界 case(P1-1)

领域检查

  • A. 兼容性与配置 — 全部 ✅
  • B. 正确性与逻辑 — 全部 ✅
  • C. 线程安全与并发 — 全部 ✅
  • D. 性能 — 全部 ✅(grid 固定化修复了 replay 参数过期)
  • E. 分布式 — N/A
  • F. 跨平台 — 全部 ✅(CUDA/ROCm 对称处理,uintptr_t 正确使用)
  • G-I — 全部 ✅

Review 意见

问题

  1. 缺少 fused copy kernel 单元测试 [P1] ⚠️ 连续 7 轮 review 未修复 (v1→v6)

    新增的 fusedCopyKernelfusedStridedCopyKernel 是核心新功能,包含非平凡逻辑(int4 向量化快速路径、remainder 处理、2D strided 寻址),但没有任何独立的单元测试。

    需要覆盖的 case:

    • 对齐 vs 非对齐指针(int4 快速路径 vs byte fallback)
    • size 为 0、不是 16 的倍数(remainder 路径)
    • strided copy: src_stride != dst_stride(copySmallerIntoLarger 语义)
    • strided copy: 1D tensor fallback 到 contiguous copy
    • num_copies = 0(early return)和 num_copies = MAX_FUSED_D2D_COPIES(边界)

    风险:kernel 中的 remainder 处理和 strided 寻址逻辑如果有 off-by-one 或对齐错误,会导致静默数据损坏,且只在特定 tensor shape 下触发,难以通过端到端测试发现。

小问题

  1. PR title typo [P3]: "Optimize kerenel launch" → "Optimize kernel launch"

整体评价

代码质量良好。将多次独立 memcpy 合为 fused kernel launch 是合理的性能优化方向,host/device 双副本架构设计清晰,pinned memory 推广全面。CUDA graph copy kernel 的 grid size 固定化修复了 replay 参数过期的潜在问题。

唯一阻塞项是 fused copy kernel 缺少单元测试,该问题已连续 7 轮 review 未修复。

P0x0, P1x1 — 建议补充 fused copy kernel 测试后合入

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 30(GitHub) files, +993/-186
Review 类型: 增量 review v7(1 个新 commit since 0bd789715456
上次 review SHA: 0bd7897154563bc03795b8f929c4640b6bb55307
当前 head SHA: 81e3ec3db1199f229587cc1144a90592288b60e5

核心目标

将 CUDA graph prepareInputs 和 PyWrappedModel forward 中的多次独立 D2D memcpy 合并为单次 fused kernel launch,减少 kernel launch 开销。同时将多个 host tensor 改为 pinned memory 以支持异步 H2D 传输,并为 cu_seqlens 等字段引入 host/device 双副本架构。


增量变更分析(v6 → v7)

本次增量仅 1 个新 commit:

Commit Message 变更
81e3ec3db119 test: add fused copy kernel tests +2 files (+415 lines)

新增文件

1. rtp_llm/models_py/bindings/common/kernels/test/BUILD

  • 新增 fuse_copy_kernel_test 测试 target
  • 正确使用 cc_test_wrapperany_cuda_coptsany_cuda_deps
  • 依赖 fuse_copy_kernel 库和 gtest
  • exec_properties = {"gpu": "H20"} 指定 GPU 执行环境

2. rtp_llm/models_py/bindings/common/kernels/test/fuse_copy_kernel_test.cc

388 行 C++ gtest,覆盖两大类 kernel:

FusedCopy(invokeFusedCopy)测试:

  • ZeroCopies: num_copies=0 no-op 安全性
  • SingleAlignedCopy: 1024 字节对齐拷贝(int4 向量化快速路径)
  • UnalignedDstCopy: dst 偏移 1 字节触发 byte-by-byte 慢路径
  • NonMultipleOf16Size: size=37 测试 remainder 循环
  • MultipleCopies: 4 个不同大小的批量拷贝
  • MaxFusedCopies: MAX_FUSED_D2D_COPIES 边界

FusedStridedCopy(invokeFusedStridedCopy)测试:

  • ZeroCopies: num_copies=0 no-op
  • SingleStridedCopy: src_stride > row_bytes(strided-to-compact)
  • CompactToStrided: dst_stride > row_bytes(compact-to-strided)
  • MultipleStridedCopies: 3 个不同规格的批量 strided 拷贝
  • SingleRowCopy: nrows=1 边界 case

v6 遗留问题追踪

问题 v6 级别 v7 状态 说明
缺少 fused copy kernel 单元测试 P1 ✅ 已修复 新增 388 行 gtest,覆盖对齐/非对齐/remainder/strided/边界 case
PR title typo "kerenel" P3 未修复 仍为 "Optimize kerenel launch"
kv_cache_block_id 不清零注释 P2 未修复 保持现状,注释已充分说明
initCapture 下标赋值风格 P2 未修复 非阻塞
copyParamsAssert 可改 static P2 未修复 非阻塞

Checklist 检查结果(增量部分)

通用原则

测试

检查项 结果
新功能有对应测试 ✅ fused copy kernel 测试已补齐
边界 case 覆盖 ✅ 覆盖 0 copies、max copies、非对齐、非 16 倍数、单行 strided

代码质量

检查项 结果
Commit 原子性 ✅ 单独 commit 只含测试代码
Commit message 准确性 ✅ "test: add fused copy kernel tests" 准确

领域检查

H. 测试与 CI

检查项 结果
测试覆盖充分 ✅ 覆盖 v6 指出的所有关键 case
Smoke 测试配置一致性 ✅ BUILD 配置规范

F. 跨平台(ROCm/ARM)

检查项 结果
CUDA/ROCm 两侧 binding 对称 ✅ 测试通过条件编译兼容两侧

其余领域检查项(A-E, G, I)与 v6 一致,无新变更,全部 ✅。


Review 意见

问题

无 P0 或 P1 问题。

小问题

  1. PR title typo [P3]: "Optimize kerenel launch" → "Optimize kernel launch"(从 v3 起已指出,非阻塞)

  2. kv_cache_block_id 不清零 [P2]: 保持现状,注释已充分说明不被 attention kernel 消费(从 v4 起降级为 P2)

  3. initCapture 下标赋值风格 [P2]: 保持现状(从 v4 起)

  4. copyParamsAssert 可改 static [P2]: 保持现状(从 v4 起)

测试质量评估

新增测试质量良好:

  • 使用 RAII 风格的 gtest fixture 管理 CUDA stream 生命周期
  • 辅助函数 deviceAlloc/deviceAllocZero/deviceToHost 封装清晰
  • 每个 test case 有明确的验证逻辑(逐字节比对)
  • 覆盖了 v6 review 中列出的所有关键 case(对齐 vs 非对齐、remainder、strided、边界值)
  • ROCm 兼容性通过条件编译处理

整体评价

v7 新增的 fused copy kernel 测试完整解决了从 v1 到 v6 连续 6 轮 review 指出的唯一 P1 问题。测试覆盖全面,代码质量良好。剩余 P2/P3 均为非阻塞建议项。

P0x0, P1x0, P2x3, P3x1 — ✅ LGTM ready to ci

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832 (增量 review v7, 4 个新 commit)

v6 问题修复状态

v6 问题 状态 说明
P1: 缺少 fused copy kernel 测试 ✅ 已修复 fuse_copy_kernel_test.cc +388 行

经过 7 轮 review,P1(缺少测试)终于修复。fused copy kernel 测试覆盖充分。

P2: 混入 3 个无关 commit(decode perf dataset mode、trace name control),建议分离。

LGTM ready to ci(P0x0, P1x0, P2x1)

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt (隐智)
规模: 31(GitHub) files, +1000/-191
Review 类型: 增量 review(1 个新 commit: 85e37faachore: use pin mem for cp input

核心目标

通过三项优化减少 CUDA graph 路径和 forward 路径的 kernel launch 开销:

  1. 引入 fused copy kernel,将多个独立 D2D memcpy 合并为单次 kernel launch
  2. cu_seqlens 从 pinned CPU tensor 拆分为 device tensor + pinned host mirror,使 CUDA graph prepareInputs 中的拷贝全部走 D2D fused kernel
  3. 全面将 CPU 侧 int32 tensor 迁移到 pinned memory,加速 H2D 传输

改动逻辑拆解

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

1. Fused Copy Kernel(新增)

  • fuse_copy_util.h: 定义 FusedD2DCopyParams(最多 16 路 contiguous D2D)和 FusedStridedCopyParams(最多 16 路 strided D2D)
  • fuse_copy_kernel.cu: 实现 fusedCopyKernel(16-byte vectorized fast path + byte fallback)和 fusedStridedCopyKernel(row-major strided copy)
  • fuse_copy_kernel.h: CUDA/ROCm 双平台声明
  • FusedCopyOp.cc: 获取当前 stream 并调用 kernel 的 wrapper
  • ExecOps.h: 注册 fusedCopy() / fusedStridedCopy() 全局接口

2. CUDA Graph prepareInputs 重构(cuda_graph_runner.cc)

  • 删除 copySmallerIntoLarger() 方法,替换为 tryAddStridedD2DCopy lambda 收集 strided copy 参数
  • 将所有 D2D copy 收集到 FusedD2DCopyParams / FusedStridedCopyParams,最后通过 fusedCopy() / fusedStridedCopy() 两次 kernel launch 完成
  • H2H copy 放在 D2D 之后执行,让 GPU 尽早开始工作
  • 移除 kv_cache_block_id_{device,host} 的 fill(0) 和 copy(注释说明这些仅用于 cache store,不参与 CUDA graph replay 中的 attention kernel)
  • prepare_cuda_graph 调用统一到函数末尾

3. cu_seqlens 拆分为 host + device

  • OpDefs.h: 新增 cu_seqlens_host 字段(pinned CPU mirror)
  • cuda_graph_runner.cc: initKernelInternalMemory 中 cu_seqlens 创建为 pinned + .cuda() 分离
  • cuda_graph_prefill.cc: 先写 cu_seqlens_host.copy_() 到 device
  • cuda_graph_utils.h/cc: CaptureMemoryHold 传播新字段

4. PyWrappedModel fused H2D copy

  • tensorHoldHostAndToCuda() 不再用 .to(kCUDA, non_blocking=true),改为创建空 CUDA tensor + 收集到 d2d_copies_,在 forward() / forwardMicroBatched() 中统一 fusedCopy(d2d_copies_) 一次性发射
  • 新增 pinned_check_remaining_ 计数器,前 3 次 forward 检查 is_pinned() 做 sanity check

5. Pinned Memory 迁移

  • EmbeddingExecutor.cc: model_input 的 combo_tokens/input_lengths 等改用 pinned memory
  • MtpExecutor.cc / MtpBatchStreamProcessor.cc: spec_prefix_lengths、lm_output_indexes 等改用 pinned memory
  • CudaFlashInfer.cc: host workspace 和 CPU buffer 改用 pinned memory
  • OpDefsUtils.h: padding_offset_host 改用 pinned memory
  • PyWrappedModel.cc: cu_seqlens、kv_cache_block_id clone 后 pin_memory

6. CUDA Graph Copy Kernel 修复(cuda_graph_copy_kernel.cu)

  • invokeCudaGraphCopySmall2Large / invokeCudaGraphCopyLarge2Small: grid size 从动态计算改为固定 1024,兼容 CUDA graph capture

7. 新增 commit(增量部分): ContextParallelProcessorBase.cc

  • CP 输入 tensor 全部改用 pinned memory

8. 测试

  • fuse_copy_kernel_test.cc: 388 行 gtest,覆盖 zero copies、aligned/unaligned、remainder、multiple copies、max capacity、strided copy 各种 case

Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ 每个模块职责清晰
OCP ✅ 通过 add() 接口扩展
LSP ✅ 不涉及继承变更
ISP ✅ 接口精简
DIP ✅ ExecOps.h 提供抽象接口
DRY ✅ copySmallerIntoLarger 被统一替代
KISS ✅ fused copy 设计简洁
YAGNI

架构审视

检查项 结果
抽象边界
依赖方向
状态完整性 ✅ d2d_copies_ 每次 forward 开头 clear()
错误语义
可观测性 ✅ 新增 PROFILE_SCOPE
可演进性
可运维性

测试

检查项 结果
新功能有对应测试 ✅ 388 行 kernel 测试
边界 case 覆盖

代码质量与文档

检查项 结果
Commit 原子性
PR description ❌ 为空

领域检查

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

B. 正确性与逻辑 — 全部 ✅

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

D. 性能 — 全部 ✅

E. 分布式 — 全部 ✅

F. 跨平台(ROCm/ARM) 全部 ✅

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

H. 测试与 CI — 全部 ✅

I. 代码质量 — 全部 ✅


Review 意见

问题

  1. fusedStridedCopyKernel 使用 64-bit 整数除法计算 row/col [P2]
    fuse_copy_kernel.cu:

    const size_t row = idx / rbytes;
    const size_t col = idx % rbytes;

    GPU 上 size_t 整数除法开销较大。当前数据量小影响有限,但未来若用于更大数据建议用 2D grid indexing 或位运算替代。

  2. tensorHoldHostAndToCuda 中 per-forward torch::empty CUDA 分配 [P2]
    PyWrappedModel.cc:

    auto cuda_tensor = torch::empty(tensor.sizes(), ...device(torch::kCUDA));

    每次 forward 多次调用。PyTorch caching allocator 会复用内存,但 allocator lock contention 在高并发下仍有开销。长期可考虑预分配复用。

  3. kv_cache_block_id_{device,host} 不再 fill(0) 和 copy 的安全性 [P2]
    移除了对 kv_cache_block_id_devicekv_cache_block_id_host 的 fill(0) 和 copy。注释说明仅用于 cache store 且在 CUDA graph 外读取原始 inputs。建议在注释中补充"如果新增消费者需要在 CUDA graph 内使用这些字段,必须恢复 fill+copy"的警告。

  4. PR description 为空 [P3]
    建议补充动机、设计思路和性能数据。

小问题

  • PR title typo: "kerenel" → "kernel"
  • fuse_copy_util.hcopyParamsAssert 可用项目已有的 RTP_LLM_CHECK_WITH_INFO 替代,保持风格统一

整体评价

高质量的性能优化 PR,通过 fused copy kernel 和 pinned memory 迁移系统性地减少了 CUDA graph 路径和 forward 路径的 kernel launch 开销。代码结构清晰,测试覆盖充分,CUDA/ROCm 双平台兼容。增量 commit(CP pinned memory)是对同一优化方向的自然延伸。

LGTM ready to ci

@wht21
Copy link
Copy Markdown
Collaborator

wht21 commented Apr 20, 2026

internal source has been updated, please review the changes!

Copy link
Copy Markdown
Collaborator

@LLLLKKKK LLLLKKKK left a comment

Choose a reason for hiding this comment

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

Code Review — PR #832

Optimize kernel launch — LGTM, 高质量性能优化

LGTM ready to ci (P1: 0, P2: 0, P3: 2)

详细 review 见 GitHub comment history。

🤖 Review by Claude Code

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 31(GitHub) files, +1000/-191

核心目标

将 CUDA graph 和 PyWrappedModel forward 路径中大量零散的 D2D/H2D memcpy 合并为单次 fused kernel launch,减少 kernel launch 开销;同时将关键 CPU tensor 统一迁移到 pinned memory,加速 H2D 传输。


改动逻辑拆解

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

1. 新增 Fused Copy Kernel(核心新增)

  • fuse_copy_util.h:定义 FusedD2DCopyParams(最多 16 路 contiguous D2D)和 FusedStridedCopyParams(最多 16 路 strided D2D)数据结构,通过 add() 收集拷贝任务
  • fuse_copy_kernel.cu:实现两个 GPU kernel——fusedCopyKernel(支持 int4 向量化快速路径 + byte fallback 慢路径)和 fusedStridedCopyKernel(按行 stride 拷贝)
  • fuse_copy_kernel.h / FusedCopyOp.cc:封装 invokeFusedCopy / invokeFusedStridedCopy,获取当前 CUDA stream 并 launch kernel
  • ExecOps.h:声明 fusedCopy() / fusedStridedCopy() 供上层调用

2. CUDA Graph Runner 重构(cuda_graph_runner.cc

  • 删除 copySmallerIntoLarger() 方法,替换为 lambda tryAddStridedD2DCopy / tryAddD2DCopy / stridedCopyHost
  • prepareInputs() 中将所有 D2D 拷贝收集到 FusedD2DCopyParamsFusedStridedCopyParams,最后通过 fusedCopy() / fusedStridedCopy() 两次 kernel launch 完成
  • H2H 拷贝放在 D2D 之后执行,让 GPU 尽早开始工作
  • 新增 cu_seqlens_host 字段(pinned CPU mirror),cu_seqlens 改为 CUDA device tensor
  • 不再拷贝 kv_cache_block_id_{host,device}(注释说明仅用于 cache store,不参与 CUDA graph replay 中的 attention kernel)

3. PyWrappedModel H2D Fused Copy

  • tensorHoldHostAndToCuda() 不再调用 tensor.to(kCUDA, non_blocking),改为手动创建 CUDA tensor + 收集到 d2d_copies_,在 forward() / forwardMicroBatched() 中统一 fusedCopy(d2d_copies_) 一次 launch
  • 新增 pinned_check_remaining_ 计数器,前 3 次 forward 检查 tensor 是否 pinned

4. Pinned Memory 统一迁移

  • buildPyAttentionInputsEmbeddingExecutorContextParallelProcessorBaseMtpBatchStreamProcessorMtpExecutorFlashInferAttnParams 中的 CPU tensor 统一改用 pinned memory

5. CUDA Graph Copy Kernel Grid 修复

  • cuda_graph_copy_kernel.cu:grid 从动态计算改为固定 grid(1024),避免 CUDA graph capture 时读取 device 指针导致的问题

6. 测试

  • 新增 fuse_copy_kernel_test.cc:覆盖 FusedCopy 和 FusedStridedCopy 的多种场景

7. Bug Fix

  • copy_utils.h:修复 USEING_CUDAUSING_CUDA 拼写错误

Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP
OCP
LSP
ISP
DIP
DRY
KISS
YAGNI

架构审视

检查项 结果
抽象边界
依赖方向
状态完整性
错误语义 copyParamsAssert 使用 throw 而非项目统一宏
可观测性
可演进性
可运维性

测试

检查项 结果
新功能有对应测试
删除的测试有等价替代
边界 case 覆盖
分布式改动有多卡测试 ✅ 不涉及

代码质量与文档

检查项 结果
无关改动分离
mega-PR 拆分
Commit 原子性
Commit message 准确性
PR description ❌ 过于简略
日志频率控制

领域检查

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

B. 正确性与逻辑 — ❌ 见 P2-2

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

D. 性能 — ❌ 见 P2-1

E. 分布式 — 全部 ✅

F. 跨平台(ROCm/ARM) — 全部 ✅

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

H. 测试与 CI — 全部 ✅

I. 代码质量 — ❌ 见 P3-2


Review 意见

问题

  1. tensorHoldHostAndToCuda 语义变更:per-forward GPU 分配未消除 [P2]

    重构后的 tensorHoldHostAndToCuda 对每个 tensor 调用 torch::empty(..., kCUDA) 创建新的 device tensor,然后将 H2D copy 收集到 d2d_copies_。虽然 launch 开销通过 fused kernel 减少了,但 per-forward 的 torch::empty CUDA 分配仍然存在(PyTorch caching allocator 有锁开销)。

    对于 CUDA graph 路径这不是问题(graph 路径有预分配),但对于非 graph 的 forward() / forwardMicroBatched() 路径,每次 forward 仍有多次 CUDA malloc。

    建议:当前实现已经比原来的 tensor.to(kCUDA, non_blocking) 更好(因为 to() 内部也会分配),可作为后续优化项——考虑预分配 device buffer pool 复用。

  2. 删除 copySmallerIntoLarger 丢失维度校验 [P2]

    copySmallerIntoLarger 包含完整的维度检查(dim 匹配、每维 size 不超过 target),新的 tryAddStridedD2DCopy lambda 仅检查 src.defined() && src.numel() > 0,不验证 src/dst 维度兼容性。如果上游传入维度不匹配的 tensor,会静默写越界。

    建议:在 tryAddStridedD2DCopy 中添加 debug-mode assert 验证 src.dim() == dst.dim()src.size(i) <= dst.size(i),至少在 debug build 中捕获错误。

  3. copyParamsAssert 使用 throw 而非项目统一的错误处理宏 [P2]

    fuse_copy_util.h 中的 copyParamsAssert 使用 throw std::runtime_error,而项目其他地方统一使用 RTP_LLM_CHECK_WITH_INFO。由于 fuse_copy_util.h 被 CUDA kernel 代码 include,可能无法直接使用项目宏。

    建议:如果宏在 host-only 代码中可用,建议在 FusedCopyOp.cc(host 侧)的 add() 调用前做校验;当前 throw 在 header-only 场景下是合理的 fallback。

  4. kv_cache_block_id_{host,device} 不再清零和拷贝的正确性假设 [P2]

    prepareInputs 中删除了对 kv_cache_block_id_devicekv_cache_block_id_hostfill_(0)copySmallerIntoLarger 调用。注释说明这些字段仅用于 cache store(在 CUDA graph 外执行),不被 attention kernel 消费。

    这是一个正确性关键假设。如果未来有 kernel 开始读取这些字段,会导致使用 stale 数据。

    建议:在 OpDefs.hkv_cache_block_id_device / kv_cache_block_id_host 字段注释中明确标注 "NOT used during CUDA graph replay",防止后续开发者误用。

小问题

  1. PR description 过于简略 [P3] — PR body 仅 "fuse d2d & d2d stride copy",缺少性能对比数据和设计说明。建议补充 benchmark 数据。

  2. Pinned memory 分配方式不统一 [P3] — 部分用 .pinned_memory(true) option,部分用 .pin_memory() 后缀。建议统一风格。

  3. initKernelInternalMemory 中两种 pinned memory 写法混用 [P3] — 同一函数内应保持一致。

整体评价

高质量的性能优化 PR,核心思路清晰:将分散的 memcpy 合并为 fused kernel launch 以减少 GPU launch 开销,同时统一使用 pinned memory 加速 H2D 传输。Fused copy kernel 实现简洁高效(int4 向量化 + byte fallback),测试覆盖全面。CUDA graph copy kernel 的固定 grid 修复也解决了 capture 时读取 device 指针的潜在问题。

P0: 0, P1: 0, P2: 4, P3: 3

LGTM ready to ci — 当前 review 未发现阻塞级或重要级问题,可进入 CI 验证和合入流程;P2/P3 建议后续改进但不阻塞。

🤖 Review by Claude Code

Copy link
Copy Markdown
Collaborator

@LLLLKKKK LLLLKKKK left a comment

Choose a reason for hiding this comment

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

Code Review (增量) — PR #832

Optimize kernel launch — LGTM (增量无新问题)

LGTM ready to ci (P1: 0, P2: 4, P3: 3)

🤖 Review by Claude Code

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kerenel launch
Author: Vinkle-hzt
规模: 31(GitHub) files, +1002/-191
Review 类型: 检测到 force push/rebase(上次 reviewed SHA 不在当前 commit 列表中),本次为 PR 全量 review。

核心目标

将 CUDA graph 和 PyWrappedModel forward 路径中大量零散的 D2D/H2D memcpy 合并为单次 fused kernel launch,减少 kernel launch 开销;同时将关键 CPU tensor 统一迁移到 pinned memory,加速 H2D 传输。

Rebase 分析

当前 3 个 commit 的 committer date 均为 2026-04-21,与上次 review 时的代码内容实质相同,仅做了 rebase。无新增功能代码变更。


改动逻辑拆解

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

1. 新增 Fused Copy Kernel(核心新增)

  • fuse_copy_util.h:定义 FusedD2DCopyParams(最多 16 路 contiguous D2D)和 FusedStridedCopyParams(最多 16 路 strided D2D)数据结构,通过 add() 收集拷贝任务
  • fuse_copy_kernel.cu:实现两个 GPU kernel——fusedCopyKernel(支持 int4 向量化快速路径 + byte fallback 慢路径)和 fusedStridedCopyKernel(按行 stride 拷贝)
  • fuse_copy_kernel.h / FusedCopyOp.cc:封装 invokeFusedCopy / invokeFusedStridedCopy,获取当前 CUDA stream 并 launch kernel
  • ExecOps.h:声明 fusedCopy() / fusedStridedCopy() 供上层调用

2. CUDA Graph Runner 重构(cuda_graph_runner.cc

  • 删除 copySmallerIntoLarger() 方法,替换为 lambda tryAddStridedD2DCopy / tryAddD2DCopy / stridedCopyHost
  • prepareInputs() 中将所有 D2D 拷贝收集到 FusedD2DCopyParamsFusedStridedCopyParams,最后通过 fusedCopy() / fusedStridedCopy() 两次 kernel launch 完成
  • H2H 拷贝放在 D2D 之后执行,让 GPU 尽早开始工作
  • 新增 cu_seqlens_host 字段(pinned CPU mirror),cu_seqlens 改为 CUDA device tensor
  • 不再拷贝 kv_cache_block_id_{host,device}(注释说明仅用于 cache store,不参与 CUDA graph replay)

3. PyWrappedModel H2D Fused Copy

  • tensorHoldHostAndToCuda() 改为手动创建 CUDA tensor + 收集到 d2d_copies_,在 forward() / forwardMicroBatched() 中统一 fusedCopy(d2d_copies_) 一次 launch
  • 新增 pinned_check_remaining_ 计数器,前 3 次 forward 检查 tensor 是否 pinned

4. Pinned Memory 统一迁移

  • buildPyAttentionInputsEmbeddingExecutorContextParallelProcessorBaseMtpBatchStreamProcessorMtpExecutorFlashInferAttnParams 中的 CPU tensor 改用 pinned memory

5. CUDA Graph Copy Kernel Grid 修复

  • cuda_graph_copy_kernel.cu:grid 从动态计算改为固定 grid(1024),避免 CUDA graph capture 时读取 device 指针

6. OpDefs 扩展

  • PyAttentionInputs 新增 cu_seqlens_host 字段 + pybind 注册

7. 测试

  • 新增 fuse_copy_kernel_test.cc:覆盖 FusedCopy 和 FusedStridedCopy 多种场景

8. Bug Fix

  • copy_utils.h:修复 USEING_CUDAUSING_CUDA 拼写错误

Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ 每个模块职责清晰
OCP ✅ 通过 add() 接口扩展
LSP ✅ 不涉及继承
ISP ✅ 接口精简
DIP ✅ 上层通过 ExecOps 抽象调用
DRY ✅ 分散调用统一为 fused 模式
KISS ✅ kernel 实现简洁
YAGNI ✅ MAX=16 足够当前场景

架构审视

检查项 结果
抽象边界
依赖方向
状态完整性 d2d_copies_ 每次 forward clear
错误语义 ❌ 见 P2-3
可观测性
可演进性
可运维性

测试

检查项 结果
新功能有对应测试
删除的测试有等价替代
边界 case 覆盖
分布式改动有多卡测试 ✅ 不涉及

代码质量与文档

检查项 结果
无关改动分离
mega-PR 拆分
Commit 原子性
Commit message 准确性
PR description ❌ 见 P3-1
日志频率控制

领域检查

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

B. 正确性与逻辑 — ❌ 见 P2-2

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

D. 性能 — ❌ 见 P2-1

E. 分布式 — 全部 ✅

F. 跨平台(ROCm/ARM) — 全部 ✅

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

H. 测试与 CI — 全部 ✅

I. 代码质量 — ❌ 见 P3-2


Review 意见

问题

  1. tensorHoldHostAndToCuda per-forward GPU 分配未消除 [P2]

    重构后的 tensorHoldHostAndToCuda 对每个 tensor 调用 torch::empty(..., kCUDA) 创建新的 device tensor。虽然 launch 开销通过 fused kernel 减少了,但 per-forward 的 torch::empty CUDA 分配仍然存在(PyTorch caching allocator 有锁开销)。

    建议:当前实现已经比原来的 tensor.to(kCUDA, non_blocking) 更好,可作为后续优化项——考虑预分配 device buffer pool 复用。

  2. 删除 copySmallerIntoLarger 丢失维度校验 [P2]

    copySmallerIntoLarger 包含完整的维度检查(dim 匹配、每维 size 不超过 target),新的 tryAddStridedD2DCopy lambda 仅检查 src.defined() && src.numel() > 0,不验证 src/dst 维度兼容性。如果上游传入维度不匹配的 tensor,会静默写越界。

    建议:在 tryAddStridedD2DCopy 中添加 debug-mode assert 验证 src.dim() == dst.dim()src.size(i) <= dst.size(i)

  3. copyParamsAssert 使用 throw 而非项目统一的错误处理宏 [P2]

    fuse_copy_util.h 中的 copyParamsAssert 使用 throw std::runtime_error,而项目其他地方统一使用 RTP_LLM_CHECK_WITH_INFO

    建议:如果宏在 host-only 代码中可用,建议在 FusedCopyOp.cc(host 侧)做校验;当前 throw 在 header-only 场景下是合理的 fallback。

  4. kv_cache_block_id_{host,device} 不再清零和拷贝的正确性假设 [P2]

    prepareInputs 中删除了对 kv_cache_block_id_devicekv_cache_block_id_hostfill_(0)copySmallerIntoLarger 调用。注释说明这些字段仅用于 cache store,不被 attention kernel 消费。

    建议:在 OpDefs.h 的字段注释中明确标注 "NOT used during CUDA graph replay; only for cache store outside graph"。

小问题

  1. PR description 过于简略 [P3] — 缺少性能对比数据和设计说明
  2. Pinned memory 分配方式不统一 [P3] — .pinned_memory(true) vs .pin_memory() 混用
  3. initKernelInternalMemory 中两种 pinned memory 写法混用 [P3]

整体评价

本次为 rebase 后的全量 re-review。代码内容与上次 review 实质相同,未引入新的功能变更。上次提出的 4 个 P2 建议(维度校验丢失、per-forward CUDA 分配、非标准错误处理、kv_cache_block_id 假设)和 3 个 P3 nit 均未修复,但这些均为非阻塞建议项。

P0: 0, P1: 0, P2: 4, P3: 3

LGTM ready to ci — 当前 review 未发现阻塞级或重要级问题,可进入 CI 验证和合入流程;P2/P3 建议后续改进但不阻塞。

🤖 Review by Claude Code

@Vinkle-hzt Vinkle-hzt enabled auto-merge (rebase) April 22, 2026 03:14
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 RTP-LLM PR #832 Code Review (Re-review)

Optimize kernel launch by @Vinkle-hzt (隐智)
Commit: 867fc1cf | Files: 31 | +1003 / -192

目标

优化 kernel launch 开销:新增 fused copy kernel 将多个小 D2D copy 合并为单次 kernel launch,并修复 cuda graph copy kernel 使用固定 grid size。

关键变更

  1. Fused Copy Kernel — 新增 fusedCopyKernelfusedStridedCopyKernel,支持最多 16 个 copy 任务合并为单次 launch,int4 向量化快速路径 + byte fallback
  2. Cuda Graph Copy 固定 gridinvokeCudaGraphCopySmall2Large/Large2Small 改为固定 grid(1024) 和 block(256),适配 cuda graph 捕获要求
  3. PyWrappedModel 重构 — 将多个独立 copy 操作替换为 fused copy 调用
  4. Typo 修复USEING_CUDAUSING_CUDA
  5. 测试 — 新增 388 行 fused copy kernel 测试,覆盖对齐/非对齐、strided copy、边界情况

✅ 优点

  • Fused copy 设计简洁,int4 向量化路径对齐检查正确
  • 固定 grid size 是 cuda graph 的正确做法
  • 测试覆盖全面

问题

🔵 P2 (1):

  1. MAX_FUSED_D2D_COPIES = 16 硬编码 — 如果未来模型层数增多导致 copy 任务超过 16,会 throw。建议在调用侧做分批处理,或在文档中明确限制。

结论

LGTM — 实现质量高,kernel launch 优化方向正确,测试充分。

Copy link
Copy Markdown
Collaborator

@LLLLKKKK LLLLKKKK left a comment

Choose a reason for hiding this comment

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

Code Review: Optimize kerenel launch

Summary

Optimizes kernel launch overhead by consolidating CUDA graph capture/replay logic, reducing redundant operations in the model forward path, and streamlining the prefill/decode dispatch. 31 files, ~1813 lines.

Findings

[P1] No test coverage for the CUDA graph runner refactoring (cuda_graph_runner.cc)
The core of this PR is a significant rewrite of cuda_graph_runner.cc (+194/-126 lines). CUDA graph capture/replay is correctness-critical — incorrect parameter updates during replay can cause silent data corruption. The existing test (cuda_graph_decode_padding.py) has only a minor change. Add tests that verify replay correctness with varying batch sizes.

[P2] Large refactoring scope across 31 files
The changes touch CUDA graph, model forward, embedding executor, context parallel, and multiple Python modules. While the changes are related, the scope makes it hard to bisect regressions. Consider splitting into: (a) CUDA graph runner refactoring, (b) model forward path optimization, (c) embedding executor changes.

[P3] Typo in PR title: "kerenel" → "kernel"

Overall

Performance optimization with reasonable approach. Main concern is test coverage for the CUDA graph runner rewrite.


🤖 Automated review by Claude Code

Copy link
Copy Markdown
Collaborator

@LLLLKKKK LLLLKKKK left a comment

Choose a reason for hiding this comment

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

Code Review Update: Optimize kernel launch

Additional Findings (deeper analysis)

[P1] kv_cache_block_id_device/host no longer cleared or copied in CUDA graph path (cuda_graph_runner.cc)
Old code filled these with 0 and copied from inputs. New code removes all of this, claiming they're "NOT consumed by any GPU attention kernel during CUDA graph replay." If any downstream code (cache store, debug logging) reads these from py_model_inputs_, it will see stale data. Verify cache store never reads from the graph instance's block IDs.

[P1] prepare_cuda_graph call reordered relative to padding-reset operations
Old decode path called prepare_cuda_graph before prefill-specific resets. New code calls it after. Verify prepare_cuda_graph is order-independent with respect to padding fill operations.

[P2] stridedCopyHost lambda has no dimension validation — old copySmallerIntoLarger had explicit checks. Add debug asserts for dst.size(0) >= src.size(0).

[P2] tryAddStridedD2DCopy only handles 2D tensors — higher dimensions silently lose data. Add RTP_LLM_CHECK(src.dim() <= 2).

[P2] Inconsistent pinned memory API — mix of .pin_memory() and .pinned_memory(true). Standardize on the latter (more efficient).

Positive Notes

Good test coverage: fuse_copy_kernel_test.cc (388 lines) covers aligned/unaligned, single/multiple copies, strided variants, and edge cases.


🤖 Automated review by Claude Code

@Vinkle-hzt Vinkle-hzt changed the title Optimize kerenel launch Optimize kernel launch Apr 23, 2026
@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kernel launch
Author: Vinkle-hzt (隐智)
规模: 31(GitHub) files, +1003/-191
Review 类型: 检测到 force push/rebase,本次为 PR 全量 review(第 8 轮)。
Head SHA: 22735d02bb84
CI 状态: 功能测试 SUCCESS(27/27 jobs passed)

核心目标

通过三项优化减少 CUDA graph 路径和 forward 路径的 kernel launch 开销:

  1. 引入 fused D2D copy kernel,将 prepareInputs 中多次独立 memcpy 合并为两次 fused kernel launch(contiguous + strided)
  2. PyWrappedModel::tensorHoldHostAndToCuda 中累积 H2D copy,跨 micro-batch 合并后一次性 flush
  3. 将关键 CPU tensor 统一迁移到 pinned memory,加速 H2D 传输;拆分 cu_seqlens 为 host(pinned)+ device 双份

改动逻辑拆解

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

1. Fused Copy Kernel(新增核心)

  • fuse_copy_util.h: 定义 FusedD2DCopyParams / FusedStridedCopyParams POD 结构体,MAX_FUSED_*_COPIES = 64
  • fuse_copy_kernel.cu: 实现 fusedCopyKernel(16-byte vectorized fast path + byte fallback)和 fusedStridedCopyKernel(2D strided copy)
  • FusedCopyOp.cc: 注册到 ExecOps,处理 CUDA/ROCm 分发

2. CUDA Graph Runner 重构

  • prepareInputs: 删除 copySmallerIntoLarger,改用 lambda 收集 copy 参数,最后两次 fused kernel launch
  • 删除 kv_cache_block_id_device/host 的 fill(0) + copy(注释说明 attention kernel 不使用,cache store 在 graph 外读原始 inputs)
  • H2H copy 使用 stridedCopyHost lambda(row-by-row memcpy)

3. cu_seqlens Host/Device 拆分

  • 新增 cu_seqlens_host 字段(pinned CPU mirror)
  • capture 时写 host 再 copy_ 到 device,避免 GPU 端 fill

4. PyWrappedModel Fused H2D

  • tensorHoldHostAndToCuda: 不再 tensor.to(kCUDA),改为创建空 CUDA tensor + 累积到 d2d_copies_
  • 所有 micro-batch 累积完后一次 fusedCopy(d2d_copies_) flush
  • pinned_check_remaining_: 前 3 次 forward 检查 is_pinned() 作为 sanity check

5. Pinned Memory 迁移

  • EmbeddingExecutor.ccContextParallelProcessorBase.ccMtpBatchStreamProcessor.ccMtpExecutor.ccCudaFlashInfer.cc 中关键 CPU tensor 统一改用 pinned memory

6. cuda_graph_copy_kernel 修复

  • grid size 从动态计算改为固定 dim3(1024),兼容 CUDA Graph capture

7. 测试

  • fuse_copy_kernel_test.cc: 540 行 GTest,覆盖 zero copies、aligned/unaligned、remainder、multiple copies、max capacity、pinned H2D、mixed source、strided copy 等场景

Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ fused copy 逻辑独立为 FusedCopyOp + kernel,职责清晰
OCP ✅ 通过 lambda 收集 copy 参数,新增 copy 只需 add 调用
DRY ✅ 消除了 copySmallerIntoLarger 与 optimizedCopyAsync 的重复模式
KISS ✅ kernel 实现简洁,vectorized + byte fallback 两条路径
YAGNI ✅ MAX=64 有合理的 sizing rationale 文档

架构审视

检查项 结果
抽象边界 ✅ fuse_copy_util.h 纯 POD,kernel 层独立,Op 层做 stream 分发
状态完整性 ✅ d2d_copies_ 每次 forward 开头 clear,flush 后不再使用
错误语义 ✅ copyParamsAssert 超限时 throw,num_copies==0 时 early return
可演进性 ✅ MAX 常量有详细 sizing rationale,扩展指引清晰

测试

检查项 结果
新功能有对应测试 ✅ fuse_copy_kernel_test.cc 覆盖充分
边界 case 覆盖 ✅ zero copies、unaligned、non-multiple-of-16、single row、max capacity

领域检查

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

B. 正确性与逻辑 — 全部 ✅

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

D. 性能 — ❌ 见 P2-1

E-I — 全部 ✅


Review 意见

问题

  1. tensorHoldHostAndToCuda 中 per-forward GPU 分配 [P2]

    tensorHoldHostAndToCuda 每次调用都执行 torch::empty(..., device=kCUDA) 创建新的 CUDA tensor。在 forwardMicroBatched 路径中,每个 micro-batch 的 buildPyAttentionInputs 会调用多次(cu_seqlens、cu_kv_seqlens、padding_offset 等),总计约 6+ 次 per-forward GPU 分配。

    虽然 fused copy 消除了 kernel launch 开销,但 torch::empty 的 CUDA allocator 开销仍然存在。考虑在 PyWrappedModel 中预分配这些 buffer 并复用,可进一步减少 allocator 压力。这是后续优化方向,不阻塞当前 PR。

    文件: rtp_llm/cpp/models/PyWrappedModel.cc

小问题

  • [P3] stridedCopyHost lambda 当 src_stride == dst_stride == row_bytes 时可用单次 memcpy 替代逐行拷贝。
  • [P3] copy_utils.hUSEING_CUDAUSING_CUDA 的 typo 修复属于无关改动,理想情况下应在独立 commit 中。

v7 问题修复状态

历史问题 状态
P1: 缺少 fused copy kernel 测试 ✅ 已修复(540 行 GTest)
P1: kv_cache_block_id 拷贝删除 ✅ 已确认安全
P2: cuda_graph_copy_kernel 动态 grid ✅ 已修复(固定 grid)
P2: pinned memory 不一致 ✅ 已修复
P2: MAX_FUSED_D2D_COPIES 不足 ✅ 已修复(提升至 64)

整体评价

经过 8 轮 review 迭代,PR 质量已显著提升。核心 fused copy kernel 实现简洁正确,测试覆盖充分,CI 全绿(27/27)。pinned memory 迁移全面且一致。历史 P0/P1 问题均已解决。

LGTM ready to ci — 当前 review 未发现阻塞级或重要级问题,可进入合入流程。P2/P3 建议后续改进但不阻塞。

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kernel launch
Author: Vinkle-hzt (隐智)
规模: 31(GitHub) files, +1003/-191
Head SHA: 22735d0
Commits: 4 (refactor: fused copy + test + CP pinned mem + raise cap to 64)

核心目标

通过三项优化减少 CUDA graph 和 forward 路径的 kernel launch 开销:

  1. 引入 fused D2D copy kernel,将 prepareInputs 中多次独立 memcpy 合并为两次 fused kernel launch(contiguous + strided)
  2. 在 PyWrappedModel::tensorHoldHostAndToCuda 中累积 H2D copy,跨 micro-batch 合并后一次性 flush
  3. 将关键 CPU tensor 统一迁移到 pinned memory;拆分 cu_seqlens 为 host(pinned)+ device 双份

改动逻辑拆解

1. Fused Copy Kernel(新增核心)

  • fuse_copy_util.h: FusedD2DCopyParams / FusedStridedCopyParams POD 结构体,MAX=64,附带详细 sizing rationale(worst-case 20 copies for forwardMicroBatched with 2 micro-batches + 4 hybrid groups)
  • fuse_copy_kernel.cu: fusedCopyKernel(int4 向量化快速路径 + byte fallback)和 fusedStridedCopyKernel(按行 stride 拷贝)
  • FusedCopyOp.cc: 获取当前 CUDA/ROCm stream 并 launch kernel
  • ExecOps.h: 声明 fusedCopy() / fusedStridedCopy() 全局接口

2. CUDA Graph prepareInputs 重构

  • 删除 copySmallerIntoLarger(), 替换为 lambda 收集 copy 参数 → 两次 fused kernel launch
  • H2H 放在 D2D 之后让 GPU 尽早开始工作
  • 移除 kv_cache_block_id_{host,device} 的 fill+copy(注释说明不被 attention kernel 消费)

3. PyWrappedModel Fused H2D

  • tensorHoldHostAndToCuda() 不再 tensor.to(kCUDA), 改为累积到 d2d_copies_ → forward 末尾一次 flush
  • pinned_check_remaining_ 前 3 次 forward 检查 is_pinned sanity check

4. Pinned Memory 统一迁移

EmbeddingExecutor、ContextParallelProcessorBase、MtpBatchStreamProcessor、MtpExecutor、FlashInferAttnParams、OpDefsUtils 中 CPU tensor 统一改用 pinned memory

5. CUDA Graph Copy Kernel Grid 修复

grid 从动态计算改为固定 dim3(1024), 避免 CUDA Graph capture 时读取 device 指针

6. 测试

540 行 GTest, 覆盖 zero copies、aligned/unaligned、remainder、max capacity、pinned H2D、mixed source、strided copy、micro-batch worst-case 等场景


Checklist 检查结果

通用原则

类别 结果
软件工程原则 (SRP/OCP/DRY/KISS/YAGNI) 全部 ✅
架构审视 全部 ✅
测试 ✅ 540 行 kernel 测试,边界覆盖全面
代码质量 ✅ (PR description 过于简略 — P3)

RTP-LLM 领域检查

A-I 全部 ✅


Review 意见

问题

  1. tryAddStridedD2DCopy 丢失维度校验 [P2]

    copySmallerIntoLarger 包含完整的维度检查(dim 匹配、每维 size ≤ target)。新的 tryAddStridedD2DCopy lambda 仅检查 src.defined() && src.numel() > 0。建议添加 debug-mode assert 验证 src.dim() == dst.dim()src.size(i) <= dst.size(i)

  2. fusedStridedCopyKernel 使用 64-bit 整数除法 [P2]

    const size_t row = idx / rbytes; — GPU 上 size_t 除法开销较大。当前数据量小影响有限,未来可考虑 2D grid indexing 替代。

  3. tensorHoldHostAndToCuda per-forward GPU 分配 [P2]

    每次 forward 对每个 tensor 调用 torch::empty(..., kCUDA)。虽然比原来 tensor.to(kCUDA) 已有改善(fused launch 减少了开销),但 allocator 锁 contention 仍在。可作为后续优化项——预分配 device buffer pool 复用。

  4. kv_cache_block_id 删除 fill+copy 的假设 [P2]

    注释已说明不被 attention kernel 消费。建议在 OpDefs.h 字段注释中明确标注 "NOT used during CUDA graph replay"。

小问题

  • [P3] PR description 过于简略,缺少性能对比数据
  • [P3] stridedCopyHost 当 strides 相同时可单次 memcpy
  • [P3] USEING_CUDA typo 修复理想情况下应在独立 commit

整体评价

高质量的性能优化 PR,经过 8 轮 review 迭代质量稳步提升。fused copy 架构设计合理,D2D 收集 → 单次 flush 模式清晰。MAX=64 有详细 sizing rationale,测试覆盖全面(540 行含 micro-batch worst-case),CI 全绿(27/27)。

P0: 0, P1: 0, P2: 4, P3: 3

LGTM ready to ci — 当前 review 未发现阻塞级或重要级问题,可进入合入流程;P2/P3 建议后续改进但不阻塞。

🤖 Review by Claude Code

@LLLLKKKK
Copy link
Copy Markdown
Collaborator

🤖 AI Code Review — PR #832

PR 概述

Title: Optimize kernel launch
Author: Vinkle-hzt
规模: 31(GitHub) files, +1206/-197

核心目标

将 CUDA Graph 路径和 PyWrappedModel forward 路径中大量零散的 D2D memcpy / kernel launch 合并为单次 fused kernel launch,减少 kernel launch overhead。同时将多处 CPU tensor 转为 pinned memory,为 async H2D copy 提供基础。


改动逻辑拆解

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

1. Fused Copy Kernel 基础设施(新增)

  • fuse_copy_util.h:定义 FusedD2DCopyParams / FusedStridedCopyParams POD 结构体,编译期固定 MAX_FUSED_D2D_COPIES=64 / MAX_FUSED_STRIDED_COPIES=64,附详细 sizing rationale 注释
  • fuse_copy_kernel.cu:实现 fusedCopyKernel(支持 int4 向量化快速路径 + byte fallback)和 fusedStridedCopyKernel(2D strided copy)
  • FusedCopyOp.cc:ExecOps 层封装,支持 CUDA + ROCm 双平台

2. CudaGraphRunner::prepareInputs 重构

  • 删除 copySmallerIntoLarger,替换为 fused copy 收集 + 单次发射
  • H2H copy 放在 D2D 之后执行,让 GPU 尽早开始 kernel 执行
  • 新增 cu_seqlens_host(pinned CPU mirror)分离 host/device 数据流
  • 新增 input_lengths_d / prefix_lengths_d 作为 device-side mirror

3. PyWrappedModel forward 路径优化

  • tensorHoldHostAndToCuda 改为累积 copy 参数到 d2d_copies_,所有 micro-batch 累积后一次性 fusedCopy() 发射
  • 新增 pinned_check_remaining_ 机制:前 3 次 forward 检查 is_pinned() 做 sanity check

4. Pinned Memory 转换(多文件)

  • CudaFlashInfer.ccEmbeddingExecutor.ccContextParallelProcessorBase.ccMtpBatchStreamProcessor.ccMtpExecutor.ccPyWrappedModel.ccOpDefsUtils.h 中 CPU tensor 改为 pinned memory

5. CUDA Graph Copy Kernel 修复

  • cuda_graph_copy_kernel.cu:grid size 从动态计算改为固定 dim3(1024),避免 CUDA Graph capture 时 grid 依赖 host 端动态值

6. 测试

  • 新增 fuse_copy_kernel_test.cc(540 行,14 个 test case),覆盖全面

Checklist 检查结果

通用原则

软件工程原则

检查项 结果
SRP ✅ fused copy 基础设施独立为单独文件和 BUILD target
OCP ✅ 通过 lambda + params 结构体扩展
LSP ✅ 不涉及继承变更
ISP ✅ 接口精简
DIP ✅ ExecOps 层抽象
DRY ✅ 多处 copy 逻辑统一收敛
KISS ✅ kernel 实现简洁
YAGNI ✅ MAX=64 headroom 合理

架构审视

检查项 结果
抽象边界 ✅ fuse_copy_util.h → fuse_copy_kernel → FusedCopyOp → ExecOps,层次清晰
依赖方向
状态完整性 ✅ d2d_copies_ 每次 forward 入口 clear()
错误语义 ✅ 超限 throw,fail-fast
可观测性 ✅ 新增 PROFILE_SCOPE
可演进性 ✅ sizing rationale 注释指导扩容
可运维性 ✅ pinned sanity check

测试

检查项 结果
新功能有对应测试 ✅ 14 个 test case
删除的测试有等价替代
边界 case 覆盖

代码质量与文档

检查项 结果
Commit 原子性 ✅ 4 个 commit 结构合理
PR description ❌ P2 — 过于简略

领域检查

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

Review 意见

问题

  1. tensorHoldHostAndToCuda 每次调用 torch::empty(..., kCUDA) 产生 per-forward GPU 分配 [P2]

    PyWrappedModel::tensorHoldHostAndToCuda 现在每次调用都执行 torch::empty(tensor.sizes(), ... kCUDA) 创建新的 CUDA tensor。在 forwardMicroBatched 路径中,每个 micro-batch 的 buildPyAttentionInputs 会多次调用此函数,累计约 6+ 次 per-forward GPU 分配。

    原来的 .to(kCUDA, non_blocking=true) 也有分配,所以这不是回退,但既然本 PR 的目标是减少 launch overhead,可以考虑后续将这些 CUDA tensor 预分配并复用(类似 CUDA Graph 路径的 capture_mem_hold_ 模式),进一步消除分配器开销。

    当前实现功能正确,标记为后续优化方向。

  2. fuse_copy_kernel.cu 的 ROCm 编译兼容性 [P2]

    fuse_copy_kernel.cu 使用 cudaStream_t 作为函数参数类型。在 ROCm 路径下,fuse_copy_kernel.h 通过 #include "rtp_llm/cpp/rocm/cuda_shims.h" 提供 typedef。但 .cu 文件本身只 include 了 fuse_copy_kernel.h,未直接 include ROCm shims。

    建议确认 ROCm CI 已覆盖此路径,或在 .cu 文件中显式添加 ROCm guard。

  3. kv_cache_block_id_device / kv_cache_block_id_host 不再 fill_(0) 和 copy 的安全性 [P2]

    cuda_graph_runner.cc 中移除了对这些字段的 fill_(0)copySmallerIntoLarger 调用。注释说明这些是 physical block IDs 仅供 cache store 使用,不参与 CUDA graph replay 的 attention kernel。

    假设成立则正确。建议在 OpDefs.h 的字段注释中明确标注 "NOT updated during CUDA graph replay",防止后续开发者误用。

  4. PR description 过于简略 [P2]

    PR body 仅 "fuse d2d & d2d stride copy",建议补充优化动机、性能数据、设计决策和影响范围。

小问题

  • [P3] copy_utils.h 的 typo 修复和 PyWrappedModel.h 的空行删除应分离到独立 commit
  • [P3] fuse_copy_kernel.cuFUSED_COPY_BLOCKS_PER_TASK = 8FUSED_COPY_THREADS = 256 的选择缺少注释说明调优依据

整体评价

这是一个高质量的性能优化 PR。核心思路清晰:将分散的 D2D memcpy 和 kernel launch 合并为 fused kernel,同时将 CPU tensor 转为 pinned memory 以支持 async transfer。代码结构良好,sizing rationale 文档化充分,测试覆盖全面。CUDA Graph 路径的 grid size 修复也是正确的改进。

未发现 P0 或 P1 级别问题。P2 问题均为建议性改进,不阻塞合入。

LGTM ready to ci

@Vinkle-hzt Vinkle-hzt merged commit 2d9b44c into alibaba:main Apr 23, 2026
2 of 3 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.

3 participants