HIXL 端到端冒烟测试(E2E Smoke Tests)实战指南:四种部署模式的传输验证与调试
【免费下载链接】hixlHIXL(Huawei Xfer Library)是一个灵活、高效的昇腾单边通信库,面向集群场景提供简单、可靠、高效的点对点数据传输能力。项目地址: https://gitcode.com/cann/hixl
本文基于 HIXL(Huawei Xfer Library)开源仓库中的端到端测试套件(tests/e2e/README_en.md),系统讲解该套件如何跨进程验证 HIXL 的 D2D、D2RH、D2RD 等点对点数据传输能力与数据完整性,覆盖 Real-Real、Standalone Same-Host、Dummy-Real 共享内存、Scale Reconnect 四种部署模式。读完本文,你将掌握 HIXL E2E 测试的环境准备、运行方式、环境变量调优、测试架构设计(设备/端口/内存分配策略)以及常见问题的排查方法,并能参照现有模式编写新的端到端用例。
一、E2E 冒烟测试的定位与价值
HIXL 面向集群场景提供简单、可靠、高效的点对点数据传输能力,其核心能力体现在跨进程、跨设备的 RDMA/HCCS 读写。端到端冒烟测试(End-to-End Smoke Test)用于在真实硬件上快速验证两件事:
- 传输功能可用性:不同部署模式下,HIXL 引擎能否完成建链、WRITE、READ、断链、解注册、销毁的全流程;
- 数据完整性:写入端与读取端的数据模式字节是否完全一致,是否存在丢包或错位。
该套件以 pytest 为框架,使用multiprocessing的spawn上下文拉起多个独立进程模拟真实部署拓扑,每个测试用例都是一个可独立运行的"迷你集群"。
二、前置条件与环境准备
在运行 E2E 测试前,需要满足以下软硬件要求(以当前仓库 README 声明的版本为准):
| 类别 | 要求 |
|---|---|
| 硬件 | 至少 2 张 NPU 卡(Atlas A2/A3) |
| 驱动 | Ascend NPU Driver >= 25.5.0 |
| CANN | CANN >= 9.1.0 |
| Python | Python 3.10+ |
依赖安装命令:
pip install pytest torch==2.13.0+cpu --index-url https://download.pytorch.org/whl/cpu pip install torch-npu==2.13.0rc1其中torch-npu用于在进程内执行torch.npu.set_device()与 NPU 内存分配;hixlPython 包来自本仓库(src/python/hixl_py),通过 pybind11 暴露了Hixl引擎类与register_mem、transfer_sync等接口(见 hixl_py.cc)。
三、测试场景总览
套件包含四个测试文件,分别模拟四种典型部署形态:
| 测试文件 | 部署模式 | 核心验证点 |
|---|---|---|
| test_real_real.py | Real-Real | D2D、D2RH 跨设备批量读写 |
| test_standalone_same_host.py | Standalone Same-Host | Store Service + App 同主机 D2RH |
| test_dummy_real_shared_mem.py | Dummy-Real 共享内存 | 跨进程 Device 内存共享 + D2RD/D2RH 全流程 |
| test_scale_reconnect.py | 大规模多链路 + 设备抖动 | 每设备 250 条逻辑链路传输、抖动重连 |
3.1 Real-Real 模式(test_real_real.py)
模拟两个独立的 RealClient(类似于 vLLM 的 Prefill 节点与 Decode 节点),Client 与 Server 分属两个进程,使用错位设备分配策略保证两进程不共享物理设备。
用例:
test_normal_full_flow_d2rd_batch_read_write:D2D(Device to Device)跨设备批量读/写test_normal_full_flow_d2rh_batch_read_write:D2RH(Device to Remote Host)跨设备批量读/写
架构(以 4 卡ASCEND_RT_VISIBLE_DEVICES=0,1,2,3为例):
Client Process (devices [0,1,2,3]) Server Process (devices [1,2,3,0]) ├─ engine[0] (dev 0) ──────────────> engine[0] (dev 1) ├─ engine[1] (dev 1) ──────────────> engine[1] (dev 2) ├─ engine[2] (dev 2) ──────────────> engine[2] (dev 3) └─ engine[3] (dev 3) ──────────────> engine[3] (dev 0)数据流(对应 test_real_real.py 中的执行序列):
- Client 填充
0xDD,Server 填充0xCC; - Client 执行 WRITE,将
0xDD写入 Server 内存; - Client 将本地内存清零;
- Client 执行 READ 从 Server 读回数据,期望读到
0xDD(验证 WRITE 成功)——注意 READ 验证的是"读回的数据与本地原始填充一致",从而证明远端确实保存了客户端写入的内容。
代码实现上,Server 进程在_server_worker中为每个引擎分配设备内存并注册为hixl.MEM_DEVICE;D2RH 场景则使用alloc_host_mem_pinned分配 pinned 主机内存并注册为hixl.MEM_HOST(见 test_real_real.py)。Client 进程在_client_worker中完成 connect → WRITE → 清零 → READ → verify → disconnect → deregister → finalize 的完整闭环(test_real_real.py)。
3.2 Standalone Same-Host 模式(test_standalone_same_host.py)
模拟 Mooncake 的 standalone 部署:Store Service 与 App 同主机共存。Store 进程分配一大块pinned 主机内存(大小为MEM_SIZE * N),每个引擎都注册同一base_addr与total_size;App 进程的每个引擎分配设备内存。
用例:
test_normal_full_flow_same_host_d2rh_write:D2RH 同主机写
架构:
App Process (devices [0,1,2,3]) Store Process (devices [1,2,3,0]) ├─ engine[0] (dev 0) ──────────────> engine[0] (dev 1) ├─ engine[1] (dev 1) ──────────────> engine[1] (dev 2) ├─ engine[2] (dev 2) ──────────────> engine[2] (dev 3) └─ engine[3] (dev 3) ──────────────> engine[3] (dev 0) └─ shared host memory (base_addr)数据流:
- App 填充
0xFF; - App[i] WRITE
0xFF到 Store 主机内存偏移i * MEM_SIZE处——多引擎各写各的偏移段,避免写同一段内存造成冲突(见 test_standalone_same_host.py); - App 清零本地内存;
- App[i] READ 同一偏移,期望读到
0xFF。
3.3 Dummy-Real 共享内存模式(test_dummy_real_shared_mem.py)
该场景模拟 Mooncake dummy-real 部署模式,核心是验证跨进程的 Device 内存共享:Dummy 进程分配 Device 内存并通过 ACL IPC key 导出,Real 进程通过 IPC key 导入后注册到 HIXL 引擎,从而让对端可以直接对这段内存发起 RDMA 读写。
用例:
test_normal_full_flow_d2rd_d2rh_read:D2RD + D2RH 全流程
进程架构:
Local Dummy (devices [0,1,2,3]) Local Real (devices [0,1,2,3]) ├─ allocate device memory ├─ import IPC key ├─ fill 0xAA ├─ create engines └─ export IPC key └─ register device + host memory │ ▼ Remote Real (devices [1,2,3,0]) Remote Dummy (devices [1,2,3,0]) ├─ import IPC key ├─ allocate device memory ├─ create engines ├─ fill 0xBB ├─ register device + host memory └─ export IPC key └─ verify D2RH WRITE result数据流(完整 15 步时序见 test_dummy_real_shared_mem.py):
- D2RD WRITE:Local Device(0xAA)→ Remote Device;
- D2RD READ:Remote Device → Local Device(期望 0xAA);
- D2RH WRITE:Local Device(0xAA)→ Remote Host;
- D2RH READ:Remote Host → Local Device(期望 0xAA)。
IPC 关键点:导出时使用ACL_RT_IPC_MEM_EXPORT_FLAG_DISABLE_PID_VALIDATION(0x1)标志跳过 PID 校验,允许任意进程导入(需要 driver >= 26.1.1);导入使用默认标志0x0。对应代码为 test_dummy_real_shared_mem.py 中的_export_ipc_key/_import_ipc_key。
3.4 Scale Reconnect 大规模链路与设备抖动(test_scale_reconnect.py)
验证两个高可用能力:大规模多链路传输与设备抖动(flapping)后的重连。
用例:
test_normal_flow_multi_links:N 设备 × 每设备 250 条逻辑链路批量传输(默认HIXL_E2E_LINKS_PER_DEV=250);test_flapping_dev_reconnect:指定设备(FLAP_DEV = 2)抖动场景下的重连能力。
架构:
Client Process (devices [0,1,2,3]) Server Process (devices [1,2,3,0]) ├─ engine[0] (dev 0) ──┐ ├─ engine[0] (dev 1) │ ├─ link 0 │ │ ├─ link 0 │ ├─ link 1 │ │ ├─ link 1 │ └─ ... │ │ └─ ... │ └─ link 249 │ │ └─ link 249 ├─ engine[1] (dev 1) ──┤ ├─ engine[1] (dev 2) ├─ engine[2] (dev 2) ──┤ ├─ engine[2] (dev 3) └─ engine[3] (dev 3) ──┘ └─ engine[3] (dev 0)多链路场景中,Client 为每个 engine 分配TRANSFER_SIZE_PER_LINK * LINKS_PER_DEV大小的设备内存,逐条构造TransferOpDesc(local_addr, remote_addr + offset, len)执行 WRITE(见 test_scale_reconnect.py)。抖动场景则按"Pre-flap 正常 WRITE → Server 端 deregister + finalize 模拟设备下线 → Client 尝试传输 → Server 重新初始化 + 重新注册(新内存地址经队列回传)→ Client disconnect + reconnect → Post-reconnect WRITE"的节奏验证断线重建能力(test_scale_reconnect.py 与_client_worker_flap)。
四、运行测试
4.1 基本用法
# 设置环境变量 export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 source /usr/local/Ascend/cann/set_env.sh # 运行全部测试 python3 -m pytest tests/e2e/ -v # 运行单个测试文件 python3 -m pytest tests/e2e/test_real_real.py -v # 显示详细输出(包含日志) python3 -m pytest tests/e2e/test_real_real.py -v -spytest 的 e2e 配置由仓库根目录的 pytest_e2e.ini 提供,指定了testpaths = tests/e2e、用例收集规则(test_*.py/Test*/test_*)以及requires_fabric_mem标记(FabricMem 相关用例需要 A3 硬件)。
4.2 环境变量说明
| 变量 | 默认值 | 说明 |
|---|---|---|
ASCEND_RT_VISIBLE_DEVICES | 0,1,2,3 | 可见 NPU 设备列表 |
HIXL_E2E_MIN_NPU | 2 | 最低 NPU 数量要求,低于该值测试被跳过 |
HIXL_E2E_LINKS_PER_DEV | 250 | 每设备逻辑链路数(scale-reconnect 场景) |
HIXL_E2E_TRANSFER_SIZE | 4096 | 每条链路的传输大小,单位字节(scale-reconnect 场景) |
HIXL_E2E_REGISTER_SIZE | 268435456(256MB) | 注册内存大小(scale-reconnect 场景) |
其中HIXL_E2E_MIN_NPU在 conftest.py 中读取,由 session 级 autouse fixture 统一检查:若get_npu_count()小于阈值则pytest.skip,并提示可通过HIXL_E2E_MIN_NPU覆盖。HIXL_E2E_LINKS_PER_DEV等三个变量在 test_scale_reconnect.py 中解析,且均做了> 0的参数校验。
4.3 典型运行示例
# 4 卡运行全部用例 export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 python3 -m pytest tests/e2e/ -v # 自定义链路参数 export HIXL_E2E_LINKS_PER_DEV=500 export HIXL_E2E_TRANSFER_SIZE=8192 python3 -m pytest tests/e2e/test_scale_reconnect.py -v # 跳过 NPU 数量检查(用于调试) export HIXL_E2E_MIN_NPU=0 python3 -m pytest tests/e2e/test_real_real.py -v五、测试架构设计原理
5.1 设备分配策略(错位分配)
utils.py 中的get_device_lists()从ASCEND_RT_VISIBLE_DEVICES解析设备数量并返回两组错位列表:
- Client/App:
[0, 1, 2, 3](前半/全部逻辑设备) - Server/Store:
[1, 2, 3, 0](偏移 +1 取模)
即server_devs[i] = (i + 1) % n。这样保证client[i]与server[i]一定落在不同的物理设备上,所有连接都是真实的跨设备 D2D 路径,避免资源冲突,也杜绝了"同设备伪 D2D"掩盖传输问题的可能。
5.2 端口分配策略
get_port()(utils.py)基于固定基址与偏移生成互不冲突的监听端口:
BASE_PORT = 39000 port = BASE_PORT + scenario_idx * 100 + role_offset + dev_id + engine_offset其中:role_offset为 0(server/remote)或 100(client);engine_offset为 200(fabric/hccs/alt 引擎)或 0。不同测试文件使用不同的SCENARIO_IDX(如 real_real 的 D2D 用 0、D2RH 用 5,standalone 用 7,scale 用 4)进行场景隔离。
示例(SCENARIO_IDX=3,dev_id=0):
| 角色 | 端口 |
|---|---|
server | 39300 |
client | 39400 |
server_fabric | 39500 |
client_fabric | 39600 |
5.3 内存管理
- Device 内存:
torch.zeros(size, dtype=torch.uint8, device="npu")分配,通过data_ptr()取地址(见alloc_device_mem); - Host 内存:
torch.empty(size, dtype=torch.uint8).pin_memory()分配页对齐内存,保证可被 ACL 注册(见alloc_host_mem_pinned); - IPC 共享:跨进程共享 Device 内存时,通过
acl.rt.ipc_mem_get_export_key/acl.rt.ipc_mem_import_by_key导出/导入 IPC key; - 内存注册:
RegisteredMem封装了engine.register_mem(hixl.MemDesc(addr, size), mem_type)与析构时自动deregister_mem,内存类型区分hixl.MEM_DEVICE与hixl.MEM_HOST(utils.py); - 传输描述:
build_op_descs按16 * 1024字节块把一段连续内存切分为多个hixl.TransferOpDesc(local_addr, remote_addr, len),供transfer_sync批量下发(utils.py)。
5.4 资源清理顺序
为确保多进程场景下不残留连接与内存句柄,清理顺序为:
- Client 侧:
disconnect→deregister→finalize - Server 侧:
deregister→finalize
所有测试文件(包括异常分支)都遵循这一顺序,异常处理中也会逐个disconnect、deregister、finalize,并通过result_queue.put(False)上报失败。
5.5 引擎初始化参数
所有用例共用create_engine()(utils.py),默认初始化参数为:
options = { hixl.OPTION_AUTO_CONNECT: "1", hixl.OPTION_GLOBAL_RESOURCE_CONFIG: '{"comm_resource_config.protocol_desc": ["roce:device", "roce:host"]}', }即开启 Auto Connect(可跳过显式建链直接传输)并声明使用 roce:device 与 roce:host 两种通信协议。这些 option 的取值含义可参考 docs/zh/api/python/HIXL-interface.md 中initialize的 options 说明表。
六、调试技巧
6.1 查看详细日志
# 启用控制台输出(-s 显示 print 与日志) python3 -m pytest tests/e2e/test_real_real.py -v -s各 worker 进程的日志前缀带有角色标签,便于区分,例如[S1-SERVER]、[S0-CLIENT]、[S2-R-DUMMY]、[S5-CLIENT-FLAP]等。conftest.py中logging.basicConfig统一格式化时间戳与级别,并抑制了torch._inductor、torch的噪声日志。
6.2 查看 HIXL 底层日志
# 设置日志级别:0=DEBUG, 1=INFO, 2=WARNING, 3=ERROR export ASCEND_GLOBAL_LOG_LEVEL=1 # 设置日志路径 export ASCEND_PROCESS_LOG_PATH=/tmp/hixl_logs mkdir -p /tmp/hixl_logs # 运行测试 python3 -m pytest tests/e2e/test_real_real.py -v # 查看日志 ls /tmp/hixl_logs/plog-*.log6.3 常见问题排查
Q:测试被跳过,提示 "Need >= 2 NPUs"
# 检查 NPU 数量 npu-smi info -l | grep "NPU" # 覆盖环境变量阈值 export HIXL_E2E_MIN_NPU=0Q:连接超时(Connection timeout)
# 检查端口是否被占用(端口范围在 39xxx) netstat -tlnp | grep 39 # 增大超时(修改代码中的 CONNECT_TIMEOUT_MS)代码中CONNECT_TIMEOUT_MS = 10000、TRANSFER_TIMEOUT_MS = 30000定义于 utils.py,可作为调参入口。
Q:数据校验失败
- 检查日志中 WRITE/READ 的返回值是否均为
hixl.SUCCESS; - 核对设备分配是否正确:
client[i]与server[i]应落在不同物理设备上(错位策略失效通常会导致跨进程共享设备冲突)。
七、文件结构与扩展新用例
7.1 目录结构
tests/e2e/ ├── __init__.py # 包初始化文件 ├── conftest.py # pytest 配置与 fixture(NPU 数量检查、FabricMem 标记) ├── utils.py # 公共工具函数(设备列表、端口、内存、引擎封装) ├── test_real_real.py # Real-Real 模式测试 ├── test_standalone_same_host.py # Standalone 同主机模式测试 ├── test_dummy_real_shared_mem.py # Dummy-Real 共享内存模式测试 ├── test_scale_reconnect.py # 大规模链路 + 设备抖动重连测试 ├── README.md # 中文文档 └── README_en.md # 本文档 pytest_e2e.ini # pytest e2e 配置(仓库根目录)7.2 编写新用例的约定
参照现有模式新增用例时,应遵守以下约定(对应 README 的 Contributing 一节):
- 新测试用例遵循现有模式(多进程 spawn + Queue/Event 同步 + 断言验证);
- 关键步骤使用
logger.info(...)记录(包含角色标签、设备映射、操作与返回码); - 使用
result_queue传递 worker 执行结果,主进程统一断言; - 保证资源清理顺序正确:
disconnect→deregister→finalize; - 提交前运行
ruff check与ruff format校验代码风格。
八、总结
HIXL E2E 冒烟测试套件以四种部署模式(Real-Real、Standalone Same-Host、Dummy-Real 共享内存、Scale Reconnect)为骨架,通过错位设备分配、场景化端口隔离、IPC 内存共享与多进程同步机制,在真实 NPU 硬件上完整覆盖了 D2D、D2RD、D2RH 的 WRITE/READ 全链路与数据一致性验证,是快速定位 HIXL 传输问题、评估集群部署可行性的第一道防线。结合 tests/e2e 目录下的源码与本文的调试指南,开发者可以快速上手运行、排查乃至扩展自己的端到端验证场景。
【免费下载链接】hixlHIXL(Huawei Xfer Library)是一个灵活、高效的昇腾单边通信库,面向集群场景提供简单、可靠、高效的点对点数据传输能力。项目地址: https://gitcode.com/cann/hixl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考