组调用
组函数 mcclGroupStart 与 mcclGroupEnd 可以用来将多个调用合并为一个。这有三个用途:管理单个线程上的多个 GPU(以避免死锁)、聚合通信操作以提高性能,或合并多个发送/接收点对点操作(见 点对点通信 部分)。所有三种用途可以结合使用,有一个例外:对 mcclCommInitRank() 的调用不能与其他调用合并。
单线程管理多个 GPU
当单个线程管理多个设备时,必须使用组语义。这是因为每个 MCCL 调用可能需要阻塞,等待其他 threads/ranks 到达,然后才能在给 定的 MUSA stream 上有效地发布 MCCL 操作。因此,像下面这样在多个设备上的简单循环可能会在第一个调用上阻塞,等待其他调用:
for (int i=0; i<nLocalDevs; i++) {
mcclAllReduce(..., comm[i], stream[i]);
}
要定义这些调用是同一集体操作的一部分,应使用 mcclGroupStart 和 mcclGroupEnd:
mcclGroupStart();
for (int i=0; i<nLocalDevs; i++) {
mcclAllReduce(..., comm[i], stream[i]);
}
mcclGroupEnd();
这将告诉 MCCL 将 mcclGroupStart 和 mcclGroupEnd 之间的所有调用视为对多个设备的单个调用。
注意:当在组内调用时,stream 操作(如 mcclAllReduce)可能在未在 MUSA stream 上排队操作的情况下返回。因此,只能在 mcclGroupEnd 返回后调用 MUSA stream 操作,如 musaStreamSynchronize。
组调用还必须用于创建一个通信器,当一个线程管理多个设备时:
mcclGroupStart();
for (int i=0; i<nLocalDevs; i++) {
musaSetDevice(device[i]);
mcclCommInitRank(comms+i, nranks, commId, rank[i]);
}
mcclGroupEnd();
注意:在组内的每个 MCCL 通信调用之前不需要设置 MUSA 设备,但在组内调用 mcclCommInitRank 时仍然需要。
相关链接: