---
title: HcclCommSymWinRegister
description: "| 产品 | 是否支持 |"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/API/hcclug/hcclcpp_07_0069.html
sourcePath: /source/zh/canncommercial/900/API/hcclug/hcclcpp_07_0069.html
indexId: 185230766031c1068a23fa3aa049e4bf66a058e96cb43adfc5db3b846f5860a161
---
# HcclCommSymWinRegister

#### 产品支持情况

| 产品 | 是否支持 |
| --- | --- |
| Atlas 350 加速卡 | ☓ |
| Atlas A3 训练系列产品 / Atlas A3 推理系列产品 | √ |
| Atlas A2 训练系列产品 / Atlas A2 推理系列产品 | ☓ |
| Atlas 200I/500 A2 推理产品 | ☓ |
| Atlas 推理系列产品 | ☓ |
| Atlas 训练系列产品 | ☓ |


#### 功能说明

用户在申请虚拟内存和物理内存并完成映射后，可调用此接口将虚拟内存注册为对称内存。

对称内存是一种内存管理模型，允许并行处理单元（例如每个rank）以一种“全局可见”但“无需显式地址交换”的方式访问彼此的内存。

对称内存的基本实现模型如下图所示，每个rank通过提前预留相同大小、相同布局的虚拟地址来实现。


- 为每个rank申请虚拟内存，假设每个rank对应的虚拟内存大小为heap_size，通信域中的rank数量为rank_size，则通信域中总虚拟内存大小为heap_size*rank_size。
- 每个rank的虚拟地址布局都是相同的。
- 不同rank的物理地址映射到每个rank对应位置的虚拟地址，实现对其他rank内存的访问。

对称内存功能使得HCCL可以直接对业务传入的内存进行操作，无需经过中间缓冲区（HCCL buffer），从而减少内存拷贝开销。


#### 函数原型

```
HcclResult HcclCommSymWinRegister(HcclComm comm, void *addr, uint64_t size, CommSymWindow *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));
```
