用户缓冲区注册
用户缓冲区注册是一个功能,它允许MCCL直接通过用户缓冲区发送/接收/操作数据,无需额外的内部复制(零复制)。它可以加速集体操作,并大大减少资源使用(例如#通道使用)。MCCL提供了两种注册用户缓冲区的方式;一种是MUSA图注册,另一种是本地注册。MCCL要求对于所有MCCL通信函数调用(例如,allreduce、sendrecv等),如果任何等级在通信器中传递注册缓冲区给MCCL通信函数,同一通信器中的所有其他等级也必须传递其注册缓冲区;否则,混合注册和非注册缓冲区可能导致未定义行为。
MTLink Sharp缓冲区注册
从2.19.x版本开始,MCCL支持MTLink Sharp(MTLS)的用户缓冲区注册;任何支持MTLS算法的MCCL集体操作(例如,allreduce)都可以利用这一特性。
要启用基于MUSA图的MTLS缓冲区注册,用户必须遵守几个要求:
- 缓冲区是通过
mcclMemAlloc()或合格的分配器分配的(见内存分配器)。 - MCCL操作是在每个等级的MUSA图捕获的流上启动的。
- 在每个等级的集体操作中,缓冲区的头部地址偏移是相同的。
注册的缓冲区将在MUSA图被销毁时取消注册。这里是一个基于MUSA图的缓冲区注册示例:
void* sendbuff;
void* recvbuff;
size_t count = 1 << 25;
CHECK(mcclMemAlloc(&sendbuff, count * sizeof(float)));
CHECK(mcclMemAlloc(&recvbuff, count * sizeof(float)));
musaGraph_t graph;
CHECK(musaStreamBeginCapture(stream, musaStreamCaptureModeThreadLocal));
CHECK(mcclAllReduce(sendbuff, recvbuff, 1024, mcclFloat, mcclSum, comm, stream));
// 每个等级的sendbuff和recvbuff头部地址偏移相同
CHECK(mcclAllReduce((void*)((float*)sendbuff + 1024), (void*)((float*)recvbuff + 2048), 1024, mcclFloat, mcclSum, comm, stream));
CHECK(musaStreamEndCapture(stream, &graph));
musaGraphExec_t instance;
CHECK(musaGraphInstantiate(&instance, graph, NULL, NULL, 0));
CHECK(musaGraphLaunch(instance, stream));
CHECK(musaStreamSynchronize(stream));
CHECK(musaGraphExecDestroy(instance));
CHECK(musaGraphDestroy(graph));
CHECK(mcclMemFree(sendbuff));
CHECK(mcclMemFree(recvbuff));
另一方面,要启用基于本地的MTLS缓冲区注册,用户必须遵守以下要求:
-
缓冲区是通过
mcclMemAlloc()或合格的分配器分配的(见内存分配器)。 -
在每个等级调用集体操作之前,使用
mcclCommRegister()注册缓冲区。 -
像往常一样调用MCCL集体操作,但同样保持缓冲区头部地址的偏移对每个等级都是相同的。
注册的缓冲区将在用户显式调用 mcclCommDeregister() 时取消注册。这里是一个基于本地的缓冲区注册示例:
void* sendbuff;
void* recvbuff;
size_t count = 1 << 25;
void* sendRegHandle;
void* recvRegHandle;
CHECK(mcclMemAlloc(&sendbuff, count * sizeof(float)));
CHECK(mcclMemAlloc(&recvbuff, count * sizeof(float)));
CHECK(mcclCommRegister(comm, sendbuff, count * sizeof(float), &sendRegHandle));
CHECK(mcclCommRegister(comm, recvbuff, count * sizeof(float), &recvRegHandle));
CHECK(mcclAllReduce(sendbuff, recvbuff, 1024, mcclFloat, mcclSum, comm, stream));
CHECK(mcclAllReduce((void*)((float*)sendbuff + 1024), (void*)((float*)recvbuff + 2048), 1024, mcclFloat, mcclSum, comm, stream));
CHECK(musaStreamSynchronize(stream));
CHECK(mcclCommDeregister(comm, sendRegHandle));
CHECK(mcclCommDeregister(comm, recvRegHandle));
CHECK(mcclMemFree(sendbuff));
CHECK(mcclMemFree(recvbuff));
对于基于本地的注册,用户可以在程序开始时注册缓冲区一次,并多次重用缓冲区以利用注册的好处。
为了节省内存,也可以分配一大块缓冲区并只注册一次。sendbuff和recvbuff可以通过大块进一步分配,以实现零复制MCCL操作,只要sendbuff和recvbuff满足偏移要求。以下示例显示了一个用例:
void* buffer;
void* handle;
void* sendbuff;
void* recvbuff;
size_t size = 1 << 29;
CHECK(mcclMemAlloc(&buffer, size));
CHECK(mcclCommRegister(comm, buffer, size, &handle));
// 分配缓冲区块给sendbuff和recvbuff
sendbuff = buffer;
recvbuff = (void*)((uint8_t*)buffer + (1 << 20));
CHECK(mcclAllReduce(sendbuff, recvbuff, 1024, mcclFloat, mcclSum, comm, stream));
CHECK(musaStreamSynchronize(stream));
CHECK(mcclCommDeregister(comm, handle));
CHECK(mcclMemFree(sendbuff));
IB Sharp缓冲区注册
MCCL 2.21.x支持IB Sharp缓冲区注册,任何支持IB Sharp算法的MCCL集体操作都可以从该特性中受益,例如allreduce、reducescatter和allgather。目前,MCCL仅支持每个节点包含1个等级的通信器的IB Sharp缓冲区注册,注册可以减少MCCL SM使用量至1。
通过MUSA图启用IB Sharp缓冲区注册:
-
使用任何MUSA分配器(例如,musaMalloc/mcclMemAlloc)分配发送和接收缓冲区
-
使用MUSA图启动MCCL集体操作
通过本地注册启用IB Sharp缓冲区注册:
-
使用任何MUSA分配器(例如,musaMalloc/mcclMemAlloc)分配发送和接收缓冲区
-
在通信器中的每个等级使用mcclCommRegister注册发送和接收缓冲区
-
启动MCCL集体操作
通用缓冲区注册
从2.23.x版本开始,MCCL支持节点内缓冲区注册,它 针对所有点对点节点内通信(例如,Allgather Ring)并带来较小的内存压力,更好的通信和计算重叠性能。通过在开始时使用mcclCommRegister注册缓冲区或应用MUSA图,可以为MCCL集体操作和sendrecv启用节点内缓冲区注册。
用户缓冲区可以通过VMM API(即,cuMem*)、任何基于VMM的分配器(内存分配器)或mcclMemAlloc分配。通过传统musa API(例如,musaMalloc)分配的缓冲区也可以用于注册。然而,由于执行期间可能挂起和失败和中止期间的段错误,因此不推荐使用传统缓冲区进行注册;目前,默认情况下禁用了传统缓冲区注册,用户可以设置MCCL_LEGACY_MUSA_REGISTER=1以启用它。
内存分配器
为了方便,MCCL提供了mcclMemAlloc函数,帮助用户通过VMM API分配缓冲区,稍后可以用于MCCL注册。它仅设计用于MCCL,因此不推荐在应用程序的任何地方使用mcclMemAlloc分配的缓冲区。
对于高级用户,如果您想为MTLS UB创建自己的内存分配器,分配器分配的缓冲区需要满足以下要求:
- 使用共享标志分配缓冲区 CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR以及在支持的GPU上CU_MEM_HANDLE_TYPE_FABRIC。
- 缓冲区物理内存大小是CUMEM推荐粒度的倍数(即cuMemGetAllocationGranularity(..., CU_MEM_ALLOC_GRANULARITY_RECOMMENDED`))
- 缓冲区虚拟头部地址至少与CUMEM推荐粒度对齐,大小是CUMEM推荐粒度的倍数。
对于使用VMM API的通用缓冲区注册,分配器需要满足与MTLS UB分配器相同的要求。

