昇腾社区首页
中文
注册
开发者
下载

创建资源

通信资源计算

通信算子在执行时依赖底层的硬件通信资源,因此在算子任务编排下发前,首先需要申请所需的通信资源。HCCL通信资源主要分为三类:
  • Thread:用于表达单个rank内的并发关系,相同Thread上的task严格顺序执行,不同Thread上的task可以并发执行。无论何种展开模式,Thread均可分为1个主Thread和若干个从Thread,由该主Thread来控制这些从Thread上的任务的开始和结束,其中主Thread必须申请,从Thread的申请数量由每个通信算法单独计算。
  • Notify:用于做同步,包括rank内Thread间同步和rank间同步。
  • Channel:用于跨rank传输数据的通道。
不同的通信算法所需的通信资源数量往往不相同。下面以单机4卡的拓扑组网、使用AI CPU通信引擎为例,分别讲解Ring环状通信算法、Mesh全连接通信算法所需的通信资源数量计算逻辑。
  • Ring环状通信算法

    Ring算法的硬件拓扑如下图所示,每个rank从上一个rank接收数据,同时将数据发送到下一个rank。

    上述组网中Ring环状通信算法所需要的通信资源数量如下:

    • Thread:每个rank分别跟左右两个rank进行通信,且左右两端通信可以异步执行,因此每个rank一共需要2个Thread资源。
    • Notify:每个rank分别跟左右两个rank进行同步,同步操作分为Record和Wait,二者需要配对使用,因此每个rank一共需要4个Notify资源。
    • Channel:每个rank分别跟左右两个rank进行通信,因此每个rank一共需要建立2条Channel通信链路。
  • Mesh全连接通信算法

    Mesh算法的硬件拓扑如下图所示,每个rank与其他所有rank直接通信。

    上述组网中Mesh全连接通信算法所需要的通信资源数量如下:

    • Thread:每个rank跟其他所有rank进行通信,且所有通信可以异步执行,因此每个rank一共需要3个Thread资源。
    • Notify:每个rank跟其他所有rank进行同步,同步操作分为前同步和后同步,二者需要配对使用,因此每个rank一共需要6个Notify资源。
    • Channel:每个rank跟其他所有rank进行通信,因此每个rank一共需要建立3条Channel通信通道。

综上所述,针对Ring环状通信算法、Mesh全连接通信算法,每个rank所需的通信资源数量如下表所示。

表1 单机4卡拓扑中,算法所需各类通信资源的数量对比

通信资源

Ring算法

Mesh算法

Thread

2

3

Notify

4

6

Channel

2

3

代码示例

下面以自定义点对点Send/Receive通信算子为例,介绍其在Host上的资源创建代码片段。

申请Thread资源:

1
2
3
4
5
CommEngine engine = CommEngine::COMM_ENGINE_AICPU;  // AI CPU通信引擎
uint32_t threadNum = 1;             // 申请1个通信线程
uint32_t notifyNumPerThread = 0;    // 不额外申请通信线程中的同步资源
ThreadHandle thread;
HcclThreadAcquire(comm, engine, threadNum, notifyNumPerThread, &thread);

建立通信链路Channel,两个rank之间建立1条通信通道:

1
2
3
4
5
6
7
HcclChannelDesc channelDesc;
HcclChannelDescInit(&channelDesc, 1);
channelDesc.remoteRank = destRank;
channelDesc.channelProtocol = CommProtocol::COMM_PROTOCOL_HCCS;
channelDesc.notifyNum = 2;
ChannelHandle channelHandle;
HcclChannelAcquire(comm, engine, &channelDesc, 1, &channelHandle);

分配通信内存:

1
2
3
4
5
6
7
8
// 分配并获取本端通信内存
void *localAddr;
uint64_t localSize;
HcclGetHcclBuffer(comm, &localAddr, &localSize);
// 获取远端通信内存,用于后续读写操作
void *remoteAddr;
uint64_t remoteSize;
HcclChannelGetHcclBuffer(comm, channelHandle, &remoteAddr, &remoteSize);