Prhub

#44648 [Bugfix] [ROCm] [Critical] fallback to regular abi for ROCm

原始 PR 作者 tjtanaa 合并时间 2026-06-05 23:51 文件变更 6 提交数 2 评论 6 代码增减 +127 / -25

执行摘要

ROCm 回退非稳定 ABI 修复构建失败

由于 PR #44334 要求 torch 2.11 的 stable ABI API,但 ROCm 官方仅支持 torch 2.10,导致 ROCm 构建失败(见 issue #44641)。此 PR 通过条件编译为 ROCm 回退到非 stable ABI 解决构建错误。

此 PR 是必要的构建修复,值得精读以理解 vLLM 稳定 ABI 迁移策略和条件编译模式。开发者应关注 TODO 注释,待 ROCm 升级 torch 后系统清理回退代码。

讨论亮点

Review 中无重大争议。作者在评论中解释了文件移动的意图(将同一条件编译块分组)以及 cuda_view.cu 是旧实现。审核者 Harry-Chen 批准。未解决的问题:等待 ROCm 升级到 torch 2.11 后需移除所有的 TODO 回退代码。

实现拆解

  1. 非稳定 ABI 注入:在 csrc/torch_bindings.cppTORCH_LIBRARY_EXPAND 中添加 get_cuda_view_from_cpu_tensor_cuda_utils 库(get_device_attribute, get_max_shared_memory_per_block_device_attribute)的注册,由 #ifdef USE_ROCM 保护。

  2. 稳定 ABI 条件编译:在 csrc/libtorch_stable/torch_bindings.cpp 中将 get_cuda_view_from_cpu_tensor 的注册和 _cuda_utils 的片段移到 #ifndef USE_ROCM 下,ROCm 不编译这些部分。

  3. 新核心实现文件:创建 csrc/cuda_view.cu,包含 get_cuda_view_from_cpu_tensor 的非稳定 ABI 版本实现(旧版 UVA 逻辑),该文件仅在 ROCm 构建时通过 CMake 加入。

  4. 头文件调整csrc/ops.hUSE_ROCM 下增加 get_cuda_view_from_cpu_tensor 声明;csrc/libtorch_stable/ops.h 将同一声明移出共享区域,移入 #endif 外部(即 ROCm 不可见)。

  5. 构建系统适配CMakeLists.txt 为 HIP 设置 TORCH_TARGET_VERSION=0x020A(2.10),调整 VLLM_EXT_SRCVLLM_STABLE_EXT_SRC 列表,确保 cuda_view.cucuda_utils_kernels.cu 在正确的位置编译。

  6. 测试验证:通过 UVA kernel 测试和 silu_and_mul_per_block_quant 测试,确认构建和功能正常。

文件 模块 状态 重要度
csrc/torch_bindings.cpp 算子注册 modified 6.03
csrc/libtorch_stable/torch_bindings.cpp 稳定 ABI modified 5.96
csrc/cuda_view.cu UVA 实现 added 5.22

关键符号

get_cuda_view_from_cpu_tensor get_device_attribute get_max_shared_memory_per_block_device_attribute

关键源码片段

csrc/torch_bindings.cpp dependency-wiring

非稳定 ABI 入口,添加了 ROCm 下 `get_cuda_view_from_cpu_tensor` 和 `_cuda_utils` 的注册,是回退的核心。

// csrc/torch_bindings.cpp ( 修改后版本的关键添加部分 )
#include "cuda_utils.h"TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
  // ... 先前已有 op 注册 ...  // ---- ROCm 回退:因 ROCm 使用 torch 2.10 ,稳定 ABI 无法编译 ----
  #ifdef USE_ROCM
  // TODO: 移除此块当 ROCm 升级到 torch 2.11
  ops.def("get_cuda_view_from_cpu_tensor(Tensor cpu_tensor) -> Tensor");
  ops.impl("get_cuda_view_from_cpu_tensor", torch::kCPU,
           &get_cuda_view_from_cpu_tensor);
  #endif  // ... 后续其他 op 注册 ...
}// 同样在文件末尾添加 _cuda_utils 库注册
// ( 对于 ROCm,这些不能在稳定 ABI 中编译,故放在这里 )
#ifdef USE_ROCM
TORCH_LIBRARY_EXPAND(CONCAT(TORCH_EXTENSION_NAME, _cuda_utils), cuda_utils) {
  cuda_utils.def("get_device_attribute(int attribute, int device_id) -> int");
  cuda_utils.impl("get_device_attribute", &get_device_attribute);
  cuda_utils.def(
    "get_max_shared_memory_per_block_device_attribute(int device_id) -> int");
  cuda_utils.impl("get_max_shared_memory_per_block_device_attribute",
                  &get_max_shared_memory_per_block_device_attribute);
}
#endif
csrc/libtorch_stable/torch_bindings.cpp core-logic

稳定 ABI 库的注册文件,将 `get_cuda_view_from_cpu_tensor` 和 `_cuda_utils` 的注册移入 `#ifndef USE_ROCM` 保护,确保 ROCm 不编译。

// csrc/libtorch_stable/torch_bindings.cpp ( 修改部分 )
// 在 stable ABI 库中,ROCm 跳过这部分注册STABLE_TORCH_LIBRARY_IMPL(_C, CUDA, ops) {
  // ... 原有大量 op 实现 ...
}// ----- ROCm 回退:稳定 ABI 部分仅对 CUDA 生效 -----
#ifndef USE_ROCM
// TODO: 移除此保护块当 ROCm 升级到 torch 2.11
STABLE_TORCH_LIBRARY_IMPL(_C, CPU, ops) {
  ops.impl("get_cuda_view_from_cpu_tensor",
           TORCH_BOX(&get_cuda_view_from_cpu_tensor));
}// 注册 _cuda_utils 稳定 ABI 库
STABLE_TORCH_LIBRARY_FRAGMENT(_C_cuda_utils, cuda_utils) {
  cuda_utils.def("get_device_attribute(int attribute, int device_id) -> int");
  cuda_utils.def(
    "get_max_shared_memory_per_block_device_attribute(int device_id) -> int");
}STABLE_TORCH_LIBRARY_IMPL(_C_cuda_utils, CompositeExplicitAutograd, cuda_utils) {
  cuda_utils.impl("get_device_attribute", TORCH_BOX(&get_device_attribute));
  cuda_utils.impl("get_max_shared_memory_per_block_device_attribute",
                  TORCH_BOX(&get_max_shared_memory_per_block_device_attribute));
}
#endif
csrc/cuda_view.cu dependency-wiring

新增文件,包含 `get_cuda_view_from_cpu_tensor` 在非稳定 ABI 下的完整实现,是 ROCm 回退的运行时核心。

// csrc/cuda_view.cu ( 新增文件,ROCm 专用,待 torch 升级后移除 )
// TODO: Remove this once ROCm upgrade to torch 2.11.#include <torch/all.h>
#include <torch/cuda.h>
#include <cuda_runtime.h>torch::Tensor get_cuda_view_from_cpu_tensor(torch::Tensor& cpu_tensor) {
  // 确保输入是 CPU 张量
  TORCH_CHECK(cpu_tensor.device().is_cpu(), "Input tensor must be on CPU");  // 处理空张量
  if (cpu_tensor.numel() == 0) {
    return torch::empty(cpu_tensor.sizes(),
                       cpu_tensor.options().device(torch::kCUDA));
  }  if (cpu_tensor.is_pinned()) {
    // 如果 CPU 张量是 page-locked 的,直接获取设备指针
    void* host_ptr = const_cast<void*>(cpu_tensor.data_ptr());
    void* device_ptr = nullptr;
    cudaError_t err = cudaHostGetDevicePointer(&device_ptr, host_ptr, 0);
    TORCH_CHECK(err == cudaSuccess,
                "cudaHostGetDevicePointer failed: ", cudaGetErrorString(err));    // 构建一个 CUDA 视图张量,引用同一个数据
    return torch::from_blob(
        device_ptr, cpu_tensor.sizes(), cpu_tensor.strides(),
        [base = cpu_tensor](void*) {}, // 保持 CPU 张量存活
        cpu_tensor.options().device(torch::kCUDA));
  }  // 如果 CPU 张量未 pin,分配新的 pinned 缓冲区并拷贝数据
  torch::Tensor contiguous_cpu = cpu_tensor.contiguous();
  size_t nbytes = contiguous_cpu.nbytes();  void* host_ptr = nullptr;
  cudaError_t err = cudaHostAlloc(&host_ptr, nbytes, cudaHostAllocMapped);
  if (err != cudaSuccess) {
    AT_ERROR("cudaHostAlloc failed: ", cudaGetErrorString(err));
  }  err = cudaMemcpy(host_ptr, contiguous_cpu.data_ptr(), nbytes,
                   cudaMemcpyDefault);
  if (err != cudaSuccess) {
    cudaFreeHost(host_ptr);
    AT_ERROR("cudaMemcpy failed: ", cudaGetErrorString(err));
  }  void* device_ptr = nullptr;
  err = cudaHostGetDevicePointer(&device_ptr, host_ptr, 0);
  if (err != cudaSuccess) {
    cudaFreeHost(host_ptr);
    AT_ERROR("cudaHostGetDevicePointer failed: ", cudaGetErrorString(err));
  }  // 使用 lambda 在张量析构时释放 pinned 内存
  auto deleter = [host_ptr](void*) { cudaFreeHost(host_ptr); };  return torch::from_blob(device_ptr, contiguous_cpu.sizes(),
                          contiguous_cpu.strides(), deleter,
                          contiguous_cpu.options().device(torch::kCUDA));
}

评论区精华

文件移动和分组 other

作者评论说明在 `libtorch_stable/torch_bindings.cpp` 中将 `#ifndef USE_ROCM` 块移动到一起是为了分组。

结论:无争议,审核通过。 · 已解决

cuda_view.cu 旧实现说明 other

作者评论指出 `csrc/cuda_view.cu` 是旧实现,将来 ROCm 升级后需移除。

结论:已记录 TODO,待后续清理。 · 已解决

风险与影响

核心风险是版本兼容性:当前使用非稳定 ABI 在 ROCm 上,若未来 PyTorch 2.10 不再支持或发生接口变更,可能需额外适配。但回退代码标注了清晰的 TODO,且仅影响 ROCm 路径。CUDA 路径完全不受影响。需要确保 ROCm CI 持续覆盖 UVA 和量化 kernel 测试。

影响范围:所有 ROCm 用户(修复构建阻塞,使 vLLM 在 ROCm 上恢复正常编译)。影响程度:关键,因为若无此修复 ROCm 完全不可用。影响面:仅限于构建系统、算子注册和头文件声明;运行时行为无变更。

平台兼容性依赖 需后续清理

关联 Issue

#44641 [Bug][ROCm]: Build Failure Caused by Torch Version

完整报告

参与讨论