Merge remote-tracking branch 'nccl/master' into develop
[ROCm/rccl commit: 53a1f91857]
This commit is contained in:
@@ -23,11 +23,33 @@ DECLARE_CUDA_PFN(cuMemGetAddressRange, 3020);
|
||||
/* proxy.cc */
|
||||
DECLARE_CUDA_PFN(cuCtxCreate, 3020);
|
||||
DECLARE_CUDA_PFN(cuCtxDestroy, 4000);
|
||||
DECLARE_CUDA_PFN(cuCtxGetCurrent, 4000);
|
||||
DECLARE_CUDA_PFN(cuCtxSetCurrent, 4000);
|
||||
DECLARE_CUDA_PFN(cuCtxGetDevice, 2000);
|
||||
/* cuMem API support */
|
||||
DECLARE_CUDA_PFN(cuMemAddressReserve, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemAddressFree, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemCreate, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemGetAllocationGranularity, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemExportToShareableHandle, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemImportFromShareableHandle, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemMap, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemRelease, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemSetAccess, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemUnmap, 10020);
|
||||
#if CUDA_VERSION >= 11070
|
||||
/* transport/collNet.cc/net.cc*/
|
||||
DECLARE_CUDA_PFN(cuMemGetHandleForAddressRange, 11070); // DMA-BUF support
|
||||
#endif
|
||||
#if CUDA_VERSION >= 12010
|
||||
/* NVSwitch Multicast support */
|
||||
DECLARE_CUDA_PFN(cuMulticastAddDevice, 12010);
|
||||
DECLARE_CUDA_PFN(cuMulticastBindMem, 12010);
|
||||
DECLARE_CUDA_PFN(cuMulticastBindAddr, 12010);
|
||||
DECLARE_CUDA_PFN(cuMulticastCreate, 12010);
|
||||
DECLARE_CUDA_PFN(cuMulticastGetGranularity, 12010);
|
||||
DECLARE_CUDA_PFN(cuMulticastUnbind, 12010);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* CUDA Driver functions loaded with dlsym() */
|
||||
@@ -39,6 +61,7 @@ DECLARE_CUDA_PFN(cuGetProcAddress, 11030);
|
||||
|
||||
static void *cudaLib;
|
||||
int ncclCudaDriverVersionCache = -1;
|
||||
bool ncclCudaLaunchBlocking = false;
|
||||
|
||||
#if CUDART_VERSION >= 11030
|
||||
/*
|
||||
@@ -62,9 +85,33 @@ static ncclResult_t cudaPfnFuncLoader(void) {
|
||||
LOAD_SYM(cuMemGetAddressRange, 3020, 1);
|
||||
LOAD_SYM(cuCtxCreate, 3020, 1);
|
||||
LOAD_SYM(cuCtxDestroy, 4000, 1);
|
||||
LOAD_SYM(cuCtxGetCurrent, 4000, 1);
|
||||
LOAD_SYM(cuCtxSetCurrent, 4000, 1);
|
||||
LOAD_SYM(cuCtxGetDevice, 2000, 1);
|
||||
/* cuMem API support */
|
||||
#if CUDA_VERSION >= 11030
|
||||
LOAD_SYM(cuMemAddressReserve, 10020, 1);
|
||||
LOAD_SYM(cuMemAddressFree, 10020, 1);
|
||||
LOAD_SYM(cuMemCreate, 10020, 1);
|
||||
LOAD_SYM(cuMemGetAllocationGranularity, 10020, 1);
|
||||
LOAD_SYM(cuMemExportToShareableHandle, 10020, 1);
|
||||
LOAD_SYM(cuMemImportFromShareableHandle, 10020, 1);
|
||||
LOAD_SYM(cuMemMap, 10020, 1);
|
||||
LOAD_SYM(cuMemRelease, 10020, 1);
|
||||
LOAD_SYM(cuMemSetAccess, 10020, 1);
|
||||
LOAD_SYM(cuMemUnmap, 10020, 1);
|
||||
#endif
|
||||
#if CUDA_VERSION >= 11070
|
||||
LOAD_SYM(cuMemGetHandleForAddressRange, 11070, 1); // DMA-BUF support
|
||||
#endif
|
||||
#if CUDA_VERSION >= 12010
|
||||
/* NVSwitch Multicast support */
|
||||
LOAD_SYM(cuMulticastAddDevice, 12010, 1);
|
||||
LOAD_SYM(cuMulticastBindMem, 12010, 1);
|
||||
LOAD_SYM(cuMulticastBindAddr, 12010, 1);
|
||||
LOAD_SYM(cuMulticastCreate, 12010, 1);
|
||||
LOAD_SYM(cuMulticastGetGranularity, 12010, 1);
|
||||
LOAD_SYM(cuMulticastUnbind, 12010, 1);
|
||||
#endif
|
||||
return ncclSuccess;
|
||||
}
|
||||
@@ -74,6 +121,11 @@ static pthread_once_t initOnceControl = PTHREAD_ONCE_INIT;
|
||||
static ncclResult_t initResult;
|
||||
|
||||
static void initOnceFunc() {
|
||||
do {
|
||||
char* val = getenv("CUDA_LAUNCH_BLOCKING");
|
||||
ncclCudaLaunchBlocking = val!=nullptr && val[0]!=0 && !(val[0]=='0' && val[1]==0);
|
||||
} while (0);
|
||||
|
||||
CUresult res;
|
||||
/*
|
||||
* Load CUDA driver library
|
||||
@@ -85,9 +137,10 @@ static void initOnceFunc() {
|
||||
else
|
||||
snprintf(path, 1024, "%s%s", ncclCudaPath, "libcuda.so");
|
||||
|
||||
(void) dlerror(); // Clear any previous errors
|
||||
cudaLib = dlopen(path, RTLD_LAZY);
|
||||
if (cudaLib == NULL) {
|
||||
WARN("Failed to find CUDA library (NCCL_CUDA_PATH='%s') : %s", ncclCudaPath ? ncclCudaPath : "", dlerror());
|
||||
WARN("Failed to find CUDA library %s (NCCL_CUDA_PATH='%s') : %s", path, ncclCudaPath ? ncclCudaPath : "", dlerror());
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* See COPYRIGHT for license information
|
||||
*/
|
||||
|
||||
#include "ipcsocket.h"
|
||||
#include "utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
// Enable Linux abstract socket naming
|
||||
#define USE_ABSTRACT_SOCKET
|
||||
|
||||
#define NCCL_IPC_SOCKNAME_STR "/tmp/nccl-socket-%d-%lx"
|
||||
|
||||
/*
|
||||
* Create a Unix Domain Socket
|
||||
*/
|
||||
ncclResult_t ncclIpcSocketInit(ncclIpcSocket *handle, int rank, uint64_t hash, volatile uint32_t* abortFlag) {
|
||||
int fd = -1;
|
||||
struct sockaddr_un cliaddr;
|
||||
char temp[NCCL_IPC_SOCKNAME_LEN] = "";
|
||||
|
||||
if (handle == NULL) {
|
||||
return ncclInternalError;
|
||||
}
|
||||
|
||||
handle->fd = -1;
|
||||
handle->socketName[0] = '\0';
|
||||
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
|
||||
WARN("UDS: Socket creation error : %d", errno);
|
||||
return ncclSystemError;
|
||||
}
|
||||
|
||||
bzero(&cliaddr, sizeof(cliaddr));
|
||||
cliaddr.sun_family = AF_UNIX;
|
||||
|
||||
// Create unique name for the socket.
|
||||
int len = snprintf(temp, NCCL_IPC_SOCKNAME_LEN, NCCL_IPC_SOCKNAME_STR, rank, hash);
|
||||
if (len > (sizeof(cliaddr.sun_path) - 1)) {
|
||||
WARN("UDS: Cannot bind provided name to socket. Name too large");
|
||||
return ncclInternalError;
|
||||
}
|
||||
#ifndef USE_ABSTRACT_SOCKET
|
||||
unlink(temp);
|
||||
#endif
|
||||
|
||||
TRACE(NCCL_INIT, "UDS: Creating socket %s", temp);
|
||||
|
||||
strncpy(cliaddr.sun_path, temp, len);
|
||||
#ifdef USE_ABSTRACT_SOCKET
|
||||
cliaddr.sun_path[0] = '\0'; // Linux abstract socket trick
|
||||
#endif
|
||||
if (bind(fd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0) {
|
||||
WARN("UDS: Binding to socket %s failed : %d", temp, errno);
|
||||
close(fd);
|
||||
return ncclSystemError;
|
||||
}
|
||||
|
||||
handle->fd = fd;
|
||||
strcpy(handle->socketName, temp);
|
||||
|
||||
handle->abortFlag = abortFlag;
|
||||
// Mark socket as non-blocking
|
||||
if (handle->abortFlag) {
|
||||
int flags;
|
||||
EQCHECK(flags = fcntl(fd, F_GETFL), -1);
|
||||
SYSCHECK(fcntl(fd, F_SETFL, flags | O_NONBLOCK), "fcntl");
|
||||
}
|
||||
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIpcSocketClose(ncclIpcSocket *handle) {
|
||||
if (handle == NULL) {
|
||||
return ncclInternalError;
|
||||
}
|
||||
if (handle->fd <= 0) {
|
||||
return ncclSuccess;
|
||||
}
|
||||
#ifndef USE_ABSTRACT_SOCKET
|
||||
if (handle->socketName[0] != '\0') {
|
||||
unlink(handle->socketName);
|
||||
}
|
||||
#endif
|
||||
close(handle->fd);
|
||||
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIpcSocketRecvFd(ncclIpcSocket *handle, int *recvFd) {
|
||||
struct msghdr msg = {0, 0, 0, 0, 0, 0, 0};
|
||||
struct iovec iov[1];
|
||||
|
||||
// Union to guarantee alignment requirements for control array
|
||||
union {
|
||||
struct cmsghdr cm;
|
||||
char control[CMSG_SPACE(sizeof(int))];
|
||||
} control_un;
|
||||
|
||||
struct cmsghdr *cmptr;
|
||||
char dummy_buffer[1];
|
||||
int ret;
|
||||
|
||||
msg.msg_control = control_un.control;
|
||||
msg.msg_controllen = sizeof(control_un.control);
|
||||
|
||||
iov[0].iov_base = (void *)dummy_buffer;
|
||||
iov[0].iov_len = sizeof(dummy_buffer);
|
||||
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
while ((ret = recvmsg(handle->fd, &msg, 0)) <= 0) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
WARN("UDS: Receiving data over socket failed : %d", errno);
|
||||
return ncclSystemError;
|
||||
}
|
||||
if (handle->abortFlag && *handle->abortFlag) return ncclInternalError;
|
||||
}
|
||||
|
||||
if (((cmptr = CMSG_FIRSTHDR(&msg)) != NULL) && (cmptr->cmsg_len == CMSG_LEN(sizeof(int)))) {
|
||||
if ((cmptr->cmsg_level != SOL_SOCKET) || (cmptr->cmsg_type != SCM_RIGHTS)) {
|
||||
WARN("UDS: Receiving data over socket failed");
|
||||
return ncclSystemError;
|
||||
}
|
||||
|
||||
memmove(recvFd, CMSG_DATA(cmptr), sizeof(*recvFd));
|
||||
} else {
|
||||
WARN("UDS: Receiving data over socket %s failed", handle->socketName);
|
||||
return ncclSystemError;
|
||||
}
|
||||
|
||||
TRACE(NCCL_INIT|NCCL_P2P, "UDS: Got recvFd %d from socket %s", *recvFd, handle->socketName);
|
||||
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclIpcSocketSendFd(ncclIpcSocket *handle, const int sendFd, int rank, uint64_t hash) {
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
char temp[NCCL_IPC_SOCKNAME_LEN];
|
||||
|
||||
union {
|
||||
struct cmsghdr cm;
|
||||
char control[CMSG_SPACE(sizeof(int))];
|
||||
} control_un;
|
||||
|
||||
struct cmsghdr *cmptr;
|
||||
struct sockaddr_un cliaddr;
|
||||
|
||||
// Construct client address to send this shareable handle to
|
||||
bzero(&cliaddr, sizeof(cliaddr));
|
||||
cliaddr.sun_family = AF_UNIX;
|
||||
|
||||
int len = snprintf(temp, NCCL_IPC_SOCKNAME_LEN, NCCL_IPC_SOCKNAME_STR, rank, hash);
|
||||
if (len > (sizeof(cliaddr.sun_path) - 1)) {
|
||||
WARN("UDS: Cannot connect to provided name for socket. Name too large");
|
||||
return ncclInternalError;
|
||||
}
|
||||
(void) strncpy(cliaddr.sun_path, temp, len);
|
||||
|
||||
TRACE(NCCL_INIT, "UDS: Sending fd %d to UDS socket %s", sendFd, temp);
|
||||
|
||||
#ifdef USE_ABSTRACT_SOCKET
|
||||
cliaddr.sun_path[0] = '\0'; // Linux abstract socket trick
|
||||
#endif
|
||||
|
||||
msg.msg_control = control_un.control;
|
||||
msg.msg_controllen = sizeof(control_un.control);
|
||||
|
||||
cmptr = CMSG_FIRSTHDR(&msg);
|
||||
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmptr->cmsg_level = SOL_SOCKET;
|
||||
cmptr->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
memmove(CMSG_DATA(cmptr), &sendFd, sizeof(sendFd));
|
||||
|
||||
msg.msg_name = (void *)&cliaddr;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_un);
|
||||
|
||||
iov[0].iov_base = (void *)"";
|
||||
iov[0].iov_len = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
ssize_t sendResult;
|
||||
while ((sendResult = sendmsg(handle->fd, &msg, 0)) <= 0) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||
WARN("UDS: Sending data over socket %s failed : %d", temp, errno);
|
||||
return ncclSystemError;
|
||||
}
|
||||
if (handle->abortFlag && *handle->abortFlag) return ncclInternalError;
|
||||
}
|
||||
|
||||
return ncclSuccess;
|
||||
}
|
||||
@@ -24,8 +24,14 @@ static enum { hsaUninitialized, hsaInitializing, hsaInitialized, hsaError } hsaS
|
||||
|
||||
static void *hsaLib;
|
||||
static uint16_t version_major, version_minor;
|
||||
bool ncclCudaLaunchBlocking = false;
|
||||
|
||||
ncclResult_t rocmLibraryInit(void) {
|
||||
do {
|
||||
char* val = getenv("CUDA_LAUNCH_BLOCKING");
|
||||
ncclCudaLaunchBlocking = val!=nullptr && val[0]!=0 && !(val[0]=='0' && val[1]==0);
|
||||
} while (0);
|
||||
|
||||
hsa_status_t res;
|
||||
|
||||
if (hsaState == hsaInitialized)
|
||||
|
||||
@@ -51,7 +51,7 @@ static ncclResult_t socketProgressOpt(int op, struct ncclSocket* sock, void* ptr
|
||||
|
||||
static ncclResult_t socketProgress(int op, struct ncclSocket* sock, void* ptr, int size, int* offset) {
|
||||
int closed;
|
||||
NCCLCHECK(socketProgressOpt(op, sock, ptr, size, offset, 0, &closed));
|
||||
NCCLCHECK(socketProgressOpt(op, sock, ptr, size, offset, 0 /*block*/, &closed));
|
||||
if (closed) {
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
WARN("socketProgress: Connection closed by remote peer %s", ncclSocketToString(&sock->addr, line, 0));
|
||||
@@ -827,23 +827,47 @@ ncclResult_t ncclSocketRecv(struct ncclSocket* sock, void* ptr, int size) {
|
||||
}
|
||||
|
||||
// Receive or detect connection closed
|
||||
ncclResult_t ncclSocketTryRecv(struct ncclSocket* sock, void* ptr, int size, int* closed) {
|
||||
ncclResult_t ncclSocketTryRecv(struct ncclSocket* sock, void* ptr, int size, int* closed, bool blocking) {
|
||||
int offset = 0;
|
||||
if (sock == NULL) {
|
||||
WARN("ncclSocketTryRecv: pass NULL socket");
|
||||
return ncclInvalidArgument;
|
||||
}
|
||||
*closed = 0;
|
||||
while (offset < size) {
|
||||
// Block until connection closes or nbytes received
|
||||
if (blocking) {
|
||||
while (offset < size) {
|
||||
NCCLCHECK(socketProgressOpt(NCCL_SOCKET_RECV, sock, ptr, size, &offset, 0, closed));
|
||||
if (*closed) return ncclSuccess;
|
||||
}
|
||||
} else {
|
||||
NCCLCHECK(socketProgressOpt(NCCL_SOCKET_RECV, sock, ptr, size, &offset, 0, closed));
|
||||
if (*closed) return ncclSuccess;
|
||||
|
||||
// If any bytes were received, block waiting for the rest
|
||||
if (offset > 0) {
|
||||
while (offset < size) {
|
||||
NCCLCHECK(socketProgressOpt(NCCL_SOCKET_RECV, sock, ptr, size, &offset, 0, closed));
|
||||
if (*closed) return ncclSuccess;
|
||||
}
|
||||
// No bytes were received, return ncclInProgress
|
||||
} else {
|
||||
return ncclInProgress;
|
||||
}
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclSocketClose(struct ncclSocket* sock) {
|
||||
if (sock != NULL) {
|
||||
if (sock->fd >= 0) close(sock->fd);
|
||||
if (sock->fd >= 0) {
|
||||
/* shutdown() is needed to send FIN packet to proxy thread; shutdown() is not affected
|
||||
* by refcount of fd, but close() is. close() won't close a fd and send FIN packet if
|
||||
* the fd is duplicated (e.g. fork()). So shutdown() guarantees the correct and graceful
|
||||
* connection close here. */
|
||||
shutdown(sock->fd, SHUT_RDWR);
|
||||
close(sock->fd);
|
||||
}
|
||||
sock->state = ncclSocketStateClosed;
|
||||
sock->fd = -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user