Add support for external network.
Dynamically load external network from libnccl-net.so. Add init function in networks. Move PCI scoring to net.cu, only ask transport to provide a path. Simplify CUDA PCI path detection. Add dummy external network
This commit is contained in:
+90
-60
@@ -19,11 +19,21 @@
|
||||
#define NET_BITS_PER_IF 3
|
||||
#define NET_BITS_PER_IF_MASK ((1<<NET_BITS_PER_IF)-1)
|
||||
static_assert(sizeof(ncclTvalue_t)*8 >= NET_MAX_IFS*NET_BITS_PER_IF, "NET_MAX_IFS*NET_BITS_PER_IF must fit in a ncclTvalue_t");
|
||||
static ncclTvalue_t getTvalue(short* distances, int ndev) {
|
||||
ncclTvalue_t tvalue = 0;
|
||||
for (int d=0; d<ndev; d++) {
|
||||
int score = 1 + PATH_SOC - distances[d];
|
||||
// Keep 3 bits of score info per dev
|
||||
tvalue |= ((score & NET_BITS_PER_IF_MASK)<<(NET_BITS_PER_IF*d));
|
||||
}
|
||||
return tvalue;
|
||||
}
|
||||
|
||||
struct netInfo {
|
||||
int rank;
|
||||
int ndev;
|
||||
short scores[NET_MAX_IFS];
|
||||
ncclTvalue_t tValue;
|
||||
short distances[NET_MAX_IFS];
|
||||
};
|
||||
|
||||
struct netConnectInfo {
|
||||
@@ -38,7 +48,7 @@ struct netSendResources {
|
||||
struct ncclRecvMem* devHostRecvMem;
|
||||
struct ncclSendMem* hostDevMem;
|
||||
int netDev;
|
||||
bool cudaSupport;
|
||||
int useGdr;
|
||||
struct ncclRecvMem* devNetMem;
|
||||
uint64_t llStep;
|
||||
uint64_t llLastCleaning;
|
||||
@@ -53,7 +63,7 @@ struct netRecvResources {
|
||||
struct ncclRecvMem* devHostRecvMem;
|
||||
struct ncclRecvMem* hostDevMem;
|
||||
int netDev;
|
||||
bool cudaSupport;
|
||||
int useGdr;
|
||||
uint64_t llStep;
|
||||
uint64_t llLastCleaning;
|
||||
};
|
||||
@@ -64,26 +74,37 @@ ncclResult_t netFillInfo(ncclTinfo_t* opaqueInfo, int rank) {
|
||||
struct netInfo* info = (struct netInfo*)opaqueInfo;
|
||||
static_assert(sizeof(struct netInfo) <= sizeof(ncclTinfo_t), "NET Info too large");
|
||||
info->rank = rank;
|
||||
int *scores;
|
||||
NCCLCHECK(ncclNetDevices(&info->ndev, &scores));
|
||||
NCCLCHECK(ncclNetDevices(&info->ndev));
|
||||
if (info->ndev == 0) {
|
||||
WARN("Error : Network returned 0 device");
|
||||
return ncclSystemError;
|
||||
}
|
||||
if (info->ndev > NET_MAX_IFS) info->ndev = NET_MAX_IFS;
|
||||
for (int d=0; d<info->ndev; d++) info->scores[d] = scores[d];
|
||||
free(scores);
|
||||
|
||||
// Find distance with current GPU
|
||||
int cudaDev;
|
||||
cudaGetDevice(&cudaDev);
|
||||
char* cudaPath;
|
||||
NCCLCHECK(getCudaPath(cudaDev, &cudaPath));
|
||||
|
||||
char line[1024];
|
||||
sprintf(line, "CUDA Dev %d, %s NIC distance : ", cudaDev, ncclNetName());
|
||||
for (int d=0; d<info->ndev; d++) {
|
||||
char* nicPath;
|
||||
ncclResult_t err = ncclNetPciPath(d, &nicPath);
|
||||
info->distances[d] = (err != ncclSuccess || nicPath == NULL || cudaPath == NULL) ? PATH_SOC : pciDistance(nicPath, cudaPath);
|
||||
sprintf(line+strlen(line), " %s", pathDists[info->distances[d]]);
|
||||
if (err == ncclSuccess) free(nicPath);
|
||||
}
|
||||
INFO(NCCL_INIT|NCCL_NET, "%s", line);
|
||||
free(cudaPath);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
/* Determine if we can communicate with the peer */
|
||||
ncclResult_t netCanConnect(ncclTvalue_t* ret, ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo) {
|
||||
ret[0] = 0;
|
||||
struct netInfo* myInfo = (struct netInfo*)myOpaqueInfo;
|
||||
for (int d=0; d<myInfo->ndev; d++) {
|
||||
// Keep 3 bits of score info per dev
|
||||
ret[0] |= ((myInfo->scores[d] & NET_BITS_PER_IF_MASK)<<(NET_BITS_PER_IF*d));
|
||||
}
|
||||
ret[0] = getTvalue(myInfo->distances, myInfo->ndev);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
@@ -175,13 +196,13 @@ ncclResult_t netGetRings(int nranks, int* groups, int* subgroups, ncclTvalue_t*
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
int getDev(int ringId, int nDev, short* scores) {
|
||||
int maxScore = 0;
|
||||
for (int d=0; d<nDev; d++) if (scores[d] > maxScore) maxScore = scores[d];
|
||||
int getDev(int ringId, int nDev, short* distances) {
|
||||
int minDistance = PATH_SOC;
|
||||
for (int d=0; d<nDev; d++) if (distances[d] < minDistance) minDistance = distances[d];
|
||||
int skip = ringId+1;
|
||||
while (skip) {
|
||||
for (int d=0; d<nDev; d++) {
|
||||
if (scores[d] == maxScore) {
|
||||
if (distances[d] == minDistance) {
|
||||
skip--;
|
||||
if (skip == 0) return d;
|
||||
}
|
||||
@@ -191,6 +212,40 @@ int getDev(int ringId, int nDev, short* scores) {
|
||||
}
|
||||
|
||||
NCCL_PARAM(NetGdrRead, "NET_GDR_READ", -2);
|
||||
NCCL_PARAM(NetGdrLevel, "NET_GDR_LEVEL", PATH_PHB);
|
||||
|
||||
static ncclResult_t netGetGdrSupport(int dev, int distance, int read, int* useGdr) {
|
||||
*useGdr = 0;
|
||||
|
||||
int cudaDev;
|
||||
CUDACHECK(cudaGetDevice(&cudaDev));
|
||||
|
||||
if (read) { // For reads (sends) only enable under certain conditions
|
||||
int gdrReadParam = ncclParamNetGdrRead();
|
||||
if (gdrReadParam == 0) return ncclSuccess;
|
||||
else if (gdrReadParam < 0) { // default : enable only on DGX2
|
||||
char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE];
|
||||
CUDACHECK(cudaDeviceGetPCIBusId(busId, NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE, cudaDev));
|
||||
int nvlinks = getNumNvlinks(busId);
|
||||
if (nvlinks < CONNECT_NVSWITCH || ncclCudaCompCap() < 7) return ncclSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are close enough that it makes sense to enable GDR
|
||||
int netGdrLevel = ncclParamNetGdrLevel();
|
||||
if (distance >= netGdrLevel) {
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/%s : GPU Direct RDMA Disabled for GPU %d / HCA %d (distance %d >= %d)", ncclNetName(), cudaDev, dev, distance, netGdrLevel);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
// Finally, check if the NIC supports it
|
||||
int flags;
|
||||
NCCLCHECK(ncclNetPtrSupport(dev, &flags));
|
||||
if (flags & NCCL_PTR_CUDA == 0) return ncclSuccess;
|
||||
*useGdr = 1;
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/%s : GPU Direct RDMA Enabled for GPU %d / HCA %d (distance %d >= %d), read %d", ncclNetName(), cudaDev, dev, distance, netGdrLevel, read);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
/* Determine if we will use this transport for this peer and return connect
|
||||
* information for this peer */
|
||||
@@ -200,34 +255,11 @@ ncclResult_t netSendSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
ring->send.transportResources = resources;
|
||||
|
||||
struct netInfo* myInfo = (struct netInfo*)myOpaqueInfo;
|
||||
resources->netDev = getDev(ring->id, myInfo->ndev, myInfo->scores);
|
||||
resources->cudaSupport = false;
|
||||
|
||||
// Get user's GDR READ setting
|
||||
int gdrReadParam = ncclParamNetGdrRead();
|
||||
|
||||
// Determine whether the GPU has NVLink
|
||||
int cudaDev;
|
||||
CUDACHECK(cudaGetDevice(&cudaDev));
|
||||
char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE];
|
||||
CUDACHECK(cudaDeviceGetPCIBusId(busId, NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE, cudaDev));
|
||||
int nvlinks = getNumNvlinks(busId);
|
||||
|
||||
// Enable GDR read when:
|
||||
// 1) user sets it, or
|
||||
// 2) we are on a NVSwitch platform (i.e. no P2P traffic over PCI-E switch) AND the GPU is Volta
|
||||
bool enableGdrRead = (gdrReadParam > 0) || (nvlinks >= CONNECT_NVSWITCH && ncclCudaCompCap() > 6 && gdrReadParam != 0);
|
||||
if (enableGdrRead) {
|
||||
int flags;
|
||||
NCCLCHECK(ncclNetPtrSupport(resources->netDev, &flags));
|
||||
if (flags & NCCL_PTR_CUDA)
|
||||
resources->cudaSupport = true;
|
||||
}
|
||||
if (resources->cudaSupport)
|
||||
INFO(INIT|NET, "Net: enabling net device %d to read from rank %d", resources->netDev, myInfo->rank);
|
||||
resources->netDev = getDev(ring->id, myInfo->ndev, myInfo->distances);
|
||||
NCCLCHECK(netGetGdrSupport(resources->netDev, myInfo->distances[resources->netDev], 1, &resources->useGdr));
|
||||
|
||||
int size = offsetof(struct ncclRecvMem, buff)+ring->buffSize;
|
||||
if (resources->cudaSupport) {
|
||||
if (resources->useGdr) {
|
||||
NCCLCHECK(ncclCudaCalloc((char**)(&resources->devNetMem), size));
|
||||
}
|
||||
|
||||
@@ -243,10 +275,8 @@ ncclResult_t netRecvSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
ring->recv.transportResources = resources;
|
||||
|
||||
struct netInfo* myInfo = (struct netInfo*)myOpaqueInfo;
|
||||
resources->netDev = getDev(ring->id, myInfo->ndev, myInfo->scores);
|
||||
int flags;
|
||||
NCCLCHECK(ncclNetPtrSupport(resources->netDev, &flags));
|
||||
resources->cudaSupport = (flags & NCCL_PTR_CUDA) ? true : false;
|
||||
resources->netDev = getDev(ring->id, myInfo->ndev, myInfo->distances);
|
||||
NCCLCHECK(netGetGdrSupport(resources->netDev, myInfo->distances[resources->netDev], 0, &resources->useGdr));
|
||||
|
||||
int sendSize = sizeof(struct ncclSendMem);
|
||||
NCCLCHECK(ncclCudaHostAlloc((void**)&resources->hostSendMem, (void**)&resources->devHostSendMem, sendSize));
|
||||
@@ -255,8 +285,8 @@ ncclResult_t netRecvSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
NCCLCHECK(ncclCudaHostAlloc((void**)&resources->hostRecvMem, (void**)&resources->devHostRecvMem, recvSize));
|
||||
|
||||
struct netInfo* peerInfo = (struct netInfo*)peerOpaqueInfo;
|
||||
INFO(INIT|NET,"Ring %02d : %d -> %d via NET/%s/%d%s%s", ring->id, peerInfo->rank, myInfo->rank, ncclNetName(), resources->netDev,
|
||||
resources->cudaSupport ? "/GDRDMA" : "",
|
||||
INFO(NCCL_INIT|NCCL_NET,"Ring %02d : %d -> %d via NET/%s/%d%s%s", ring->id, peerInfo->rank, myInfo->rank, ncclNetName(), resources->netDev,
|
||||
resources->useGdr ? "/GDRDMA" : "",
|
||||
(resources->hostDevMem != NULL) ? "/GDCopy" : "");
|
||||
struct netConnectInfo* info = (struct netConnectInfo*) connectInfo;
|
||||
NCCLCHECK(ncclNetListen(resources->netDev, &info->netHandle, &resources->netListenComm));
|
||||
@@ -267,7 +297,7 @@ ncclResult_t netSendConnect(struct ncclConnect* connectInfo, struct ncclConnecto
|
||||
// Setup device pointers
|
||||
struct netSendResources* resources = (struct netSendResources*)send->transportResources;
|
||||
|
||||
if (resources->cudaSupport) {
|
||||
if (resources->useGdr) {
|
||||
send->conn.buff = resources->devNetMem->buff;
|
||||
// We don't use devMem for llMode because the CPU has to read the data
|
||||
send->conn.llBuff = resources->devHostRecvMem->llBuff;
|
||||
@@ -299,7 +329,7 @@ ncclResult_t netRecvConnect(struct ncclConnect* connectInfo, struct ncclConnecto
|
||||
recv->conn.head = &resources->devHostSendMem->head;
|
||||
recv->conn.llHead = &resources->devHostSendMem->llHead;
|
||||
|
||||
if (resources->cudaSupport == false) {
|
||||
if (resources->useGdr == 0) {
|
||||
recv->conn.buff = resources->devHostRecvMem->buff;
|
||||
recv->conn.llBuff = resources->devHostRecvMem->llBuff;
|
||||
}
|
||||
@@ -320,7 +350,7 @@ ncclResult_t netSendFree(void* transportResources) {
|
||||
struct netSendResources* resources = (struct netSendResources*)transportResources;
|
||||
NCCLCHECK(ncclCudaHostFree(resources->hostSendMem));
|
||||
NCCLCHECK(ncclCudaHostFree(resources->hostRecvMem));
|
||||
if (resources->cudaSupport)
|
||||
if (resources->useGdr)
|
||||
CUDACHECK(cudaFree(resources->devNetMem));
|
||||
NCCLCHECK(ncclNetCloseSend(resources->netSendComm));
|
||||
free(resources);
|
||||
@@ -344,9 +374,9 @@ ncclResult_t netSendProxy(struct ncclProxyArgs* args) {
|
||||
volatile uint64_t* prevTail = &resources->hostRecvMem->tail;
|
||||
struct ncclSendMem* prevMem = resources->hostDevMem ? resources->hostDevMem : resources->hostSendMem;
|
||||
uint64_t* prevHead = llMode ? &prevMem->llHead : &prevMem->head;
|
||||
struct ncclRecvMem* localMem = resources->cudaSupport ? resources->devNetMem : resources->hostRecvMem;
|
||||
struct ncclRecvMem* localMem = resources->useGdr ? resources->devNetMem : resources->hostRecvMem;
|
||||
char* localBuff = llMode ? resources->hostRecvMem->llBuff : localMem->buff;
|
||||
int ptrType = resources->cudaSupport ? NCCL_PTR_CUDA : NCCL_PTR_HOST;
|
||||
int ptrType = resources->useGdr ? NCCL_PTR_CUDA : NCCL_PTR_HOST;
|
||||
volatile int* sizesFifo = llMode ? resources->hostRecvMem->llSizesFifo : resources->hostRecvMem->sizesFifo;
|
||||
int buffSize = llMode ? NCCL_LL_BUFF_SIZE : ring->buffSize;
|
||||
int sliceSize = buffSize / args->substeps;
|
||||
@@ -362,8 +392,8 @@ ncclResult_t netSendProxy(struct ncclProxyArgs* args) {
|
||||
|
||||
if (!args->needProxy) goto nextColl;
|
||||
|
||||
TRACE(NET,"opCount %lx head %lx tail %lx end %lx nsteps %d llMode %d", args->opCount, head, tail, end, args->nsteps, llMode);
|
||||
TRACE(NET,"opCount %lx buffSize %d sliceSize %d ptrType %d", args->opCount, buffSize, sliceSize, ptrType);
|
||||
TRACE(NCCL_NET,"opCount %lx head %lx tail %lx end %lx nsteps %d llMode %d", args->opCount, head, tail, end, args->nsteps, llMode);
|
||||
TRACE(NCCL_NET,"opCount %lx buffSize %d sliceSize %d ptrType %d", args->opCount, buffSize, sliceSize, ptrType);
|
||||
|
||||
// Update in case we skipped some collectives
|
||||
if (llMode == 0) resources->hostRecvMem->opCount = args->opCount;
|
||||
@@ -440,10 +470,10 @@ ncclResult_t netRecvProxy(struct ncclProxyArgs* args) {
|
||||
int llMode = args->llMode;
|
||||
|
||||
volatile uint64_t* nextHead = llMode ? &resources->hostSendMem->llHead : &resources->hostSendMem->head;
|
||||
struct ncclRecvMem* localMem = resources->cudaSupport ? ring->devMemRecv : resources->hostRecvMem;
|
||||
struct ncclRecvMem* localMem = resources->useGdr ? ring->devMemRecv : resources->hostRecvMem;
|
||||
char* localBuff = llMode ? localMem->llBuff : localMem->buff;
|
||||
char* nextBuff = (resources->cudaSupport == false && resources->hostDevMem) ? resources->hostDevMem->buff : NULL;
|
||||
int ptrType = resources->cudaSupport ? NCCL_PTR_CUDA : NCCL_PTR_HOST;
|
||||
char* nextBuff = (resources->useGdr == 0 && resources->hostDevMem) ? resources->hostDevMem->buff : NULL;
|
||||
int ptrType = resources->useGdr ? NCCL_PTR_CUDA : NCCL_PTR_HOST;
|
||||
uint64_t* nextTail = resources->hostDevMem ? &resources->hostDevMem->tail : &resources->hostRecvMem->tail;
|
||||
|
||||
int buffSize = llMode ? NCCL_LL_BUFF_SIZE : ring->buffSize;
|
||||
@@ -458,8 +488,8 @@ ncclResult_t netRecvProxy(struct ncclProxyArgs* args) {
|
||||
|
||||
if (!args->needProxy) goto nextColl;
|
||||
|
||||
TRACE(NET,"opCount %lx head %lx tail %lx end %lx nsteps %d llMode %d", args->opCount, head, tail, end, args->nsteps, llMode);
|
||||
TRACE(NET,"opCount %lx buffSize %d sliceSize %d ptrType %d", args->opCount, buffSize, sliceSize, ptrType);
|
||||
TRACE(NCCL_NET,"opCount %lx head %lx tail %lx end %lx nsteps %d llMode %d", args->opCount, head, tail, end, args->nsteps, llMode);
|
||||
TRACE(NCCL_NET,"opCount %lx buffSize %d sliceSize %d ptrType %d", args->opCount, buffSize, sliceSize, ptrType);
|
||||
|
||||
if (llMode == 0) {
|
||||
// Waiting for next opCount is only needed before writing nextTail.
|
||||
|
||||
+34
-69
@@ -82,8 +82,12 @@ static void* ncclIbAsyncThreadMain(void* args) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void initDevices() {
|
||||
if(wrap_ibv_symbols() != ncclSuccess) { return; }
|
||||
NCCL_PARAM(IbDisable, "IB_DISABLE", 0);
|
||||
|
||||
ncclResult_t ncclIbInit(ncclDebugLogger_t logFunction) {
|
||||
if(wrap_ibv_symbols() != ncclSuccess) { return ncclInternalError; }
|
||||
if (ncclParamIbDisable()) return ncclInternalError;
|
||||
|
||||
if (ncclNIbDevs == -1) {
|
||||
pthread_mutex_lock(&ncclIbLock);
|
||||
wrap_ibv_fork_init();
|
||||
@@ -91,9 +95,9 @@ static void initDevices() {
|
||||
ncclNIbDevs = 0;
|
||||
if (findInterfaces(ncclIbIfName, &ncclIbIfAddr, MAX_IF_NAME_SIZE, 1) != 1) {
|
||||
WARN("NET/IB : No IP interface found.");
|
||||
return;
|
||||
return ncclInternalError;
|
||||
}
|
||||
INFO(INIT|NET,"NET/IB : Using interface %s for sideband communication", ncclIbIfName);
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/IB : Using interface %s for sideband communication", ncclIbIfName);
|
||||
|
||||
// Detect IB cards
|
||||
int nIbDevs;
|
||||
@@ -105,7 +109,7 @@ static void initDevices() {
|
||||
bool searchNot = userIbEnv && userIbEnv[0] == '^';
|
||||
int nUserIfs = parseStringList(userIbEnv, userIfs, MAX_IB_DEVS);
|
||||
|
||||
if (ncclSuccess != wrap_ibv_get_device_list(&devices, &nIbDevs)) return;
|
||||
if (ncclSuccess != wrap_ibv_get_device_list(&devices, &nIbDevs)) return ncclInternalError;
|
||||
|
||||
for (int d=0; d<nIbDevs; d++) {
|
||||
struct ibv_context * context;
|
||||
@@ -134,7 +138,7 @@ static void initDevices() {
|
||||
if (! (matchIfList(devices[d]->name, port, userIfs, nUserIfs) ^ searchNot)) {
|
||||
continue;
|
||||
}
|
||||
INFO(INIT|NET,"NET/IB: [%d] %s:%d/%s ", d, devices[d]->name, port,
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/IB: [%d] %s:%d/%s ", d, devices[d]->name, port,
|
||||
portAttr.link_layer == IBV_LINK_LAYER_INFINIBAND ? "IB" : "RoCE");
|
||||
ncclIbDevs[ncclNIbDevs].device = d;
|
||||
ncclIbDevs[ncclNIbDevs].port = port;
|
||||
@@ -145,38 +149,29 @@ static void initDevices() {
|
||||
pthread_create(&ncclIbAsyncThread, NULL, ncclIbAsyncThreadMain, context);
|
||||
}
|
||||
|
||||
if (found == 0) { if (ncclSuccess != wrap_ibv_close_device(context)) { return; } }
|
||||
if (found == 0) { if (ncclSuccess != wrap_ibv_close_device(context)) { return ncclInternalError; } }
|
||||
}
|
||||
}
|
||||
if (nIbDevs && (ncclSuccess != wrap_ibv_free_device_list(devices))) { return; };
|
||||
if (nIbDevs && (ncclSuccess != wrap_ibv_free_device_list(devices))) { return ncclInternalError; };
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&ncclIbLock);
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbDevices(int* ndev, int** scores) {
|
||||
initDevices();
|
||||
ncclResult_t ncclIbDevices(int* ndev) {
|
||||
*ndev = ncclNIbDevs;
|
||||
int cudaDev;
|
||||
cudaGetDevice(&cudaDev);
|
||||
char* cudaPath;
|
||||
ncclResult_t err1 = getCudaPath(cudaDev, &cudaPath);
|
||||
int* sc;
|
||||
NCCLCHECK(ncclCalloc(&sc, ncclNIbDevs));
|
||||
char line[1024];
|
||||
sprintf(line, "CUDA Dev %d, IB Ports : ", cudaDev);
|
||||
for (int d=0; d<ncclNIbDevs; d++) {
|
||||
char* mlxPath;
|
||||
ncclResult_t err2 = getMlxPath(ncclIbDevs[d].devName, &mlxPath);
|
||||
int distance = (err1 != ncclSuccess || err2 != ncclSuccess || mlxPath == NULL || cudaPath == NULL) ? PATH_SOC : pciDistance(mlxPath, cudaPath);
|
||||
sprintf(line+strlen(line), "%s/%d(%s) ", ncclIbDevs[d].devName, ncclIbDevs[d].port, pathDists[distance]);
|
||||
sc[d] = 1+PATH_SOC-distance;
|
||||
if (err2 == ncclSuccess) free(mlxPath);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIbPciPath(int dev, char** path) {
|
||||
char devicepath[PATH_MAX];
|
||||
snprintf(devicepath, PATH_MAX, "/sys/class/infiniband/%s/device", ncclIbDevs[dev].devName);
|
||||
*path = realpath(devicepath, NULL);
|
||||
if (*path == NULL) {
|
||||
WARN("Could not find real path of %s", devicepath);
|
||||
return ncclSystemError;
|
||||
}
|
||||
INFO(INIT|NET,"%s", line);
|
||||
if (err1 == ncclSuccess) free(cudaPath);
|
||||
*scores = sc;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
@@ -207,45 +202,21 @@ ncclResult_t ncclIbGdrSupport(int ibDev) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
NCCL_PARAM(IbGdrLevel, "IB_GDR_LEVEL", -2);
|
||||
NCCL_PARAM(IbCudaSupport, "IB_CUDA_SUPPORT", -2);
|
||||
|
||||
ncclResult_t ncclIbPtrSupport(int dev, int* supportedTypes) {
|
||||
initDevices();
|
||||
*supportedTypes = NCCL_PTR_HOST;
|
||||
|
||||
int cudaDev;
|
||||
if (cudaGetDevice(&cudaDev) != cudaSuccess) return ncclSuccess;
|
||||
CUDACHECK(cudaGetDevice(&cudaDev));
|
||||
|
||||
int ibGdrLevel = PATH_PHB;
|
||||
if (ncclParamIbCudaSupport() != -2) ibGdrLevel = ncclParamIbCudaSupport() ? PATH_SOC + 1 : 0;
|
||||
if (ncclParamIbGdrLevel() != -2) ibGdrLevel = ncclParamIbGdrLevel();
|
||||
if (ibGdrLevel > 0) {
|
||||
int gdrSupport = ncclIbGdrSupport(dev);
|
||||
if (gdrSupport > 0) {
|
||||
INFO(INIT|NET,"NET/IB : GPU Direct RDMA Disabled for GPU %d / HCA %s (%s)", cudaDev, ncclIbDevs[dev].devName, gdrSupport == 1 ? "no module" : "not supported by GPU");
|
||||
ibGdrLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ibGdrLevel <= 0) return ncclSuccess;
|
||||
|
||||
char* cudaPath;
|
||||
if (getCudaPath(cudaDev, &cudaPath) != ncclSuccess) return ncclSuccess;
|
||||
char* mlxPath;
|
||||
if (getMlxPath(ncclIbDevs[dev].devName, &mlxPath) != ncclSuccess) { free(cudaPath); return ncclSuccess; }
|
||||
int distance = (mlxPath == NULL || cudaPath == NULL) ? PATH_SOC : pciDistance(mlxPath, cudaPath);
|
||||
free(mlxPath); free(cudaPath);
|
||||
if (distance < ibGdrLevel) {
|
||||
*supportedTypes |= NCCL_PTR_CUDA;
|
||||
} else {
|
||||
INFO(INIT|NET,"NET/IB : GPU Direct RDMA Disabled for GPU %d / HCA %s (distance %d >= %d)", cudaDev, ncclIbDevs[dev].devName, distance, ibGdrLevel);
|
||||
if (ncclIbGdrSupport(dev) != ncclSuccess) {
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/IB : GPU Direct RDMA Disabled for GPU %d / HCA %s (no module or not supported by GPU)", cudaDev, ncclIbDevs[dev].devName);
|
||||
return ncclSuccess;
|
||||
}
|
||||
*supportedTypes |= NCCL_PTR_CUDA;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static ncclResult_t GetSocketAddr(union socketAddress* addr) {
|
||||
if (ncclNIbDevs == -1) initDevices();
|
||||
memcpy(addr, &ncclIbIfAddr, sizeof(*addr));
|
||||
return ncclSuccess;
|
||||
}
|
||||
@@ -442,7 +413,6 @@ ncclResult_t ncclIbConnect(int dev, void* opaqueHandle, void** sendComm) {
|
||||
*sendComm = comm;
|
||||
|
||||
// IB Setup
|
||||
initDevices(); /*NOTE: We need to do this for ncclNet unit test that bypasses nccl initialization*/
|
||||
ibv_context* ctx = ncclIbDevs[dev].context;
|
||||
NCCLCHECK(ncclIbInitVerbs(ctx, &comm->verbs));
|
||||
uint8_t ib_port = ncclIbDevs[dev].port;
|
||||
@@ -464,13 +434,13 @@ ncclResult_t ncclIbConnect(int dev, void* opaqueHandle, void** sendComm) {
|
||||
// RoCE support
|
||||
qpInfo.lid = portAttr.lid;
|
||||
if (qpInfo.lid) { // IB
|
||||
INFO(INIT|NET,"NET/IB: Dev %d Port %d qpn %d mtu %d LID %d", dev, ib_port, qpInfo.qpn, qpInfo.mtu, qpInfo.lid);
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/IB: Dev %d Port %d qpn %d mtu %d LID %d", dev, ib_port, qpInfo.qpn, qpInfo.mtu, qpInfo.lid);
|
||||
} else { // RoCE
|
||||
union ibv_gid gid;
|
||||
NCCLCHECK(wrap_ibv_query_gid(ctx, ib_port, ncclParamIbGidIndex(), &gid));
|
||||
qpInfo.spn = gid.global.subnet_prefix;
|
||||
qpInfo.iid = gid.global.interface_id;
|
||||
INFO(INIT|NET,"NET/IB: Dev %d Port %d qpn %d mtu %d GID %ld (%lX/%lX)", dev, ib_port, qpInfo.qpn, qpInfo.mtu, ncclParamIbGidIndex(), qpInfo.spn, qpInfo.iid);
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/IB: Dev %d Port %d qpn %d mtu %d GID %ld (%lX/%lX)", dev, ib_port, qpInfo.qpn, qpInfo.mtu, ncclParamIbGidIndex(), qpInfo.spn, qpInfo.iid);
|
||||
}
|
||||
|
||||
NCCLCHECK(socketSend(comm->fd, &qpInfo, sizeof(qpInfo)));
|
||||
@@ -649,7 +619,7 @@ ncclResult_t ncclIbGetMr(struct ncclIbVerbs* verbs, void* data, int size, struct
|
||||
NCCLCHECK(wrap_ibv_reg_mr(&verbs->mrPool[elem].mr, verbs->pd, (void*)regAddr, regSize, IBV_ACCESS_LOCAL_WRITE|IBV_ACCESS_REMOTE_WRITE|IBV_ACCESS_REMOTE_READ));
|
||||
*mrRet = verbs->mrPool+elem;
|
||||
verbs->mrPool[elem].refcnt++;
|
||||
TRACE(INIT,"elem %d regAddr %lx size %ld rkey %x", elem, regAddr, regSize, (verbs->mrPool+elem)->mr->rkey);
|
||||
TRACE(NCCL_INIT,"elem %d regAddr %lx size %ld rkey %x", elem, regAddr, regSize, (verbs->mrPool+elem)->mr->rkey);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
@@ -903,7 +873,9 @@ ncclResult_t ncclIbCloseListen(void* listenComm) {
|
||||
|
||||
ncclNet_t ncclNetIb = {
|
||||
"IB",
|
||||
ncclIbInit,
|
||||
ncclIbDevices,
|
||||
ncclIbPciPath,
|
||||
ncclIbPtrSupport,
|
||||
ncclIbListen,
|
||||
ncclIbConnect,
|
||||
@@ -917,10 +889,3 @@ ncclNet_t ncclNetIb = {
|
||||
ncclIbCloseListen
|
||||
};
|
||||
|
||||
NCCL_PARAM(IbDisable, "IB_DISABLE", 0);
|
||||
|
||||
bool ncclIbSupport() {
|
||||
if (ncclParamIbDisable()) return 0;
|
||||
initDevices();
|
||||
return ncclNIbDevs > 0;
|
||||
}
|
||||
|
||||
+33
-40
@@ -8,67 +8,58 @@
|
||||
#include "core.h"
|
||||
#include "socket.h"
|
||||
#include "net.h"
|
||||
#include "topo.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Init functions */
|
||||
static char ncclNetIfNames[MAX_IF_NAME_SIZE*MAX_IFS];
|
||||
static union socketAddress ncclNetIfAddrs[MAX_IFS];
|
||||
static int ncclNetIfs = -1;
|
||||
pthread_mutex_t ncclSocketLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
ncclResult_t ncclSocketInit(ncclDebugLogger_t logFunction) {
|
||||
if (ncclNetIfs == -1) {
|
||||
pthread_mutex_lock(&ncclSocketLock);
|
||||
if (ncclNetIfs == -1) {
|
||||
ncclNetIfs = findInterfaces(ncclNetIfNames, ncclNetIfAddrs, MAX_IF_NAME_SIZE, MAX_IFS);
|
||||
INFO(NCCL_INIT|NCCL_NET,"NET/Socket : %d interfaces found", ncclNetIfs);
|
||||
if (ncclNetIfs <= 0) {
|
||||
WARN("NET/Socket : no interface found");
|
||||
return ncclInternalError;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&ncclSocketLock);
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclSocketPtrSupport(int dev, int* supportedTypes) {
|
||||
*supportedTypes = NCCL_PTR_HOST;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static char ncclNetIfNames[MAX_IF_NAME_SIZE*MAX_IFS];
|
||||
static union socketAddress ncclNetIfAddrs[MAX_IFS];
|
||||
static int ncclNetIfs = -1;
|
||||
pthread_mutex_t ncclSocketLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void initDevices() {
|
||||
if (ncclNetIfs == -1) {
|
||||
pthread_mutex_lock(&ncclSocketLock);
|
||||
if (ncclNetIfs == -1) {
|
||||
ncclNetIfs = findInterfaces(ncclNetIfNames, ncclNetIfAddrs, MAX_IF_NAME_SIZE, MAX_IFS);
|
||||
INFO(INIT|NET,"NET/Socket : %d interfaces found", ncclNetIfs);
|
||||
if (ncclNetIfs <= 0) {
|
||||
WARN("NET/Socket : no interface found");
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&ncclSocketLock);
|
||||
}
|
||||
ncclResult_t ncclSocketDevices(int* ndev) {
|
||||
*ndev = ncclNetIfs;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclSocketDevices(int* ndev, int** scores) {
|
||||
initDevices();
|
||||
*ndev = ncclNetIfs;
|
||||
int cudaDev;
|
||||
cudaGetDevice(&cudaDev);
|
||||
char* cudaPath;
|
||||
ncclResult_t err1 = getCudaPath(cudaDev, &cudaPath);
|
||||
int* sc;
|
||||
NCCLCHECK(ncclCalloc(&sc, ncclNetIfs));
|
||||
char line[1024];
|
||||
sprintf(line, "CUDA Dev %d, IP Interfaces : ", cudaDev);
|
||||
for (int i=0; i<ncclNetIfs; i++) {
|
||||
char* sockPath;
|
||||
ncclResult_t err2 = getSockPath(ncclNetIfNames+i*MAX_IF_NAME_SIZE, &sockPath);
|
||||
int distance = (err1 != ncclSuccess || err2 != ncclSuccess || sockPath == NULL || cudaPath == NULL) ? PATH_SOC : pciDistance(sockPath, cudaPath);
|
||||
sprintf(line+strlen(line), "%s(%s) ", ncclNetIfNames+i*MAX_IF_NAME_SIZE, pathDists[distance]);
|
||||
sc[i] = 1+PATH_SOC-distance;
|
||||
if (err2 == ncclSuccess) free(sockPath);
|
||||
ncclResult_t ncclSocketPciPath(int dev, char** path) {
|
||||
char devicepath[PATH_MAX];
|
||||
snprintf(devicepath, PATH_MAX, "/sys/class/net/%s/device", ncclNetIfNames+dev*MAX_IF_NAME_SIZE);
|
||||
*path = realpath(devicepath, NULL);
|
||||
if (*path == NULL) {
|
||||
INFO(NCCL_NET|NCCL_INIT, "Could not find real path of %s", devicepath);
|
||||
return ncclSystemError;
|
||||
}
|
||||
INFO(INIT|NET,"%s", line);
|
||||
if (err1 == ncclSuccess) free(cudaPath);
|
||||
*scores = sc;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static ncclResult_t GetSocketAddr(int dev, union socketAddress* addr) {
|
||||
if (ncclNetIfs == -1) initDevices();
|
||||
if (dev >= ncclNetIfs) return ncclInternalError;
|
||||
memcpy(addr, ncclNetIfAddrs+dev, sizeof(*addr));
|
||||
return ncclSuccess;
|
||||
@@ -223,7 +214,9 @@ ncclResult_t ncclSocketClose(void* opaqueComm) {
|
||||
|
||||
ncclNet_t ncclNetSocket = {
|
||||
"Socket",
|
||||
ncclSocketInit,
|
||||
ncclSocketDevices,
|
||||
ncclSocketPciPath,
|
||||
ncclSocketPtrSupport,
|
||||
ncclSocketListen,
|
||||
ncclSocketConnect,
|
||||
|
||||
@@ -85,7 +85,7 @@ ncclResult_t p2pCanConnect(ncclTvalue_t* ret, ncclTinfo_t* myOpaqueInfo, ncclTin
|
||||
// See if CUDA can do P2P
|
||||
int p2p;
|
||||
if (cudaDeviceCanAccessPeer(&p2p, myInfo->cudaDev, peerInfo->cudaDev) != cudaSuccess) {
|
||||
INFO(INIT|P2P,"peer query failed between dev %d and dev %d",
|
||||
INFO(NCCL_INIT|NCCL_P2P,"peer query failed between dev %d and dev %d",
|
||||
myInfo->cudaDev, peerInfo->cudaDev);
|
||||
return ncclSuccess;
|
||||
}
|
||||
@@ -454,7 +454,7 @@ ncclResult_t p2pSendSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
info.direct = 1;
|
||||
info.directPtr = ring->devMemSend;
|
||||
if (myInfo->cudaDev == peerInfo->cudaDev) {
|
||||
INFO(INIT|P2P,"Ring %02d : %d -> %d via P2P/common device", ring->id, myInfo->rank, peerInfo->rank);
|
||||
INFO(NCCL_INIT|NCCL_P2P,"Ring %02d : %d -> %d via P2P/common device", ring->id, myInfo->rank, peerInfo->rank);
|
||||
} else {
|
||||
// Enable P2P access
|
||||
cudaError_t err = cudaDeviceEnablePeerAccess(peerInfo->cudaDev, 0);
|
||||
@@ -465,7 +465,7 @@ ncclResult_t p2pSendSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
peerInfo->cudaDev, err, cudaGetErrorString(err));
|
||||
return ncclInternalError;
|
||||
}
|
||||
INFO(INIT|P2P,"Ring %02d : %d[%d] -> %d[%d] via P2P/direct pointer",
|
||||
INFO(NCCL_INIT|NCCL_P2P,"Ring %02d : %d[%d] -> %d[%d] via P2P/direct pointer",
|
||||
ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
}
|
||||
} else {
|
||||
@@ -477,7 +477,7 @@ ncclResult_t p2pSendSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
myInfo->rank, peerInfo->cudaDev, err, cudaGetErrorString(err));
|
||||
return ncclInternalError;
|
||||
}
|
||||
INFO(INIT|P2P,"Ring %02d : %d[%d] -> %d[%d] via P2P/IPC",
|
||||
INFO(NCCL_INIT|NCCL_P2P,"Ring %02d : %d[%d] -> %d[%d] via P2P/IPC",
|
||||
ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
//TRACE_DUMP_IPC(&info.devIpc);
|
||||
}
|
||||
@@ -495,7 +495,7 @@ ncclResult_t p2pRecvSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
info.direct = 1;
|
||||
info.directPtr = ring->devMemRecv;
|
||||
if (myInfo->cudaDev == peerInfo->cudaDev) {
|
||||
TRACE(INIT|P2P,"%d <- %d via P2P/common device", myInfo->rank, peerInfo->rank);
|
||||
TRACE(NCCL_INIT|NCCL_P2P,"%d <- %d via P2P/common device", myInfo->rank, peerInfo->rank);
|
||||
} else {
|
||||
// Enable P2P access
|
||||
cudaError_t err = cudaDeviceEnablePeerAccess(peerInfo->cudaDev, 0);
|
||||
@@ -506,7 +506,7 @@ ncclResult_t p2pRecvSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
peerInfo->cudaDev, err, cudaGetErrorString(err));
|
||||
return ncclInternalError;
|
||||
}
|
||||
TRACE(INIT|P2P,"Ring %02d : %d[%d] <- %d[%d] via P2P/direct pointer", ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
TRACE(NCCL_INIT|NCCL_P2P,"Ring %02d : %d[%d] <- %d[%d] via P2P/direct pointer", ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
}
|
||||
} else {
|
||||
info.direct = 0;
|
||||
@@ -517,7 +517,7 @@ ncclResult_t p2pRecvSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
myInfo->rank, peerInfo->cudaDev, err, cudaGetErrorString(err));
|
||||
return ncclInternalError;
|
||||
}
|
||||
TRACE(INIT|P2P,"Ring %02d : %d[%d] <- %d[%d] via P2P/IPC", ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
TRACE(NCCL_INIT|NCCL_P2P,"Ring %02d : %d[%d] <- %d[%d] via P2P/IPC", ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
//TRACE_DUMP_IPC(&info.devIpc);
|
||||
}
|
||||
static_assert(sizeof(struct p2pConnectInfo) <= sizeof(struct ncclConnect), "p2p Connect Info is too big");
|
||||
|
||||
@@ -168,10 +168,10 @@ ncclResult_t shmSendSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
char shmName[MAX_SHM_NAME_LEN];
|
||||
sprintf(shmName, "nccl-shm-send-%lx-%d-%d", myInfo->pidHash, ring->id, myInfo->rank);
|
||||
info.shmSize = resources->shmSize = sizeof(struct ncclSendMem);
|
||||
TRACE(SHM,"Open shmName %s shmSize %d", shmName, info.shmSize);
|
||||
TRACE(NCCL_SHM,"Open shmName %s shmSize %d", shmName, info.shmSize);
|
||||
NCCLCHECK(shmOpen(shmName, resources->shmSize, (void**)&resources->hostMem, (void**)&resources->devHostMem, 1));
|
||||
|
||||
INFO(INIT|SHM,"Ring %02d : %d[%d] -> %d[%d] via direct shared memory", ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
INFO(NCCL_INIT|NCCL_SHM,"Ring %02d : %d[%d] -> %d[%d] via direct shared memory", ring->id, myInfo->rank, myInfo->cudaDev, peerInfo->rank, peerInfo->cudaDev);
|
||||
info.id = ring->id; info.rank = myInfo->rank; info.pidHash = myInfo->pidHash;
|
||||
static_assert(sizeof(struct shmRecvConnectInfo) <= sizeof(struct ncclConnect), "shm Connect Recv Info is too big");
|
||||
memcpy(connectInfo, &info, sizeof(struct shmRecvConnectInfo));
|
||||
@@ -189,7 +189,7 @@ ncclResult_t shmRecvSetup(ncclTinfo_t* myOpaqueInfo, ncclTinfo_t* peerOpaqueInfo
|
||||
char shmName[MAX_SHM_NAME_LEN];
|
||||
sprintf(shmName, "nccl-shm-recv-%lx-%d-%d", myInfo->pidHash, ring->id, myInfo->rank);
|
||||
info.shmSize = resources->shmSize = offsetof(struct ncclRecvMem, buff)+ring->buffSize;
|
||||
TRACE(SHM,"Open shmName %s shmSize %d", shmName, info.shmSize);
|
||||
TRACE(NCCL_SHM,"Open shmName %s shmSize %d", shmName, info.shmSize);
|
||||
NCCLCHECK(shmOpen(shmName, resources->shmSize, (void**)&resources->hostMem, (void**)&resources->devHostMem, 1));
|
||||
|
||||
info.id = ring->id; info.rank = myInfo->rank; info.pidHash = myInfo->pidHash;
|
||||
@@ -207,7 +207,7 @@ ncclResult_t shmSendConnect(struct ncclConnect* connectInfo, struct ncclConnecto
|
||||
char shmName[MAX_SHM_NAME_LEN];
|
||||
sprintf(shmName, "nccl-shm-recv-%lx-%d-%d", info->pidHash, info->id, info->rank);
|
||||
resources->remShmSize = info->shmSize;
|
||||
TRACE(SHM,"Open shmName %s shmSize %d", shmName, info->shmSize);
|
||||
TRACE(NCCL_SHM,"Open shmName %s shmSize %d", shmName, info->shmSize);
|
||||
NCCLCHECK(shmOpen(shmName, resources->remShmSize, (void**)&resources->remHostMem, (void**)&resources->devRemHostMem, 0));
|
||||
// Remove the file to ensure proper clean-up
|
||||
NCCLCHECK(shmUnlink(shmName));
|
||||
@@ -231,7 +231,7 @@ ncclResult_t shmRecvConnect(struct ncclConnect* connectInfo, struct ncclConnecto
|
||||
char shmName[MAX_SHM_NAME_LEN];
|
||||
sprintf(shmName, "nccl-shm-send-%lx-%d-%d", info->pidHash, info->id, info->rank);
|
||||
resources->remShmSize = info->shmSize;
|
||||
TRACE(SHM,"Open shmName %s shmSize %d", shmName, info->shmSize);
|
||||
TRACE(NCCL_SHM,"Open shmName %s shmSize %d", shmName, info->shmSize);
|
||||
NCCLCHECK(shmOpen(shmName, resources->remShmSize, (void**)&resources->remHostMem, (void**)&resources->devRemHostMem, 0));
|
||||
NCCLCHECK(shmUnlink(shmName));
|
||||
recv->conn.head = &resources->devRemHostMem->head;
|
||||
|
||||
Reference in New Issue
Block a user