从 NCCL 1 迁移到 NCCL 2

如果您正在使用 NCCL 1.x 并希望迁移到 NCCL 2.x,请注意 API 略有更改。NCCL 2.x 支持 NCCL 1.x 支持的所有集合操作,但 API 略有修改。

此外,当单个线程管理多个 GPU 的 NCCL 调用时,NCCL 2.x 也需要使用“Group API”。

以下列表总结了当应用程序具有管理多个 GPU 的 NCCL 调用的单个线程,并从 NCCL 1.x 移植到 2.x 时,NCCL API 的使用中可能需要的更改

初始化

在 1.x 版本中,NCCL 必须使用 ncclCommInitAll 在单个线程中初始化,或者让每个 GPU 一个线程并发调用 ncclCommInitRank。NCCL 2.x 保留了这两种初始化模式。它使用 Group API 添加了一种新模式,其中可以像通信调用一样在循环中调用 ncclCommInitRank,如下所示。循环必须由 Group start 和 end API 保护。

ncclGroupStart();
for (int i=0; i<ngpus; i++) {
  cudaSetDevice(i);
  ncclCommInitRank(comms+i, ngpus, id, i);
}
ncclGroupEnd();

通信

在 NCCL 2.x 中,可以通过在单个线程上的循环中进行调用来为不同的设备启动集体操作。这类似于 NCCL 1.x 中的用法。但是,此循环必须在 2.x 中由 Group API 保护。与 1.x 不同,应用程序不必在进行通信 API 调用之前选择相关的 CUDA 设备。NCCL 运行时在内部选择与 NCCL 通信器句柄关联的设备。例如

ncclGroupStart();
for (int i=0; i<nLocalDevs; i++) {
  ncclAllReduce(..., comm[i], stream[i]);
}
ncclGroupEnd();

当每个线程仅使用一个设备或每个进程一个设备时,API 的通用用法从 NCCL 1.x 到 2.x 保持不变。在这种情况下,不需要使用 group API。

计数

作为参数提供的计数现在是 size_t 类型,而不是整数。

AllGather 和 ReduceScatter 的原地使用

有关更多信息,请参阅“原地操作”。

AllGather 参数顺序

AllGather 函数的参数已重新排序。原型从以下更改为

ncclResult_t  ncclAllGather(const void* sendbuff, int count, ncclDataType_t datatype,
   void* recvbuff, ncclComm_t comm, cudaStream_t stream);

ncclResult_t  ncclAllGather(const void* sendbuff, void* recvbuff, size_t sendcount,
   ncclDataType_t datatype, ncclComm_t comm, cudaStream_t stream);

recvbuff 参数已移至 sendbuff 之后,以便与所有其他操作保持一致。

数据类型

NCCL 2.x 中添加了新的数据类型。NCCL 1.x 中存在的类型没有更改,并且仍然可以在 NCCL 2.x 中使用。

错误代码

错误代码已合并到 ncclInvalidArgument 类别中,并已简化。创建了新的 ncclInvalidUsage 代码以涵盖新的编程错误。