UCX v1.19.0 CUDA 依赖与 CUDA Hook 机制分析
2026/8/5 14:08:06 网站建设 项目流程

分析对象:OpenUCX tagv1.19.0
分析日期:2026-08-04


1. UCX v1.19.0 CUDA 依赖

1.1. CUDA 编译/运行依赖

1.1.1 启用开关

配置选项说明
--with-cuda[=DIR]启用 CUDA 支持并指定 CUDA Toolkit 路径(默认guess,自动探测)
--without-cuda显式禁用 CUDA
--with-gdrcopy[=DIR]启用 GDR COPY(GPUDirect RDMA 低延迟拷贝)支持
--with-iodemo-cudaio_demo测试程序添加 CUDA 支持

1.1.2 configure 检查项

config/m4/cuda.m4中的UCX_CHECK_CUDA会依次检查:

组件头文件库(符号检查)是否必须
CUDA Driver<cuda.h>libcudacuDeviceGetUuid
CUDA Runtime<cuda_runtime.h>libcudartcudaGetDeviceCount
NVML<nvml.h>libnvidia-mlnvmlInit
NVCCnvcc可执行文件否(仅影响部分测试/示例编译)
CUDA Static Runtimelibcudart_static

注意:NVML 是硬性要求。若显式使用--with-cuda但找不到nvml.hlibnvidia-mlconfigure会直接报错。

1.1.3 构建产物

模块产物路径
UCT CUDAlibuct_cuda.sosrc/uct/cuda/
UCM CUDAlibucm_cuda.sosrc/ucm/cuda/
perftest CUDAlibucx_perftest_cuda.sosrc/tools/perf/cuda/
GDR COPYlibuct_cuda_gdrcopy.sosrc/uct/cuda/gdr_copy/

CUDA 传输组件包括:

  • cuda_copy:Host↔Device、Device↔Device 数据拷贝
  • cuda_ipc:同一节点 GPU 间通过 CUDA IPC 共享内存
  • gdr_copy:GPUDirect RDMA 低延迟拷贝(需单独安装 gdrcopy)

1.1.4 最低 CUDA 版本推断

源码中多处使用CUDA_VERSION/CUDART_VERSION做条件编译:

特性宏检查所需 CUDA 版本
cudaMallocAsync/cuMemAllocAsync钩子CUDA_VERSION >= 11020/CUDART_VERSION >= 11020CUDA 11.2
cudaTypedefs.h、部分 fabric handle 类型CUDA_VERSION >= 11070CUDA 11.7
cuCtxGetId上下文有效性检查CUDA_VERSION >= 12000CUDA 12.0
nvmlDeviceGetGpuFabricInfo新 API(测试)CUDA_VERSION >= 12050CUDA 12.5

结论:UCX v1.19.0 的核心 CUDA 代码可在较老版本 CUDA 上编译,但新特性(CUDA Fabric Handle / MNNVL / Grace 主机内存)需要CUDA 11.7+,部分功能需CUDA 12.0+ / 12.5+。官方 CI 脚本buildlib/az-helpers.sh显示当前使用CUDA 12.8进行验证。

1.1.5 包依赖

  • RPMucx.spec.inucx-cuda子包包含libuct_cuda.so.*libucm_cuda.so.*libucx_perftest_cuda.so.*ucx-gdrcopy依赖ucx-cuda
  • DEBdebian/ucx-cuda.installdebian/ucx-gdrcopy.install包含对应模块。

1.1.6 常用构建命令

# 自动探测 CUDA(默认)./contrib/configure-release--prefix=/opt/ucx# 显式启用并指定 CUDA 路径./contrib/configure-release--prefix=/opt/ucx\--with-cuda=/usr/local/cuda\--with-gdrcopy=/usr/local/gdrcopy# 完全禁用 CUDA./contrib/configure-release--prefix=/opt/ucx --without-cuda

1.2. UCX v1.19.0 是否仍会 Hook CUDA 库?

结论:是的,UCX v1.19.0 仍然会通过 UCM(Unified Communication Memory)对 CUDA Driver API 和 CUDA Runtime API 进行 Hook。

1.2.1 Hook 实现位置

核心实现文件:

  • src/ucm/cuda/cudamem.c
  • src/ucm/cuda/cudamem.h

1.2.2 被 Hook 的 CUDA 函数

CUDA Driver API
分配类释放类
cuMemAlloccuMemFree
cuMemAlloc_v2cuMemFree_v2
cuMemAllocManagedcuMemFreeHost
cuMemAllocPitchcuMemFreeHost_v2
cuMemAllocPitch_v2cuMemUnmap
cuMemMapcuMemFreeAsync(CUDA 11.2+)
cuMemAllocAsync(CUDA 11.2+)
cuMemAllocFromPoolAsync(CUDA 11.2+)
cuModuleGetGlobal_v2
CUDA Runtime API
分配类释放类
cudaMalloccudaFree
cudaMallocManagedcudaFreeHost
cudaMallocPitchcudaFreeAsync(CUDA 11.2+)
cudaMallocAsync(CUDA 11.2+)
cudaMallocFromPoolAsync(CUDA 11.2+)
cudaGetSymbolAddress

1.2.3 Hook 机制

ucm_cudamem_install()会依次尝试两种 Hook 方式:

  1. Bistro(二进制指令级插桩)

    • 用于 CUDA Driver API
    • 通过ucm_bistro_patch()修改目标函数入口指令
    • 即使 CUDA Runtime 被静态链接到应用中,也能拦截 Runtime 对 Driver API 的调用
  2. Reloc(ELF 重定位表修改)

    • 用于 CUDA Driver API 和 CUDA Runtime API
    • 通过ucm_reloc_modify()修改动态链接重定位表
    • 如果应用静态链接了 CUDA Runtime,可能会漏掉部分内存事件

默认启用策略(src/ucm/util/sys.c):

.cuda_hook_modes=#ifUCM_BISTRO_HOOKSUCS_BIT(UCM_MMAP_HOOK_BISTRO)|#endifUCS_BIT(UCM_MMAP_HOOK_RELOC),

即:如果平台支持 Bistro,则同时启用 Bistro + Reloc;否则只启用 Reloc

1.2.4 运行时配置

通过环境变量UCX_MEM_CUDA_HOOK_MODE可以控制 Hook 模式(src/ucs/config/ucm_opts.c):

模式说明
none不设置 CUDA Hook
reloc通过 ELF 重定位表设置 Hook;对静态链接 CUDA Runtime 的应用可能漏事件
bistro通过二进制指令级插桩设置 Hook;可拦截静态链接应用对 Driver API 的调用

UCX_MEM_CUDA_HOOK_MODE是位图类型,可同时指定多个模式,例如UCX_MEM_CUDA_HOOK_MODE=bistro,reloc

1.2.5 Hook 触发的事件

CUDA 内存 Hook 会向上层派发两类 UCM 事件:

  • UCM_EVENT_MEM_TYPE_ALLOC:CUDA 内存分配事件
  • UCM_EVENT_MEM_TYPE_FREE:CUDA 内存释放事件

这些事件被 UCS 内存类型缓存(memtype cache)等模块消费,用于:

  • 自动识别指针是否为 GPU 内存
  • 避免重复的内存属性查询
  • 支持 RMA / Rendezvous 协议正确选择传输路径

1.2.6 历史背景与兼容性

  • UCX 早期版本曾因 CUDA Hook 导致部分 NVIDIA GPU 应用出现兼容性问题(尤其是应用静态链接 CUDA Runtime 时)。
  • 从后续版本开始,UCX 引入了Bistro + Reloc 双模式以及UCX_MEM_CUDA_HOOK_MODE配置项,允许用户按需关闭或调整 Hook 行为。
  • 在 v1.19.0 中,相关代码仍然完整保留并默认启用,说明 CUDA Hook 仍是 UCX GPU 内存感知的核心机制。

1.3. 综合结论

  1. UCX v1.19.0 构建 CUDA 支持需要:CUDA Toolkit(cuda.hcuda_runtime.h-lcuda-lcudart)以及 NVIDIA 驱动的 NVML(nvml.h-lnvidia-ml)。
  2. UCX v1.19.0 仍然 Hook CUDA 库:通过src/ucm/cuda/cudamem.c对 CUDA Driver API 和 CUDA Runtime API 的内存分配/释放函数进行 Hook,默认启用 Bistro + Reloc 双模式。
  3. Hook 可被关闭或调整:通过环境变量UCX_MEM_CUDA_HOOK_MODE=none可完全禁用;使用relocbistro可单独选择模式。

2. UCX v1.19.0 x86 平台下 Bistro 与 Reloc CUDA Hook 对比分析

分析对象:OpenUCX tagv1.19.0
分析日期:2026-08-04


问题

在 x86 平台上,UCX v1.19.0 默认对 CUDA 内存分配/释放同时使用BistroReloc两种 Hook 模式。

问题:

  1. 是否可以只启用Reloc,关闭Bistro
  2. 如果关闭 Bistro,仅使用 Reloc,能否达到与两者同时启用相同的目的?

简短结论

问题结论
能否只启用 Reloc?可以。通过环境变量UCX_MEM_CUDA_HOOK_MODE=reloc即可。
是否能达到相同目的?不能 100% 等价。对动态链接 CUDA Runtime 的应用基本等价;但对静态链接 CUDA Runtime的应用,Reloc 可能漏掉部分 CUDA 内存事件。

2.1. 两种 Hook 模式的实现机制

2.1.1 Bistro(二进制指令级插桩)

  • 实现文件src/ucm/bistro/bistro_x86_64.c
  • 原理:直接修改目标函数入口处的机器指令,插入一条跳转到 Hook 函数的指令。
  • 特点
    • 不依赖 ELF 重定位表。
    • 只要调用者执行到被 Hook 函数的入口地址,就会被拦截。
    • 即使 CUDA Runtime 被静态链接进应用,只要它调用的是动态库libcuda.so中的 Driver API 函数入口,就能被拦截。
  • x86_64 补丁形式
    • 优先使用 5 字节的相对跳转JMP rel32
    • 若 Hook 函数距离超过 32 位范围,则使用 12 字节的movabs %rax, addr; jmp *%rax

2.1.2 Reloc(ELF 重定位表修改)

  • 实现文件src/ucm/util/reloc.c
  • 原理:修改动态库的.got/.plt等重定位表,将对外部符号(如cuMemAlloc)的解析结果指向 Hook 函数。
  • 特点
    • 只影响通过动态链接解析的符号引用。
    • 对动态链接的libcudart.solibcuda.so有效。
    • 若 CUDA Runtime 被静态链接到应用中,且应用绕过动态重定位直接调用 Driver API(例如通过dlsym或链接时解析的地址),则可能无法被拦截。

2.2. 默认行为与配置方式

2.2.1 默认启用策略

src/ucm/util/sys.c

ucm_global_config_tucm_global_opts={....cuda_hook_modes=#ifUCM_BISTRO_HOOKSUCS_BIT(UCM_MMAP_HOOK_BISTRO)|#endifUCS_BIT(UCM_MMAP_HOOK_RELOC),...};

在 x86 Linux 上,config/m4/ucm.m4会检查SYS_mmap等系统调用号。只要这些宏存在,就会定义UCM_BISTRO_HOOKS=1

因此x86 平台默认同时启用 Bistro + Reloc

2.2.2 运行时关闭 Bistro 的方法

通过环境变量UCX_MEM_CUDA_HOOK_MODE控制(src/ucs/config/ucm_opts.c):

# 仅使用 Reloc,关闭 BistroUCX_MEM_CUDA_HOOK_MODE=reloc# 仅使用 BistroUCX_MEM_CUDA_HOOK_MODE=bistro# 两者都启用(默认)UCX_MEM_CUDA_HOOK_MODE=bistro,reloc# 完全关闭 CUDA HookUCX_MEM_CUDA_HOOK_MODE=none

2.2.3 编译时彻底禁用 Bistro

如果希望编译出的 UCX 根本不包含 Bistro 代码,可以在不支持 Bistro 的平台上编译,或手动修改config/m4/ucm.m4的判定逻辑。但在普通 x86 Linux 上无法通过 configure 选项直接关闭,因为UCM_BISTRO_HOOKS是自动根据系统调用是否存在来决定的。


2.3. 关闭 Bistro 后的影响

2.3.1 CUDA Driver API 的 Hook

src/ucm/cuda/cudamem.c中安装 Driver API Hook 的逻辑:

status=ucm_cuda_install_hooks(ucm_cuda_driver_funcs,"driver",UCM_MMAP_HOOK_BISTRO,&driver_api_hooks);...status=ucm_cuda_install_hooks(ucm_cuda_driver_funcs,"driver",UCM_MMAP_HOOK_RELOC,&driver_api_hooks);
  • 默认先尝试 Bistro,再尝试 Reloc。
  • 若设置UCX_MEM_CUDA_HOOK_MODE=reloc,则 Bistro 步骤会被跳过,仅执行 Reloc。

结果

  • 对动态链接 CUDA Runtime 的应用:通常仍然可以正常工作,因为libcudart.so调用libcuda.so时会经过重定位表。
  • 对静态链接 CUDA Runtime 的应用:可能漏掉部分内存分配/释放事件。

2.3.2 CUDA Runtime API 的 Hook

src/ucm/cuda/cudamem.c

status=ucm_cuda_install_hooks(ucm_cuda_runtime_funcs,"runtime",UCM_MMAP_HOOK_RELOC,&runtime_api_hooks);
  • Runtime API只使用 Reloc,从不用 Bistro。
  • 因此关闭 Bistro 对 Runtime API 的 Hook 没有影响。

2.3.3 文档中的明确说明

src/ucs/config/ucm_opts.c中对两种模式的描述:

reloc - Use ELF relocation table to set hooks. In this mode, if any part of the application is linked with Cuda runtime statically, some memory events may be missed and not reported. bistro - Use binary instrumentation to set hooks. In this mode, it's possible to intercept calls from the Cuda runtime library to Cuda driver APIs, so memory events are reported properly even for statically-linked applications.

这已经明确说明:Reloc 无法完全替代 Bistro 在静态链接场景下的能力


2.4. 实际使用建议

2.4.1 何时可以安全地只使用 Reloc?

如果你的应用满足以下条件,可以只启用 Reloc:

  • 应用使用动态链接的 CUDA Runtime(libcudart.so)。
  • 没有通过dlsym(RTLD_NEXT, "cuMemAlloc")等方式绕过 PLT/GOT 直接调用 Driver API。
  • 对 CUDA 内存事件的完整性要求不极端(允许偶发漏报)。

2.4.2 何时必须保留 Bistro?

以下情况建议保留 Bistro(默认):

  • 应用静态链接了 CUDA Runtime。
  • 应用或某些第三方库通过dlsym动态获取 CUDA Driver API 地址。
  • 需要确保所有 CUDA 内存分配/释放事件都被 UCX 感知,以支持 GPU 内存的 RMA/Rendezvous 协议。

2.4.3 如果 Bistro 导致兼容性问题

在某些环境中,Bistro 可能因为以下原因失败:

  • 目标函数前几条指令无法被ucm_bistro_relocate_one()识别。
  • 多线程竞争导致补丁应用失败。
  • 某些安全机制(如 SELinux、PaX、某些容器环境)禁止修改只读代码页。

此时可以尝试:

UCX_MEM_CUDA_HOOK_MODE=reloc

如果 Reloc 也不能满足需求,可以完全关闭:

UCX_MEM_CUDA_HOOK_MODE=none

但关闭后 UCX 将无法自动追踪 CUDA 内存,可能影响 GPU 内存的传输优化。


2.5. 总结

对比项BistroReloc
拦截层级函数入口机器指令ELF 重定位表
是否需要动态链接
静态链接 CUDA Runtime可有效拦截 Driver API 调用可能漏事件
x86 默认是否启用
单独使用是否可行
能否完全替代两者不能完全替代 Bistro

最终答案

  • 在 x86 平台上,可以通过UCX_MEM_CUDA_HOOK_MODE=reloc只启用 Reloc、关闭 Bistro。
  • 但这不等价于默认的 Bistro + Reloc:对动态链接 CUDA Runtime 的应用基本足够,对静态链接 CUDA Runtime 的应用可能丢失部分 CUDA 内存事件。
  • 如果应用没有静态链接 CUDA Runtime 且没有绕过 PLT/GOT 调用 Driver API,则只使用 Reloc 通常可以达到相同目的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询