Mooncake 集成 Sunrise Link Transport 实战指南:TENT 框架下的 GPU 直连传输后端

原创2026-10-04 22:31:231,672 阅读
文章标签:大模型人工智能模型推理服务缓存KV存储高性能计算通信分布式数据库

Mooncake 集成 Sunrise Link Transport 实战指南:TENT 框架下的 GPU 直连传输后端

导读

本文档面向需要在 Mooncake 分布式推理/缓存系统中启用曦望(Sunrise)GPU 直连互连硬件的开发者。Sunrise Link 被 Mooncake 以 SUNRISE_LINK 传输类型集成进 TENT 传输框架,本文将从传输流水线、依赖安装、CMake 编译、benchmark 运行验证、环境变量与配置调优到源码级实现原理,完整讲解如何在本仓库中构建、启用并验证该传输后端,读完即可上手在自有 Sunrise 硬件集群上跑通端到端传输。

Sunrise Link 是曦望(Sunrise)开发的 GPU 间高速直连互连技术。在 Mooncake 中,它作为 GPU 传输后端集成于 TENT(Transfer Engine with Notification Transport)传输框架,借助 Tang Runtime(tangrt)提供设备内存分配、指针属性查询、Peer Copy 与 IPC 句柄能力,并在 TENT 中以 SUNRISE_LINK 传输类型注册。运行时,当编译开启 USE_SUNRISE 且配置项 transports/sunrise_link/enable=true 时,TransferEngineImpl 会加载 Sunrise Link Transport(相关加载逻辑见 transport_loader.cpp)。


传输流水线

Sunrise Link Transport 的完整工作流程可分为以下五个阶段,与源码 sunrise_link_transport.cpp 中的实现一一对应:

  1. 初始化(Init):通过 dlopen 动态加载 libptml_shared.so 与 libtangrt_shared.so,并通过 dlsym 解析 ptmlInit、ptmlPtlinkEnableAll、ptmlPtlinkPhytopoDetect、ptmlDeviceGetCount 等符号,随后调用 ptmlInit() 初始化 PTML(Port Topology Management Layer)运行时。实现见 initSunriseLink()(sunrise_link_transport.cpp)。

  2. 拓扑检测(Topology):调用 ptmlPtlinkPhytopoDetect 逐设备发现芯片间物理端口,扫描每个端口的 link_status,构建 C2C 映射 (local_chipid, remote_chipid) → local_port,同时填充 topology_map_(device_id → 活跃 peer 端口列表)。实现见 detectTopology()(sunrise_link_transport.cpp)。

  3. 内存注册(Registration):addMemoryBuffer() 对 location 类型为 cuda/npu 的缓冲区调用 tangIpcGetMemHandle 生成 IPC 句柄,序列化后写入 desc.shm_path 供远程节点使用;CPU/通配符缓冲区则记录 gpu_id = -1(sunrise_link_transport.cpp)。

  4. 传输执行(Execution):依据源/目标指针属性分派路径——

    • 同设备:tangMemcpy(DeviceToDevice);
    • 跨设备:优先 tangMemcpyPeer,失败后重试 tangMemcpyPeer_v2,再回退到 tangDeviceGetPeerPointer 映射 + C2C memcpy(C2cMemcpyWithPeerMap);
    • 远程:通过 relocateRemoteAddress() 调用 tangIpcOpenMemHandle 打开远端 IPC 句柄后进行 peer copy;
    • 主机 ↔ 设备:根据 tangMemoryType 选择 tangMemcpyDeviceToHost / tangMemcpyHostToDevice / tangMemcpyHostToHost 方向(MemcpyKindForPointers)。
  5. 异步路径(Async):当传输大小超过 async_memcpy_threshold 时改用 tangMemcpyAsync,使用按设备缓存的线程本地 stream(ThreadLocalTangStreamPool),并在 getTransferStatus 中通过 tangStreamQuery / tangStreamSynchronize 完成异步收尾。

值得注意的实现细节:源码注释明确指出 peer copy 不能使用进程级全局锁——若为所有 tangMemcpyPeer_v2 加锁,会串行化所有并发设备拷贝,使多线程 C2C benchmark 比 PCCL(可并发执行大量设备拷贝)慢约 3 个数量级。因此实现只对 tangSetDevice + 非 peer 的 tangMemcpy 使用每设备互斥锁,peer 拷贝直接携带设备 ID 并发执行(sunrise_link_transport.cpp)。此外,指针属性查询同样刻意不加锁,避免多线程吞吐被全局锁卡死。


新增依赖

除 Mooncake 基础依赖外,Sunrise Link Transport 额外依赖 Tang Runtime(tangrt)与 PTML:

依赖项 说明
头文件路径 /usr/local/tangrt/include
库路径 /usr/local/tangrt/lib/linux-x86_64(扁平布局下也可能为 /usr/local/tangrt/lib)
共享库 libtangrt_shared.so(运行时按默认安装路径加载)

请确保 tangrt 与 ptml 相关运行库能被动态链接器找到(例如通过 LD_LIBRARY_PATH 或系统库搜索路径)。动态库路径的解析逻辑位于 TangRtSharedObjectPath():优先读取 MC_TANGRT_LIB_DIR 环境变量直接定位 .so 目录;否则按 MC_TANGRT_ROOT + MC_TANGRT_LIB_ARCH 拼出 <root>/lib/<arch>/<soname>,若该路径不存在则回退到 <root>/lib/<soname>(sunrise_link_transport.cpp)。


构建与编译

前置条件

  • 已安装可用的 Tang Runtime(默认路径 /usr/local/tangrt),并保证 include 与 lib 目录就位;
  • 编译环境可访问 Mooncake 仓库及其基础依赖。

CMake 配置与编译

# 克隆 Mooncake 仓库
git clone https://github.com/kvcache-ai/Mooncake.git
cd Mooncake

# 启用 TENT + Sunrise Link
mkdir build && cd build
cmake .. -DUSE_TENT=ON -DUSE_SUNRISE=ON

# 编译
make -j$(nproc)

如果 Tang Runtime 安装在非默认路径,通过 MC_TANGRT_ROOT 指定:

cmake .. -DUSE_TENT=ON -DUSE_SUNRISE=ON -DMC_TANGRT_ROOT=/opt/tangrt

从 CMake 源码可以确认 USE_SUNRISE 的完整影响面(在 mooncake-transfer-engine 目录下):

  • TENT 侧:tent/src/CMakeLists.txt 在 USE_SUNRISE 开启时向 tent_interface 注入 USE_SUNRISE 编译宏,并链接 ${MC_TANGRT_ROOT}/lib/linux-x86_64;tent/src/transport/sunrise_link/CMakeLists.txt 编译 tent_xport_sunrise_link 静态库并链接 ${SUNRISE_LIBRARIES};
  • 经典 TE 侧:src/transport/CMakeLists.txt 在 USE_SUNRISE 开启时引入 src/transport/sunrise_link 子目录并将 sunrise_link_transport 对象库并入 transport 目标;
  • Benchmark:benchmark/CMakeLists.txt 为 tebench 定义 -DUSE_SUNRISE、引入 Tang 头文件与库路径,并在 USE_SUNRISE 时链接 tangrt_shared、为 RPATH 追加 ${MC_TANGRT_ROOT}/lib。

USE_SUNRISE 还驱动了整个经典 TE benchmark 层的“CUDA 兼容接口”:benchmark/utils.h 在 USE_CUDA 未定义时包含 cuda_alike.h(gpu_vendor/sunrise.h),使 VRAM 分配、cudaMemset、指针属性判断等代码在 Sunrise 平台上以 Tang API 的封装形态运行(见 include/cuda_alike.h、include/sunrise_allocator.h)。


运行与测试

使用 transfer_engine_bench(经典 TE 后端)

transfer_engine_bench 支持 sunrise_link 协议,可用于基本连通性与性能验证(协议分发逻辑见 multi_transport.cpp)。

# 终端 1:目标端(Target)
./transfer_engine_bench \
  --mode=target \
  --protocol=sunrise_link \
  --local_server_name=10.0.0.2 \
  --metadata_server=P2PHANDSHAKE \
  --gpu_id=0

# 终端 2:发起端(Initiator)
./transfer_engine_bench \
  --mode=initiator \
  --protocol=sunrise_link \
  --metadata_server=P2PHANDSHAKE \
  --segment_id=10.0.0.2:$PORT \
  --gpu_id=0 \
  --block_size=8388608 \
  --batch_size=32

说明:当 metadata_server=P2PHANDSHAKE 时,目标端实际监听端口可能为动态分配端口。请以目标端日志中打印的实际端口替换 --segment_id 中的 $PORT。

transfer_engine_bench 的入口在 example/transfer_engine_bench.cpp,其中 use_vram、init_mem、gpu_id、block_size、batch_size 等 flag 在 USE_SUNRISE 编译路径下同样生效。

使用 tebench(TENT 后端)

角色由 --target_seg_name 决定:为空 → 目标端,否则 → 发起端。

# 终端 1:目标端
./tebench --backend=tent --metadata_type=p2p --xport_type=sunrise_link \
  --seg_type=VRAM --local_gpu_id=0

# 终端 2:发起端
./tebench --backend=tent --metadata_type=p2p --xport_type=sunrise_link \
  --seg_type=VRAM --target_seg_name=192.168.172.52:168 \
  --local_gpu_id=1 --target_gpu_id=0

tebench 的 TENT 后端实现位于 benchmark/tent_backend.cpp:VRAM 段在 USE_SUNRISE 下使用 cudaSetDevice(Tang 封装)完成设备切换与分配,并提供按 GPU 的线程绑核(pinThread)逻辑,因为 Tang 指针查询对线程所属设备上下文敏感。经典 TE 后端则位于 benchmark/te_backend.cpp,其中 USE_SUNRISE 路径下会显式安装 Sunrise Link Transport,确保 IPC 句柄在 benchmark 发起传输之前就由已安装的传输后端生成。

单元测试

仓库为 Sunrise Link 提供了三层测试,全部仅在 USE_SUNRISE 开启时编译(tests/CMakeLists.txt、tent/tests/CMakeLists.txt):


环境变量

变量 描述 默认值
MC_TANGRT_ROOT Tang Runtime 根目录 /usr/local/tangrt
MC_TANGRT_LIB_DIR .so 目录路径,直接指定后优先于 MC_TANGRT_ROOT + 架构查找 (未设置)
MC_TANGRT_LIB_ARCH <root>/lib/ 下的架构子目录 linux-x86_64

三者均作用于运行时 dlopen 的库定位(TangRtSharedObjectPath())。需要特别说明的是,MC_TANGRT_ROOT 同时是编译期变量(CMake 通过 -DMC_TANGRT_ROOT 指定),而 MC_TANGRT_LIB_DIR / MC_TANGRT_LIB_ARCH 是运行时环境变量,二者职责不同:前者决定头文件与链接目录,后者决定进程启动后从哪个路径加载共享库。


配置项说明(TENT)

Sunrise Link 支持通过配置文件调整行为。配置的读取入口有两处:install() 中读取 async_memcpy_threshold 并乘以 1024 换算为字节(sunrise_link_transport.cpp),startTransfer() 中读取 enable_port_striping(sunrise_link_transport.cpp),而 transports/sunrise_link/enable 由 TENT 传输加载器在装配传输列表时消费(transport_loader.cpp)。

选项 类型 描述 默认值
transports/sunrise_link/enable bool 是否启用该传输 true
transports/sunrise_link/async_memcpy_threshold int 触发异步 memcpy 的最小传输大小(MiB),设为 0 禁用异步路径 0
transports/sunrise_link/enable_port_striping bool 为大型跨设备拷贝(>4 MiB)启用多端口条带化 false

关键配置项的底层行为

  • async_memcpy_threshold:仅在存在可用 stream(stream && threshold > 0 && len >= threshold)时才走异步路径。异步任务在 getTransferStatus 中通过 tangStreamQuery 判断是否 tangSuccess(完成)或 tangErrorNotReady(未就绪)来推进状态机。注意:跨设备 peer 拷贝路径始终走同步 tangMemcpyPeer,异步仅作用于同设备与主机-设备路径。
  • enable_port_striping:当启用且本端到对端存在多个活跃端口(ports_sd.size() > 1)、且传输长度 ≥ 4 MiB(kMultiPortThreshold = 4ull << 20)时,将一次拷贝按端口数均分(余数分摊到前 rem 个 lane),逐 lane 调用 C2cMemcpyWithPeerMap 并行条带化传输,任一路失败即整体回退到单端口 peer copy。

可根据业务负载与设备拓扑(端口数量、带宽、传输块大小分布)微调上述参数。


注意事项与实现要点

  1. 设备上下文(Device Context):Transport 内部统一管理 tangSetDevice,并在查询前后通过 SavedTangDevice 保存/恢复原设备;直接调用 Tang API 时,需在查询指针属性前手动设置正确设备。
  2. IPC 句柄生命周期:远端地址通过 relocateRemoteAddress() 解析,tangIpcOpenMemHandle 打开的句柄缓存在 relocate_map_(带线程本地快照与 RWSpinlock),在 uninstall() 中统一 tangIpcCloseMemHandle 释放并 dlclose 两个动态库。
  3. 并发 Peer Copy:每设备互斥锁保护上下文相关操作(ScopedTangDeviceOps);跨设备拷贝按固定顺序(较低设备 ID 优先)获取源/目标锁,防止死锁;而 peer 拷贝本体不加全局锁以保障多线程吞吐。
  4. 映射主机指针规范化(Mapped Host Pointer Normalization):Sunrise S2 路径可能通过 tangHostAlloc 分配映射 GPU 内存,NormalizeMappedHostPointer() 通过 tangHostGetDevicePointer 取出对应的设备指针并更新属性,确保 peer copy 路径选择正确。
  5. 同设备 IPC 特判:当发起端与目标端使用同一 GPU ID(典型单卡 P2P bench 场景)时,指针实际是同一设备上下文内的 IPC 句柄,此时 tangMemcpyPeer 不适用,源码会直接走 tangSetDevice + tangMemcpy(DeviceToDevice)。
  6. 拓扑探测容错:单设备 ptmlPtlinkPhytopoDetect 失败仅告警并跳过,不影响整体安装;C2C 映射按 (local_chipid, remote_chipid) 去重,端口列表在条带化前会排序去重。

扩展阅读

登录后查看全文
Mooncake