Mooncake Ascend Transports
导言
我看到 Mooncake 为 Ascend 提供了三个编译开关:USE_ASCEND、USE_ASCEND_DIRECT 和 USE_UBSHMEM。最直接的问题是:它们是不是三套并列的通信 engine?特别是后两个名字里已经有 Direct 和 SHMEM,是否意味着数据传输已经由 AIV 直驱?
沿着合入 PR 和源码调用链看下去,答案逐渐清楚:这不是三套同层方案,而是 Mooncake 先后解决“能传”“通用地传”和“把远端内存映射后再传”三个问题留下的三条路径。更重要的是,按当前可见源码,三者都不能直接称为 AIV 直驱。
本文以 Mooncake main 在 2026-08-25 的提交 43365d45 为代码截面。后文沿已合入 PR、关联 Issue、Mooncake 文档、CANN API、HiXL 与 CANN SHMEM 开源代码展开,但不把不同强度的证据混在一起。
证据边界
事实由 PR、Issue、文档或源码直接支持;推断来自多处事实的合并,但项目没有直接宣告;判断用于选型和未来演进,只有在给定前提下成立。
先别急着比较开关¶
三个名字摆在 common.cmake 里,很容易让人把它们理解成三个可以自由叠加的后端:
USE_ASCEND → HCCL 低层内存传输 → 先让 Ascend 能接入 Transfer Engine
USE_ASCEND_DIRECT → ADXL/HiXL 一边引擎 → 统一多链路、多内存方向和异步请求
USE_UBSHMEM → CANN VMM/Fabric → 把远端物理内存映射成专用快路
但这三个箭头回答的并不是同一个问题。第一条更靠近 HCCL 内部 transport,第二条把能力收敛成通用传输 API,第三条则从传输协议进一步下沉到内存分配与映射。
构建方式也印证了这一点。Mooncake 的 common.cmake 同时声明三个开关,但 ascend_transport/CMakeLists.txt 使用 if / elseif / else 选择 HCCL、异构 HCCL、UBShmem 或 Direct 源文件;multi_transport.cpp 再把运行时协议映射到具体类。Direct 与 HCCL 都使用 ascend 协议名,只有 UBShmem 使用独立的 ubshmem。
独立选项不等于可叠加
PR #1399 的作者在 review 中确认 USE_UBSHMEM 应是 independent option,意思是它能够被单独选择,不必藏在 USE_ASCEND_DIRECT 之下。当前 CMake 的 elseif 又表明实现源文件按 flavor 选择。两句话并不冲突:配置入口独立,最终构建的 Ascend transport 仍基本互斥。
既然不是三条平行线,它们为什么会先后出现?要回答这个问题,最好不要从参数表开始,而是回到每一阶段遇到的具体困难。
三条路径怎样长出来¶
USE_ASCEND:先解决能不能传¶
第一阶段的约束很现实。Mooncake Transfer Engine 已经有统一的内存注册、segment metadata、batch transfer 和状态轮询接口,但 Ascend 端缺少可以直接接上的后端。PR #502 选择复用 HCCL 的低层传输组件:
- 同 HCCS 域内建立 IPC 类路径,跨 HCCS 域使用 RoCE 类路径。
- 注册本地内存,并把远端访问所需的信息传播给对端。
- 把 Transfer Engine 的读写切片翻译成
TransportMem::Read/Write。 - 用 ACL stream 和同步接口管理执行顺序与完成状态。
当前旧实现仍能在 hccl_transport.cpp 与 hccl_transport_mem_c.cpp 中看到:worker 创建 ACL stream,内存层初始化 HCCL dispatcher,根据拓扑创建 TransportMem,最终把请求落实到 Write/Read。
因此,USE_ASCEND 虽然依赖 HCCL,却不是为每个 KV block 调一次 AllReduce。它使用的是 HCCL 的低层内存传输能力,为 Transfer Engine 暴露一边读写。
推断:这是一条最快接通既有 HCCL 软硬件生态的桥梁,代价是 Mooncake 自己需要管理较多 HCCL 低层对象、版本差异和边界条件。随着支持矩阵扩大,这套实现的维护成本会逐渐高于专门的一边传输产品接口。
PR #619 随后增加批量同步传输、Debian 支持和一批修复。PR 报告,在其测试条件下,128 KB 非连续块使用 batch 接口,相比逐次 transferSync 的带宽提升超过 100%。这说明第一阶段很快从“接通”进入了性能和可部署性修整。
USE_ASCEND_DIRECT:再解决怎样通用地传¶
Issue #719 把下一阶段的目标写得很具体:同时覆盖 HBM/DDR、Device RDMA、SDMA、Host RDMA、同构与 A2/A3 异构部署。这样的组合已经不适合由 Mooncake 针对每条链路分别拼装。
PR #740 因此引入 Ascend Direct,把接口收敛为一条更稳定的生命周期:
Initialize engine
→ RegisterMem
→ Connect peer
→ TransferSync / TransferAsync
→ Query completion
→ Disconnect / DeregisterMem / Finalize
在当前 Mooncake 源码中,transfer_executor_base.cpp 创建 adxl::AdxlEngine,负责初始化、注册内存与连接;async_transfer_executor.cpp 组装 adxl::TransferOpDesc 并调用 TransferAsync。
这个变化的关键不是给旧实现换一个名字,而是重新划分责任:Mooncake 提交起点、终点和长度,ADXL/HiXL 负责处理 HCCS、RDMA、SDMA 或中转 buffer 等具体路径。
随后,PR #764 和 PR #856 分别处理 ADXL 错误码、CANN 版本与 TCP 端口问题。HiXL 开源后,Mooncake 又通过 PR #1037 和 PR #1049 短暂引入 hixl transport 名称,再改回面向用户的 Ascend Direct。
当前 HiXL 仓库把旧接口放在“待废弃 ADXL 接口”下,同时提供新的 HIXL API。这表示 ADXL 是可见 API 的旧名字,HiXL 是正在演进的产品与接口层。Mooncake 源码仍使用 adxl::AdxlEngine,所以不能仅凭上游仓库名称就声称 Mooncake 已完成 HIXL 新 API 迁移。
USE_UBSHMEM:再把问题下沉到内存语义¶
通用一边传输仍然遵循一个熟悉的模型:注册本地和远端内存,然后提交一条同时包含两端地址的传输描述符。Fabric Memory 想再往前走一步——让远端物理内存先被导出和映射,之后本地代码可以用映射地址表达远端读写。
PR #1170 先让 Store 的 Ascend Direct 支持 Fabric Memory 模式。Issue #1312 随后把目标描述为基于 CANN VMM API 的 “NVLink-like Transport”,作为 Ascend Direct 的补充;PR #1399 最终把它实现为独立的 UBShmemTransport 和 USE_UBSHMEM 开关。
这里的 “like” 只适合解释远端内存的可映射性和地址使用方式,不自动承诺与 NVIDIA NVLink 相同的缓存一致性、拓扑、指令集、带宽或故障语义。
独立 UBShmem path 带来了四个直接变化:
- 数据路径更专用:完成映射后,不再为每次传输调用 Mooncake 中的 ADXL
Transfer*,而是用 ACL runtime 对映射地址做异步 copy。 - 元数据更直接:传递 Fabric/IPC shareable handle、基址和长度,接收端导入后按 offset 重定位。
- Allocator 必须配套:上层需要从一开始就分配可导出的物理内存,不能把普通
aclrtMalloc的任意 buffer 事后变成 Fabric Memory。 - 并行度可以独立调优:PR #1591 用 worker 和 stream pool 改善大量 KV block 的批量传输。
PR #1519 又增加 MC_USE_UBSHMEM_IPC=1、Fabric allocator 和 Python NPU pluggable allocator,把能力扩展到同机跨进程 IPC。PR #3214 则用 100%、90% 一直回退到 50% 的 best-effort 分配改善启动成功率,并处理 1 GiB 对齐问题。
推断:UBShmem 不是为了证明 ADXL/HiXL 做不到 Fabric Memory,毕竟 #1170 已经证明 Direct 也有 Fabric 模式。它更像是把 Fabric Memory 从“通用引擎的一种内部能力”提取成 Mooncake 能显式选择、单独分配和单独调优的快路。
走到这里,三条路径的演进关系已经形成:
下一步需要停下来解释 VMM。否则,UBShmem 很容易被误读成“远端地址已经像本地指针一样可用”,进而又被误读成 AIV 直驱。
CANN VMM 到底做了什么¶
先用货架理解¶
传统 aclrtMalloc 像是一次性拿到“货架 + 仓库地址”的组合。VMM 把它拆成多个可分别管理的对象:
- 查询粒度:先确认物理内存最小按多大单位申请。
- 申请物理内存:
aclrtMallocPhysical真正获得物理内存,返回的是 handle,不是普通指针。 - 预留虚拟地址:
aclrtReserveMemAddress在当前进程留下连续地址,此时地址后面还没有内存。 - 建立映射:
aclrtMapMem把虚拟地址绑定到物理内存。 - 设置权限:指定哪些 Device 可以访问这段映射。
- 导出凭证:把物理内存 handle 转成跨进程或跨 Fabric 传递的 shareable handle。
- 远端导入:另一进程恢复 handle,在自己的地址空间重新 Reserve、Map 和 SetAccess。
可以继续用两个仓库来理解其他容易混淆的术语:
- One-sided / RMA:A 仓库发出“把货放到 B 的 3 号货架”,不要求 B 的管理员同步调用一次
recv。 - Zero-copy:货物尽量从源货架直接运到目标货架,中间不再落到临时仓库倒一次。
- Direct transport:运输公司根据条件选择内部高速通道或跨园区道路,用户只提交起点、终点和长度。
- Fabric Memory:B 把某些货架通过共享凭证开放给 A,A 在自己的地址簿里为它们安排地址。
- AIV 直驱:A 的现场工人自己填写硬件能识别的工作单并提交,不必为每一批货回到 Host/AICPU 调度员。
这五件事可以组合,却不互相蕴含。货架出现在本地地址簿里,不代表 AIV 获得了提交通信任务的权限;数据没有经过中转 buffer,也不代表 Host 没有参与下发。
地址为什么需要重定位¶
两边的虚拟地址不必相同。因此,发送端告诉接收端的不能只是一枚裸指针,而应包含共享 handle、原始基址、长度、设备与协议属性。接收端导入后,需要按照偏移重定位:
一个地址为什么能指向远端内存
假设对端导出一段 1 GiB 物理内存,原始基址为 B_remote。Mooncake 请求读取其中偏移 64 MiB 的 KV block。接收端把相同物理内存导入并映射到本地虚拟基址 B_local,实际提交给 ACL copy 的地址是 B_local + 64 MiB,而不是直接使用对端进程的裸指针。
这个类比有三个边界:
- 映射不是普通 CPU 共享内存,不能假设硬件缓存自动一致。
- 地址可以表达,不等于任意节点都物理可达;拓扑、芯片、驱动和 Fabric 域仍有限制。
- copy API 返回或入队,不等于数据已经完成;必须用 stream、event 或 request 建立完成边界。
回到真实对象¶
CANN 官方 aclrtMallocPhysical 文档明确说明:接口申请 Device 物理内存并返回 handle,可与 Reserve/Map 配合获得连续虚拟地址,也可与 Export/Import 配合实现多进程物理内存共享。Mooncake UBShmem 在此基础上增加远端 metadata、地址重定位、worker 和完成状态。
一段 Fabric Memory 的完整生命周期是:
查询 allocation granularity
→ 填写 aclrtPhysicalMemProp
→ aclrtMallocPhysical 得到 physical handle
→ aclrtReserveMemAddress 得到本地 VA range
→ aclrtMapMem 建立 VA→physical 映射
→ aclrtMemSetAccess 设置访问权限
→ aclrtMemExportToShareableHandleV2 导出 Fabric handle
→ 通过 Mooncake metadata 分发 handle、base、size
→ 对端 aclrtMemImportFromShareableHandle 导入
→ 对端 Reserve + Map + SetAccess
→ 按 offset 计算 mapped remote address
→ aclrtMemcpyAsync 提交 read/write
→ 同步 stream 或检查 event 后标记 slice 成功
→ Unmap / FreeAddress / ReleasePhysical 清理
这里至少有五类对象不能混为一谈:
| 对象 | 作用 | 生命周期错误的后果 |
|---|---|---|
| Physical handle | 代表一段实际 Device 物理内存 | 过早 release 会使所有映射失效 |
| Virtual address range | 当前进程的地址表达 | 不能跨进程直接复用裸地址,需要重定位 |
| Shareable handle | 把物理内存能力传给其他参与者 | 泄漏会扩大未授权访问面 |
| ACL stream/event | 建立 copy 顺序与完成边界 | 入队即标成功会让上层过早复用或释放 buffer |
| Mooncake segment metadata | 连接协议名、engine、handle、base 与 size | 过期或拓扑变化会导致错误导入、越界或不可达 |
PR #1399 的 review 恰好暴露了两个边界:
- 初版在
aclrtMemcpyAsync入队后过早markSuccess();review 后改为同步 stream 再标记完成。VMM 解决寻址,不能替代完成语义。 - 导出使用
ACL_RT_VMM_EXPORT_FLAG_DISABLE_PID_VALIDATION,review 指出它可能扩大 handle 的导入范围。共享能力越强,凭证分发与隔离越重要。
把类比和真实对象对齐后,关系如下:
| 比喻 | 技术对象 | 对应 Mooncake 行为 |
|---|---|---|
| 物理货架 | aclrtDrvMemHandle 背后的 Device physical memory |
Fabric allocator 申请可导出的大页物理内存 |
| 本地门牌 | reserved virtual address | 每个进程分别保留地址,数值不要求相同 |
| 门牌绑定货架 | aclrtMapMem |
使本地 VA 指向导入的本地或远端物理内存 |
| 仓库通行证 | Fabric/IPC shareable handle | 经 Mooncake metadata 交给对端导入 |
| 访问名单 | aclrtMemSetAccess |
授予目标 Device 对映射区域的访问权限 |
| 搬运单 | aclrtMemcpyAsync 参数 |
指定 read/write 的本地地址、映射地址和长度 |
| 确认回执 | stream/event/request completion | 完成后才能让上层复用、释放或消费 KV block |
VMM 的责任到这里就结束了:它让一段物理内存可以被分配、共享和映射,却没有回答“谁来提交通信任务”。这正是 AIV 直驱要回答的另一个问题。
Direct 为什么不等于 AIV 直驱¶
Direct 之所以容易误导,是因为它同时出现在数据路径和控制路径的讨论里。真正的分界线其实只有一个:谁在提交通信任务。把术语放在同一张坐标表中,会更容易看清它们各自保证什么:
| 概念 | 它真正回答的问题 | 它不保证什么 | Mooncake 对应 |
|---|---|---|---|
| One-sided / RMA | 一次远端读写是否要求对端 CPU 同步匹配操作 | 不保证没有 Host 发起,也不保证零拷贝 | HCCL TransportMem、ADXL、Fabric 映射都可表现为一边访问 |
| Zero-copy | 是否避免额外 bounce buffer 或 CPU staging copy | 不保证没有内存注册、描述符和控制面 | Direct 满足条件时可直传;小块或未注册内存可能走 buffer pool |
| Direct transfer | 注册内存是否通过 HCCS/RDMA/SDMA 等直接搬运 | 不保证提交者是 AIV | USE_ASCEND_DIRECT 的核心语义 |
| VMM | 物理内存、虚拟地址、映射、权限和共享 handle 能否分别管理 | 不定义传输协议和完成同步 | USE_UBSHMEM 的内存基础 |
| Fabric Memory | 共享物理内存能否被导出、导入并映射 | 不自动提供缓存一致性或任意拓扑可达性 | Direct Fabric mode 与 UBShmem 都涉及 |
| AIV 直驱 | AIV Kernel 是否在 Device 侧准备并提交通信任务 | 不代表 AIV 亲自搬字节,也不保证峰值带宽更高 | 当前三条 Mooncake 路径均缺少这一证据 |
判断 AIV 直驱,可以检查四件事:
- 是否存在运行在 AIV/Vector Core 上的 Device Kernel?
- 通信描述符、WQE 或 SQE 是否由该 Kernel 在 Device 侧准备?
- 是否由 AIV 执行 doorbell 或等价提交,而不是每次回到 Host/AICPU?
- 完成状态是否能在 Device 侧被观察,并继续推进计算或通信流水?
满足 one-sided、zero-copy、VMM 或 Fabric Memory,都不能代替这四项。
真正的对照证据可以在 CANN SHMEM 开源代码中看到。以 2026-08-25 的 dca9886a 提交为截面,SDMA Device helper 明确写有 AIV direct STARS、准备 SQE 并 ring doorbell;UDMA Device helper 和 RDMA Device backend 则明确出现准备 WQE 与 ring doorbell。这类代码才是 AIV 直驱的强证据。更完整的概念说明可参考 AIV Direct Drive。
HCCL 路径¶
Mooncake 的可见调用链是:
Mooncake Host worker
→ 选择 slice
→ TransportMem::Write / Read
→ ACL stream
→ HCCL/transport 执行与同步
→ markSuccess
HCCL 本身支持 AIV communication engine;例如 HCCL_OP_EXPANSION_MODE=AIV 可让特定通信算子在 AI Vector Core 展开。vLLM Ascend 的调优文档 也把 AIV engine 描述为 Vector Core 直接调度 RoCE、减少 AICPU 中介。
这个事实为什么不能直接套到 Mooncake?因为 Mooncake 在这条路径中没有调用已声明 AIV expansion 的 AllReduce/AlltoAll 等 collective,也没有设置可见的 AIV expansion mode 或启动 AIV 通信 Kernel。TransportMem 内部可能随闭源库版本选择不同机制,但“可能”不能作为架构归类的证据。
结论:不能认定为 AIV 直驱,按可见实现应归为 Host 驱动的 HCCL 低层 RMA。
Ascend Direct 路径¶
Mooncake 的调用链是:
Mooncake Host executor
→ AdxlEngine::RegisterMem / Connect
→ AdxlEngine::TransferSync / TransferAsync
→ ADXL/HiXL 内部选择 HCCS、RDMA、SDMA 或 buffer path
→ Host 查询 request 或等待完成
ADXL 旧接口文档还指出,小于 256 KiB 或存在未注册内存时可能启用中转 buffer pool。这再次说明:Direct 是目标抽象,不保证每个请求在所有条件下都严格零中转。
对当前上游 HiXL 源码的旁证也要谨慎使用。2026-08-25 的 499e6c33 版本中,Fabric Memory engine 默认可启用 FabricMemAicpuTransferService,Host service 路径则调用 aclrtMemcpyAsync。这至少证明公开实现中存在 Host 与 AICPU 展开路径,不能把 HiXL/Fabric 自动等同于 AIV。
Mooncake 实际链接的 CANN/ADXL 版本可能不同,所以这份证据只能否定“必然 AIV”,不能宣称所有 ADXL 实现永远不会增加 AIV backend。
结论:不是 Mooncake 接口层的 AIV 直驱,而是 Host 调用 ADXL/HiXL 的一边直传。
UBShmem 路径¶
ubshmem_transport.cpp 的关键动作是:导入或映射 Fabric/IPC handle,计算映射后的地址,Host worker 在 ACL stream 上调用 aclrtMemcpyAsync,最后同步 stream 并更新 slice 状态。
Host metadata/import
→ CANN VMM 映射远端物理内存
→ Host 调用 aclrtMemcpyAsync(mapped_addr)
→ runtime / DMA path 搬运
→ Host stream synchronization
这里没有 CANN SHMEM Device API,没有 AIV Kernel,也没有由 AIV 准备 WQE/SQE 和 ring doorbell 的代码。UBShmemTransport 使用的是 UB/Fabric Memory 语义,但当前 Mooncake 实现并不是对 CANN shmem Device 编程库的直接封装。
至于 aclrtMemcpyAsync 最终在某款芯片、某个 CANN 版本和某种映射类型下由 SDMA、HCCS 还是其他 runtime engine 完成,Mooncake 公开层没有给出足以覆盖所有组合的答案。可以确认提交者是 Host API,不能越过证据声称特定物理 engine。
结论:当前明确不是 AIV 直驱。
三条路径放在同一套判据下,结果如下:
| 检查项 | HCCL path | Ascend Direct | UBShmem | 真正 AIV SHMEM/URMA 路径 |
|---|---|---|---|---|
| 一边远端访问 | 是 | 是 | 是 | 是 |
| 可实现零拷贝 | 条件满足时 | 条件满足时 | 映射后可避免传统中转 | 是 |
| VMM/Fabric 映射 | 不是核心 | 可选 Fabric mode | 是,核心机制 | 可以组合使用 |
| AIV Device Kernel 可见 | 否 | 否 | 否 | 是 |
| AIV 准备 WQE/SQE | 否 | 否 | 否 | 是 |
| AIV ring doorbell | 否 | 否 | 否 | 是 |
| AIV 直驱结论 | 否/无证据 | 否 | 否 | 是 |
性能数字能说明什么¶
#1399:大块吞吐不错,但缺少横向对照¶
PR #1399 使用 transfer-engine-bench、12 个 initiator thread、batch size 1 测 D2RD。作者给出的结果是:
| Block size | Write GB/s | Read GB/s |
|---|---|---|
| 64 KiB | 7.76 | 8.34 |
| 128 KiB | 15.77 | 15.73 |
| 256 KiB | 31.86 | 30.27 |
| 512 KiB | 60.49 | 58.31 |
| 1 MiB | 108.83 | 108.57 |
| 2 MiB | 118.57 | 148.85 |
| 4 MiB | 131.45 | 158.17 |
| 8 MiB | 134.60 | 162.70 |
| 12 MiB | 135.69 | 164.20 |
应使用 PR 作者原表,而不是 bot summary 中的 “199.14 GB/s”;后者与原始表格不一致。
这组数字能够支持“UBShmem 在大块下达到较高吞吐”,却不能独立证明它优于 Direct。PR 没有给出同环境的三后端对照,硬件拓扑、CANN/驱动版本、预热和重复次数也不充分。
#1591:Fabric 与并行度才是主变量¶
PR #1591 在单机 16 NPU 的 Store 场景中比较非 Fabric Direct、Direct Fabric、原始 UBShmem 和 stream-pool UBShmem:
| Key 数量 | Direct | Direct Fabric | UBShmem | UBShmem stream pool |
|---|---|---|---|---|
| 32 | 62.78 ms | 21.29 ms | 28.49 ms | 21.10 ms |
| 64 | 123.90 ms | 40.86 ms | 56.04 ms | 41.66 ms |
| 128 | 262.77 ms | 78.27 ms | 115.94 ms | 80.22 ms |
| 256 | 518.35 ms | 156.23 ms | 234.38 ms | 164.27 ms |
| 512 | 1017.84 ms | 311.96 ms | 463.01 ms | 326.15 ms |
在 512 keys 点上,Direct Fabric 相对非 Fabric Direct 约为 3.26 倍,stream-pool UBShmem 约为 3.12 倍;Direct Fabric 只比 stream-pool UBShmem 快约 4.35%。32 keys 时,UBShmem stream pool 甚至略快于 Direct Fabric。
这组对照把主变量暴露得更清楚:
- Fabric Memory 能力贡献了主要差距。非 Fabric Direct 与另外两条 Fabric path 的差距最大。
- 并行提交与同步结构是第二个关键因素。原始 UBShmem 到 stream pool 的提升说明单 stream、串行 worker 会浪费 Fabric 带宽。
- 结果没有呈现“因为 AIV 直驱而额外领先”的形状。UBShmem 事实上不是 AIV 直驱,优化后的曲线与 Direct Fabric 很接近。
- 证据只覆盖单机单 workload。跨节点、不同 block size、并发租户、芯片和 CANN 版本仍需重新测量。
换句话说,这些性能数据更支持“Fabric Memory + 并行度”的解释,而不是“AIV 直驱”的解释。
实际应该怎样选择¶
理解演进和 AIV 判据后,再做横向比较就不会只盯着名字:
| 维度 | USE_ASCEND |
USE_ASCEND_DIRECT |
USE_UBSHMEM |
|---|---|---|---|
| 对外 protocol | ascend |
ascend |
ubshmem |
| Mooncake 类 | HcclTransport |
AscendDirectTransport |
UBShmemTransport |
| 建链抽象 | HCCL socket、dispatcher、TransportMem |
AdxlEngine::Connect |
分发 handle,导入并映射远端物理内存 |
| 内存准备 | HCCL registration/export/grant | AdxlEngine::RegisterMem |
MallocPhysical、Reserve、Map、SetAccess、Export/Import |
| 单次提交 | TransportMem::Write/Read |
TransferSync/TransferAsync |
aclrtMemcpyAsync |
| 完成方式 | ACL stream 同步与 slice 状态 | ADXL request/同步接口 | stream pool 同步后标记 slice 完成 |
| 链路选择 | Mooncake/HCCL 处理 IPC、RoCE 等 | ADXL/HiXL 选择 HCCS/RDMA 等 | ACL/Fabric runtime;公开层不说明具体搬运 engine |
| Host 内存支持 | 取决于旧实现能力 | 文档明确覆盖 H2D、D2H、D2D | 核心目标是 Device Fabric Memory,不是通用 Host RDMA |
| 跨机通用性 | 可用但维护负担较高 | 三者中最通用 | 依赖可达域、芯片和 CANN/驱动能力 |
| 当前定位 | 文档提示废弃 | 推荐主路径 | 特化补充与优化路径 |
落到部署选择,可以按问题而不是按名字判断:
- 新部署需要跨节点、Host/Device 多种方向和通用容错:优先 Ascend Direct,除非当前 CANN/驱动组合只验证过旧 HCCL path。
- 必须兼容已有旧版本环境:保留
USE_ASCEND,但把迁移 Direct 纳入计划,因为 Mooncake 当前 Ascend Transport 文档 已明确提示废弃。 - A3 Fabric Memory 域内搬运大量 KV block,而且能控制 allocator 与进程模型:评估 UBShmem,并与 Direct Fabric mode 做同硬件 A/B,不要只和非 Fabric Direct 比。
- 目标是让算子 Kernel 自己发起细粒度通信:三个开关都不是充分条件,需要调研 CANN SHMEM/URMA Device API 或 HCCL AIV engine,并重新设计 Transfer Engine 的 Device 队列和完成机制。
当前 Mooncake 构建文档 对 UBShmem 给出的门槛包括 CANN 9.0.0 及以上、Driver 26.0.0 及以上和 Lingqu 1.5 及以上。它不是打开一个 CMake 开关就能在任意 Ascend 机器上工作的通用共享内存。
如何做同条件 A/B
在同一机器、同一 allocator、同一 KV block 分布下,至少比较 ascend、ascend + Fabric 和 ubshmem 三组;同时记录小块延迟、聚合带宽、CPU/AICPU/AIV 占用、内存注册时间、Fabric 大页申请成功率和错误恢复。只拿 #1399 的峰值数字与另一台机器上的 Direct 数字比较没有意义。
证据还缺在哪里¶
现在仍有七个问题不能从现有材料中确定:
aclrtMemcpyAsync的物理执行 engine:在不同芯片、Fabric 映射类型和 CANN 版本下究竟使用 SDMA、HCCS 还是其他路径,需要对应版本的官方说明或 profiler trace,不能从函数名推断。- 三个开关的正式组合矩阵:当前 CMake 表明它们基本互斥,但文档没有列出所有非法组合及配置时报错行为。
- #1399 基准环境:缺少完整芯片型号、拓扑、CANN/Driver/Lingqu、NUMA、预热、重复次数和误差条,峰值数字只适合作为开发者自测。
- Fabric handle 的多租户隔离:
DISABLE_PID_VALIDATION的使用边界、容器隔离和 handle 分发授权需要安全设计,不能只依赖 metadata 不泄漏。 - ADXL 到 HIXL 的迁移时间:上游已把 ADXL 文档标为待废弃,但 Mooncake 尚未给出公开完成日期。
- A2/A3/950 的能力差异:VMM API 存在,不等于 Fabric Memory transport 在所有产品上等价可用;API、Fabric handle、跨卡拓扑和性能需要分别验证。
- 失败恢复语义:远端进程退出、handle 失效、Fabric 映射断开或 stream 超时时,Store 如何对 segment、replica 和正在消费的 KV block 做原子回滚,仍需故障注入验证。
回到最初的问题¶
现在可以重新回答开头的两个问题。
USE_ASCEND、USE_ASCEND_DIRECT 和 USE_UBSHMEM 不是三个并列的 HCCL engine,而是三次能力下沉留下的路径:HCCL 先解决可用性,ADXL/HiXL 收敛通用直传,CANN VMM/Fabric Memory 再提供专用映射快路。它们的配置入口独立,当前构建产物却基本按 flavor 二选一。
它们也都不能仅凭 one-sided、zero-copy、Direct 或远端内存映射,被称为 AIV 直驱。当前能看到的是 Host worker、AdxlEngine::Transfer* 或 aclrtMemcpyAsync;真正改变结论所需的证据,是 AIV Device Kernel 准备 WQE/SQE、提交 doorbell 并在 Device 侧推进完成状态。
至于底层 runtime 在特定芯片和 CANN 版本中最终选择哪种物理搬运 engine,现有公开材料还不能覆盖所有组合。部署时最稳妥的做法仍然是:新环境优先验证 Ascend Direct,Fabric 域内再对 Direct Fabric 与 UBShmem 做同条件 A/B;如果目标真的是算子内 AIV 发起通信,就把它当成另一项独立设计,而不是从这三个开关的名字反推。
附录:完整时间线¶
主线只保留了推动架构变化的节点。完整合入过程如下:
| 时间 | 事件 | 直接变化 | 动机与意义 |
|---|---|---|---|
| 2025-06-16 至 07-01 | PR #502 合入 | 引入 USE_ASCEND、HCCL 相关依赖、内存注册、连接与 D2D 传输 |
先让 Transfer Engine 在 Ascend 上可用;复用 HCCL 的 HCCS/RoCE 能力,而不是从零实现传输栈 |
| 2025-07-12 至 07-18 | PR #619 合入 | 增加批量同步传输、Debian 支持与修复 | 早期路径进入性能与可部署性修整;PR 报告 128 KB 非连续块批传带宽较逐次 transferSync 提升超过 100% |
| 2025-08-06 | Issue #719 提出 | 要求高性能零拷贝 P2P,覆盖 Device RDMA、SDMA、Host RDMA 与 A2/A3 异构场景 | 项目需要的不只是“Ascend 可用”,而是完整、稳定的直传抽象 |
| 2025-08-13 至 08-18 | PR #740 合入 | 引入 USE_ASCEND_DIRECT 与 Ascend Direct transport |
将链路、注册和异步请求交给 ADXL,减少 Mooncake 自己拼装 HCCL 低层对象 |
| 2025-08 至 09 | PR #764、PR #856 | 适配 ADXL 错误码、CANN 版本并修复 TCP 端口问题 | Direct 从原型进入版本兼容和连接可靠性修复阶段 |
| 2025-10 至 11 | HiXL 开源;PR #1037、PR #1049 | 曾引入 hixl transport 名称,随后改回 Ascend Direct |
底层产品向 HiXL 演进,对外名称保持稳定 |
| 2025-12-05 至 12-27 | PR #1170 合入 | Store 的 Ascend Direct 支持 Fabric Memory 模式与特殊 Host 分配 | Fabric Memory 先作为 Direct 的能力进入 Store,早于独立 UBShmem |
| 2025-12-31 | Issue #1312 提出 | 建议用 CANN VMM 支持 Fabric Memory,作为 Direct 的 NVLink-like 补充 | 目标下沉到远端内存可映射的内存语义 |
| 2026-01-18 至 01-26 | PR #1399 合入 | 新增 USE_UBSHMEM、VMM Fabric handle 与准确性测试 |
Fabric Memory 成为独立协议和专用数据路径 |
| 2026-02-09 至 02-14 | PR #1519 合入 | 增加 IPC mode、Fabric allocator 和 Python NPU allocator | 扩展到同机跨进程,并解决上层怎样获得可共享内存 |
| 2026-03-02 | PR #1591 合入 | 8 个 worker、每请求 4 个 stream;接入 Store | 修补串行同步和单 stream 的并行度不足 |
| 2026-07 至 08-05 | PR #3214 合入 | Fabric 内存从 100% 逐步回退到 50%,1 GiB 对齐,优先 ADXL 分配 | 处理大页粒度、连续容量、碎片和启动成功率 |
两个 Issue 的最终状态容易制造误读:#719 和 #1312 后来都因 stale 流程被标记为 not_planned 或关闭,但核心能力分别已通过 #740 和 #1399 合入。Issue 的管理状态不是“功能从未实现”的证据。
附录:可能的演进¶
以下都是判断,不是 Mooncake 已经宣布的 roadmap。
Direct 迁移到 HIXL 新接口¶
中期最自然的方向,是保留 Ascend Direct 这个用户概念,同时把 Mooncake 内部从待废弃的 adxl::AdxlEngine 迁到 HIXL 新 API。
- 成立前提:HIXL 新接口覆盖注册内存、异步 batch、错误码、连接恢复和 Fabric Memory。
- 领先信号:Mooncake 出现
hixl::Hixl头文件与对象,构建依赖不再使用 ADXL compatibility API,Direct 文档开始区分 HIXL 版本。 - 反向信号:上游长期维护 ADXL 兼容层,Mooncake 实测迁移收益不足,或新接口缺少关键异步能力。
Fabric 能力向 Direct 收敛¶
Direct Fabric 与 stream-pool UBShmem 的性能接近,allocator 逻辑又在 PR #3214 中趋于共享。因此,Fabric Memory 未来可能更像 Direct 的 capability,而不是长期维护完全平行的 transport。
- 成立前提:Direct 能暴露与 UBShmem 一样可控的 allocator、IPC/Fabric mode、stream 并行度和错误恢复。
- 领先信号:构建系统不再用独立源文件 flavor,运行时根据 topology/capability 自动选择 Fabric path,
ubshmemprotocol 被兼容映射到ascend。 - 反向信号:独立 VMM path 在部署体积、依赖、调优自由度或新硬件适配速度上持续明显优于通用 HIXL。
真正 AIV transport 以新后端出现¶
如果 Mooncake 要服务算子内细粒度 KV/EP 通信,真正 AIV 直驱更可能以 CANN SHMEM/URMA/TENT/UB Device backend 或新的 Device queue 进入,而不是悄悄把现有三个开关中的某一个改名为 AIV。
- 成立前提:Transfer Engine 能把远端地址、队列、权限和完成状态安全地交给 Device Kernel,并支持 persistent kernel 或 kernel 内批量提交。
- 领先信号:源码出现
shmem_device_*、AIV kernel、WQE/SQE、doorbell 和 Device-side completion;基准重点转向小消息控制时延与通算重叠。 - 反向信号:Mooncake 的主工作负载仍是 Host 调度的大块 KV bulk copy,Host 提交成本相对链路时间很小,额外占用 AIV 反而挤压计算资源。
AIV 直驱未必是终点
AIV 直驱主要缩短细粒度控制路径并改善通算流水。对于数 MiB 以上的大块 KV,一次 Host 提交的固定开销可能已被传输时间摊薄;此时 Fabric 映射、并行 stream、批处理、拓扑路由和内存分配成功率,可能比“由谁敲 doorbell”更重要。
附录:误解与自检¶
四个常见误解可以作为快速检查:
- “用了 HCCL 就是集合通信。”这里主要复用
TransportMem做一边读写,不是为每个 KV block 调AllReduce。 - “Ascend Direct 就是 AIV Direct。”前者是 transport 名,后者描述 Device 侧控制路径;Mooncake 当前 Direct 由 Host 调 ADXL。
- “VMM 映射后就是缓存一致的全局内存。”VMM 提供地址与物理内存映射,不自动提供 CPU 式缓存一致性、任意拓扑可达或完成顺序。
- “UBShmem 已接入 CANN SHMEM Device API。”当前 Mooncake 类使用 CANN VMM 与 ACL copy,未出现 CANN SHMEM 的 AIV Device 调用链。
如果希望确认自己已经分清五个维度,可以继续回答三个问题:
- 一个 transport 同时满足 one-sided 和 zero-copy,但每次请求都由 Host 调用异步 API 提交,它是否属于 AIV 直驱?需要哪类新增证据才能改变结论?
- 为什么
aclrtMemImportFromShareableHandle成功后仍不能直接使用导出进程的原始虚拟地址?Mooncake metadata 至少需要保留哪些字段才能正确重定位? - 如果同一环境下 Direct Fabric 与 UBShmem stream pool 的延迟接近,但非 Fabric Direct 慢三倍,最应该优先验证的性能假设是什么?哪些指标能够把 Fabric 能力、并行度和提交者身份的贡献分开?
参考文献¶
- Mooncake PR #502:首个 Ascend HCCL transport
- Mooncake Issue #719:Ascend Direct 需求
- Mooncake PR #740:Ascend Direct 实现
- Mooncake PR #1170:Ascend Direct Fabric Memory
- Mooncake Issue #1312:CANN VMM 与 Fabric Memory 需求
- Mooncake PR #1399:UBShmem transport
- Mooncake PR #1519:UBShmem IPC allocator
- Mooncake PR #1591:stream pool 与 Store 接入
- Mooncake PR #3214:Fabric Memory best-effort allocation
- Mooncake Ascend Direct 文档
- CANN VMM:aclrtMallocPhysical
- HiXL:待废弃 ADXL 接口
- CANN SHMEM 开源仓库
- vLLM Ascend:AIV HCCL engine 调优说明