Merge remote-tracking branch 'nccl/master' into develop
This commit is contained in:
@@ -104,7 +104,7 @@ struct sendResources {
|
||||
int rank;
|
||||
int nranks;
|
||||
int netDev;
|
||||
int useGdr;
|
||||
enum ncclTopoGdrMode useGdr;
|
||||
int useDmaBuf;
|
||||
uint64_t* gdcSync;
|
||||
void* gdrDesc;
|
||||
@@ -126,7 +126,7 @@ struct recvResources {
|
||||
int rank;
|
||||
int nranks;
|
||||
int netDev;
|
||||
int useGdr;
|
||||
enum ncclTopoGdrMode useGdr;
|
||||
int useDmaBuf;
|
||||
int needFlush;
|
||||
uint64_t* gdcSync;
|
||||
@@ -146,9 +146,19 @@ static ncclResult_t canConnect(int* ret, struct ncclComm* comm, struct ncclTopoG
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
// Returns the flags to be used by a call to cuMemGetHandleForAddressRange.
|
||||
static inline int getHandleForAddressRangeFlags(ncclTopoGdrMode useGdr) {
|
||||
int flags = 0;
|
||||
#if CUDA_VERSION >= 12080
|
||||
// Force mapping on PCIe on systems with both PCI and C2C attachments.
|
||||
if (useGdr == ncclTopoGdrModePci) flags = CU_MEM_RANGE_FLAG_DMA_BUF_MAPPING_TYPE_PCIE;
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
struct setupReq {
|
||||
int netDev;
|
||||
int useGdr;
|
||||
enum ncclTopoGdrMode useGdr;
|
||||
int needFlush;
|
||||
struct ncclCollNetSharedRes* collNet;
|
||||
};
|
||||
@@ -171,8 +181,8 @@ static ncclResult_t sendSetup(struct ncclComm* comm, struct ncclTopoGraph* graph
|
||||
req.collNet = comm->collNetSharedRes;
|
||||
NCCLCHECK(ncclProxyCallBlocking(comm, &send->proxyConn, ncclProxyMsgSetup, &req, sizeof(req), NULL, 0));
|
||||
|
||||
INFO(NCCL_INIT|NCCL_NET,"CollNet %02d/%1d : %d [send] via COLLNET/%s/%d%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, collNetName(comm), req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", comm, comm->nRanks);
|
||||
INFO(NCCL_INIT|NCCL_NET,"CollNet %02d/%1d : %d [send] via COLLNET/%s/%d%s%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, collNetName(comm), req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", req.useGdr==ncclTopoGdrModePci ? "(PCI)" : "", comm, comm->nRanks);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
@@ -185,7 +195,7 @@ static ncclResult_t recvSetup(struct ncclComm* comm, struct ncclTopoGraph* graph
|
||||
NCCLCHECK(ncclTopoCheckGdr(comm->topo, myInfo->rank, netId, 0, &req.useGdr));
|
||||
recv->conn.flags |= req.useGdr ? NCCL_DIRECT_NIC : 0;
|
||||
// Determine whether we need to flush the GDR buffer on recv or not
|
||||
if (req.useGdr) NCCLCHECK(ncclTopoNeedFlush(comm, req.netDev, myInfo->rank, &req.needFlush));
|
||||
if (req.useGdr) NCCLCHECK(ncclTopoNeedFlush(comm, netId, req.netDev, myInfo->rank, &req.needFlush));
|
||||
|
||||
recv->proxyConn.tpLocalRank = comm->topParentLocalRanks[comm->localRank];
|
||||
NCCLCHECK(ncclProxyConnect(comm, TRANSPORT_COLLNET, 0, myInfo->rank, &recv->proxyConn));
|
||||
@@ -195,8 +205,8 @@ static ncclResult_t recvSetup(struct ncclComm* comm, struct ncclTopoGraph* graph
|
||||
req.collNet = comm->collNetSharedRes;
|
||||
NCCLCHECK(ncclProxyCallBlocking(comm, &recv->proxyConn, ncclProxyMsgSetup, &req, sizeof(req), &info->collNetHandle, sizeof(collNetHandle_t)));
|
||||
|
||||
INFO(NCCL_INIT|NCCL_NET,"CollNet %02d/%1d : %d [receive] via COLLNET/%s/%d%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, collNetName(comm), req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", comm, comm->nRanks);
|
||||
INFO(NCCL_INIT|NCCL_NET,"CollNet %02d/%1d : %d [receive] via COLLNET/%s/%d%s%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, collNetName(comm), req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", req.useGdr==ncclTopoGdrModePci ? "(PCI)" : "", comm, comm->nRanks);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
@@ -459,6 +469,7 @@ static ncclResult_t recvProxySetup(struct ncclProxyConnection* connection, struc
|
||||
}
|
||||
|
||||
static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, struct ncclProxyState* proxyState, void* reqBuff, int reqSize, void* respBuff, int respSize, int* done) {
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
if (reqSize != sizeof(struct collNetConnectArgs)) { WARN("sendProxyConnect: reqSize is %d != %ld", reqSize, sizeof(struct collNetConnectArgs)); return ncclInternalError; }
|
||||
struct collNetConnectArgs* args = (struct collNetConnectArgs*)reqBuff;
|
||||
static_assert(sizeof(collNetSendConnectInfo) <= sizeof(struct ncclConnect), "Collnet Send Connect info is too big");
|
||||
@@ -510,16 +521,17 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
int bank = resources->useGdr ? NCCL_NET_MAP_SHARED_DEVMEM : NCCL_NET_MAP_SHARED_HOSTMEM;
|
||||
struct connectMapMem* mapMem = map->mems+bank;
|
||||
NCCLCHECK(sharedBuffersInit(connection->collNet, resources->useGdr, &mapMem->gpuPtr, &mapMem->cpuPtr, &mapMem->size));
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr ? 1 : 0, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
|
||||
int dmabuf_fd = -1;
|
||||
#if CUDA_VERSION >= 11070
|
||||
/* DMA-BUF support */
|
||||
if (resources->useGdr && resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)mapMem->cpuPtr, mapMem->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0));
|
||||
NCCLCHECK(proxyState->ncclCollNet->regMrDmaBuf(resources->collNetComm, mapMem->cpuPtr, mapMem->size,
|
||||
NCCL_PTR_CUDA, 0ULL, dmabuf_fd,
|
||||
&resources->sendMhandles[NCCL_PROTO_SIMPLE]));
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)mapMem->cpuPtr, mapMem->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)));
|
||||
NCCLCHECKGOTO(proxyState->ncclCollNet->regMrDmaBuf(resources->collNetComm, mapMem->cpuPtr, mapMem->size,
|
||||
NCCL_PTR_CUDA, 0ULL, dmabuf_fd,
|
||||
&resources->sendMhandles[NCCL_PROTO_SIMPLE]),
|
||||
ret, fail);
|
||||
(void)close(dmabuf_fd);
|
||||
} else // FALL-THROUGH to nv_peermem GDR path
|
||||
#endif
|
||||
@@ -530,10 +542,18 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
}
|
||||
|
||||
*((struct connectMap**)respBuff) = &resources->map;
|
||||
return ncclSuccess;
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
fail:
|
||||
if (dmabuf_fd != -1) {
|
||||
(void)close(dmabuf_fd);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static ncclResult_t recvProxyConnect(struct ncclProxyConnection* connection, struct ncclProxyState* proxyState, void* reqBuff, int reqSize, void* respBuff, int respSize, int* done) {
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
if (reqSize != sizeof(struct collNetConnectArgs)) { WARN("recvProxyConnect: reqSize is %d != %ld", reqSize, sizeof(struct collNetConnectArgs)); return ncclInternalError; }
|
||||
struct collNetConnectArgs* args = (struct collNetConnectArgs*)reqBuff;
|
||||
|
||||
@@ -579,16 +599,17 @@ static ncclResult_t recvProxyConnect(struct ncclProxyConnection* connection, str
|
||||
int bank = resources->useGdr ? NCCL_NET_MAP_SHARED_DEVMEM : NCCL_NET_MAP_SHARED_HOSTMEM;
|
||||
struct connectMapMem* mapMem = map->mems+bank;
|
||||
NCCLCHECK(sharedBuffersInit(connection->collNet, resources->useGdr, &mapMem->gpuPtr, &mapMem->cpuPtr, &mapMem->size));
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr ? 1 : 0, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
|
||||
int dmabuf_fd = -1;
|
||||
#if CUDA_VERSION >= 11070
|
||||
/* DMA-BUF support */
|
||||
if (resources->useGdr && resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)mapMem->cpuPtr, mapMem->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0));
|
||||
NCCLCHECK(proxyState->ncclCollNet->regMrDmaBuf(resources->collNetComm, mapMem->cpuPtr, mapMem->size,
|
||||
NCCL_PTR_CUDA, 0ULL, dmabuf_fd,
|
||||
&resources->mhandles[NCCL_PROTO_SIMPLE]));
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)mapMem->cpuPtr, mapMem->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)));
|
||||
NCCLCHECKGOTO(proxyState->ncclCollNet->regMrDmaBuf(resources->collNetComm, mapMem->cpuPtr, mapMem->size,
|
||||
NCCL_PTR_CUDA, 0ULL, dmabuf_fd,
|
||||
&resources->mhandles[NCCL_PROTO_SIMPLE]),
|
||||
ret, fail);
|
||||
(void)close(dmabuf_fd);
|
||||
} else // FALL-THROUGH to nv_peermem GDR path
|
||||
#endif
|
||||
@@ -605,7 +626,14 @@ static ncclResult_t recvProxyConnect(struct ncclProxyConnection* connection, str
|
||||
|
||||
if (respSize != sizeof(struct connectMap*)) { WARN("recvProxyConnect: respSize is %d != %ld", respSize, sizeof(void*)); return ncclInternalError; }
|
||||
*((struct connectMap**)respBuff) = &resources->map;
|
||||
return ncclSuccess;
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
fail:
|
||||
if (dmabuf_fd != -1) {
|
||||
(void)close(dmabuf_fd);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static ncclResult_t sendProxyFree(struct ncclProxyConnection* connection, struct ncclProxyState* proxyState) {
|
||||
@@ -742,7 +770,7 @@ static ncclResult_t collNetIallreduce(struct ncclProxyState* proxyState, struct
|
||||
}
|
||||
|
||||
static ncclResult_t collNetRegIallgather(struct ncclProxyState* proxyState, struct sendResources *resources, struct ncclProxyArgs *args, struct ncclProxySubArgs *sub, ssize_t nBytesIn, ssize_t allBeg, ssize_t recvBeg, void *recvMhandle, void **request) {
|
||||
ncclNetSGE_v9_t recvParts;
|
||||
ncclNetSGE_t recvParts;
|
||||
ssize_t sizePerRank = args->specifics.collnetDirect.sizePerRank;
|
||||
char *region = NCCL_NET_MAP_GET_POINTER(&resources->map, gpu, buffs[NCCL_PROTO_SIMPLE]);
|
||||
ssize_t nBytes;
|
||||
@@ -784,7 +812,7 @@ static ncclResult_t collNetRegIallgather(struct ncclProxyState* proxyState, stru
|
||||
}
|
||||
|
||||
static ncclResult_t collNetIallgather(struct ncclProxyState* proxyState, struct sendResources *resources, struct ncclProxyArgs *args, struct ncclProxySubArgs *sub, ssize_t nBytes, ssize_t allBeg, ssize_t sendBeg, ssize_t recvBeg, void *sendMhandle, void *recvMhandle, void **request) {
|
||||
ncclNetSGE_v9_t recvParts;
|
||||
ncclNetSGE_t recvParts;
|
||||
ssize_t sizePerRank = args->specifics.collnetDirect.sizePerRank;
|
||||
char *region = NCCL_NET_MAP_GET_POINTER(&resources->map, gpu, buffs[NCCL_PROTO_SIMPLE]);
|
||||
recvParts.mhandle = recvMhandle;
|
||||
@@ -801,7 +829,7 @@ static ncclResult_t collNetIallgather(struct ncclProxyState* proxyState, struct
|
||||
}
|
||||
|
||||
static ncclResult_t collNetRegIreducescatter(struct ncclProxyState* proxyState, struct sendResources *resources, struct ncclProxyArgs *args, struct ncclProxySubArgs *sub, ssize_t nBytesIn, ssize_t allBeg, ssize_t sendBeg, void *sendMhandle, void **request) {
|
||||
ncclNetSGE_v9_t sendParts;
|
||||
ncclNetSGE_t sendParts;
|
||||
ssize_t sizePerRank = args->specifics.collnetDirect.sizePerRank;
|
||||
char *region = NCCL_NET_MAP_GET_POINTER(&resources->map, gpu, buffs[NCCL_PROTO_SIMPLE]);
|
||||
ssize_t nBytes;
|
||||
@@ -840,7 +868,7 @@ static ncclResult_t collNetRegIreducescatter(struct ncclProxyState* proxyState,
|
||||
}
|
||||
|
||||
static ncclResult_t collNetIreducescatter(struct ncclProxyState* proxyState, struct sendResources *resources, struct ncclProxyArgs *args, struct ncclProxySubArgs *sub, ssize_t nBytes, ssize_t allBeg, ssize_t sendBeg, ssize_t recvBeg, void *sendMhandle, void *recvMhandle, void **request) {
|
||||
ncclNetSGE_v9_t sendParts;
|
||||
ncclNetSGE_t sendParts;
|
||||
ssize_t sizePerRank = args->specifics.collnetDirect.sizePerRank;
|
||||
char *region = NCCL_NET_MAP_GET_POINTER(&resources->map, gpu, buffs[NCCL_PROTO_SIMPLE]);
|
||||
sendParts.mhandle = sendMhandle;
|
||||
@@ -1156,6 +1184,7 @@ struct collnetRegInfo {
|
||||
|
||||
static ncclResult_t collnetRegisterBuffer(struct ncclComm* comm, const void* userbuff, size_t buffSize, int type, struct ncclReg* regRecord, int* outRegBufFlag, void** outHandle) {
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
int gdrEnable = -1;
|
||||
if (regRecord) {
|
||||
if (regRecord->state & COLLNET_REG_COMPLETE) {
|
||||
// reuse previous registration
|
||||
@@ -1171,6 +1200,7 @@ static ncclResult_t collnetRegisterBuffer(struct ncclComm* comm, const void* use
|
||||
|
||||
if (conn->flags & NCCL_DIRECT_NIC) {
|
||||
struct ncclProxyConnector* proxyconn = (type == collNetRecv) ? &comm->channels[0].peers[comm->nRanks]->recv[type].proxyConn : &comm->channels[0].peers[comm->nRanks]->send[type].proxyConn;
|
||||
gdrEnable = 1;
|
||||
NCCLCHECKGOTO(ncclProxyCallBlocking(comm, proxyconn, ncclProxyMsgRegister, &info, sizeof(struct collnetRegInfo), &handle, sizeof(void*)), ret, fail);
|
||||
if (handle) {
|
||||
regRecord->state |= COLLNET_REG_COMPLETE;
|
||||
@@ -1180,7 +1210,8 @@ static ncclResult_t collnetRegisterBuffer(struct ncclComm* comm, const void* use
|
||||
INFO(NCCL_REG, "rank %d - COLLNET register userbuff %p (handle %p), buffSize %ld, type %s", comm->rank, userbuff, handle, buffSize, type == collNetRecv ? "Recv" : "Send");
|
||||
}
|
||||
} else {
|
||||
WARN("rank %d - COLLNET failed to register userbuff %p (handle %p), buffSize %ld, type %s, GDR is not enabled", comm->rank, userbuff, handle, buffSize, type == collNetRecv ? "Recv" : "Send");
|
||||
gdrEnable = 0;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1189,6 +1220,7 @@ exit:
|
||||
fail:
|
||||
*outRegBufFlag = 0;
|
||||
*outHandle = NULL;
|
||||
INFO(NCCL_REG, "rank %d - COLLNET failed to register userbuff %p, buffSize %ld, type %s, GDR %d", comm->rank, userbuff, buffSize, type == collNetRecv ? "Recv" : "Send", gdrEnable);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -1274,17 +1306,20 @@ static ncclResult_t sendProxyRegBuffer(struct ncclProxyConnection* connection, s
|
||||
assert(reqSize == sizeof(struct collnetRegInfo));
|
||||
assert(respSize == sizeof(void*));
|
||||
|
||||
int dmabuf_fd = -1;
|
||||
#if CUDART_VERSION >= 11070
|
||||
/* DMA-BUF support */
|
||||
if (resources->useGdr && resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0), ret, peermem);
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)), ret, peermem);
|
||||
NCCLCHECKGOTO(proxyState->ncclCollNet->regMrDmaBuf(resources->collNetComm, (void*)info->buffer, info->size, NCCL_PTR_CUDA, 0ULL, dmabuf_fd, &handle), ret, peermem);
|
||||
(void)close(dmabuf_fd);
|
||||
needReg = false;
|
||||
}
|
||||
#endif
|
||||
peermem:
|
||||
if (dmabuf_fd != -1) {
|
||||
(void)close(dmabuf_fd);
|
||||
dmabuf_fd = -1;
|
||||
}
|
||||
if (needReg) {
|
||||
NCCLCHECKGOTO(proxyState->ncclCollNet->regMr(resources->collNetComm, (void*)info->buffer, info->size, NCCL_PTR_CUDA, &handle), ret, fail);
|
||||
}
|
||||
@@ -1307,17 +1342,20 @@ static ncclResult_t recvProxyRegBuffer(struct ncclProxyConnection* connection, s
|
||||
|
||||
assert(reqSize == sizeof(struct collnetRegInfo));
|
||||
assert(respSize == sizeof(void*));
|
||||
int dmabuf_fd = -1;
|
||||
#if CUDART_VERSION >= 11070
|
||||
/* DMA-BUF support */
|
||||
if (resources->useGdr && resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0), ret, peermem);
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)), ret, peermem);
|
||||
NCCLCHECKGOTO(proxyState->ncclCollNet->regMrDmaBuf(resources->collNetComm, (void*)info->buffer, info->size, NCCL_PTR_CUDA, 0ULL, dmabuf_fd, &handle), ret, peermem);
|
||||
(void)close(dmabuf_fd);
|
||||
needReg = false;
|
||||
}
|
||||
#endif
|
||||
peermem:
|
||||
if (dmabuf_fd != -1) {
|
||||
(void)close(dmabuf_fd);
|
||||
dmabuf_fd = -1;
|
||||
}
|
||||
if (needReg) {
|
||||
NCCLCHECKGOTO(proxyState->ncclCollNet->regMr(resources->collNetComm, (void*)info->buffer, info->size, NCCL_PTR_CUDA, &handle), ret, fail);
|
||||
}
|
||||
@@ -1606,4 +1644,4 @@ struct ncclTransport collNetTransport = {
|
||||
canConnect,
|
||||
{ sendSetup, sendConnect, sendFree, NULL, sendProxySetup, sendProxyConnect, sendProxyFree, sendProxyProgress, sendProxyRegBuffer, sendProxyDeregBuffer },
|
||||
{ recvSetup, recvConnect, recvFree, NULL, recvProxySetup, recvProxyConnect, recvProxyFree, recvProxyProgress, recvProxyRegBuffer, recvProxyDeregBuffer }
|
||||
};
|
||||
};
|
||||
|
||||
+54
-32
@@ -103,7 +103,7 @@ struct sendNetResources {
|
||||
int tpLocalRank;
|
||||
int tpRemoteRank;
|
||||
int netDev;
|
||||
int useGdr;
|
||||
enum ncclTopoGdrMode useGdr;
|
||||
int useDmaBuf;
|
||||
int maxRecvs;
|
||||
uint64_t* gdcSync;
|
||||
@@ -135,7 +135,7 @@ struct recvNetResources {
|
||||
int tpRemoteRank;
|
||||
int tpRemoteProxyRank;
|
||||
int netDev;
|
||||
int useGdr;
|
||||
enum ncclTopoGdrMode useGdr;
|
||||
int useDmaBuf;
|
||||
int needFlush;
|
||||
int maxRecvs;
|
||||
@@ -188,7 +188,7 @@ struct setupReq {
|
||||
int tpRemoteRank;
|
||||
int shared;
|
||||
int netDev;
|
||||
int useGdr;
|
||||
enum ncclTopoGdrMode useGdr;
|
||||
int needFlush;
|
||||
int channelId;
|
||||
int connIndex;
|
||||
@@ -201,6 +201,16 @@ static_assert(sizeof(ncclNetHandle_t) + sizeof(int) <= CONNECT_SIZE, "Not large
|
||||
// Forward declaration
|
||||
static ncclResult_t sendProxyProgress(struct ncclProxyState* proxyState, struct ncclProxyArgs* args);
|
||||
|
||||
// Returns the flags to be used by a call to cuMemGetHandleForAddressRange.
|
||||
static inline int getHandleForAddressRangeFlags(ncclTopoGdrMode useGdr) {
|
||||
int flags = 0;
|
||||
#if CUDA_VERSION >= 12080
|
||||
// Force mapping on PCIe on systems with both PCI and C2C attachments.
|
||||
if (useGdr == ncclTopoGdrModePci) flags = CU_MEM_RANGE_FLAG_DMA_BUF_MAPPING_TYPE_PCIE;
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Determine if we will use this transport for this peer and return connect
|
||||
* information for this peer */
|
||||
static ncclResult_t sendSetup(struct ncclComm* comm, struct ncclTopoGraph* graph, struct ncclPeerInfo* myInfo, struct ncclPeerInfo* peerInfo, struct ncclConnect* connectInfo, struct ncclConnector* send, int channelId, int connIndex) {
|
||||
@@ -232,11 +242,14 @@ static ncclResult_t sendSetup(struct ncclComm* comm, struct ncclTopoGraph* graph
|
||||
NCCLCHECK(ncclProxyCallBlocking(comm, &send->proxyConn, ncclProxyMsgSetup, &req, sizeof(req), NULL, 0));
|
||||
|
||||
if (proxyRank == myInfo->rank) {
|
||||
INFO(NCCL_INIT|NCCL_NET,"Channel %02d/%d : %d[%lx] -> %d[%lx] [send] via NET/%s/%d%s%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, myInfo->busId, peerInfo->rank, peerInfo->busId, comm->ncclNet->name, req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", req.shared ? "/Shared" : "", comm, comm->nRanks);
|
||||
INFO(NCCL_INIT|NCCL_NET,"Channel %02d/%d : %d[%d] -> %d[%d] [send] via NET/%s/%d%s%s%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, myInfo->nvmlDev, peerInfo->rank, peerInfo->nvmlDev, comm->ncclNet->name, req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", req.useGdr==ncclTopoGdrModePci ? "(PCI)" : "",
|
||||
req.shared ? "/Shared" : "", comm, comm->nRanks);
|
||||
} else {
|
||||
INFO(NCCL_INIT|NCCL_NET,"Channel %02d/%d : %d[%lx] -> %d[%lx] [send] via NET/%s/%d(%d)%s%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, myInfo->busId, peerInfo->rank, peerInfo->busId, comm->ncclNet->name, req.netDev,
|
||||
proxyRank, req.useGdr ? "/GDRDMA" : "", req.shared ? "/Shared" : "", comm, comm->nRanks);
|
||||
INFO(NCCL_INIT|NCCL_NET,"Channel %02d/%d : %d[%d] -> %d[%d] [send] via NET/%s/%d(%d)%s%s%s comm %p nRanks %02d", channelId, connIndex, myInfo->rank, myInfo->nvmlDev, peerInfo->rank, peerInfo->nvmlDev, comm->ncclNet->name, req.netDev,
|
||||
proxyRank,
|
||||
req.useGdr ? "/GDRDMA" : "", req.useGdr==ncclTopoGdrModePci ? "(PCI)" : "",
|
||||
req.shared ? "/Shared" : "", comm, comm->nRanks);
|
||||
}
|
||||
*((int*)connectInfo) = comm->topParentRanks[proxyRank];
|
||||
memcpy((uint8_t*)connectInfo + sizeof(ncclNetHandle_t), &req.useGdr, sizeof(int));
|
||||
@@ -268,7 +281,7 @@ static ncclResult_t recvSetup(struct ncclComm* comm, struct ncclTopoGraph* graph
|
||||
|
||||
// Determine whether we need to flush the GDR buffer on recv or not
|
||||
if (req.useGdr) {
|
||||
NCCLCHECK(ncclTopoNeedFlush(comm, req.netDev, myInfo->rank, &req.needFlush));
|
||||
NCCLCHECK(ncclTopoNeedFlush(comm, netId, req.netDev, myInfo->rank, &req.needFlush));
|
||||
CUDACHECK(hipDeviceGetAttribute((int*)&req.curr_hdp_reg, hipDeviceAttributeHdpMemFlushCntl, myInfo->cudaDev));
|
||||
recv->conn.curr_hdp_reg = req.curr_hdp_reg;
|
||||
}
|
||||
@@ -281,18 +294,19 @@ static ncclResult_t recvSetup(struct ncclComm* comm, struct ncclTopoGraph* graph
|
||||
req.tpRemoteRank = comm->topParentRanks[peerInfo->rank];
|
||||
NCCLCHECK(ncclProxyCallBlocking(comm, &recv->proxyConn, ncclProxyMsgSetup, &req, sizeof(req), connectInfo, sizeof(ncclNetHandle_t)));
|
||||
memcpy((uint8_t*)connectInfo + sizeof(ncclNetHandle_t), &req.useGdr, sizeof(int));
|
||||
INFO(NCCL_INIT|NCCL_NET,"Channel %02d/%d : %d[%lx] -> %d[%lx] [receive] via NET/%s/%d%s%s comm %p nRanks %02d", channelId, connIndex, peerInfo->rank, peerInfo->busId, myInfo->rank, myInfo->busId, comm->ncclNet->name, req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", req.shared ? "/Shared" : "", comm, comm->nRanks);
|
||||
INFO(NCCL_INIT|NCCL_NET,"Channel %02d/%d : %d[%d] -> %d[%d] [receive] via NET/%s/%d%s%s%s comm %p nRanks %02d", channelId, connIndex, peerInfo->rank, peerInfo->nvmlDev, myInfo->rank, myInfo->nvmlDev, comm->ncclNet->name, req.netDev,
|
||||
req.useGdr ? "/GDRDMA" : "", req.useGdr==ncclTopoGdrModePci ? "(PCI)" : "",
|
||||
req.shared ? "/Shared" : "", comm, comm->nRanks);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static ncclResult_t netMapShm(struct ncclComm *comm, struct connectMapMem* mem) {
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, &mem->createDesc, (void**)&mem->cpuPtr, (void**)&mem->gpuPtr, &mem->attachDesc));
|
||||
static ncclResult_t netMapShm(struct ncclComm *comm, struct ncclProxyConnector* proxyConn, struct connectMapMem* mem) {
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, proxyConn->rank, &mem->createDesc, (void**)&mem->cpuPtr, (void**)&mem->gpuPtr, &mem->attachDesc));
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static ncclResult_t netCreateShm(struct ncclProxyState* proxyState, struct connectMapMem* mem) {
|
||||
NCCLCHECK(ncclShmAllocateShareableBuffer(proxyState->tpRank, mem->size, false, &mem->createDesc, (void**)&mem->cpuPtr, (void**)&mem->gpuPtr));
|
||||
NCCLCHECK(ncclShmAllocateShareableBuffer(mem->size, false, &mem->createDesc, (void**)&mem->cpuPtr, (void**)&mem->gpuPtr));
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
@@ -326,6 +340,7 @@ static ncclResult_t netDumpMap(struct connectMap* map) {
|
||||
|
||||
struct netSendConnectArgs {
|
||||
ncclNetHandle_t handle;
|
||||
int trafficClass;
|
||||
};
|
||||
|
||||
struct netRecvConnectArgs {
|
||||
@@ -349,6 +364,7 @@ static ncclResult_t sendConnect(struct ncclComm* comm, struct ncclConnect* conne
|
||||
INFO(NCCL_PROXY, "sendConnect ncclProxyCallAsync opId=%p", opId);
|
||||
netSendConnectArgs args = {0};
|
||||
memcpy(&args.handle, connectInfo, sizeof(ncclNetHandle_t));
|
||||
args.trafficClass = comm->config.trafficClass;
|
||||
NCCLCHECK(ncclProxyCallAsync(comm, &send->proxyConn, ncclProxyMsgConnect, &args, sizeof(netSendConnectArgs), sizeof(struct connectMap), opId));
|
||||
} else {
|
||||
opId = send;
|
||||
@@ -377,7 +393,7 @@ static ncclResult_t sendConnect(struct ncclComm* comm, struct ncclConnect* conne
|
||||
}
|
||||
}
|
||||
} else if (!(map->sameProcess && map->cudaDev == comm->cudaDev)) {
|
||||
if (!map->sameProcess) NCCLCHECK(netMapShm(comm, map->mems + NCCL_NET_MAP_HOSTMEM));
|
||||
if (!map->sameProcess) NCCLCHECK(netMapShm(comm, &send->proxyConn, map->mems + NCCL_NET_MAP_HOSTMEM));
|
||||
if (map->mems[NCCL_NET_MAP_DEVMEM].size) {
|
||||
map->mems[NCCL_NET_MAP_DEVMEM].gpuPtr = NULL;
|
||||
NCCLCHECK(ncclP2pImportShareableBuffer(comm, send->proxyConn.rank,
|
||||
@@ -744,9 +760,11 @@ static ncclResult_t ncclNetGetDeviceHandle(ncclNetDeviceType type, int version,
|
||||
static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, struct ncclProxyState* proxyState, void* reqBuff, int reqSize, void* respBuff, int respSize, int* done) {
|
||||
ncclNet_ctxt_t ncclNetCtxt = {};
|
||||
struct sendNetResources* resources = (struct sendNetResources*)(connection->transportResources);
|
||||
ncclNetCommConfig_t commConfig = {0};
|
||||
if (reqSize != sizeof(netSendConnectArgs)) return ncclInternalError;
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
netSendConnectArgs* req = (netSendConnectArgs*) reqBuff;
|
||||
commConfig.trafficClass = req->trafficClass == NCCL_CONFIG_UNDEF_INT ? NCCL_NET_TRAFFIC_CLASS_UNDEF : req->trafficClass;
|
||||
NCCLCHECK(ncclNetGetDeviceHandle(resources->netDeviceType, resources->netDeviceVersion, false /*isRecv*/, &resources->netDeviceHandle));
|
||||
bool rccl_anp = !(strcmp(proxyState->ncclNet->name, RCCL_ANP_PLUGIN_STR));
|
||||
if (resources->shared) {
|
||||
@@ -770,9 +788,9 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
if (comms->sendComm[resources->channelId] == NULL) {
|
||||
if (rccl_anp) {
|
||||
ncclNetCtxt.chId = resources->channelId;
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, req->handle, comms->sendComm + resources->channelId, (ncclNetDeviceHandle_t **)&ncclNetCtxt);
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, &commConfig, req->handle, comms->sendComm + resources->channelId, (ncclNetDeviceHandle_t **)&ncclNetCtxt);
|
||||
} else {
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, req->handle, comms->sendComm + resources->channelId, &resources->netDeviceHandle);
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, &commConfig, req->handle, comms->sendComm + resources->channelId, &resources->netDeviceHandle);
|
||||
}
|
||||
}
|
||||
resources->netSendComm = comms->sendComm[resources->channelId];
|
||||
@@ -780,18 +798,18 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
} else {
|
||||
if (rccl_anp) {
|
||||
ncclNetCtxt.chId = resources->channelId;
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, req->handle, &resources->netSendComm, (ncclNetDeviceHandle_t **)&ncclNetCtxt);
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, &commConfig, req->handle, &resources->netSendComm, (ncclNetDeviceHandle_t **)&ncclNetCtxt);
|
||||
} else {
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, req->handle, &resources->netSendComm, &resources->netDeviceHandle);
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, &commConfig, req->handle, &resources->netSendComm, &resources->netDeviceHandle);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Connect to remote peer
|
||||
if (rccl_anp) {
|
||||
ncclNetCtxt.chId = resources->channelId;
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, req->handle, &resources->netSendComm, (ncclNetDeviceHandle_t **)&ncclNetCtxt);
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, &commConfig, req->handle, &resources->netSendComm, (ncclNetDeviceHandle_t **)&ncclNetCtxt);
|
||||
} else {
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, req->handle, &resources->netSendComm, &resources->netDeviceHandle);
|
||||
ret = proxyState->ncclNet->connect(resources->netDev, &commConfig, req->handle, &resources->netSendComm, &resources->netDeviceHandle);
|
||||
}
|
||||
connection->proxyAppendPtr = &connection->proxyAppend;
|
||||
}
|
||||
@@ -818,7 +836,7 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
|
||||
if (resources->shared == 0) { // Only allocate dedicated buffers for ring/tree, not for p2p
|
||||
for (int p=0; p<NCCL_NUM_PROTOCOLS; p++) {
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, p!= NCCL_PROTO_LL && resources->useGdr, proxyState->buffSizes[p], buffs[p]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, p!= NCCL_PROTO_LL && resources->useGdr ? 1 : 0, proxyState->buffSizes[p], buffs[p]);
|
||||
resources->buffSizes[p] = proxyState->buffSizes[p];
|
||||
}
|
||||
} else {
|
||||
@@ -835,7 +853,7 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
resources->buffSizes[NCCL_PROTO_LL] = proxyState->buffSizes[NCCL_PROTO_LL];
|
||||
}
|
||||
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr ? 1 : 0, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
}
|
||||
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, 0, sizeof(struct ncclSendMem), sendMem);
|
||||
@@ -901,7 +919,7 @@ static ncclResult_t sendProxyConnect(struct ncclProxyConnection* connection, str
|
||||
int type = NCCL_NET_MAP_DEV_MEM(map, buffs[p]) ? NCCL_PTR_CUDA : NCCL_PTR_HOST;
|
||||
if (type == NCCL_PTR_CUDA && resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)resources->buffers[p], resources->buffSizes[p], CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0));
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)resources->buffers[p], resources->buffSizes[p], CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)));
|
||||
NCCLCHECK(proxyState->ncclNet->regMrDmaBuf(resources->netSendComm, resources->buffers[p], resources->buffSizes[p], type, 0ULL, dmabuf_fd, &resources->mhandles[p]));
|
||||
(void)close(dmabuf_fd);
|
||||
} else // FALL-THROUGH to nv_peermem GDR path
|
||||
@@ -1016,7 +1034,7 @@ static ncclResult_t recvProxyConnect(struct ncclProxyConnection* connection, str
|
||||
|
||||
if (resources->shared == 0) { // Only allocate dedicated buffers for ring/tree, not for p2p
|
||||
for (int p=0; p<NCCL_NUM_PROTOCOLS; p++) {
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, resources->useGdr, proxyState->buffSizes[p], buffs[p]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, resources->useGdr ? 1 : 0, proxyState->buffSizes[p], buffs[p]);
|
||||
resources->buffSizes[p] = proxyState->buffSizes[p];
|
||||
}
|
||||
} else {
|
||||
@@ -1027,14 +1045,14 @@ static ncclResult_t recvProxyConnect(struct ncclProxyConnection* connection, str
|
||||
proxyState, resources->useGdr, resources->tpLocalRank, 1, 1, proxyState->p2pnChannels,
|
||||
&mapMem->gpuPtr, &mapMem->cpuPtr, &mapMem->size, NULL));
|
||||
resources->buffSizes[NCCL_PROTO_SIMPLE] = mapMem->size;
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 1, resources->useGdr ? 1 : 0, mapMem->size, buffs[NCCL_PROTO_SIMPLE]);
|
||||
}
|
||||
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, 0, sizeof(struct ncclSendMem), sendMem);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, 0, sizeof(struct ncclRecvMem), recvMem);
|
||||
|
||||
if (proxyState->allocP2pNetLLBuffers) {
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, 0 /*resources->useGdr*/, proxyState->buffSizes[NCCL_PROTO_LL], buffs[NCCL_PROTO_LL]);
|
||||
NCCL_NET_MAP_ADD_POINTER(map, 0, 0 /*devMem*/, proxyState->buffSizes[NCCL_PROTO_LL], buffs[NCCL_PROTO_LL]);
|
||||
resources->buffSizes[NCCL_PROTO_LL] = proxyState->buffSizes[NCCL_PROTO_LL];
|
||||
}
|
||||
|
||||
@@ -1087,7 +1105,7 @@ static ncclResult_t recvProxyConnect(struct ncclProxyConnection* connection, str
|
||||
int type = NCCL_NET_MAP_DEV_MEM(map, buffs[p]) ? NCCL_PTR_CUDA : NCCL_PTR_HOST;
|
||||
if (type == NCCL_PTR_CUDA && resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)resources->buffers[p], resources->buffSizes[p], CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0));
|
||||
CUCHECK(cuMemGetHandleForAddressRange((void *)&dmabuf_fd, (CUdeviceptr)resources->buffers[p], resources->buffSizes[p], CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)));
|
||||
NCCLCHECK(proxyState->ncclNet->regMrDmaBuf(resources->netRecvComm, resources->buffers[p], resources->buffSizes[p], type, 0ULL, dmabuf_fd, &resources->mhandles[p]));
|
||||
(void)close(dmabuf_fd);
|
||||
} else // FALL-THROUGH to nv_peermem GDR path
|
||||
@@ -1326,7 +1344,7 @@ static ncclResult_t sendProxyProgress(struct ncclProxyState* proxyState, struct
|
||||
// Coverity complains about the size here as pointing to an out-of-scope temporary. Which is nonsense,
|
||||
// since size is a plain integer.
|
||||
// coverity[use_invalid:FALSE]
|
||||
NCCLCHECK(proxyState->ncclNet->isend(resources->netSendComm, buff, size, resources->tpRank, sub->sendMhandle, sub->requests+buffSlot));
|
||||
NCCLCHECK(proxyState->ncclNet->isend(resources->netSendComm, buff, size, resources->tpRank, sub->sendMhandle, sub, sub->requests+buffSlot));
|
||||
if (sub->requests[buffSlot] != NULL) {
|
||||
|
||||
#if defined(ENABLE_NPKIT) && defined(ENABLE_NPKIT_EVENT_NET_SEND_ENTRY) && defined(ENABLE_NPKIT_EVENT_NET_SEND_EXIT)
|
||||
@@ -1348,6 +1366,7 @@ static ncclResult_t sendProxyProgress(struct ncclProxyState* proxyState, struct
|
||||
TRACE(NCCL_NET, "sendProxy [%ld/%d/%d] Isend posted, req %p, buff %p, size %d, proto %d, myRank %d, channelId %d, mhandle %p", sub->transmitted, buffSlot, sub->nsteps, sub->requests[buffSlot], buff, size, p, proxyState->tpRank, sub->channelId, sub->sendMhandle);
|
||||
sub->transSize += size;
|
||||
sub->transmitted += args->sliceSteps;
|
||||
sub->profilerSteps++;
|
||||
ncclProfilerRecordProxyOpEventState(s, args, sub->transmitted, sub->transSize, ncclProfilerProxyOpSendTransmitted);
|
||||
ncclProfilerRecordProxyStepEventState(s, args, transmittedStepId, ncclProfilerProxyStepSendWait);
|
||||
args->idle = 0;
|
||||
@@ -1499,6 +1518,7 @@ static ncclResult_t recvProxyProgress(struct ncclProxyState* proxyState, struct
|
||||
size_t sizes[NCCL_PROXY_MAX_SUBS];
|
||||
int tags[NCCL_PROXY_MAX_SUBS];
|
||||
void* mhandles[NCCL_PROXY_MAX_SUBS];
|
||||
void* phandles[NCCL_PROXY_MAX_SUBS];
|
||||
for (int i=0; i<subGroup->groupSize; i++) {
|
||||
struct ncclProxySubArgs* sub = subGroup + i;
|
||||
int postedStepId = sub->posted;
|
||||
@@ -1542,6 +1562,7 @@ static ncclResult_t recvProxyProgress(struct ncclProxyState* proxyState, struct
|
||||
if (sub->nbytes < sizes[subCount]) sizes[subCount] = sub->nbytes;
|
||||
tags[subCount] = resources->tpRemoteRank;
|
||||
mhandles[subCount] = sub->recvMhandle;
|
||||
phandles[subCount] = sub;
|
||||
subCount++;
|
||||
}
|
||||
}
|
||||
@@ -1551,7 +1572,7 @@ static ncclResult_t recvProxyProgress(struct ncclProxyState* proxyState, struct
|
||||
void** requestPtr = subGroup->requests+(step%NCCL_STEPS);
|
||||
bool ignoreCompletion = ncclParamNetOptionalRecvCompletion() && ((args->protocol == NCCL_PROTO_LL128) || (args->protocol == NCCL_PROTO_LL)) && (subCount == 1);
|
||||
if (ignoreCompletion) *requestPtr = (void *)NCCL_NET_OPTIONAL_RECV_COMPLETION;
|
||||
NCCLCHECK(proxyState->ncclNet->irecv(resources->netRecvComm, subCount, ptrs, sizes, tags, mhandles, requestPtr));
|
||||
NCCLCHECK(proxyState->ncclNet->irecv(resources->netRecvComm, subCount, ptrs, sizes, tags, mhandles, phandles, requestPtr));
|
||||
if (*requestPtr) {
|
||||
subGroup->recvRequestsCache[step%NCCL_STEPS] = *requestPtr;
|
||||
subGroup->recvRequestsSubCount = subCount;
|
||||
@@ -1576,6 +1597,7 @@ static ncclResult_t recvProxyProgress(struct ncclProxyState* proxyState, struct
|
||||
#endif
|
||||
|
||||
sub->posted += args->sliceSteps;
|
||||
sub->profilerSteps++;
|
||||
ncclProfilerRecordProxyOpEventState(s+i, args, sub->posted, sub->transSize, ncclProfilerProxyOpRecvPosted);
|
||||
ncclProfilerRecordProxyStepEventState(s+i, args, postedStepId, ncclProfilerProxyStepRecvWait);
|
||||
}
|
||||
@@ -1828,7 +1850,7 @@ exit:
|
||||
return ret;
|
||||
fail:
|
||||
*outRegBufFlag = 0;
|
||||
WARN("rank %d failed to NET register userbuff %p buffSize %ld GDR flag %d", comm->rank, userbuff, buffSize, gdrFlag);
|
||||
INFO(NCCL_REG, "rank %d failed to NET register userbuff %p buffSize %ld GDR flag %d", comm->rank, userbuff, buffSize, gdrFlag);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -1909,7 +1931,7 @@ static ncclResult_t sendProxyRegBuffer(struct ncclProxyConnection* connection, s
|
||||
/* DMA-BUF support */
|
||||
if (resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void*)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0), ret, peermem);
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void*)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)), ret, peermem);
|
||||
NCCLCHECKGOTO(proxyState->ncclNet->regMrDmaBuf(resources->netSendComm, (void*)info->buffer, info->size, NCCL_PTR_CUDA, 0ULL, dmabuf_fd, &handle), ret, peermem);
|
||||
(void)close(dmabuf_fd);
|
||||
needReg = false;
|
||||
@@ -1943,7 +1965,7 @@ static ncclResult_t recvProxyRegBuffer(struct ncclProxyConnection* connection, s
|
||||
/* DMA-BUF support */
|
||||
if (resources->useDmaBuf) {
|
||||
int dmabuf_fd;
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void*)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, 0), ret, peermem);
|
||||
CUCHECKGOTO(cuMemGetHandleForAddressRange((void*)&dmabuf_fd, (CUdeviceptr)info->buffer, info->size, CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD, getHandleForAddressRangeFlags(resources->useGdr)), ret, peermem);
|
||||
NCCLCHECKGOTO(proxyState->ncclNet->regMrDmaBuf(resources->netRecvComm, (void*)info->buffer, info->size, NCCL_PTR_CUDA, 0ULL, dmabuf_fd, &handle), ret, peermem);
|
||||
(void)close(dmabuf_fd);
|
||||
needReg = false;
|
||||
|
||||
+161
-36
@@ -12,6 +12,7 @@
|
||||
#include "graph.h"
|
||||
#include "utils.h"
|
||||
#include "param.h"
|
||||
#include "profiler/net_ib.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
@@ -88,6 +89,11 @@ struct ncclIbDev ncclIbDevs[MAX_IB_DEVS];
|
||||
pthread_mutex_t ncclIbLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int ncclIbRelaxedOrderingEnabled = 0;
|
||||
|
||||
#define NCCL_IB_LLSTR(ll) (((ll) == IBV_LINK_LAYER_INFINIBAND) ? "IB" : (((ll) == IBV_LINK_LAYER_ETHERNET) ? "RoCE" : "UNSPECIFIED"))
|
||||
|
||||
#define NCCL_IB_SL_DEFAULT 0
|
||||
#define NCCL_IB_TC_DEFAULT 0
|
||||
|
||||
NCCL_PARAM(IbGidIndex, "IB_GID_INDEX", -1);
|
||||
NCCL_PARAM(IbRoutableFlidIbGidIndex, "IB_ROUTABLE_FLID_GID_INDEX", 1);
|
||||
NCCL_PARAM(IbRoceVersionNum, "IB_ROCE_VERSION_NUM", 2);
|
||||
@@ -95,8 +101,8 @@ NCCL_PARAM(IbTimeout, "IB_TIMEOUT", 20);
|
||||
NCCL_PARAM(IbRetryCnt, "IB_RETRY_CNT", 7);
|
||||
NCCL_PARAM(IbPkey, "IB_PKEY", 0);
|
||||
NCCL_PARAM(IbUseInline, "IB_USE_INLINE", 0);
|
||||
NCCL_PARAM(IbSl, "IB_SL", 0);
|
||||
NCCL_PARAM(IbTc, "IB_TC", 0);
|
||||
NCCL_PARAM(IbSl, "IB_SL", -1);
|
||||
NCCL_PARAM(IbTc, "IB_TC", -1);
|
||||
NCCL_PARAM(IbArThreshold, "IB_AR_THRESHOLD", 8192);
|
||||
NCCL_PARAM(IbPciRelaxedOrdering, "IB_PCI_RELAXED_ORDERING", 2);
|
||||
NCCL_PARAM(IbAdaptiveRouting, "IB_ADAPTIVE_ROUTING", -2);
|
||||
@@ -330,6 +336,9 @@ static ncclResult_t ncclIbRoceGetVersionNum(const char* deviceName, int portNum,
|
||||
close(fd);
|
||||
|
||||
if (ret == -1) {
|
||||
// In containerized environments, read could return EINVAL if the GID index is not mapped to the
|
||||
// container sysfs. In this case return ncclSuccess and let the caller move to next GID index.
|
||||
if (errno == EINVAL) return ncclSuccess;
|
||||
WARN("NET/IB: read failed in ncclIbRoceGetVersionNum: %s", strerror(errno));
|
||||
return ncclSystemError;
|
||||
}
|
||||
@@ -362,7 +371,7 @@ static ncclResult_t ncclUpdateGidIndex(struct ibv_context* context, uint8_t port
|
||||
return ncclSuccess;
|
||||
}
|
||||
int usrRoceVer = roceVer;
|
||||
int gidRoceVerNum, gidRoceVerNumCandidate;
|
||||
int gidRoceVerNum, gidRoceVerNumCandidate = -1;
|
||||
const char* deviceName = wrap_ibv_get_device_name(context->device);
|
||||
NCCLCHECK(ncclIbRoceGetVersionNum(deviceName, portNum, *gidIndex, &gidRoceVerNum));
|
||||
NCCLCHECK(ncclIbRoceGetVersionNum(deviceName, portNum, gidIndexCandidate, &gidRoceVerNumCandidate));
|
||||
@@ -533,8 +542,8 @@ ncclResult_t ncclIbMakeVDeviceInternal(int* d, ncclNetVDeviceProps_t* props) {
|
||||
}
|
||||
ncclIbDev* dev = ncclIbDevs + props->devs[i];
|
||||
if (dev->link != dev0->link) {
|
||||
WARN("NET/IB : Trying to merge multiple devices together with different link_layer properties %s -> %d, %s -> %d. Try only selecting NICs with one type of link using NCCL_IB_HCA",
|
||||
dev0->devName, dev0->link, dev->devName, dev->link);
|
||||
WARN("NET/IB : Attempted to merge incompatible devices: [%d]%s:%d/%s and [%d]%s:%d/%s. Try selecting NICs of only one link type using NCCL_IB_HCA",
|
||||
props->devs[0], dev0->devName, dev0->portNum, NCCL_IB_LLSTR(dev0->link), props->devs[i], dev->devName, dev->portNum, NCCL_IB_LLSTR(dev->link));
|
||||
return ncclInvalidUsage;
|
||||
}
|
||||
}
|
||||
@@ -551,8 +560,11 @@ ncclResult_t ncclIbMakeVDevice(int* d, ncclNetVDeviceProps_t* props) {
|
||||
return res;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbInit(ncclDebugLogger_t logFunction) {
|
||||
static ncclProfilerCallback_t ncclProfilerFunction;
|
||||
|
||||
ncclResult_t ncclIbInit(ncclDebugLogger_t logFunction, ncclProfilerCallback_t profFunction) {
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
ncclProfilerFunction = profFunction;
|
||||
if (ncclParamIbDisable()) return ncclInternalError;
|
||||
static int shownIbHcaEnv = 0;
|
||||
if(wrap_ibv_symbols() != ncclSuccess) { return ncclInternalError; }
|
||||
@@ -574,7 +586,7 @@ ncclResult_t ncclIbInit(ncclDebugLogger_t logFunction) {
|
||||
}
|
||||
|
||||
// Check if user defined which IB device:port to use
|
||||
char* userIbEnv = getenv("NCCL_IB_HCA");
|
||||
const char* userIbEnv = ncclGetEnv("NCCL_IB_HCA");
|
||||
if (userIbEnv != NULL && shownIbHcaEnv++ == 0) INFO(NCCL_NET|NCCL_ENV, "NCCL_IB_HCA set to %s", userIbEnv);
|
||||
struct netIf userIfs[MAX_IB_DEVS];
|
||||
bool searchNot = userIbEnv && userIbEnv[0] == '^';
|
||||
@@ -641,7 +653,7 @@ ncclResult_t ncclIbInit(ncclDebugLogger_t logFunction) {
|
||||
if (ncclParamIbAdaptiveRouting() != -2) ncclIbDevs[ncclNIbDevs].ar = ncclParamIbAdaptiveRouting();
|
||||
|
||||
TRACE(NCCL_NET,"NET/IB: [%d] %s:%s:%d/%s speed=%d context=%p pciPath=%s ar=%d", d, devices[d]->name, devices[d]->dev_name, ncclIbDevs[ncclNIbDevs].portNum,
|
||||
portAttr.link_layer == IBV_LINK_LAYER_INFINIBAND ? "IB" : "RoCE", ncclIbDevs[ncclNIbDevs].speed, context, ncclIbDevs[ncclNIbDevs].pciPath, ncclIbDevs[ncclNIbDevs].ar);
|
||||
NCCL_IB_LLSTR(portAttr.link_layer), ncclIbDevs[ncclNIbDevs].speed, context, ncclIbDevs[ncclNIbDevs].pciPath, ncclIbDevs[ncclNIbDevs].ar);
|
||||
|
||||
PTHREADCHECKGOTO(pthread_create(&ncclIbAsyncThread, NULL, ncclIbAsyncThreadMain, ncclIbDevs + ncclNIbDevs), "pthread_create", ret, fail);
|
||||
ncclSetThreadName(ncclIbAsyncThread, "NCCL IbAsync %2d", ncclNIbDevs);
|
||||
@@ -672,7 +684,7 @@ ncclResult_t ncclIbInit(ncclDebugLogger_t logFunction) {
|
||||
ncclIbRelaxedOrderingEnabled = ncclIbRelaxedOrderingCapable();
|
||||
for (int d = 0; d < ncclNIbDevs; d++) {
|
||||
snprintf(line+strlen(line), sizeof(line)-strlen(line), " [%d]%s:%d/%s", d, ncclIbDevs[d].devName,
|
||||
ncclIbDevs[d].portNum, ncclIbDevs[d].link == IBV_LINK_LAYER_INFINIBAND ? "IB" : "RoCE");
|
||||
ncclIbDevs[d].portNum, NCCL_IB_LLSTR(ncclIbDevs[d].link));
|
||||
}
|
||||
char addrline[SOCKET_NAME_MAXLEN+1];
|
||||
INFO(NCCL_INIT|NCCL_NET, "NET/IB : Using%s %s; OOB %s:%s", line, ncclIbRelaxedOrderingEnabled ? "[RO]" : "",
|
||||
@@ -913,6 +925,8 @@ struct ncclIbConnectionMetadata {
|
||||
char devName[MAX_MERGED_DEV_NAME];
|
||||
uint64_t fifoAddr;
|
||||
int ndevs;
|
||||
int tc;
|
||||
int sl;
|
||||
};
|
||||
|
||||
enum ncclIbCommState {
|
||||
@@ -954,12 +968,23 @@ struct ncclIbGidInfo {
|
||||
#define NCCL_NET_IB_REQ_FLUSH 3
|
||||
const char* reqTypeStr[] = { "Unused", "Send", "Recv", "Flush" };
|
||||
|
||||
#define MAX_QPS_PER_REQ 8
|
||||
struct ncclProfilerInfo {
|
||||
void* qpEventHandles[MAX_QPS_PER_REQ];
|
||||
int qpIndex[MAX_QPS_PER_REQ];
|
||||
int nEventHandles;
|
||||
ncclProfilerNetIbDescr_v1_t data;
|
||||
};
|
||||
|
||||
struct ncclIbRequest {
|
||||
struct ncclIbNetCommBase* base;
|
||||
int type;
|
||||
struct ncclSocket* sock;
|
||||
int events[NCCL_IB_MAX_DEVS_PER_NIC];
|
||||
struct ncclIbNetCommDevBase* devBases[NCCL_IB_MAX_DEVS_PER_NIC];
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
struct ncclProfilerInfo pInfo[NCCL_NET_IB_MAX_RECVS];
|
||||
#endif
|
||||
int nreqs;
|
||||
union {
|
||||
struct {
|
||||
@@ -1169,7 +1194,7 @@ ncclResult_t ncclIbCreateQp(uint8_t ib_port, struct ncclIbNetCommDevBase* base,
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbRtrQp(struct ibv_qp* qp, struct ncclIbGidInfo* sGidInfo, uint32_t dest_qp_num, struct ncclIbDevInfo* info, bool fifoTc) {
|
||||
ncclResult_t ncclIbRtrQp(struct ibv_qp* qp, struct ncclIbGidInfo* sGidInfo, uint32_t dest_qp_num, struct ncclIbDevInfo* info, bool fifoTc, int tc, int sl) {
|
||||
struct ibv_qp_attr qpAttr;
|
||||
memset(&qpAttr, 0, sizeof(struct ibv_qp_attr));
|
||||
qpAttr.qp_state = IBV_QPS_RTR;
|
||||
@@ -1185,7 +1210,7 @@ ncclResult_t ncclIbRtrQp(struct ibv_qp* qp, struct ncclIbGidInfo* sGidInfo, uint
|
||||
qpAttr.ah_attr.grh.flow_label = 0;
|
||||
qpAttr.ah_attr.grh.sgid_index = sGidInfo->localGidIndex;
|
||||
qpAttr.ah_attr.grh.hop_limit = 255;
|
||||
qpAttr.ah_attr.grh.traffic_class = fifoTc && ncclParamIbFifoTc() != -1 ? ncclParamIbFifoTc() : ncclParamIbTc();
|
||||
qpAttr.ah_attr.grh.traffic_class = fifoTc && ncclParamIbFifoTc() != -1 ? ncclParamIbFifoTc() : tc;
|
||||
} else {
|
||||
//pick lid if subnet prefixs are same, FLID if they are not
|
||||
if (ncclIbExtractLocalSubnetPrefix(sGidInfo->localGid.global.subnet_prefix) ==
|
||||
@@ -1207,10 +1232,10 @@ ncclResult_t ncclIbRtrQp(struct ibv_qp* qp, struct ncclIbGidInfo* sGidInfo, uint
|
||||
qpAttr.ah_attr.grh.hop_limit = 255;
|
||||
}
|
||||
}
|
||||
qpAttr.ah_attr.sl = ncclParamIbSl();
|
||||
qpAttr.ah_attr.sl = sl;
|
||||
qpAttr.ah_attr.src_path_bits = 0;
|
||||
qpAttr.ah_attr.port_num = info->ib_port;
|
||||
TRACE(NCCL_NET, "NET/IB : ncclIbRtrQp qpn=%u mtu=%d dst=%u ll=%u port=%u", qp->qp_num, info->mtu, dest_qp_num, info->link_layer, info->ib_port);
|
||||
TRACE(NCCL_NET, "NET/IB : ncclIbRtrQp qpn=%u mtu=%d dst=%u ll=%u port=%u sl: %d tc: %d", qp->qp_num, info->mtu, dest_qp_num, info->link_layer, info->ib_port, qpAttr.ah_attr.sl, qpAttr.ah_attr.grh.traffic_class);
|
||||
NCCLCHECK(wrap_ibv_modify_qp(qp, &qpAttr, IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU | IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER));
|
||||
return ncclSuccess;
|
||||
}
|
||||
@@ -1249,12 +1274,13 @@ fail:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbConnect(int dev, void* opaqueHandle, void** sendComm, ncclNetDeviceHandle_t** /*sendDevComm*/) {
|
||||
ncclResult_t ncclIbConnect(int dev, ncclNetCommConfig_t* config, void* opaqueHandle, void** sendComm, ncclNetDeviceHandle_t** /*sendDevComm*/) {
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
struct ncclIbHandle* handle = (struct ncclIbHandle*) opaqueHandle;
|
||||
struct ncclIbCommStage* stage = &handle->stage;
|
||||
struct ncclIbSendComm* comm = (struct ncclIbSendComm*)stage->comm;
|
||||
int ready;
|
||||
uint8_t link_layer = IBV_LINK_LAYER_UNSPECIFIED;
|
||||
*sendComm = NULL;
|
||||
|
||||
if (stage->state == ncclIbCommStateConnect) goto ib_connect_check;
|
||||
@@ -1284,7 +1310,7 @@ ib_connect_check:
|
||||
// IB Setup
|
||||
struct ncclIbMergedDev* mergedDev;
|
||||
if (dev >= ncclNMergedIbDevs) {
|
||||
WARN("NET/IB : Trying to use non-existant virtual device %d", dev);
|
||||
WARN("NET/IB : Trying to use non-existent virtual device %d", dev);
|
||||
return ncclInternalError;
|
||||
}
|
||||
|
||||
@@ -1390,8 +1416,17 @@ ib_recv_dev_list:
|
||||
devInfo->gid.global.subnet_prefix, devInfo->gid.global.interface_id, devInfo->fifoRkey, commDev->fifoMr->lkey);
|
||||
}
|
||||
}
|
||||
if (link_layer == IBV_LINK_LAYER_UNSPECIFIED) link_layer = devInfo->link_layer;
|
||||
if (link_layer != devInfo->link_layer) {
|
||||
int ibDev0 = comm->devs[0].base.ibDevN;
|
||||
WARN("NET/IB : Attempted to connect incompatible devices: [%d]%s:%d/%s and [%d]%s:%d/%s. Try selecting NICs of only one link type using NCCL_IB_HCA",
|
||||
commDev->base.ibDevN, ibDev->devName, ibDev->portNum, NCCL_IB_LLSTR(ibDev->portAttr.link_layer), ibDev0, ncclIbDevs[ibDev0].devName, ncclIbDevs[ibDev0].portNum, NCCL_IB_LLSTR(link_layer));
|
||||
return ncclInternalError;
|
||||
}
|
||||
}
|
||||
meta.fifoAddr = (uint64_t)comm->fifo;
|
||||
meta.sl = (ncclParamIbSl() != -1) ? ncclParamIbSl() : (config && config->trafficClass != NCCL_NET_TRAFFIC_CLASS_UNDEF) ? config->trafficClass : NCCL_IB_SL_DEFAULT;
|
||||
meta.tc = (ncclParamIbTc() != -1) ? ncclParamIbTc() : (config && config->trafficClass != NCCL_NET_TRAFFIC_CLASS_UNDEF) ? config->trafficClass : NCCL_IB_TC_DEFAULT;
|
||||
strncpy(meta.devName, mergedDev->devName, MAX_MERGED_DEV_NAME);
|
||||
|
||||
stage->state = ncclIbCommStateSend;
|
||||
@@ -1417,13 +1452,16 @@ ib_connect:
|
||||
|
||||
comm->base.nRemDevs = remMeta.ndevs;
|
||||
|
||||
int link_layer;
|
||||
link_layer = remMeta.devs[0].link_layer;
|
||||
for (int i = 1; i < remMeta.ndevs; i++) {
|
||||
if (remMeta.devs[i].link_layer != link_layer) {
|
||||
WARN("NET/IB : Can't connect net devices with different link_layer. i=%d remMeta.ndevs=%d link_layer=%d rem_link_layer=%d",
|
||||
i, remMeta.ndevs, link_layer, remMeta.devs[i].link_layer);
|
||||
return ncclInternalError;
|
||||
// ensure that the remote devices have the same link layer than the local devices used in the connection.
|
||||
if (comm->base.vProps.ndevs > 0) {
|
||||
int ibDev0 = comm->devs[0].base.ibDevN;
|
||||
link_layer = ncclIbDevs[ibDev0].portAttr.link_layer;
|
||||
for (int i = 0; i < remMeta.ndevs; i++) {
|
||||
if (remMeta.devs[i].link_layer != link_layer) {
|
||||
WARN("NET/IB : Remote %s device is incompatible with the local [%d]%s:%d/%s. Try selecting NICs of only one link type using NCCL_IB_HCA",
|
||||
NCCL_IB_LLSTR(remMeta.devs[i].link_layer), ibDev0, ncclIbDevs[ibDev0].devName, ncclIbDevs[ibDev0].portNum, NCCL_IB_LLSTR(link_layer));
|
||||
return ncclInternalError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1457,7 +1495,7 @@ ib_connect:
|
||||
|
||||
ncclIbDev* ibDev = ncclIbDevs + commDev->base.ibDevN;
|
||||
remDevInfo->mtu = std::min(remDevInfo->mtu, ibDev->portAttr.active_mtu);
|
||||
NCCLCHECKGOTO(ncclIbRtrQp(qp, &commDev->base.gidInfo, remQpInfo->qpn, remDevInfo, false), ret, fail);
|
||||
NCCLCHECKGOTO(ncclIbRtrQp(qp, &commDev->base.gidInfo, remQpInfo->qpn, remDevInfo, false, remMeta.tc, remMeta.sl), ret, fail);
|
||||
NCCLCHECKGOTO(ncclIbRtsQp(qp), ret, fail);
|
||||
}
|
||||
|
||||
@@ -1544,6 +1582,7 @@ ncclResult_t ncclIbAccept(void* listenComm, void** recvComm, ncclNetDeviceHandle
|
||||
struct ncclIbCommStage* stage = &lComm->stage;
|
||||
struct ncclIbRecvComm* rComm = (struct ncclIbRecvComm*)stage->comm;
|
||||
int ready;
|
||||
int link_layer = IBV_LINK_LAYER_UNSPECIFIED;
|
||||
*recvComm = NULL;
|
||||
|
||||
if (stage->state == ncclIbCommStateAccept) goto ib_accept_check;
|
||||
@@ -1582,7 +1621,7 @@ ib_recv_dev_list:
|
||||
ncclNetVDeviceProps_t remoteVProps;
|
||||
memcpy(&remoteVProps, stage->buffer, sizeof(ncclNetVDeviceProps_t));
|
||||
if (lComm->dev >= ncclNMergedIbDevs) {
|
||||
WARN("NET/IB : Trying to use non-existant virtual device %d", lComm->dev);
|
||||
WARN("NET/IB : Trying to use non-existent virtual device %d", lComm->dev);
|
||||
return ncclInternalError;
|
||||
}
|
||||
|
||||
@@ -1641,6 +1680,13 @@ ib_recv:
|
||||
ibDev = ncclIbDevs + ibDevN;
|
||||
NCCLCHECKGOTO(ncclIbGetGidIndex(ibDev->context, ibDev->portNum, &ibDev->portAttr, &rCommDev->base.gidInfo.localGidIndex), ret, fail);
|
||||
NCCLCHECKGOTO(wrap_ibv_query_gid(ibDev->context, ibDev->portNum, rCommDev->base.gidInfo.localGidIndex, &rCommDev->base.gidInfo.localGid), ret, fail);
|
||||
if (link_layer == IBV_LINK_LAYER_UNSPECIFIED) link_layer = ibDev->portAttr.link_layer;
|
||||
if (link_layer != ibDev->portAttr.link_layer) {
|
||||
int ibDev0 = rComm->devs[0].base.ibDevN;
|
||||
WARN("NET/IB : Attempted to connect incompatible devices: [%d]%s:%d/%s and [%d]%s:%d/%s. Try selecting NICs of only one link type using NCCL_IB_HCA",
|
||||
ibDevN, ibDev->devName, ibDev->portNum, NCCL_IB_LLSTR(ibDev->portAttr.link_layer), ibDev0, ncclIbDevs[ibDev0].devName, ncclIbDevs[ibDev0].portNum, NCCL_IB_LLSTR(link_layer));
|
||||
return ncclInternalError;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy remDevInfo for things like remGidInfo, remFifoAddr, etc.
|
||||
@@ -1648,6 +1694,12 @@ ib_recv:
|
||||
rComm->base.remDevs[i] = remMeta.devs[i];
|
||||
rComm->base.remDevs[i].remoteGid.global.interface_id = rComm->base.remDevs[i].gid.global.interface_id;
|
||||
rComm->base.remDevs[i].remoteGid.global.subnet_prefix = rComm->base.remDevs[i].gid.global.subnet_prefix;
|
||||
if (remMeta.devs[i].link_layer != link_layer) {
|
||||
int ibDev0 = rComm->devs[0].base.ibDevN;
|
||||
WARN("NET/IB : Remote %s device is incompatible with the local [%d]%s:%d/%s. Try selecting NICs of only one link type using NCCL_IB_HCA",
|
||||
NCCL_IB_LLSTR(remMeta.devs[i].link_layer), ibDev0, ncclIbDevs[ibDev0].devName, ncclIbDevs[ibDev0].portNum, NCCL_IB_LLSTR(link_layer));
|
||||
return ncclInternalError;
|
||||
}
|
||||
}
|
||||
|
||||
// Stripe QP creation across merged devs
|
||||
@@ -1675,17 +1727,18 @@ ib_recv:
|
||||
// However, this has been confirmed to be intentional.
|
||||
// coverity[copy_paste_error]
|
||||
NCCLCHECKGOTO(wrap_ibv_set_ece(qp->qp, &remMeta.qpInfo[q].ece, &meta.qpInfo[q].ece_supported), ret, fail);
|
||||
|
||||
// Query the reduced ece for this QP (matching enhancements between the requestor and the responder)
|
||||
// Store this in our own qpInfo for returning to the requestor
|
||||
if (meta.qpInfo[q].ece_supported)
|
||||
NCCLCHECKGOTO(wrap_ibv_query_ece(qp->qp, &meta.qpInfo[q].ece, &meta.qpInfo[q].ece_supported), ret, fail);
|
||||
} else {
|
||||
meta.qpInfo[q].ece_supported = 0;
|
||||
}
|
||||
|
||||
NCCLCHECKGOTO(ncclIbRtrQp(qp->qp, &rCommDev->base.gidInfo, remMeta.qpInfo[q].qpn, remDevInfo, true), ret, fail);
|
||||
NCCLCHECKGOTO(ncclIbRtrQp(qp->qp, &rCommDev->base.gidInfo, remMeta.qpInfo[q].qpn, remDevInfo, true, remMeta.tc, remMeta.sl), ret, fail);
|
||||
NCCLCHECKGOTO(ncclIbRtsQp(qp->qp), ret, fail);
|
||||
|
||||
// Query the reduced ece for this QP (matching enhancements between the requestor and the responder)
|
||||
// Store this in our own qpInfo for returning to the requestor
|
||||
if (remMeta.qpInfo[q].ece_supported && meta.qpInfo[q].ece_supported) {
|
||||
NCCLCHECKGOTO(wrap_ibv_query_ece(qp->qp, &meta.qpInfo[q].ece, &meta.qpInfo[q].ece_supported), ret, fail);
|
||||
}
|
||||
}
|
||||
|
||||
useDmaBuf = (ncclIbDmaBufSupport(lComm->dev) == ncclSuccess);
|
||||
@@ -1745,7 +1798,7 @@ ib_recv:
|
||||
devInfo.gid.global.subnet_prefix = rCommDev->base.gidInfo.localGid.global.subnet_prefix;
|
||||
devInfo.gid.global.interface_id = rCommDev->base.gidInfo.localGid.global.interface_id;
|
||||
devInfo.mtu = ibDev->portAttr.active_mtu;
|
||||
NCCLCHECKGOTO(ncclIbRtrQp(rCommDev->gpuFlush.qp.qp, &rCommDev->base.gidInfo, rCommDev->gpuFlush.qp.qp->qp_num, &devInfo, false), ret, fail);
|
||||
NCCLCHECKGOTO(ncclIbRtrQp(rCommDev->gpuFlush.qp.qp, &rCommDev->base.gidInfo, rCommDev->gpuFlush.qp.qp->qp_num, &devInfo, false, remMeta.tc, remMeta.sl), ret, fail);
|
||||
NCCLCHECKGOTO(ncclIbRtsQp(rCommDev->gpuFlush.qp.qp), ret, fail);
|
||||
}
|
||||
|
||||
@@ -1763,6 +1816,8 @@ ib_recv:
|
||||
meta.devs[i].fifoRkey = rComm->devs[i].sizesFifoMr->rkey;
|
||||
}
|
||||
meta.fifoAddr = (uint64_t)rComm->sizesFifo;
|
||||
meta.sl = remMeta.sl;
|
||||
meta.tc = remMeta.tc;
|
||||
|
||||
for (int q = 0; q < rComm->base.nqps; q++) {
|
||||
meta.qpInfo[q].qpn = rComm->base.qps[q].qp->qp_num;
|
||||
@@ -1959,7 +2014,7 @@ ncclResult_t ncclIbDeregMr(void* comm, void* mhandle) {
|
||||
|
||||
NCCL_PARAM(IbSplitDataOnQps, "IB_SPLIT_DATA_ON_QPS", 0);
|
||||
|
||||
ncclResult_t ncclIbMultiSend(struct ncclIbSendComm* comm, int slot) {
|
||||
ncclResult_t ncclIbMultiSend(struct ncclIbSendComm* comm, int slot, void* pHandle) {
|
||||
struct ncclIbRequest** reqs = comm->fifoReqs[slot];
|
||||
volatile struct ncclIbSendFifo* slots = comm->fifo[slot];
|
||||
int nreqs = slots[0].nreqs;
|
||||
@@ -1977,6 +2032,9 @@ ncclResult_t ncclIbMultiSend(struct ncclIbSendComm* comm, int slot) {
|
||||
wr->wr.rdma.remote_addr = slots[r].addr;
|
||||
wr->next = wr + 1;
|
||||
wr_id += (reqs[r] - comm->base.reqs) << (r*8);
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
reqs[r]->pInfo[0].nEventHandles = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write size as immediate data. In the case of multi-send, only write
|
||||
@@ -2046,6 +2104,24 @@ ncclResult_t ncclIbMultiSend(struct ncclIbSendComm* comm, int slot) {
|
||||
}
|
||||
|
||||
struct ibv_send_wr* bad_wr;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
// QP profiling loop
|
||||
for (int r=0; r<nreqs && pHandle; r++) {
|
||||
// Store comm qpIndex for this request
|
||||
int nEventHandles = reqs[r]->pInfo[0].nEventHandles;
|
||||
reqs[r]->pInfo[0].qpIndex[nEventHandles%MAX_QPS_PER_REQ] = qpIndex;
|
||||
// Store info for profiler
|
||||
int pluginId = NCCL_PROFILER_NET_TYPE_IB | NCCL_PROFILER_NET_IB_VER;
|
||||
reqs[r]->pInfo[0].data.type = ncclProfileQp;
|
||||
reqs[r]->pInfo[0].data.qp.device = devIndex;
|
||||
reqs[r]->pInfo[0].data.qp.wr_id = comm->wrs[r].wr_id;
|
||||
reqs[r]->pInfo[0].data.qp.opcode = comm->wrs[r].opcode;
|
||||
reqs[r]->pInfo[0].data.qp.qpNum = qp->qp->qp_num;
|
||||
reqs[r]->pInfo[0].data.qp.length = comm->sges[r].length;
|
||||
NCCLCHECK(ncclProfilerFunction(&reqs[r]->pInfo[0].qpEventHandles[nEventHandles%MAX_QPS_PER_REQ], 0, pHandle, pluginId, &reqs[r]->pInfo[0].data));
|
||||
reqs[r]->pInfo[0].nEventHandles++;
|
||||
}
|
||||
#endif
|
||||
NCCLCHECK(wrap_ibv_post_send(qp->qp, comm->wrs, &bad_wr));
|
||||
|
||||
for (int r=0; r<nreqs; r++) {
|
||||
@@ -2067,7 +2143,7 @@ ncclResult_t ncclIbMultiSend(struct ncclIbSendComm* comm, int slot) {
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbIsend(void* sendComm, void* data, size_t size, int tag, void* mhandle, void** request) {
|
||||
ncclResult_t ncclIbIsend(void* sendComm, void* data, size_t size, int tag, void* mhandle, void* phandle, void** request) {
|
||||
struct ncclIbSendComm* comm = (struct ncclIbSendComm*)sendComm;
|
||||
if (comm->base.ready == 0) { WARN("NET/IB: ncclIbIsend() called when comm->base.ready == 0"); return ncclInternalError; }
|
||||
if (comm->base.ready == 0) { *request = NULL; return ncclSuccess; }
|
||||
@@ -2140,7 +2216,7 @@ ncclResult_t ncclIbIsend(void* sendComm, void* data, size_t size, int tag, void*
|
||||
}
|
||||
|
||||
TIME_START(0);
|
||||
NCCLCHECK(ncclIbMultiSend(comm, slot));
|
||||
NCCLCHECK(ncclIbMultiSend(comm, slot, phandle));
|
||||
|
||||
// Clear slots[0]->nreqs, as well as other fields to help debugging and sanity checks
|
||||
memset((void*)slots, 0, sizeof(struct ncclIbSendFifo));
|
||||
@@ -2236,7 +2312,7 @@ ncclResult_t ncclIbPostFifo(struct ncclIbRecvComm* comm, int n, void** data, siz
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbIrecv(void* recvComm, int n, void** data, size_t* sizes, int* tags, void** mhandles, void** request) {
|
||||
ncclResult_t ncclIbIrecv(void* recvComm, int n, void** data, size_t* sizes, int* tags, void** mhandles, void** phandles, void** request) {
|
||||
struct ncclIbRecvComm* comm = (struct ncclIbRecvComm*)recvComm;
|
||||
if (comm->base.ready == 0) { WARN("NET/IB: ncclIbIrecv() called when comm->base.ready == 0"); return ncclInternalError; }
|
||||
if (comm->base.ready == 0) { *request = NULL; return ncclSuccess; }
|
||||
@@ -2248,6 +2324,9 @@ ncclResult_t ncclIbIrecv(void* recvComm, int n, void** data, size_t* sizes, int*
|
||||
req->type = NCCL_NET_IB_REQ_RECV;
|
||||
req->sock = &comm->base.sock;
|
||||
req->nreqs = n;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
for (int r = 0; r < n && phandles; r++) req->pInfo[r].nEventHandles = 0;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < comm->base.vProps.ndevs; i++) {
|
||||
req->devBases[i] = &comm->devs[i].base;
|
||||
@@ -2268,6 +2347,19 @@ ncclResult_t ncclIbIrecv(void* recvComm, int n, void** data, size_t* sizes, int*
|
||||
for (int i = 0; i < nqps; i++) {
|
||||
struct ncclIbQp* qp = comm->base.qps + comm->base.qpIndex;
|
||||
ncclIbAddEvent(req, qp->devIndex, &comm->devs[qp->devIndex].base);
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
// Start a QP event for every request in the multirecv and every qp
|
||||
for (int r = 0; r < n && phandles; r++) {
|
||||
// Store info for profiler
|
||||
int pluginId = NCCL_PROFILER_NET_TYPE_IB | NCCL_PROFILER_NET_IB_VER;
|
||||
req->pInfo[r].data.type = ncclProfileQp;
|
||||
req->pInfo[r].data.qp.device = qp->devIndex;
|
||||
req->pInfo[r].data.qp.wr_id = wr.wr_id;
|
||||
req->pInfo[r].data.qp.qpNum = qp->qp->qp_num;
|
||||
NCCLCHECK(ncclProfilerFunction(&req->pInfo[r].qpEventHandles[i], 0, phandles[r], pluginId, &req->pInfo[r].data));
|
||||
req->pInfo[r].nEventHandles++;
|
||||
}
|
||||
#endif
|
||||
NCCLCHECK(wrap_ibv_post_recv(qp->qp, &wr, &bad_wr));
|
||||
comm->base.qpIndex = (comm->base.qpIndex+1)%comm->base.nqps;
|
||||
}
|
||||
@@ -2339,6 +2431,16 @@ ncclResult_t ncclIbIflush(void* recvComm, int n, void** data, int* sizes, void**
|
||||
|
||||
#define HCA_NAME(req, index) ((req)->devBases[(index)]->pd->context->device->name)
|
||||
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
static int getReqQpIndex(struct ncclIbRequest* req, int request, int qpNumber) {
|
||||
for (int i = 0; i < MAX_QPS_PER_REQ; i++) {
|
||||
int qpIndex = req->pInfo[request].qpIndex[i];
|
||||
if (req->base->qps[qpIndex].qp->qp_num == qpNumber) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ncclResult_t ncclIbTest(void* request, int* done, int* sizes) {
|
||||
struct ncclIbRequest *r = (struct ncclIbRequest*)request;
|
||||
*done = 0;
|
||||
@@ -2348,11 +2450,24 @@ ncclResult_t ncclIbTest(void* request, int* done, int* sizes) {
|
||||
TRACE(NCCL_NET, "r=%p done", r);
|
||||
*done = 1;
|
||||
if (sizes && r->type == NCCL_NET_IB_REQ_RECV) {
|
||||
for (int i=0; i<r->nreqs; i++) sizes[i] = r->recv.sizes[i];
|
||||
for (int i=0; i<r->nreqs; i++) {
|
||||
sizes[i] = r->recv.sizes[i];
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
for (int j = 0; j < r->pInfo[i].nEventHandles; j++) {
|
||||
NCCLCHECK(ncclProfilerFunction(&r->pInfo[i].qpEventHandles[j], 1, NULL, 0, NULL));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (sizes && r->type == NCCL_NET_IB_REQ_SEND) {
|
||||
sizes[0] = r->send.size;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
for (int j = 0; j < r->pInfo[0].nEventHandles; j++) {
|
||||
NCCLCHECK(ncclProfilerFunction(&r->pInfo[0].qpEventHandles[j], 1, NULL, 0, NULL));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Stop all remaining Qp events for this event
|
||||
NCCLCHECK(ncclIbFreeRequest(r));
|
||||
return ncclSuccess;
|
||||
}
|
||||
@@ -2407,6 +2522,10 @@ ncclResult_t ncclIbTest(void* request, int* done, int* sizes) {
|
||||
return ncclInternalError;
|
||||
}
|
||||
sendReq->events[i]--;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
// Stop Qp event for sendReq
|
||||
NCCLCHECK(ncclProfilerFunction(&sendReq->pInfo[j].qpEventHandles[getReqQpIndex(sendReq, j, wc->qp_num)], 1, NULL, 0, NULL));
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (req && wc->opcode == IBV_WC_RECV_RDMA_WITH_IMM) {
|
||||
@@ -2419,6 +2538,12 @@ ncclResult_t ncclIbTest(void* request, int* done, int* sizes) {
|
||||
}
|
||||
}
|
||||
req->events[i]--;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
// Stop Qp event for workFifo
|
||||
for (int j = 0; j < req->nreqs; j++) {
|
||||
NCCLCHECK(ncclProfilerFunction(&req->pInfo[j].qpEventHandles[getReqQpIndex(req, j, wc->qp_num)], 1, NULL, 0, NULL));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Once the IB fatal event is reported in the async thread, we want to propagate this error
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "socket.h"
|
||||
#include "net.h"
|
||||
#include "param.h"
|
||||
#include "profiler/net_socket.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
@@ -35,7 +36,10 @@ static ncclResult_t ncclNetSocketGetPciPath(char* devName, char** pciPath) {
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclNetSocketInit(ncclDebugLogger_t logFunction) {
|
||||
static ncclProfilerCallback_t ncclProfilerFunction;
|
||||
|
||||
ncclResult_t ncclNetSocketInit(ncclDebugLogger_t logFunction, ncclProfilerCallback_t profFunction) {
|
||||
ncclProfilerFunction = profFunction;
|
||||
if (ncclNetIfs == -1) {
|
||||
pthread_mutex_lock(&ncclNetSocketLock);
|
||||
if (ncclNetIfs == -1) {
|
||||
@@ -158,6 +162,11 @@ struct ncclNetSocketTask {
|
||||
ncclResult_t result;
|
||||
};
|
||||
|
||||
struct ncclProfilerInfo {
|
||||
void* eHandle;
|
||||
void* pHandle;
|
||||
};
|
||||
|
||||
struct ncclNetSocketRequest {
|
||||
int op;
|
||||
void* data;
|
||||
@@ -168,6 +177,7 @@ struct ncclNetSocketRequest {
|
||||
struct ncclNetSocketComm* comm;
|
||||
struct ncclNetSocketTask* tasks[MAX_SOCKETS];
|
||||
int nSubs;
|
||||
struct ncclProfilerInfo pInfo;
|
||||
};
|
||||
|
||||
struct ncclNetSocketTaskQueue {
|
||||
@@ -180,6 +190,7 @@ struct ncclNetSocketThreadResources {
|
||||
struct ncclNetSocketTaskQueue threadTaskQueue;
|
||||
int stop;
|
||||
struct ncclNetSocketComm* comm;
|
||||
struct ncclProfilerInfo* pInfo;
|
||||
pthread_mutex_t threadLock;
|
||||
pthread_cond_t threadCond;
|
||||
};
|
||||
@@ -210,6 +221,9 @@ void* persistentSocketThread(void *args_) {
|
||||
struct ncclNetSocketComm* comm = resource->comm;
|
||||
struct ncclNetSocketTaskQueue* myQueue = &resource->threadTaskQueue;
|
||||
int nSocksPerThread = comm->nSocks / comm->nThreads;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
void* eHandle[MAX_REQUESTS*MAX_SOCKETS] = { 0 };
|
||||
#endif
|
||||
while (1) {
|
||||
int idle = 1;
|
||||
int mark = myQueue->next; // mark newest task seen
|
||||
@@ -220,13 +234,33 @@ void* persistentSocketThread(void *args_) {
|
||||
for (int j=0; j<nSocksPerThread; j++) {
|
||||
struct ncclNetSocketTask* r = myQueue->tasks+i+j;
|
||||
if (r != NULL && r->used == 1 && r->offset < r->size) {
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
if (!eHandle[i+j]) {
|
||||
ncclProfilerNetSockDescr_v1_t data;
|
||||
data.type = ncclProfileSocket;
|
||||
data.sock.fd = r->sock->fd;
|
||||
data.sock.op = r->op;
|
||||
data.sock.length = r->size;
|
||||
ncclProfilerFunction(&eHandle[i+j], 0, resource->pInfo->pHandle, NCCL_PROFILER_NET_TYPE_SOCK | 1, &data);
|
||||
}
|
||||
#endif
|
||||
r->result = ncclSocketProgress(r->op, r->sock, r->data, r->size, &r->offset);
|
||||
if (r->result != ncclSuccess) {
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
ncclProfilerFunction(&eHandle[i+j], 1, NULL, 0, NULL);
|
||||
eHandle[i+j] = NULL;
|
||||
#endif
|
||||
WARN("NET/Socket : socket progress error");
|
||||
return NULL;
|
||||
}
|
||||
idle = 0;
|
||||
if (r->offset < r->size) repeat = 1;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
if (repeat == 0) {
|
||||
ncclProfilerFunction(&eHandle[i+j], 1, NULL, 0, NULL);
|
||||
eHandle[i+j] = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} while (repeat);
|
||||
@@ -326,7 +360,7 @@ fail:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ncclResult_t ncclNetSocketConnect(int dev, void* opaqueHandle, void** sendComm, ncclNetDeviceHandle_t** /*sendDevComm*/) {
|
||||
ncclResult_t ncclNetSocketConnect(int dev, ncclNetCommConfig_t* config, void* opaqueHandle, void** sendComm, ncclNetDeviceHandle_t** /*sendDevComm*/) {
|
||||
if (dev < 0 || dev >= ncclNetIfs) { // data transfer socket is based on specified dev
|
||||
return ncclInternalError;
|
||||
}
|
||||
@@ -444,7 +478,7 @@ ncclResult_t ncclNetSocketGetRequest(struct ncclNetSocketComm* comm, int op, voi
|
||||
return ncclInternalError;
|
||||
}
|
||||
|
||||
ncclResult_t ncclNetSocketGetTask(struct ncclNetSocketComm* comm, int op, void* data, int size, struct ncclNetSocketTask** req) {
|
||||
ncclResult_t ncclNetSocketGetTask(struct ncclNetSocketComm* comm, struct ncclProfilerInfo* pInfo, int op, void* data, int size, struct ncclNetSocketTask** req) {
|
||||
int tid = comm->nextSock % comm->nThreads;
|
||||
struct ncclNetSocketThreadResources* res = comm->threadResources+tid;
|
||||
struct ncclNetSocketTaskQueue* queue = &res->threadTaskQueue;
|
||||
@@ -457,6 +491,9 @@ ncclResult_t ncclNetSocketGetTask(struct ncclNetSocketComm* comm, int op, void*
|
||||
NCCLCHECK(ncclCalloc(&queue->tasks, queue->len));
|
||||
queue->next = 0;
|
||||
res->comm = comm;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
res->pInfo = pInfo;
|
||||
#endif
|
||||
pthread_mutex_init(&res->threadLock, NULL);
|
||||
pthread_cond_init(&res->threadCond, NULL);
|
||||
PTHREADCHECK(pthread_create(comm->helperThread+tid, NULL, persistentSocketThread, res), "pthread_create");
|
||||
@@ -520,7 +557,7 @@ ncclResult_t ncclNetSocketTest(void* request, int* done, int* size) {
|
||||
int taskSize = std::max(MIN_CHUNKSIZE, DIVUP(r->size, r->comm->nSocks));
|
||||
while (chunkOffset < r->size) {
|
||||
int chunkSize = std::min(taskSize, r->size-chunkOffset);
|
||||
NCCLCHECK(ncclNetSocketGetTask(r->comm, r->op, (char*)(r->data)+chunkOffset, chunkSize, r->tasks+i++));
|
||||
NCCLCHECK(ncclNetSocketGetTask(r->comm, &r->pInfo, r->op, (char*)(r->data)+chunkOffset, chunkSize, r->tasks+i++));
|
||||
chunkOffset += chunkSize;
|
||||
}
|
||||
}
|
||||
@@ -544,6 +581,16 @@ ncclResult_t ncclNetSocketTest(void* request, int* done, int* size) {
|
||||
}
|
||||
}
|
||||
} else { // progress request using main thread
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
if (!r->pInfo.eHandle) {
|
||||
ncclProfilerNetSockDescr_v1_t data;
|
||||
data.type = ncclProfileSocket;
|
||||
data.sock.fd = r->ctrlSock->fd;
|
||||
data.sock.op = r->op;
|
||||
data.sock.length = r->size;
|
||||
ncclProfilerFunction(&r->pInfo.eHandle, 0, r->pInfo.pHandle, NCCL_PROFILER_NET_TYPE_SOCK | 1, &data);
|
||||
}
|
||||
#endif
|
||||
if (r->offset < r->size) {
|
||||
NCCLCHECK(ncclSocketProgress(r->op, r->ctrlSock, r->data, r->size, &r->offset));
|
||||
}
|
||||
@@ -551,6 +598,10 @@ ncclResult_t ncclNetSocketTest(void* request, int* done, int* size) {
|
||||
if (size) *size = r->size;
|
||||
*done = 1;
|
||||
r->used = 0;
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
ncclProfilerFunction(&r->pInfo.eHandle, 1, NULL, 0, NULL);
|
||||
r->pInfo.eHandle = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -562,16 +613,26 @@ ncclResult_t ncclNetSocketRegMr(void* comm, void* data, size_t size, int type, v
|
||||
}
|
||||
ncclResult_t ncclNetSocketDeregMr(void* comm, void* mhandle) { return ncclSuccess; }
|
||||
|
||||
ncclResult_t ncclNetSocketIsend(void* sendComm, void* data, size_t size, int tag, void* mhandle, void** request) {
|
||||
ncclResult_t ncclNetSocketIsend(void* sendComm, void* data, size_t size, int tag, void* mhandle, void* phandle, void** request) {
|
||||
struct ncclNetSocketComm* comm = (struct ncclNetSocketComm*)sendComm;
|
||||
NCCLCHECK(ncclNetSocketGetRequest(comm, NCCL_SOCKET_SEND, data, (int) size, (struct ncclNetSocketRequest**)request));
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
// NCCL core profiler callback
|
||||
struct ncclNetSocketRequest* req = *(struct ncclNetSocketRequest **)request;
|
||||
req->pInfo.pHandle = phandle;
|
||||
#endif
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclNetSocketIrecv(void* recvComm, int n, void** data, size_t* sizes, int* tags, void** mhandles, void** request) {
|
||||
ncclResult_t ncclNetSocketIrecv(void* recvComm, int n, void** data, size_t* sizes, int* tags, void** mhandles, void** phandles, void** request) {
|
||||
struct ncclNetSocketComm* comm = (struct ncclNetSocketComm*)recvComm;
|
||||
if (n != 1) return ncclInternalError;
|
||||
NCCLCHECK(ncclNetSocketGetRequest(comm, NCCL_SOCKET_RECV, data[0], (int)sizes[0], (struct ncclNetSocketRequest**)request));
|
||||
#ifdef NCCL_ENABLE_NET_PROFILING
|
||||
// NCCL core profiler callback
|
||||
struct ncclNetSocketRequest* req = *(struct ncclNetSocketRequest **)request;
|
||||
if (phandles) req->pInfo.pHandle = phandles[0];
|
||||
#endif
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
|
||||
+80
-67
@@ -108,29 +108,29 @@ ncclResult_t nvlsGroupUnbind(struct ncclComm *comm, size_t size, CUmemGenericAll
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclNvlsDeregBuffer(struct ncclComm* comm, CUmemGenericAllocationHandle *mcHandler, CUdeviceptr ptr, int dev, size_t size) {
|
||||
CUCHECK(cuMulticastUnbind(*mcHandler, dev, 0/*mcOffset*/, size));
|
||||
CUCHECK(cuMemUnmap(ptr, size));
|
||||
CUCHECK(cuMemAddressFree(ptr, size));
|
||||
ncclResult_t ncclNvlsDeregBuffer(struct ncclComm* comm, CUmemGenericAllocationHandle *mcHandler, CUdeviceptr ptr, int dev, size_t ucsize, size_t mcsize) {
|
||||
CUCHECK(cuMulticastUnbind(*mcHandler, dev, 0/*mcOffset*/, ucsize));
|
||||
CUCHECK(cuMemUnmap(ptr, mcsize));
|
||||
CUCHECK(cuMemAddressFree(ptr, mcsize));
|
||||
CUCHECK(cuMemRelease(*mcHandler));
|
||||
INFO(NCCL_NVLS, "rank %d - NVLS deregistered buffer %p on device %d, size %ld", comm->rank, (void*)ptr, dev, size);
|
||||
INFO(NCCL_NVLS, "rank %d - NVLS deregistered buffer %p on device %d ucsize %ld mcsize %ld", comm->rank, (void*)ptr, dev, ucsize, mcsize);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t nvlsGroupUnmapMem(struct ncclComm *comm, size_t size, void* ucptr, CUmemGenericAllocationHandle* ucHandle, void* mcptr, CUmemGenericAllocationHandle* mcHandle) {
|
||||
INFO(NCCL_NVLS, "NVLS Unmap mem UC handle 0x%llx(%p) MC handle 0x%llx(%p)", *ucHandle, ucptr, *mcHandle, mcptr);
|
||||
ncclResult_t nvlsGroupUnmapMem(struct ncclComm *comm, size_t ucsize, void* ucptr, CUmemGenericAllocationHandle* ucHandle, size_t mcsize, void* mcptr, CUmemGenericAllocationHandle* mcHandle) {
|
||||
INFO(NCCL_NVLS, "NVLS Unmap mem UC handle 0x%llx(%p) ucsize %zu MC handle 0x%llx(%p) mcsize %zd", *ucHandle, ucptr, ucsize, *mcHandle, mcptr, mcsize);
|
||||
|
||||
// Release the UC memory and mapping
|
||||
if (ucptr) {
|
||||
CUCHECK(cuMemUnmap((CUdeviceptr)ucptr, size));
|
||||
CUCHECK(cuMemAddressFree((CUdeviceptr)ucptr, size));
|
||||
CUCHECK(cuMemUnmap((CUdeviceptr)ucptr, ucsize));
|
||||
CUCHECK(cuMemAddressFree((CUdeviceptr)ucptr, ucsize));
|
||||
CUCHECK(cuMemRelease(*ucHandle));
|
||||
}
|
||||
|
||||
// Release the MC memory and mapping
|
||||
if (mcptr) {
|
||||
CUCHECK(cuMemUnmap((CUdeviceptr)mcptr, size));
|
||||
CUCHECK(cuMemAddressFree((CUdeviceptr)mcptr, size));
|
||||
CUCHECK(cuMemUnmap((CUdeviceptr)mcptr, mcsize));
|
||||
CUCHECK(cuMemAddressFree((CUdeviceptr)mcptr, mcsize));
|
||||
CUCHECK(cuMemRelease(*mcHandle));
|
||||
}
|
||||
|
||||
@@ -197,25 +197,27 @@ fail:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static ncclResult_t nvlsAllocateMem(struct ncclComm* comm, CUmulticastGranularity_flags mcOption, const CUmemAccessDesc* desc, size_t* sizePtr, CUmemGenericAllocationHandle* ucHandle, CUmemGenericAllocationHandle* mcHandle, void** ucptr, void** mcptr) {
|
||||
static ncclResult_t nvlsAllocateMem(struct ncclComm* comm, const CUmemAccessDesc* desc, size_t size, CUmemGenericAllocationHandle* ucHandle, CUmemGenericAllocationHandle* mcHandle, void** ucptr, void** mcptr, size_t* ucsizePtr, size_t* mcsizePtr) {
|
||||
char shareableHandle[NVLS_HANDLE_SIZE];
|
||||
CUmulticastObjectProp mcprop;
|
||||
CUmemAllocationProp ucprop;
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
size_t size = *sizePtr;
|
||||
size_t originSize = size;
|
||||
size_t mcsize;
|
||||
size_t ucsize;
|
||||
size_t ucgran, mcgran;
|
||||
int allocMcHandle = 0;
|
||||
|
||||
mcsize = ucsize = size;
|
||||
*ucptr = *mcptr = NULL;
|
||||
memset(shareableHandle, '\0', sizeof(shareableHandle));
|
||||
memset(&mcprop, 0, sizeof(CUmulticastObjectProp));
|
||||
mcprop.numDevices = comm->localRanks;
|
||||
mcprop.handleTypes = ncclCuMemHandleType;
|
||||
mcprop.flags = 0;
|
||||
mcprop.size = size;
|
||||
CUCHECKGOTO(cuMulticastGetGranularity(&mcgran, &mcprop, mcOption), ret, fail);
|
||||
ALIGN_SIZE(size, mcgran);
|
||||
*sizePtr = mcprop.size = size;
|
||||
CUCHECKGOTO(cuMulticastGetGranularity(&mcgran, &mcprop, CU_MULTICAST_GRANULARITY_RECOMMENDED), ret, fail);
|
||||
ALIGN_SIZE(mcsize, mcgran);
|
||||
mcprop.size = mcsize;
|
||||
|
||||
if (comm->localRank == 0) {
|
||||
NCCLCHECKGOTO(nvlsGroupCreate(comm, &mcprop, comm->localRank, comm->localRanks, mcHandle, shareableHandle), ret, fail);
|
||||
@@ -235,26 +237,29 @@ static ncclResult_t nvlsAllocateMem(struct ncclComm* comm, CUmulticastGranularit
|
||||
ucprop.location.id = comm->cudaDev;
|
||||
ucprop.requestedHandleTypes = ncclCuMemHandleType;
|
||||
CUCHECKGOTO(cuMemGetAllocationGranularity(&ucgran, &ucprop, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED), ret, fail);
|
||||
// Map a VA for UC memory
|
||||
CUCHECKGOTO(cuMemAddressReserve((CUdeviceptr*)ucptr, size, ucgran, 0U, 0), ret, fail);
|
||||
ALIGN_SIZE(ucsize, ucgran);
|
||||
// Map a VA for UC memory with MC alignment and size
|
||||
CUCHECKGOTO(cuMemAddressReserve((CUdeviceptr*)ucptr, ucsize, ucgran, 0U, 0), ret, fail);
|
||||
|
||||
// Alloc local physical mem for this NVLS group
|
||||
CUCHECKGOTO(cuMemCreate(ucHandle, size, &ucprop, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemMap((CUdeviceptr)*ucptr, size, 0, *ucHandle, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemSetAccess((CUdeviceptr)*ucptr, size, desc, 1), ret, fail);
|
||||
CUDACHECKGOTO(cudaMemset(*ucptr, 0, size), ret, fail);
|
||||
CUCHECKGOTO(cuMemCreate(ucHandle, ucsize, &ucprop, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemMap((CUdeviceptr)*ucptr, ucsize, 0, *ucHandle, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemSetAccess((CUdeviceptr)*ucptr, ucsize, desc, 1), ret, fail);
|
||||
CUDACHECKGOTO(cudaMemset(*ucptr, 0, ucsize), ret, fail);
|
||||
|
||||
// intra-node barrier to mitigate the possible hang in cuMulticastBindMem during abort
|
||||
NCCLCHECKGOTO(bootstrapIntraNodeBarrier(comm->bootstrap, comm->localRankToRank, comm->localRank, comm->localRanks, comm->localRankToRank[0]), ret, fail);
|
||||
// Bind physical memory to the Multicast group
|
||||
// NB: It will block until all ranks have been added to the Group
|
||||
CUCHECKGOTO(cuMulticastBindMem(*mcHandle, 0/*mcOffset*/, *ucHandle, 0/*memOffset*/, size, 0/*flags*/), ret, fail);
|
||||
CUCHECKGOTO(cuMulticastBindMem(*mcHandle, 0/*mcOffset*/, *ucHandle, 0/*memOffset*/, ucsize, 0/*flags*/), ret, fail);
|
||||
|
||||
// Map mc virtual address
|
||||
CUCHECKGOTO(cuMemAddressReserve((CUdeviceptr*)mcptr, size, mcgran, 0U, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemMap((CUdeviceptr)*mcptr, size, 0, *mcHandle, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemSetAccess((CUdeviceptr)*mcptr, size, desc, 1), ret, fail);
|
||||
INFO(NCCL_NVLS, "NVLS rank %d (dev %d) alloc done, ucptr %p ucgran %ld mcptr %p mcgran %ld size %ld (%ld)", comm->rank, comm->cudaDev, *ucptr, ucgran, *mcptr, mcgran, size, originSize);
|
||||
CUCHECKGOTO(cuMemAddressReserve((CUdeviceptr*)mcptr, mcsize, mcgran, 0U, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemMap((CUdeviceptr)*mcptr, mcsize, 0, *mcHandle, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemSetAccess((CUdeviceptr)*mcptr, mcsize, desc, 1), ret, fail);
|
||||
*ucsizePtr = ucsize;
|
||||
*mcsizePtr = mcsize;
|
||||
INFO(NCCL_NVLS, "NVLS rank %d (dev %d) alloc done, ucptr %p ucgran %ld mcptr %p mcgran %ld ucsize %ld mcsize %ld (inputsize %ld)", comm->rank, comm->cudaDev, *ucptr, ucgran, *mcptr, mcgran, ucsize, mcsize, size);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
@@ -273,6 +278,7 @@ ncclResult_t ncclNvlsBufferSetup(struct ncclComm* comm) {
|
||||
size_t nvlsTotalSize = 0;
|
||||
struct ncclNvlsSharedRes* resources = NULL;
|
||||
int nChannels = -1;
|
||||
cudaStream_t deviceStream, hostStream;
|
||||
|
||||
if (comm->nvlsSupport == 0 || comm->nvlsResources->inited) return ncclSuccess;
|
||||
// initialize after checking comm->nvlsSupport
|
||||
@@ -288,10 +294,10 @@ ncclResult_t ncclNvlsBufferSetup(struct ncclComm* comm) {
|
||||
INFO(NCCL_INIT | NCCL_NVLS, "NVLS comm %p headRank %d nHeads %d buffSize %zu nvlsPerRankSize %zu nvlsTotalSize %zu",
|
||||
comm, headRank, nHeads, buffSize, nvlsPerRankSize, nvlsTotalSize);
|
||||
|
||||
NCCLCHECKGOTO(nvlsAllocateMem(comm, CU_MULTICAST_GRANULARITY_RECOMMENDED, &resources->accessDesc, &nvlsTotalSize, &resources->ucBuffHandle, &resources->mcBuffHandle, (void**)&resources->ucBuff, (void**)&resources->mcBuff), res, fail);
|
||||
resources->buffSize = nvlsTotalSize;
|
||||
NCCLCHECKGOTO(nvlsAllocateMem(comm, &resources->accessDesc, nvlsTotalSize, &resources->ucBuffHandle, &resources->mcBuffHandle, (void**)&resources->ucBuff, (void**)&resources->mcBuff, &resources->buffUCSize, &resources->buffMCSize), res, fail);
|
||||
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquireUncaptured(&comm->sharedRes->hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquire(ncclCudaGraphNone(), &comm->sharedRes->hostStream, /*concurrent=*/false, &hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquire(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, /*concurrent=*/false, &deviceStream), res, fail);
|
||||
for (int h = 0; h < nHeads; h++) {
|
||||
int nvlsPeer = comm->nRanks + 1 + h;
|
||||
for (int c = 0; c < nChannels; c++) {
|
||||
@@ -306,15 +312,16 @@ ncclResult_t ncclNvlsBufferSetup(struct ncclComm* comm) {
|
||||
peer->recv[1].conn.buffs[NCCL_PROTO_SIMPLE] = resources->ucBuff + ((h * 2 + 1) * nChannels + c) * buffSize;
|
||||
peer->send[0].conn.buffs[NCCL_PROTO_SIMPLE] = resources->mcBuff + ((h * 2 + 1) * nChannels + c) * buffSize;
|
||||
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[0], &peer->send[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[0], &peer->recv[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[1], &peer->send[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[1], &peer->recv[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[0], &peer->send[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[0], &peer->recv[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[1], &peer->send[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[1], &peer->recv[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
}
|
||||
}
|
||||
|
||||
NCCLCHECKGOTO(ncclStrongStreamWaitStream(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, &comm->sharedRes->hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStreamWaitStream(deviceStream, hostStream, comm->sharedRes->scratchEvent), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, /*concurrent=*/false), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->hostStream, /*concurrent=*/false), res, fail);
|
||||
// For now, the barrier is a must that guarantees all buffers are mc-mapped before accessing peer's buffer
|
||||
NCCLCHECKGOTO(bootstrapIntraNodeBarrier(comm->bootstrap, comm->localRankToRank, comm->localRank, comm->localRanks, comm->localRankToRank[0]), res, fail);
|
||||
comm->nvlsResources->inited = true;
|
||||
@@ -374,6 +381,7 @@ setup:
|
||||
size_t memSize = 64;
|
||||
size_t creditSize = nChannels * 2 * memSize * nHeads;
|
||||
int nvlsStepSize = comm->nvlsChunkSize;
|
||||
cudaStream_t hostStream, deviceStream;
|
||||
|
||||
NCCLCHECKGOTO(ncclCalloc(&comm->nvlsResources, 1), res, fail);
|
||||
comm->nvlsResources->inited = false;
|
||||
@@ -398,11 +406,11 @@ setup:
|
||||
resources->accessDesc.location.id = comm->cudaDev;
|
||||
resources->dev = comm->cudaDev;
|
||||
|
||||
NCCLCHECKGOTO(nvlsAllocateMem(comm, CU_MULTICAST_GRANULARITY_MINIMUM, &resources->accessDesc, &creditSize, &resources->ucCreditHandle, &resources->mcCreditHandle, (void**)&resources->ucCredit, (void**)&resources->mcCredit), res, fail);
|
||||
resources->creditSize = creditSize;
|
||||
NCCLCHECKGOTO(nvlsAllocateMem(comm, &resources->accessDesc, creditSize, &resources->ucCreditHandle, &resources->mcCreditHandle, (void**)&resources->ucCredit, (void**)&resources->mcCredit, &resources->creditUCSize, &resources->creditMCSize), res, fail);
|
||||
|
||||
// Set up head and tail only for now
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquireUncaptured(&comm->sharedRes->hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquire(ncclCudaGraphNone(), &comm->sharedRes->hostStream, /*concurrent=*/false, &hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquire(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, /*concurrent=*/false, &deviceStream), res, fail);
|
||||
for (int h = 0; h < nHeads; h++) {
|
||||
int nvlsPeer = comm->nRanks + 1 + h;
|
||||
for (int c = 0; c < nChannels; c++) {
|
||||
@@ -440,14 +448,15 @@ setup:
|
||||
peer->send[0].conn.stepSize = nvlsStepSize;
|
||||
peer->send[0].conn.flags |= NCCL_NVLS_MIN_POLL;
|
||||
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[0], &peer->send[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[0], &peer->recv[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[1], &peer->send[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[1], &peer->recv[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, comm->sharedRes->hostStream.cudaStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[0], &peer->send[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[0], &peer->recv[0].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->send[1], &peer->send[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
CUDACHECKGOTO(cudaMemcpyAsync(&comm->channels[c].devPeersHostPtr[nvlsPeer]->recv[1], &peer->recv[1].conn, sizeof(struct ncclConnInfo), cudaMemcpyHostToDevice, hostStream), res, fail);
|
||||
}
|
||||
}
|
||||
NCCLCHECKGOTO(ncclStrongStreamWaitStream(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, &comm->sharedRes->hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->hostStream), res, fail);
|
||||
NCCLCHECKGOTO(ncclStreamWaitStream(deviceStream, hostStream, comm->sharedRes->scratchEvent), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->hostStream, /*concurrent=*/false), res, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, /*concurrent=*/false), res, fail);
|
||||
}
|
||||
|
||||
// MNNVL does not support NVLS buffer registration
|
||||
@@ -488,13 +497,13 @@ ncclResult_t ncclNvlsFree(struct ncclComm* comm) {
|
||||
NCCLCHECK(ncclShmClose(resources->nvlsShmemHandle));
|
||||
|
||||
if (resources->ucCredit || resources->mcCredit) {
|
||||
NCCLCHECK(nvlsGroupUnbind(comm, resources->creditSize, &resources->mcCreditHandle));
|
||||
NCCLCHECK(nvlsGroupUnmapMem(comm, resources->creditSize, resources->ucCredit, &resources->ucCreditHandle, resources->mcCredit, &resources->mcCreditHandle));
|
||||
NCCLCHECK(nvlsGroupUnbind(comm, resources->creditUCSize, &resources->mcCreditHandle));
|
||||
NCCLCHECK(nvlsGroupUnmapMem(comm, resources->creditUCSize, resources->ucCredit, &resources->ucCreditHandle, resources->creditMCSize, resources->mcCredit, &resources->mcCreditHandle));
|
||||
}
|
||||
|
||||
if (comm->nvlsResources->inited) {
|
||||
NCCLCHECK(nvlsGroupUnbind(comm, resources->buffSize, &resources->mcBuffHandle));
|
||||
NCCLCHECK(nvlsGroupUnmapMem(comm, resources->buffSize, resources->ucBuff, &resources->ucBuffHandle, resources->mcBuff, &resources->mcBuffHandle));
|
||||
NCCLCHECK(nvlsGroupUnbind(comm, resources->buffUCSize, &resources->mcBuffHandle));
|
||||
NCCLCHECK(nvlsGroupUnmapMem(comm, resources->buffUCSize, resources->ucBuff, &resources->ucBuffHandle, resources->buffMCSize, resources->mcBuff, &resources->mcBuffHandle));
|
||||
}
|
||||
free(resources);
|
||||
comm->nvlsResources = NULL;
|
||||
@@ -513,7 +522,7 @@ ncclResult_t tryRegisterBuffer(struct ncclComm *comm, uintptr_t userBuff, size_t
|
||||
size_t minSize = SIZE_MAX;
|
||||
struct localRegData* regData = NULL;
|
||||
cudaPointerAttributes attr;
|
||||
size_t ucgran, mcgran;
|
||||
size_t ucgran, mcgran, ucsize, mcsize;
|
||||
|
||||
NCCLCHECKGOTO(ncclCalloc(®Data, comm->localRanks), ret, fail);
|
||||
|
||||
@@ -538,13 +547,12 @@ ncclResult_t tryRegisterBuffer(struct ncclComm *comm, uintptr_t userBuff, size_t
|
||||
CUCHECKGOTO(cuMemGetAllocationGranularity(&ucgran, &ucprop, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED), ret, fail);
|
||||
|
||||
CUCHECKGOTO(cuMemGetAddressRange((CUdeviceptr*)®Record->baseAddr, ®Record->baseSize, (CUdeviceptr)regRecord->addr), ret, fail);
|
||||
if (regSize % mcgran == 0) {
|
||||
regRecord->regSize = regSize;
|
||||
} else {
|
||||
regRecord->regSize = regRecord->baseSize - (regRecord->addr - regRecord->baseAddr);
|
||||
}
|
||||
|
||||
if (regRecord->addr % ucgran == 0 && regRecord->regSize % mcgran == 0) {
|
||||
if (regRecord->addr % ucgran == 0) {
|
||||
if (regSize % ucgran != 0) {
|
||||
regRecord->regUCSize = ALIGN_SIZE(regSize, ucgran);
|
||||
} else {
|
||||
regRecord->regUCSize = regSize;
|
||||
}
|
||||
regRecord->state |= NVLS_REG_POSSIBLE;
|
||||
memcpy(®Data[comm->localRank].reg, regRecord, sizeof(struct ncclReg));
|
||||
regData[comm->localRank].offset = userBuff - regRecord->addr;
|
||||
@@ -564,13 +572,17 @@ ncclResult_t tryRegisterBuffer(struct ncclComm *comm, uintptr_t userBuff, size_t
|
||||
goto fail;
|
||||
}
|
||||
/* get minimal reg size of nvls buffers */
|
||||
if (minSize > regData[i].reg.regSize)
|
||||
minSize = regData[i].reg.regSize;
|
||||
if (minSize > regData[i].reg.regUCSize)
|
||||
minSize = regData[i].reg.regUCSize;
|
||||
}
|
||||
|
||||
/* start registration */
|
||||
mcsize = ucsize = minSize;
|
||||
mcprop.size = minSize;
|
||||
CUCHECKGOTO(cuMulticastGetGranularity(&mcgran, &mcprop, CU_MULTICAST_GRANULARITY_RECOMMENDED), ret, fail);
|
||||
ALIGN_SIZE(mcsize, mcgran);
|
||||
mcprop.size = mcsize;
|
||||
|
||||
if (comm->localRank == 0) {
|
||||
NCCLCHECKGOTO(nvlsGroupCreate(comm, &mcprop, comm->localRank, comm->localRanks, &mcHandle, shareableHandle), ret, fail);
|
||||
NCCLCHECKGOTO(bootstrapIntraNodeBroadcast(comm->bootstrap, comm->localRankToRank, comm->localRank, comm->localRanks, 0, shareableHandle, NVLS_HANDLE_SIZE), ret, fail);
|
||||
@@ -583,16 +595,17 @@ ncclResult_t tryRegisterBuffer(struct ncclComm *comm, uintptr_t userBuff, size_t
|
||||
// Coverity complains that regRecord could be NULL. That won't in practice be the case because we've already checked
|
||||
// (regData[i].reg.state & NVLS_REG_POSSIBLE) of all local ranks, which would catch it and bail out.
|
||||
// coverity[var_deref_op]
|
||||
CUCHECKGOTO(cuMulticastBindAddr(mcHandle, 0, (CUdeviceptr)regRecord->addr, minSize, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMulticastBindAddr(mcHandle, 0, (CUdeviceptr)regRecord->addr, ucsize, 0), ret, fail);
|
||||
|
||||
// Create a VA for the NVLS
|
||||
CUCHECKGOTO(cuMemAddressReserve(®Ptr, minSize, mcgran, 0U, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemAddressReserve(®Ptr, mcsize, mcgran, 0U, 0), ret, fail);
|
||||
// Map the VA locally
|
||||
CUCHECKGOTO(cuMemMap(regPtr, minSize, 0, mcHandle, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemSetAccess(regPtr, minSize, &comm->nvlsResources->accessDesc, 1), ret, fail);
|
||||
CUCHECKGOTO(cuMemMap(regPtr, mcsize, 0, mcHandle, 0), ret, fail);
|
||||
CUCHECKGOTO(cuMemSetAccess(regPtr, mcsize, &comm->nvlsResources->accessDesc, 1), ret, fail);
|
||||
|
||||
regRecord->regAddr = regPtr;
|
||||
regRecord->regSize = minSize;
|
||||
regRecord->regUCSize = ucsize;
|
||||
regRecord->regMCSize = mcsize;
|
||||
regRecord->dev = comm->nvlsResources->dev;
|
||||
regRecord->mcHandle = mcHandle;
|
||||
regRecord->state |= NVLS_REG_COMPLETE;
|
||||
@@ -706,7 +719,7 @@ exit:
|
||||
return ncclSuccess;
|
||||
fail:
|
||||
regBufUsed = 0;
|
||||
WARN("rank %d failed to NVLS register sendbuff %p sendbuffSize %ld recvbuff %p recvbuffSize %ld", comm->rank, sendbuff, sendbuffSize, recvbuff, recvbuffSize);
|
||||
INFO(NCCL_REG, "rank %d failed to NVLS register sendbuff %p sendbuffSize %ld recvbuff %p recvbuffSize %ld", comm->rank, sendbuff, sendbuffSize, recvbuff, recvbuffSize);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -843,7 +856,7 @@ ncclResult_t ncclNvlsLocalRegisterBuffer(struct ncclComm *comm, const void *send
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclNvlsDeregBuffer(struct ncclComm* comm, CUmemGenericAllocationHandle *mcHandler, CUdeviceptr ptr, int dev, size_t size) {
|
||||
ncclResult_t ncclNvlsDeregBuffer(struct ncclComm* comm, CUmemGenericAllocationHandle *mcHandler, CUdeviceptr ptr, int dev, size_t ucsize, size_t mcsize) {
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -439,6 +439,7 @@ ncclResult_t p2pSendSetup(struct ncclComm* comm, struct ncclTopoGraph* graph, st
|
||||
comm->peerInfo[intermediateRank].busId, useReadStr, comm, comm->nRanks);
|
||||
}
|
||||
|
||||
memset(&req, '\0', sizeof(req));
|
||||
req.size = sendSize;
|
||||
req.refcount = 0;
|
||||
if (P2P_SAME_PID((comm->peerInfo + info->rank), peerInfo) && (comm->peerInfo[info->rank].cudaDev != peerInfo->cudaDev)) req.refcount++;
|
||||
@@ -498,6 +499,7 @@ ncclResult_t p2pRecvSetup(struct ncclComm* comm, struct ncclTopoGraph* graph, st
|
||||
info->rank = intermediateRank;
|
||||
}
|
||||
|
||||
memset(&req, '\0', sizeof(req));
|
||||
req.size = recvSize;
|
||||
req.refcount = 0;
|
||||
if (P2P_SAME_PID((comm->peerInfo + info->rank), peerInfo) && (comm->peerInfo[info->rank].cudaDev != peerInfo->cudaDev)) req.refcount++;
|
||||
@@ -559,7 +561,7 @@ ncclResult_t p2pRecvConnect(struct ncclComm* comm, struct ncclConnect* connectIn
|
||||
|
||||
if (useMemcpy) {
|
||||
// Attach to peer's SHM segment
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, &info->desc, (void**)&resources->shm, (void**)&resources->devShm, &resources->desc));
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, info->rank, &info->desc, (void**)&resources->shm, (void**)&resources->devShm, &resources->desc));
|
||||
|
||||
recv->conn.tail = &resources->devShm->recvMem.tail;
|
||||
recv->conn.head = &resources->devShm->sendMem.head;
|
||||
@@ -670,7 +672,7 @@ static ncclResult_t p2pSendProxySetup(struct ncclProxyConnection* connection, st
|
||||
|
||||
// Create a SHM segment for the peer to attach to
|
||||
shmSize = sizeof(struct ncclSendMem) + sizeof(struct ncclRecvMem);
|
||||
NCCLCHECK(ncclShmAllocateShareableBuffer(proxyState->tpRank, shmSize, false, &proxyInfo->desc, (void**)&proxyInfo->shm, (void**)&proxyInfo->devShm));
|
||||
NCCLCHECK(ncclShmAllocateShareableBuffer(shmSize, false, &proxyInfo->desc, (void**)&proxyInfo->shm, (void**)&proxyInfo->devShm));
|
||||
|
||||
NCCLCHECK(ncclCudaHostCalloc(&proxyInfo->ceRecvMem, 1));
|
||||
memcpy(respBuff, proxyInfo, sizeof(struct p2pShmProxyInfo));
|
||||
@@ -841,7 +843,7 @@ static ncclResult_t ipcRegisterBuffer(ncclComm* comm, const void* userbuff, size
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
struct ncclIpcRegInfo* newInfo = NULL;
|
||||
uintptr_t* peerRmtAddrs = NULL;
|
||||
bool legacyIpcCap = false;
|
||||
int legacyIpcCap = 0;
|
||||
size_t baseSize = 0;
|
||||
void* baseAddr = NULL;
|
||||
bool needUpdate = false;
|
||||
@@ -954,13 +956,16 @@ ncclResult_t ret = ncclSuccess;
|
||||
if (type == NCCL_IPC_COLLECTIVE) {
|
||||
// for collective, store registered remote buffers into dev memory for future reference
|
||||
if (regRecord->regIpcAddrs.devPeerRmtAddrs == NULL || needUpdate) {
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquireUncaptured(&comm->sharedRes->hostStream), ret, fail);
|
||||
cudaStream_t hostStream, deviceStream;
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquire(ncclCudaGraphNone(), &comm->sharedRes->hostStream, /*concurrent=*/false, &hostStream), ret, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamAcquire(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, /*concurrent=*/false, &deviceStream), ret, fail);
|
||||
if (regRecord->regIpcAddrs.devPeerRmtAddrs == NULL)
|
||||
NCCLCHECKGOTO(ncclCudaCallocAsync(®Record->regIpcAddrs.devPeerRmtAddrs, comm->localRanks, comm->sharedRes->hostStream.cudaStream), ret, fail);
|
||||
NCCLCHECKGOTO(ncclCudaCallocAsync(®Record->regIpcAddrs.devPeerRmtAddrs, comm->localRanks, hostStream), ret, fail);
|
||||
if (needUpdate)
|
||||
NCCLCHECKGOTO(ncclCudaMemcpyAsync(regRecord->regIpcAddrs.devPeerRmtAddrs, regRecord->regIpcAddrs.hostPeerRmtAddrs, comm->localRanks, comm->sharedRes->hostStream.cudaStream), ret, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamWaitStream(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, &comm->sharedRes->hostStream), ret, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->hostStream), ret, fail);
|
||||
NCCLCHECKGOTO(ncclCudaMemcpyAsync(regRecord->regIpcAddrs.devPeerRmtAddrs, regRecord->regIpcAddrs.hostPeerRmtAddrs, comm->localRanks, hostStream), ret, fail);
|
||||
NCCLCHECKGOTO(ncclStreamWaitStream(deviceStream, hostStream, comm->sharedRes->scratchEvent), ret, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->hostStream, /*concurrent=*/false), ret, fail);
|
||||
NCCLCHECKGOTO(ncclStrongStreamRelease(ncclCudaGraphNone(), &comm->sharedRes->deviceStream, /*concurrent=*/false), ret, fail);
|
||||
}
|
||||
peerRmtAddrs = regRecord->regIpcAddrs.devPeerRmtAddrs;
|
||||
} else {
|
||||
@@ -979,7 +984,7 @@ fail:
|
||||
*offsetOut = 0;
|
||||
*peerRmtAddrsOut = NULL;
|
||||
if (newInfo) free(newInfo);
|
||||
WARN("rank %d failed to IPC register userbuff %p buffSize %ld nPeers %d isLegacyIpc %p", comm->rank, userbuff, buffSize, nPeers, isLegacyIpc);
|
||||
INFO(NCCL_REG, "rank %d failed to IPC register userbuff %p buffSize %ld nPeers %d isLegacyIpc %d type %s", comm->rank, userbuff, buffSize, nPeers, isLegacyIpc ? *isLegacyIpc : -1, ncclCuMemHandleType == CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR ? "POSIX_FD" : "FABRIC");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*************************************************************************
|
||||
* Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* See LICENSE.txt for license information
|
||||
************************************************************************/
|
||||
#include "transport.h"
|
||||
#include "proxy.h"
|
||||
#include "profiler.h"
|
||||
|
||||
static ncclResult_t profilerProxyConnect(struct ncclProxyConnection* connection, struct ncclProxyState* proxyState, void* reqBuff, int reqSize, void* respBuff, int respSize, int* done) {
|
||||
connection->proxyAppendPtr = &connection->proxyAppend;
|
||||
connection->shared = 1;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
// The following ncclProxySubArgs are overloaded by the profiler progress function:
|
||||
// - base : is set to the current value of workCounter[channelId]
|
||||
// - posted : is set to sub->nsteps to indicate that the profiler has started the event
|
||||
// - transmitted: is set to sub->nsteps to indicate that the profiler has stopped the event
|
||||
static ncclResult_t profilerProxyProgress(struct ncclProxyState* proxyState, struct ncclProxyArgs* args) {
|
||||
if (args->state == ncclProxyOpReady) {
|
||||
for (int s = 0; s < args->nsubs; s++) {
|
||||
struct ncclProxySubArgs* sub = args->subs + s;
|
||||
sub->base = sub->workCounter;
|
||||
sub->posted = sub->transmitted = 0;
|
||||
}
|
||||
args->state = ncclProxyOpProgress;
|
||||
}
|
||||
if (args->state == ncclProxyOpProgress) {
|
||||
for (int s = 0; s < args->nsubs; s++) {
|
||||
struct ncclProxySubArgs* sub = args->subs + s;
|
||||
uint64_t* workStarted = (uint64_t *)sub->sendbuff;
|
||||
uint64_t* workCompleted = (uint64_t *)sub->recvbuff;
|
||||
if (sub->posted < sub->nsteps && sub->base <= workStarted[sub->channelId]) {
|
||||
ncclProfilerStartKernelChEvent(args, s);
|
||||
sub->posted = sub->nsteps;
|
||||
continue; // allow events on every channel to start
|
||||
}
|
||||
if (sub->transmitted < sub->nsteps && sub->base <= workCompleted[sub->channelId]) {
|
||||
ncclProfilerStopKernelChEvent(args, s);
|
||||
sub->transmitted = sub->nsteps;
|
||||
args->done++;
|
||||
}
|
||||
}
|
||||
if (args->done == args->nsubs) args->state = ncclProxyOpNone;
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
struct ncclTransport profilerTransport = {
|
||||
"Prof",
|
||||
NULL,
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL, NULL, profilerProxyConnect, NULL, profilerProxyProgress, NULL, NULL }
|
||||
};
|
||||
+13
-11
@@ -18,6 +18,7 @@ struct shmBuffInfo {
|
||||
};
|
||||
|
||||
struct shmConnectInfo {
|
||||
int rank;
|
||||
ncclShmIpcDesc_t desc;
|
||||
struct shmBuffInfo buf;
|
||||
};
|
||||
@@ -120,6 +121,7 @@ static ncclResult_t shmSendSetup(struct ncclComm* comm, struct ncclTopoGraph* gr
|
||||
NCCLCHECK(ncclProxyConnect(comm, TRANSPORT_SHM, 1, myInfo->rank, &send->proxyConn));
|
||||
NCCLCHECK(ncclProxyCallBlocking(comm, &send->proxyConn, ncclProxyMsgSetup, (void*)&req, sizeof(struct shmRequest), (void*)info, sizeof(struct shmConnectInfo)));
|
||||
|
||||
info->rank = comm->rank;
|
||||
resources->hostMem = (struct ncclSendMem*)info->buf.hptr;
|
||||
resources->devHostMem = (struct ncclSendMem*)info->buf.dptr;
|
||||
|
||||
@@ -150,6 +152,7 @@ static ncclResult_t shmRecvSetup(struct ncclComm* comm, struct ncclTopoGraph* gr
|
||||
NCCLCHECK(ncclProxyConnect(comm, TRANSPORT_SHM, 0, myInfo->rank, &recv->proxyConn));
|
||||
NCCLCHECK(ncclProxyCallBlocking(comm, &recv->proxyConn, ncclProxyMsgSetup, (void*)&req, sizeof(struct shmRequest), (void*)info, sizeof(struct shmConnectInfo)));
|
||||
|
||||
info->rank = comm->rank;
|
||||
resources->hostMem = (struct ncclRecvMem*)info->buf.hptr;
|
||||
resources->devHostMem = (struct ncclRecvMem*)info->buf.dptr;
|
||||
|
||||
@@ -163,7 +166,7 @@ static ncclResult_t shmSendConnect(struct ncclComm* comm, struct ncclConnect* co
|
||||
struct shmSendResources* resources = (struct shmSendResources*)send->transportResources;
|
||||
char* buff;
|
||||
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, &info->desc, (void**)&resources->remHostMem, (void**)&resources->devRemHostMem, &resources->remDesc));
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, info->rank, &info->desc, (void**)&resources->remHostMem, (void**)&resources->devRemHostMem, &resources->remDesc));
|
||||
|
||||
buff = shmLocality == SHM_SEND_SIDE ? (char*)(resources->devHostMem + 1) : (char*)(resources->devRemHostMem + 1);
|
||||
for (int p=0; p<NCCL_NUM_PROTOCOLS; p++) {
|
||||
@@ -197,7 +200,7 @@ static ncclResult_t shmRecvConnect(struct ncclComm* comm, struct ncclConnect* co
|
||||
struct shmConnectInfo* info = (struct shmConnectInfo*)connectInfo;
|
||||
char* buff;
|
||||
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, &info->desc, (void**)&resources->remHostMem, (void**)&resources->devRemHostMem, &resources->remDesc));
|
||||
NCCLCHECK(ncclShmImportShareableBuffer(comm, info->rank, &info->desc, (void**)&resources->remHostMem, (void**)&resources->devRemHostMem, &resources->remDesc));
|
||||
|
||||
buff = shmLocality == SHM_RECV_SIDE ? (char*)(resources->devHostMem + 1) : (char*)(resources->devRemHostMem + 1);
|
||||
for (int p=0; p<NCCL_NUM_PROTOCOLS; p++) {
|
||||
@@ -464,7 +467,7 @@ static ncclResult_t shmSendProxySetup(struct ncclProxyConnection* connection, st
|
||||
struct shmProxyInfo* proxyInfo;
|
||||
|
||||
NCCLCHECK(ncclCalloc(&proxyInfo, 1));
|
||||
NCCLCHECKGOTO(ncclShmAllocateShareableBuffer(proxyState->tpRank, req->size, req->legacy, &proxyInfo->desc, &info->buf.hptr, &info->buf.dptr), result, fail);
|
||||
NCCLCHECKGOTO(ncclShmAllocateShareableBuffer(req->size, req->legacy, &proxyInfo->desc, &info->buf.hptr, &info->buf.dptr), result, fail);
|
||||
memcpy(&info->desc, &proxyInfo->desc, sizeof(ncclShmIpcDesc_t));
|
||||
connection->transportResources = proxyInfo;
|
||||
exit:
|
||||
@@ -485,7 +488,7 @@ static ncclResult_t shmRecvProxySetup(struct ncclProxyConnection* connection, st
|
||||
struct shmProxyInfo* proxyInfo;
|
||||
|
||||
NCCLCHECK(ncclCalloc(&proxyInfo, 1));
|
||||
NCCLCHECKGOTO(ncclShmAllocateShareableBuffer(proxyState->tpRank, req->size, req->legacy, &proxyInfo->desc, &info->buf.hptr, &info->buf.dptr), result, fail);
|
||||
NCCLCHECKGOTO(ncclShmAllocateShareableBuffer(req->size, req->legacy, &proxyInfo->desc, &info->buf.hptr, &info->buf.dptr), result, fail);
|
||||
memcpy(&info->desc, &proxyInfo->desc, sizeof(ncclShmIpcDesc_t));
|
||||
connection->transportResources = proxyInfo;
|
||||
exit:
|
||||
@@ -517,9 +520,9 @@ static void initCeOperation() {
|
||||
}
|
||||
}
|
||||
|
||||
ncclResult_t ncclShmAllocateShareableBuffer(int tpProxyRank, size_t size, bool legacy, ncclShmIpcDesc_t *desc, void **hptr, void **dptr) {
|
||||
if (desc == NULL || hptr == NULL || tpProxyRank < -1) {
|
||||
WARN("Invalid argument desc %p, hptr %p, tpProxyRank %d", desc, hptr, tpProxyRank);
|
||||
ncclResult_t ncclShmAllocateShareableBuffer(size_t size, bool legacy, ncclShmIpcDesc_t *desc, void **hptr, void **dptr) {
|
||||
if (desc == NULL || hptr == NULL) {
|
||||
WARN("Invalid argument desc %p, hptr %p", desc, hptr);
|
||||
return ncclInvalidArgument;
|
||||
}
|
||||
#if CUDART_VERSION >= 12020
|
||||
@@ -532,7 +535,6 @@ ncclResult_t ncclShmAllocateShareableBuffer(int tpProxyRank, size_t size, bool l
|
||||
if (type == CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR) {
|
||||
// Return the native cuMem handle for later Export/Import via UDS
|
||||
memcpy(&desc->shmci.data, &handle, sizeof(handle));
|
||||
desc->shmci.tpProxyRank = tpProxyRank;
|
||||
} else {
|
||||
CUCHECK(cuMemExportToShareableHandle(&desc->shmci.handle, handle, type, 0));
|
||||
}
|
||||
@@ -560,7 +562,7 @@ ncclResult_t ncclShmAllocateShareableBuffer(int tpProxyRank, size_t size, bool l
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclShmImportShareableBuffer(struct ncclComm *comm, ncclShmIpcDesc_t *desc, void **hptr, void **dptr, ncclShmIpcDesc_t *descOut) {
|
||||
ncclResult_t ncclShmImportShareableBuffer(struct ncclComm *comm, int proxyRank, ncclShmIpcDesc_t *desc, void **hptr, void **dptr, ncclShmIpcDesc_t *descOut) {
|
||||
if (comm == NULL || desc == NULL || hptr == NULL || descOut == NULL) {
|
||||
WARN("Invalid argument comm %p, desc %p, hptr %p, descOut %p", comm, desc, hptr, descOut);
|
||||
return ncclInvalidArgument;
|
||||
@@ -584,7 +586,7 @@ ncclResult_t ncclShmImportShareableBuffer(struct ncclComm *comm, ncclShmIpcDesc_
|
||||
// UDS fd support
|
||||
int fd = -1;
|
||||
// Send cuMem handle to remote for conversion to an fd
|
||||
NCCLCHECK(ncclProxyClientGetFdBlocking(comm, desc->shmci.tpProxyRank, &desc->shmci.data, &fd));
|
||||
NCCLCHECK(ncclProxyClientGetFdBlocking(comm, proxyRank, &desc->shmci.data, &fd));
|
||||
CUCHECK(cuMemImportFromShareableHandle(&handle, (void *)(uintptr_t)fd, type));
|
||||
(void) close(fd);
|
||||
} else {
|
||||
@@ -625,7 +627,7 @@ ncclResult_t ncclShmImportShareableBuffer(struct ncclComm *comm, ncclShmIpcDesc_
|
||||
descOut->shmci.ptr = *hptr = (void *)hostptr;
|
||||
descOut->legacy = false;
|
||||
if (dptr) *dptr = (void *)hostptr;
|
||||
INFO(NCCL_SHM, "CUMEM imported shareable host buffer from tpProxyRank %d size %zi ptr %p, granularity %ld", desc->shmci.tpProxyRank, desc->shmci.size, descOut->shmci.ptr, granularity);
|
||||
INFO(NCCL_SHM, "CUMEM imported shareable host buffer from proxyRank %d size %zi ptr %p, granularity %ld", proxyRank, desc->shmci.size, descOut->shmci.ptr, granularity);
|
||||
} else {
|
||||
char shmPath[SHM_PATH_MAX];
|
||||
snprintf(shmPath, sizeof(shmPath), "/dev/shm/nccl-%s", desc->shmli.shmSuffix);
|
||||
|
||||
Reference in New Issue
Block a user