HcclCommSymWinRegister
产品支持情况
|
产品 |
是否支持 |
|---|---|
|
Atlas 350 加速卡 |
☓ |
|
|
√ |
|
|
☓ |
|
|
☓ |
|
|
☓ |
|
|
☓ |
功能说明
用户在申请虚拟内存和物理内存并完成映射后,可调用此接口将虚拟内存注册为对称内存。
对称内存是一种内存管理模型,允许并行处理单元(例如每个rank)以一种“全局可见”但“无需显式地址交换”的方式访问彼此的内存。
对称内存的基本实现模型如下图所示,每个rank通过提前预留相同大小、相同布局的虚拟地址来实现。

- 为每个rank申请虚拟内存,假设每个rank对应的虚拟内存大小为heap_size,通信域中的rank数量为rank_size,则通信域中总虚拟内存大小为heap_size*rank_size。
- 每个rank的虚拟地址布局都是相同的。
- 不同rank的物理地址映射到每个rank对应位置的虚拟地址,实现对其他rank内存的访问。
对称内存功能使得HCCL可以直接对业务传入的内存进行操作,无需经过中间缓冲区(HCCL buffer),从而减少内存拷贝开销。
函数原型
1
|
HcclResult HcclCommSymWinRegister(HcclComm comm, void *addr, uint64_t size, HcclCommSymWindow *winHandle, uint32_t flag) |
参数说明
|
参数名 |
输入/输出 |
说明 |
|---|---|---|
|
comm |
输入 |
HCCL通信域,建议使用超节点内最大的通信域,即覆盖最大卡数的通信域。 初始化通信域时可以通过HcclCommConfig的hcclSymWinMaxMemSizePerRank参数设置每个rank预留的对称内存大小,若不设置hcclSymWinMaxMemSizePerRank,使用默认值16GB。 当前通信域预留的总虚拟对称内存大小为:rankSize * HcclCommConfig.hcclSymWinMaxMemSizePerRank。 |
|
addr |
输入 |
预留的虚拟内存地址。 虚拟内存需要调用aclrtReserveMemAddress接口预留。 |
|
size |
输入 |
对称内存窗口的大小,0 < size <= HcclCommConfig.hcclSymWinMaxMemSizePerRank,并且size不能超过“与addr做映射的物理内存”大小(即调用aclrtMallocPhysical接口申请的Device物理内存)。 注:对称内存注册按物理内存的大小对齐,实际注册的对称内存窗口大小等于“与addr做映射的物理内存”的大小。 |
|
winHandle |
输出 |
存放“对称内存窗口资源句柄“的指针。 HcclCommSymWindow类型的定义请参见HcclCommSymWindow。 |
|
flag |
输入 |
是否启用对称内存,当前仅支持传入1。 |
返回值
HcclResult:接口成功返回HCCL_SUCCESS,其他失败。
约束说明
- 仅支持
Atlas A3 训练系列产品 /Atlas A3 推理系列产品 的超节点内通信。 - 仅支持通信算子展开模式为AI CPU的场景。
- 仅支持超节点内AI Server间使用HCCS链路进行SDMA通信的场景,不支持使用RoCE进行RDMA通信的场景(即不支持设置环境变量HCCL_INTER_HCCS_DISABLE为"TRUE",单机场景该环境变量无效)。
- 仅支持对称组网,即每个Server内卡数相同的场景。
- 该接口仅支持集合通信算子AllGather、ReduceScatter、AllReduce、AlltoAll。。
- 需确保通信域中的所有rank同时调用该注册接口。
- 所有rank的输入地址映射的物理内存大小一致(对称内存注册按物理内存的大小对齐)。
- 所有rank调用该接口时,输入的size参数需要保持一致。
- 使用对称内存功能时,算子的输入、输出内存必须调用此接口注册为对称内存。
- 调用该接口注册的内存需要使用HcclCommSymWinDeregister接口解注册。
调用示例
// 创建并初始化通信域配置项 HcclCommConfig config; HcclCommConfigInit(&config); // 按需修改通信域配置 config.hcclSymWinMaxMemSizePerRank = 10; //单位GB, 默认值为16。设置对称堆预留的虚拟内存大小 = rankSize * config.hcclSymWinMaxMemSizePerRank; // 获取通信域参数 uint32_t rankSize = 4; uint32_t rankId = 0; int32_t deviceId; ACLCHECK(aclrtGetDevice(&deviceId)); HcclRootInfo rootInfo; HCCLCHECK(HcclGetRootInfo(&rootInfo)); // 初始化集合通信域 HcclComm hcclComm; HCCLCHECK(HcclCommInitRootInfoConfig(rankSize, &rootInfo, rankId, &config, &hcclComm)); // 创建任务流 aclrtStream stream; ACLCHECK(aclrtCreateStream(&stream)); // 物理内存属性配置 aclrtPhysicalMemProp prop; prop.handleType = ACL_MEM_HANDLE_TYPE_NONE; prop.allocationType = ACL_MEM_ALLOCATION_TYPE_PINNED; prop.memAttr = ACL_HBM_MEM_HUGE; prop.location.id = deviceId; prop.location.type = ACL_MEM_LOCATION_TYPE_DEVICE; prop.reserve = 0; // 获取对齐粒度,通常为2M size_t granularity; ACLCHECK(aclrtMemGetAllocationGranularity(&prop, ACL_RT_MEM_ALLOC_GRANULARITY_RECOMMENDED, &granularity)); // size按粒度对齐 size_t size = 2 * 1024 * 1024; size_t allocSize = (size + granularity - 1) / granularity * granularity; // 预留虚拟内存 void *virPtr; ACLCHECK(aclrtReserveMemAddress(&virPtr, allocSize, 0, nullptr, 1)); // 申请物理内存 aclrtDrvMemHandle memHandle; ACLCHECK(aclrtMallocPhysical(&memHandle, allocSize, &prop, 0)); // 建立物理到虚拟的映射 ACLCHECK(aclrtMapMem(virPtr, allocSize, 0, memHandle, 0)); size_t sendBytes = 1024; size_t recvBytes = rankSize * sendBytes; HcclCommSymWindow symWin; // 注册对称内存 HCCLCHECK(HcclCommSymWinRegister(hcclComm, virPtr, sendBytes + recvBytes, &symWin, 1)); // 使用对称内存 void *sendBuff = virPtr; void *recvBuff = static_cast<char*>(sendBuff) + sendBytes; // 调用集合通信算子 HCCLCHECK(HcclAllGather(sendBuff, recvBuff, sendBytes, HCCL_DATA_TYPE_INT8, hcclComm, stream)); // 阻塞等待任务流中的集合通信任务执行完成 ACLCHECK(aclrtSynchronizeStream(stream)); // 解注册对称内存 HCCLCHECK(HcclCommSymWinDeregister(symWin)); // 释放内存 ACLCHECK(aclrtUnmapMem(virPtr)); ACLCHECK(aclrtFreePhysical(memHandle)); ACLCHECK(aclrtReleaseMemAddress(virPtr)); // 销毁任务流 ACLCHECK(aclrtDestroyStream(stream)); // 销毁通信域 HCCLCHECK(HcclCommDestroy(hcclComm));