HIXL C++ 样例实战指南:KvCache 分离部署传输与 D2D/D2H 单边通信
【免费下载链接】hixlHIXL(Huawei Xfer Library)是一个灵活、高效的昇腾单边通信库,面向集群场景提供简单、可靠、高效的点对点数据传输能力。项目地址: https://gitcode.com/cann/hixl
导读
本文围绕 CANN HIXL 开源仓库 examples/cpp 下的 C++ 样例展开,系统讲解两类典型场景的落地方法:一类是基于 LLM-DataDist 接口实现的KvCache 分离部署(disaggregated serving)传输(pull / push cache 与 blocks、角色切换),另一类是基于 HIXL 原生接口实现的Device-to-Device(D2D)、Device-to-Host(D2H)单边通信(含单进程、多进程与 FabricMem 模式)。阅读本文后,你将掌握每个样例的源码结构、命令行参数、编译方式、运行前提与协议选择策略,并理解其背后的Initialize / RegisterKvCache / TransferSync / RegisterMem等核心调用链,可直接在昇腾 A2 / A3 / A5(Ascend 950PR/950DT)集群环境中复现与二次开发。
样例整体介绍与目录结构
本目录的样例通过 LLM-DataDist、HIXL 接口实现分离部署场景下 KvCache 传输功能。其中 LLM-DataDist 系列用于 Prompt/Decoder 分离部署时缓存与 KV block 的传输,HIXL 系列用于展示单边通信的多种协议与运行形态。
examples/cpp/ ├── prompt_pull_cache_and_blocks.cpp // pull cache 和 pull blocks 的 prompt 侧实现 ├── decoder_pull_cache_and_blocks.cpp // pull cache 和 pull blocks 的 decoder 侧实现 ├── prompt_push_cache_and_blocks.cpp // push cache 和 push blocks 的 prompt 侧实现 ├── decoder_push_cache_and_blocks.cpp // push cache 和 push blocks 的 decoder 侧实现 ├── prompt_switch_roles.cpp // switch_roles 的 prompt 侧实现 ├── decoder_switch_roles.cpp // switch_roles 的 decoder 侧实现 ├── hixl_example_d2rd.cpp // HIXL D2rD 单进程场景样例 ├── hixl_example_d2rh.cpp // HIXL D2rH 单进程场景样例 ├── hixl_example_d2rd_multiproc.cpp // HIXL D2rD 多进程场景样例 ├── fabric_mem_d2d.cpp // HIXL fabric-mem 模式下的 d2d 场景样例 └── CMakeLists.txt // 编译脚本从编译脚本 examples/cpp/CMakeLists.txt 可以看到目标名称与源文件同名,其中前 6 个 LLM-DataDist 样例链接llm_datadist库,而hixl_example_d2rd、hixl_example_d2rh、hixl_example_d2rd_multiproc、fabric_mem_d2d以及仓库另附的hixl_example_quickstart链接cann_hixl库,二者均依赖acl_rt与ascend_hal。
环境与配置前提
A5 环境的 RDMA 链路说明
下面个别用例支持在 A5 环境使用 RDMA 链路执行,且需要在双机上执行,会在对应用例中特别说明。在 A5 环境中未手动配置local_comm_res时默认使用 UB 协议;如果需要使用 RDMA 链路,需要手动配置local_comm_res,配置方法参考 HIXL-interface.md 中 Initialize 的 options(Ascend 950PR/Ascend 950DT)说明。可通过以下操作获取 host 网卡的 IP 信息:
# 查询 RoCE 设备和网口的对应关系,查看状态为 Up 的网口名 ibdev2netdev # 根据网口名找出对应的 IP 信息 ifconfig从接口文档对OPTION_LOCAL_COMM_RES的描述可以确认,A5(950PR/950DT)上配置local_comm_res的version为"1.3"时使用 HixlCS 能力建链(推荐,需要 HDK 大于等于 25.5.0 且 toolkit 大于等于 9.1.0),无链路上限限制;而version为"1.0"/"1.2"的 ranktable 格式则走集合通信通信域方式建链,建议单卡建链数量不超过 512。生产环境建议通过 scripts/tools/hixl_tool 工具辅助生成真实环境的 localcommres 信息,切勿直接拷贝样例值。
软件包与驱动
执行所有样例前,需要确保已经安装驱动和固件;执行 Python 样例前还需要安装 ops 包。构建编译需要 Toolkit 开发套件包,安装方式可参考 源码构建,包括 Docker 部署与手动安装两种场景(A5 容器还需要额外挂载/dev/ummu、/dev/uburma设备与driver/topo目录)。
程序编译
参考 源码构建 中的编译执行章节,利用bash build.sh --examples进行编译:
# 若源码未改动或修改不涉及 src/ops 下的代码,建议添加 --host 参数 bash build.sh --examples bash build.sh --host --examples编译结束后,在build/examples/cpp目录下生成多个可执行文件,其名称与上表源文件名一一对应。编译依赖的第三方开源软件(googletest、json、makeself、pybind11、cann-cmake)会在编译时自动下载,离线环境可通过--cann_3rd_lib_path={your_3rd_party_path}指定已上传的依赖包目录。
LLM-DataDist 样例:分离部署 KvCache 传输
通用运行说明
- 所有样例需要成对运行,prompt 侧和 decoder 侧执行间隔时间不要过长。样例中 decoder 侧设置
WAIT_PROMPT_TIME为 5s,prompt 侧设置WAIT_TIME为 10s,用户可根据实际情况自行修改这两个变量的值以保证用例成功运行。 - 下面所有样例以 prompt 和 decoder 运行在相同机器上为前提编写,将
local_ip和remote_ip设为相同。
以 prompt_pull_cache_and_blocks.cpp 为例,源码中定义kPromptListenPort = 26000、kPromptControlPort = 26002、kPromptClusterId = 0、kNumTensors = 4、tensor shape 为{8, 16}(DT_INT32类型),并接受device_id、local_ip、可选transfer_backend、可选local_comm_res共 2~4 个参数。
配置环境变量
若运行环境上安装的是 “Ascend-cann-toolkit” 包,环境变量设置如下(${HOME}/Ascend请替换为相关软件包的实际安装路径):
source ${HOME}/Ascend/cann/set_env.sh若运行环境上安装的是 “CANN-XXX.run” 包,环境变量设置如下:
source ${HOME}/Ascend/latest/bin/setenv.bash(1)pull_cache_and_blocks:decoder 向 prompt 拉取
此样例介绍 decoder 向 prompt 进行 pull cache 和 pull blocks 的流程,其中 link 和 pull 的方向与角色无关,可以根据需求更改。默认走 adxl 传输后端;可选参数transfer_backend传hixl可切换为 hixl cs 后端。A5 环境上只支持使用 hixl cs 后端,默认走 UB 协议,可手动配置local_comm_res走 RDMA 链路。
执行 prompt 侧,参数为
device_id、local_ip、可选transfer_backend与local_comm_res,其中device_id为 prompt 要使用的 device_id,local_ip为 prompt 所在 host 的 IP:./prompt_pull_cache_and_blocks 0 10.10.170.1 hixl执行 decoder 侧,参数为
device_id、local_ip、remote_ip、可选transfer_backend与local_comm_res,其中device_id为 decoder 要使用的 device_id,local_ip为 decoder 所在 host 的 IP,remote_ip为 prompt 所在 host 的 IP:./decoder_pull_cache_and_blocks 2 10.170.10.1 10.170.10.1 hixl
从源码看,prompt 侧流程为:Initialize(写入OPTION_DEVICE_ID、OPTION_LISTEN_IP_INFO与可选的OPTION_TRANSFER_BACKEND/OPTION_LOCAL_COMM_RES)→aclrtMalloc分配 4 个 tensor buffer 并初始化 →RegisterKvCache(cache_desc, tensor_addrs, {}, cache_id)注册 KvCache → 通过 26002 端口等待 decoder 完成 unlink 的通知(WaitUnlinkDone,超时 60s)→UnregisterKvCache释放。decoder 侧则解析remote_ip建链、执行 pull,再通知 prompt 侧可以释放。
(2)push_cache_and_blocks:prompt 向 decoder 推送
此样例介绍 prompt 向 decoder 进行 push cache 和 push blocks 的流程,其中 link 和 push 的方向与角色无关,可以根据需求更改。默认走 HCCL 传输后端;可选参数transfer_backend传hixl可切换为 hixl 后端。在 A5 环境上使用 hixl 时默认走 UB 协议,可手动配置local_comm_res走 RDMA 链路。
执行 prompt 侧,参数为
device_id、local_ip、remote_ip、可选transfer_backend与local_comm_res,其中device_id为 prompt 要使用的 device_id,local_ip为 prompt 所在 host 的 IP,remote_ip为 decoder 所在 host 的 IP:./prompt_push_cache_and_blocks 0 10.10.10.1 10.10.10.1 hixl执行 decoder 侧,参数为
device_id、local_ip、可选transfer_backend与local_comm_res,其中device_id为 decoder 要使用的 device_id,local_ip为 decoder 所在 host 的 IP:./decoder_push_cache_and_blocks 4 10.10.10.1 hixl
(3)switch_roles:prompt 与 decoder 角色切换
此样例介绍 prompt 和 decoder 进行角色切换,并结合 pull 以及 push 使用流程。两端的参数均为device_id、local_ip、remote_ip三个必选参数。
执行 prompt 侧,
device_id为 prompt 要使用的 device_id,local_ip为 prompt 所在 host 的 IP,remote_ip为 decoder 所在 host 的 IP:./prompt_switch_roles 0 10.10.170.1 10.170.10.1执行 decoder 侧,
device_id为 decoder 要使用的 device_id,local_ip为 decoder 所在 host 的 IP,remote_ip为 prompt 所在 host 的 IP:./decoder_switch_roles 2 10.170.10.1 10.170.10.1
参数与后端选型小结
| 样例 | 默认传输后端 | 可选后端 | 参数(按顺序) |
|---|---|---|---|
| pull_cache_and_blocks | adxl | hixl(A5 仅支持 hixl cs 后端) | prompt:device_id local_ip [transfer_backend] [local_comm_res];decoder:device_id local_ip remote_ip [transfer_backend] [local_comm_res] |
| push_cache_and_blocks | HCCL | hixl | prompt:device_id local_ip remote_ip [transfer_backend] [local_comm_res];decoder:device_id local_ip [transfer_backend] [local_comm_res] |
| switch_roles | - | - | 两侧均为device_id local_ip remote_ip |
transfer_backend仅支持hixl取值,传其他值会在 Initialize 中直接报错并退出。local_comm_res为可选的本地通信资源 JSON 字符串,在 A5 上用于切换 RDMA 链路。
HIXL 样例:D2rD / D2rH 单边通信
运行形态说明
- 单进程用例(
hixl_example_d2rd、hixl_example_d2rh)在一个进程内启动两个 engine,无需分开终端,在大于等于 CANN-9.1.0 版本支持。 - 多进程用例(
hixl_example_d2rd_multiproc)需要分别在两个终端启动 server 和 client,server 先启动,无 CANN 版本要求。 fabric_mem_d2d需要成对运行,两个终端分别启动。
HIXL 样例进程参数说明
| 参数 | 适用样例 | 必选/可选 | 默认值 | 说明 |
|---|---|---|---|---|
--protocol=<type>[,...] | hixl_example_d2rd、hixl_example_d2rh、hixl_example_d2rd_multiproc | 必选 | - | 通信协议,支持逗号分隔多协议。hixl_example_d2rd 支持roce:device、uboe:device、ub_rtp:device、ub_ctp:device;hixl_example_d2rh 支持roce:device、uboe:device、ub_rtp:device、ub_ctp、ub_ctp:device、ub_ctp:host;hixl_example_d2rd_multiproc 支持hccs:device、roce:device、uboe:device、ub_rtp:device、ub_ctp:device。协议硬件依赖如下:hccs:device、roce:device仅支持 Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品;uboe:device、ub_rtp:device、ub_ctp、ub_ctp:device、ub_ctp:host仅支持 Ascend 950PR/Ascend 950DT。协议定义详见 HIXL 接口 中comm_resource_config.protocol_desc的 option 说明。 |
--device=<id>或--device=id1,id2 | hixl_example_d2rd、hixl_example_d2rh、hixl_example_d2rd_multiproc | 可选 | hixl_example_d2rd、hixl_example_d2rh 默认 0,2;hixl_example_d2rd_multiproc 默认 client=0、server=2 | hixl_example_d2rd、hixl_example_d2rh 使用--device=id1,id2指定两个 engine 分别绑定的 device;hixl_example_d2rd_multiproc 使用--device=<id>指定当前进程绑定的 device。 |
--version=0\|1 | hixl_example_d2rd、hixl_example_d2rh、hixl_example_d2rd_multiproc | 可选 | 1 | 配置为 0 时,表示使用 HCCL 集合通信通信域方式构筑的单边通信能力,仅支持 Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品;配置为 1 时,表示 HIXL 调用 HIXL CS 接口实现的单边通信能力,解耦通信域,推荐使用,支持 Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品、Ascend 950PR/Ascend 950DT。 |
--role=client\|server | hixl_example_d2rd_multiproc | 必选 | - | 指定当前进程为 client 或 server。 |
--local-engine=<ip:port> | hixl_example_d2rd_multiproc | 可选 | client=127.0.0.1:16000、server=127.0.0.1:16001 | 指定当前进程的 engine 地址。 |
--remote-engine=<ip:port> | hixl_example_d2rd_multiproc | 可选 | client=127.0.0.1:16001、server=127.0.0.1:16000 | 指定对端进程的 engine 地址。 |
几点源码级补充说明:
- 在 hixl_example_d2rd.cpp 的
ParseArgs中,--protocol缺失会被判定为错误;version=0模式仅接受roce:device单一协议。version=0 的 legacy 流程(ConfigLegacyOptions)会写入OPTION_LOCAL_COMM_RES={"version": "1.2"}、OPTION_GLOBAL_RESOURCE_CONFIG={"comm_resource_config.listen_port": port}与OPTION_BUFFER_POOL="0:0",并针对 roce 设置HCCL_INTRA_ROCE_ENABLE=1;而 version=1 的 v2 流程(ConfigV2Options)则写入OPTION_GLOBAL_RESOURCE_CONFIG={"comm_resource_config.protocol_desc": [...]},通过comm_resource_config.protocol_desc配置协议数组。 - 关于
protocol_desc,接口文档说明支持"ub_ctp"/"roce:device"/"hccs:device"/"ub_ctp:device"/"ub_ctp:host"/"uboe:device"/"ub_rtp:device"/"roce:host"。A5 上未配置该字段或仅配置ub_ctp:device时自动生成 Device UB 资源(Host 内存通过 UBMEM 映射到 Device 地址后使用 Device UB 链路传输);同时配置ub_ctp:device与ub_ctp:host时生成 Device+Host UB 资源并使用纯 URMA 路径,与单独配置ub_ctp等价。 - 环境变量配置与 LLM-DataDist 样例相同,按 Toolkit 包或 run 包二选一执行
source命令即可。
(1)hixl_example_d2rd:D2RD 单进程场景
单进程一个线程内启动两个 engine,分别绑定不同 device,由 engine A 发起 WRITE 传输到 engine B 的 device buffer。传输缓冲区 8 MiB,被切分为 512 个 16 KiB 的 block,逐个构造TransferOpDesc后通过TransferSync一次提交,最后将 engine B 的 device buffer 拷回 Host 校验是否为填充值0xAA(对应 Transfer/Verify)。
运行示例:
# 使用 roce:device 协议 ./hixl_example_d2rd --protocol=roce:device # 指定 device ./hixl_example_d2rd --protocol=roce:device --device=0,2 # 使用 version 0 模式(仅支持 roce:device) ./hixl_example_d2rd --protocol=roce:device --version=0(2)hixl_example_d2rh:D2RH 单进程场景
单进程一个线程内启动两个 engine,分别绑定不同 device,双方各自发起 WRITE 传输到对方的 host buffer。该样例支持纯 URMA 的ub_ctp协议及其等价写法ub_ctp:device,ub_ctp:host。
运行示例:
# 使用 roce:device 协议 ./hixl_example_d2rh --protocol=roce:device # 使用 UB CTP 纯 URMA 协议 ./hixl_example_d2rh --protocol=ub_ctp # 原有 Device+Host 写法同样使用纯 URMA 协议 ./hixl_example_d2rh --protocol=ub_ctp:device,ub_ctp:host # 使用 version 0 模式 ./hixl_example_d2rh --protocol=roce:device --version=0(3)hixl_example_d2rd_multiproc:D2RD 多进程场景
两个独立进程分别启动 engine,通过 socket 交换 buffer 地址后,由 client 发起 READ 传输并本地校验。从 hixl_example_d2rd_multiproc.cpp 可以看到,server 在local_engine端口号 +1000 的偏移端口上监听,接受 client 连接后将本地 device buffer 地址发送出去;client 通过 socket 获取远端地址后执行TransferSync(READ),再校验数据是否为填充值0xAA。该样例支持hccs:device,是唯一覆盖 HCCS 协议的多进程样例,且 version=0 模式支持roce:device与hccs:device。
运行示例(注意 server 先启动):
# 使用 roce 协议 ./hixl_example_d2rd_multiproc --role=server --protocol=roce:device ./hixl_example_d2rd_multiproc --role=client --protocol=roce:device # 使用 hccs 协议 ./hixl_example_d2rd_multiproc --role=server --protocol=hccs:device ./hixl_example_d2rd_multiproc --role=client --protocol=hccs:device # 使用 version 0 模式 ./hixl_example_d2rd_multiproc --role=server --protocol=roce:device --version=0 ./hixl_example_d2rd_multiproc --role=client --protocol=roce:device --version=0fabric_mem_d2d:FabricMem 模式 D2D 场景
版本与硬件前提
- FabricMem 仅支持 Atlas A3 训练系列产品/Atlas A3 推理系列产品,最低支持 HDK 25.5。
- HDK 25.5 不支持
aclrtMemRetainAllocationHandle。在该版本上,FabricMem 场景的 Host 内存必须使用 ADXL 提供的MallocMem/FreeMem进行申请和释放。 - HDK 26.0 及以上版本可以直接使用 ACL 接口管理 FabricMem 场景的 Host 内存。
- 当前
fabric_mem_d2d样例在AllocateBuffer中直接使用 ACL VMM 接口aclrtReserveMemAddress、aclrtMallocPhysical和aclrtMapMem分配内存,随后以MEM_DEVICE注册,未通过 ADXL 的AdxlEngine::MallocMem分配。该注册路径需要aclrtMemRetainAllocationHandle,因此样例要求 HDK 26.0 及以上版本,不兼容 HDK 25.5。样例中的aclrtMallocHost/aclrtFreeHost仅用于初始化和校验 buffer,并非 FabricMem Host 内存注册。
从 fabric_mem_d2d.cpp 源码可以看到,Initialize阶段向 options 写入OPTION_ENABLE_USE_FABRIC_MEM = "1"以开启 FabricMem 能力,随后通过Connect、TransferSync(WRITE)完成跨 engine 的显存到显存写入,两端以文件(<ip:port>命名的本地文件)方式交换对方 buffer 地址,具备 60s 等待超时。传输大小为 2 MiB,写 1 MiB。
运行方法
两个终端成对运行,参数为device_id、local engine 和 remote engine,其中device_id为当前 engine 要使用的 device_id:
终端一(server1):
./fabric_mem_d2d 0 127.0.0.1:16000 127.0.0.1:16001终端二(server2):
./fabric_mem_d2d 1 127.0.0.1:16001 127.0.0.1:16000
常见问题与排查建议
- 成对运行与超时:LLM-DataDist 样例的 prompt/decoder 必须成对启动且间隔不宜过长,若超时可增大源码中的
WAIT_PROMPT_TIME(decoder 侧,默认 5s)与WAIT_TIME(prompt 侧,默认 10s)。 - A5 默认协议与 RDMA 切换:A5 上未手动配置
local_comm_res时默认走 UB 协议;需要 RDMA 时须手动配置local_comm_res(推荐version: "1.3"),并先用ibdev2netdev、ifconfig确认 RoCE 网口与 IP。可参考 scripts/tools/hixl_tool/readme.md 使用工具生成 localcommres 信息。 - 协议与硬件不匹配:
hccs:device、roce:device仅支持 A2/A3 系列产品,uboe:device、ub_rtp:device、ub_ctp*仅支持 Ascend 950PR/950DT,选型时务必与protocol_desc的硬件依赖对齐。 - version 模式限制:version=0(HCCL 通信域方式)仅支持
roce:device(d2rd/d2rh)或roce:device/hccs:device(multiproc),且仅支持 A2/A3 系列产品;新项目建议使用默认的 version=1(HIXL CS 方式)。 - FabricMem 版本兼容:当前
fabric_mem_d2d样例基于aclrtMemRetainAllocationHandle的注册路径,要求 HDK 26.0 及以上;HDK 25.5 上应改用 ADXLMallocMem/FreeMem管理 Host 内存。
如需继续深入学习,可结合 HIXL C++ 接口文档(重点看 Initialize 的 options 与comm_resource_config.protocol_desc字段说明)以及 LLM-DataDist 接口文档 理解各 option 的完整语义;也可参考 examples/README.md 了解 Python 侧样例与其余示例。
【免费下载链接】hixlHIXL(Huawei Xfer Library)是一个灵活、高效的昇腾单边通信库,面向集群场景提供简单、可靠、高效的点对点数据传输能力。项目地址: https://gitcode.com/cann/hixl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考