Add support for IB SHARP 1PPN operation with user buffers.
Improve support for MNNVL, add NVLS support and multi-clique support.
 * Detect the NVLS clique through NVML
 * Exchange XML between peers in the same NVLS clique and fuse XMLs
   before creating the topology graph.
 * Rework bootstrap allgather algorithms to allow for large allgather
   operations intra-node (XML exchange).
Net/IB: add support for dynamic GID detection.
 * Automatically select RoCEv2/IPv4 interface by default. Allow to
   select IPv6 or even the network/mask.
Reduce NVLS memory usage.
 * Add stepSize as property of a connection to allow for different
   sizes on different peers; set it to 128K for NVLink SHARP.
Improve tuner loading
 * Look for more paths, be more consistent with the network device
   plugin.
 * Also search for tuner support inside the net plugin.
Improve tuner API
 * Add context to support multi-device per process.
Add magic number around comm object to detect comm corruption.
 * Add some basic check around communicators so that we can report a
   problem when a communicator gets corrupted or a wrong comm pointer
   is passed to NCCL.
Fix net/IB error path. Github PR #1164
Fix collnet rail mapping with split comm.
Fix packet reordering issue causing bootstrap mismatch
 * Use a different tag in ncclTransportP2pSetup for the connectInfo
   exchange and the following barrier.
Fix hang when crossNic is inconsistent between ranks.
Fix minCompCap/maxCompCap computation. Github issue #1184


[ROCm/rccl commit: ab2b89c4c3]
Cette révision appartient à :
Sylvain Jeaugey a révisé 2024-04-02 01:53:21 -07:00
1 Parent b492ab6313
révision 792c33598f
52 fichiers modifiés
+2124 -944

Aucun fichier ne correspond à votre recherche

+61 -10
Voir le fichier
@@ -680,6 +680,36 @@ static ncclResult_t registerIntraNodeBuffers(
}
}
info->regBufType = NCCL_IPC_REG_BUFFER;
} else if ((info->algorithm == NCCL_ALGO_COLLNET_DIRECT || info->algorithm == NCCL_ALGO_COLLNET_CHAIN) && comm->collNetRegSupport && info->opFull.op != ncclDevPreMulSum && info->opFull.op != ncclDevSumPostDiv) {
int sendRegBufFlag = 0;
int recvRegBufFlag = 0;
void *sendHandle, *recvHandle;
if (ncclParamLocalRegister()) {
ncclCollnetLocalRegisterBuffer(comm, info->sendbuff, info->sendbuffSize, collNetSend, &sendRegBufFlag, &sendHandle);
info->sendMhandle = sendHandle;
if (sendRegBufFlag) {
ncclCollnetLocalRegisterBuffer(comm, info->recvbuff, info->recvbuffSize, collNetRecv, &recvRegBufFlag, &recvHandle);
info->recvMhandle = recvHandle;
}
}
if ((sendRegBufFlag == 0 || recvRegBufFlag == 0) && plan->persistent && ncclParamGraphRegister()) {
ncclCollnetGraphRegisterBuffer(comm, plan, info->sendbuff, info->sendbuffSize, collNetSend, &sendRegBufFlag, &sendHandle);
info->sendMhandle = sendHandle;
if (sendRegBufFlag) {
ncclCollnetGraphRegisterBuffer(comm, plan, info->recvbuff, info->recvbuffSize, collNetRecv, &recvRegBufFlag, &recvHandle);
info->recvMhandle = recvHandle;
}
}
if (sendRegBufFlag && recvRegBufFlag) {
info->nChannels = std::max(comm->config.minCTAs, std::min(comm->config.maxCTAs, 1));
info->regBufType = NCCL_COLLNET_REG_BUFFER;
if (sendRegBufFlag == 1 && recvRegBufFlag == 1) {
INFO(NCCL_REG, "rank %d successfully registered collNet sendbuff %p (handle %p), sendbuff size %ld, recvbuff %p (handle %p), recvbuff size %ld", comm->rank, info->sendbuff, sendHandle, info->sendbuffSize, info->recvbuff, recvHandle, info->recvbuffSize);
}
}
}
fallback:
#endif
@@ -806,7 +836,7 @@ static ncclResult_t scheduleCollTasksToPlan(
while (!ncclIntruQueueEmpty(&tasks->collCBDQueue)) {
// Get nChannels and peek whether the budget allows before we enqueue
collInfo = ncclIntruQueueHead(&tasks->collCBDQueue);
collInfo->nChannels = DIVUP(collInfo->aggnBytes * tasks->usableChannels, totalCBDBytes);
collInfo->nChannels = DIVUP(collInfo->workBytes * tasks->usableChannels, totalCBDBytes);
// Haven't got nChannels info yet, relax the budget boundary a bit.
if (*nWorkBudget < collInfo->nChannels) return ncclSuccess;
@@ -1173,6 +1203,12 @@ static ncclResult_t reclaimPlan(struct ncclComm* comm, struct ncclCommCallback*
INFO(NCCL_NVLS, "rank %d - deregistered buffer %p on device %d, size %ld", comm->rank, (void*)obj->ptr, obj->dev, obj->size);
ncclMemoryPoolFree(&comm->memPool_ncclNvlsHandleList, obj);
}
while (!ncclIntruQueueEmpty(&plan->collnetHandleQueue)) {
struct ncclCollnetHandleList* obj = ncclIntruQueueDequeue(&plan->collnetHandleQueue);
NCCLCHECK(ncclCollnetDeregBuffer(comm, obj->proxyconn, obj->collnetHandle));
INFO(NCCL_REG, "rank %d - deregistered collnet buffer handle %p, size %ld, buff %p", comm->rank, obj->collnetHandle, obj->size, obj->buffer);
ncclMemoryPoolFree(&comm->memPool_ncclCollnetHandleList, obj);
}
}
ncclMemoryPoolFree(&comm->memPool_ncclKernelPlan, plan);
return ncclSuccess;
@@ -1512,7 +1548,7 @@ static ncclResult_t getTunerInfo(struct ncclInfo* collInfo, int collNetSupport,
collInfo->nChannels = 0;
if (collInfo->comm->tuner != NULL) {
NCCLCHECK(collInfo->comm->tuner->getCollInfo(
collInfo->coll, collInfo->nBytes,
collInfo->comm->tunerContext, collInfo->coll, collInfo->nBytes,
collNetSupport, nvlsSupport, numPipeOps,
&collInfo->algorithm, &collInfo->protocol, &collInfo->nChannels));
}
@@ -1649,7 +1685,7 @@ static ncclResult_t setCollWorkElem(uint64_t workCount, uint64_t workOffset, siz
static ncclResult_t initCollWorkElemReg(struct ncclComm* comm, struct ncclWorkElem* work, struct ncclChannel* channel, ncclRegBufferType regBufType, void* regBufSend[], void* regBufRecv[], struct ncclWorkElemReg* workElemReg) {
if (regBufType == NCCL_IPC_REG_BUFFER) {
workElemReg->elem = *work;
workElemReg->elem.regUsed = 1;
workElemReg->elem.regUsed = NCCL_IPC_REG_BUFFER;
for (int i = 0; i < NCCL_MAX_DIRECT_ARITY; i++) {
int peer = channel->collnetDirect.down[i];
if (peer == -1) break;
@@ -1666,10 +1702,13 @@ static ncclResult_t initCollWorkElemReg(struct ncclComm* comm, struct ncclWorkEl
}
} else if (regBufType == NCCL_NVLS_REG_BUFFER) {
workElemReg->elem = *work;
workElemReg->elem.regUsed = 1;
workElemReg->elem.regUsed = NCCL_NVLS_REG_BUFFER;
/* NVLS only has one send and recv buffer registered */
workElemReg->dnInputs[0] = regBufSend[0];
workElemReg->dnOutputs[0] = regBufRecv[0];
} else if (regBufType == NCCL_COLLNET_REG_BUFFER) {
workElemReg->elem = *work;
workElemReg->elem.regUsed = NCCL_COLLNET_REG_BUFFER;
} else {
/* impossible value */
WARN("Invalid regBufType %d\n", regBufType);
@@ -1678,7 +1717,7 @@ static ncclResult_t initCollWorkElemReg(struct ncclComm* comm, struct ncclWorkEl
return ncclSuccess;
}
NCCL_PARAM(NvlsTreeChunkSize, "NVLSTREE_MAX_CHUNKSIZE", -2);
NCCL_PARAM(NvlsTreeMaxChunkSize, "NVLSTREE_MAX_CHUNKSIZE", -2);
static ncclResult_t computeCollChunkInfo(struct ncclInfo* collInfo, size_t nBytes, int nChannels) {
int stepSize = collInfo->comm->buffSizes[collInfo->protocol] / NCCL_STEPS;
@@ -1701,7 +1740,7 @@ static ncclResult_t computeCollChunkInfo(struct ncclInfo* collInfo, size_t nByte
while (nBytes / (nChannels * chunkSize) < collInfo->comm->channels[0].collnetChain.depth * 8 && chunkSize > 65536) chunkSize /= 2;
while (nBytes / (nChannels * chunkSize) < collInfo->comm->channels[0].collnetChain.depth && chunkSize > 32768) chunkSize /= 2;
} else if (collInfo->algorithm == NCCL_ALGO_NVLS) {
int maxChunkSize = 131072;
int maxChunkSize = collInfo->comm->nvlsChunkSize;
if (collInfo->comm->nNodes > 1 && collInfo->comm->bandwidths[ncclFuncAllReduce][NCCL_ALGO_NVLS][NCCL_PROTO_SIMPLE] < 150) maxChunkSize = 32768;
if (chunkSize > maxChunkSize) chunkSize = maxChunkSize;
// Use uint64_t so that concurrentOps*chunkSize*X does not overflow
@@ -1712,7 +1751,8 @@ static ncclResult_t computeCollChunkInfo(struct ncclInfo* collInfo, size_t nByte
} else if (collInfo->algorithm == NCCL_ALGO_NVLS_TREE) {
// Use uint64_t so that concurrentOps*chunkSize*X does not overflow
uint64_t concurrentOps = nChannels * collInfo->comm->channels[0].nvls.nHeads;
int maxChunkSize = ncclParamNvlsTreeChunkSize();
chunkSize = collInfo->comm->nvlsChunkSize;
int maxChunkSize = (int)ncclParamNvlsTreeMaxChunkSize();
if (maxChunkSize == -2) maxChunkSize = collInfo->comm->nNodes >= 4 ? 65536 : chunkSize;
chunkSize = std::min(chunkSize, maxChunkSize);
if ((nBytes < (32 * (concurrentOps * chunkSize))) && (chunkSize > 262144)) chunkSize = 262144;
@@ -1747,11 +1787,22 @@ static ncclResult_t initCollProxyOp(struct ncclInfo* collInfo, int channelId, ui
proxyOp->pattern = collInfo->pattern;
proxyOp->coll = collInfo->coll;
proxyOp->root = collInfo->root;
proxyOp->reg = 0;
// This is used by P2P to reduce the receive buffer size. We don't use it in collectives
// because some protocols need to transmit more than the total size, plus they sometimes
// round up
proxyOp->nbytes = collInfo->stepSize * proxyOp->sliceSteps;
if (collInfo->regBufType == NCCL_COLLNET_REG_BUFFER) {
proxyOp->reg = 1;
proxyOp->nsteps = DIVUP(collInfo->nBytes, NCCL_MAX_COLLNET_SIZE);
proxyOp->sendMhandle = collInfo->sendMhandle;
proxyOp->recvMhandle = collInfo->recvMhandle;
proxyOp->sendbuff = (uint8_t*)collInfo->sendbuff;
proxyOp->recvbuff = (uint8_t*)collInfo->recvbuff;
proxyOp->nbytes = collInfo->nBytes;
} else {
proxyOp->reg = 0;
}
proxyOp->channelId = channelId;
proxyOp->opCount = opCount;
@@ -1958,7 +2009,7 @@ ncclResult_t ncclEnqueueCheck(struct ncclInfo* info) {
ncclResult_t ret = ncclSuccess;
int devOld = -1;
NCCLCHECKGOTO(PtrCheck(info->comm, info->opName, "comm"), ret, fail);
NCCLCHECKGOTO(CommCheck(info->comm, info->opName, "comm"), ret, fail);
// Check whether communicator is ready to communicate
NCCLCHECKGOTO(ncclCommEnsureReady(info->comm), ret, fail);
@@ -1990,7 +2041,7 @@ fail:
NCCL_API(ncclResult_t, ncclRedOpCreatePreMulSum, ncclRedOp_t *op, void *scalar, ncclDataType_t datatype, ncclScalarResidence_t residence, ncclComm_t comm);
ncclResult_t ncclRedOpCreatePreMulSum(ncclRedOp_t *op, void *scalar, ncclDataType_t datatype, ncclScalarResidence_t residence, ncclComm_t comm) {
NCCLCHECK(PtrCheck(comm, "ncclRedOpCreatePreMulSum", "comm"));
NCCLCHECK(CommCheck(comm, "ncclRedOpCreatePreMulSum", "comm"));
/* join init thread before creating PreMulSum op. */
NCCLCHECK(ncclCommEnsureReady(comm));