Merge remote-tracking branch 'nccl/master' into develop
[ROCm/rccl commit: 08a7be231b]
This commit is contained in:
@@ -105,6 +105,10 @@ ncclCommDestroy_impl(ncclComm_t comm);
|
||||
ncclResult_t
|
||||
ncclCommAbort_impl(ncclComm_t comm);
|
||||
|
||||
ncclResult_t
|
||||
ncclCommShrink_impl(ncclComm_t comm, int* excludeRanksList, int excludeRanksCount, ncclComm_t *newcomm,
|
||||
ncclConfig_t* config, int shrinkFlags);
|
||||
|
||||
ncclResult_t
|
||||
ncclCommSplit_impl(ncclComm_t comm, int color, int key, ncclComm_t* newcomm,
|
||||
ncclConfig_t* config);
|
||||
@@ -153,6 +157,12 @@ ncclCommRegister_impl(const ncclComm_t comm, void* buff, size_t size, void** han
|
||||
ncclResult_t
|
||||
ncclCommDeregister_impl(const ncclComm_t comm, void* handle);
|
||||
|
||||
ncclResult_t
|
||||
ncclCommWindowRegister_impl(ncclComm_t comm, void* buff, size_t size, ncclWindow_t* win, int winFlags);
|
||||
|
||||
ncclResult_t
|
||||
ncclCommWindowDeregister_impl(ncclComm_t comm, ncclWindow_t win);
|
||||
|
||||
ncclResult_t
|
||||
ncclAllReduceWithBias_impl(const void* sendbuff, void* recvbuff, size_t count,
|
||||
ncclDataType_t datatype, ncclRedOp_t op, ncclComm* comm,
|
||||
@@ -202,25 +212,28 @@ RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommInitRankConfig_fn, 19);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommFinalize_fn, 20);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommDestroy_fn, 21);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommAbort_fn, 22);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommSplit_fn, 23);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclGetErrorString_fn, 24);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclGetLastError_fn, 25);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommGetAsyncError_fn, 26);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommCount_fn, 27);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommCuDevice_fn, 28);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommUserRank_fn, 29);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclMemAlloc_fn, 30);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclMemFree_fn, 31);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, mscclLoadAlgo_fn, 32);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, mscclRunAlgo_fn, 33);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, mscclUnloadAlgo_fn, 34);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommRegister_fn, 35);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommDeregister_fn, 36);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclAllReduceWithBias_fn, 37);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommShrink_fn, 23);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommSplit_fn, 24);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclGetErrorString_fn, 25);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclGetLastError_fn, 26);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommGetAsyncError_fn, 27);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommCount_fn, 28);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommCuDevice_fn, 29);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommUserRank_fn, 30);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclMemAlloc_fn, 31);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclMemFree_fn, 32);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, mscclLoadAlgo_fn, 33);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, mscclRunAlgo_fn, 34);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, mscclUnloadAlgo_fn, 35);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommRegister_fn, 36);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommDeregister_fn, 37);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommWindowRegister_fn, 38);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclCommWindowDeregister_fn, 39);
|
||||
RCCL_ASSERT_OFFSET(rcclApiFuncTable, ncclAllReduceWithBias_fn, 40);
|
||||
|
||||
#undef RCCL_ASSERT_OFFSET
|
||||
|
||||
static_assert(sizeof(rcclApiFuncTable) == compute_table_size(38),
|
||||
static_assert(sizeof(rcclApiFuncTable) == compute_table_size(41),
|
||||
"Update table major/step version and add a new offset assertion if this "
|
||||
"fails to compile");
|
||||
|
||||
@@ -254,6 +267,7 @@ RcclGetFunctionTable_impl()
|
||||
&ncclCommFinalize_impl,
|
||||
&ncclCommDestroy_impl,
|
||||
&ncclCommAbort_impl,
|
||||
&ncclCommShrink_impl,
|
||||
&ncclCommSplit_impl,
|
||||
&ncclGetErrorString_impl,
|
||||
&ncclGetLastError_impl,
|
||||
@@ -268,6 +282,8 @@ RcclGetFunctionTable_impl()
|
||||
&mscclUnloadAlgo_impl,
|
||||
&ncclCommRegister_impl,
|
||||
&ncclCommDeregister_impl,
|
||||
&ncclCommWindowRegister_impl,
|
||||
&ncclCommWindowDeregister_impl,
|
||||
&ncclAllReduceWithBias_impl };
|
||||
|
||||
#if defined(RCCL_ROCPROFILER_REGISTER) && RCCL_ROCPROFILER_REGISTER > 0
|
||||
@@ -370,6 +386,9 @@ NCCL_API(ncclResult_t, ncclCommDestroy, ncclComm_t comm);
|
||||
|
||||
NCCL_API(ncclResult_t, ncclCommAbort, ncclComm_t comm);
|
||||
|
||||
NCCL_API(ncclResult_t, ncclCommShrink, ncclComm_t comm, int* excludeRanksList, int excludeRanksCount,
|
||||
ncclComm_t* newcomm, ncclConfig_t* config, int shrinkFlags);
|
||||
|
||||
NCCL_API(ncclResult_t, ncclCommSplit, ncclComm_t comm, int color, int key,
|
||||
ncclComm_t* newcomm, ncclConfig_t* config);
|
||||
|
||||
@@ -405,6 +424,11 @@ NCCL_API(ncclResult_t, ncclCommRegister, const ncclComm_t comm, void* buff, size
|
||||
|
||||
NCCL_API(ncclResult_t, ncclCommDeregister, const ncclComm_t comm, void* handle);
|
||||
|
||||
NCCL_API(ncclResult_t, ncclCommWindowRegister, ncclComm_t comm, void* buff, size_t size,
|
||||
ncclWindow_t* win, int winFlags);
|
||||
|
||||
NCCL_API(ncclResult_t, ncclCommWindowDeregister, ncclComm_t comm, ncclWindow_t win);
|
||||
|
||||
ncclResult_t
|
||||
ncclAllGather(const void* sendbuff, void* recvbuff, size_t sendcount,
|
||||
ncclDataType_t datatype, ncclComm_t comm, cudaStream_t stream)
|
||||
@@ -581,6 +605,14 @@ ncclCommAbort(ncclComm_t comm)
|
||||
return ::rccl::RcclGetFunctionTable()->ncclCommAbort_fn(comm);
|
||||
}
|
||||
|
||||
ncclResult_t
|
||||
ncclCommShrink(ncclComm_t comm, int* excludeRanksList, int excludeRanksCount, ncclComm_t* newcomm,
|
||||
ncclConfig_t* config, int shrinkFlags)
|
||||
{
|
||||
return ::rccl::RcclGetFunctionTable()->ncclCommShrink_fn(comm, excludeRanksList, excludeRanksCount,
|
||||
newcomm, config, shrinkFlags);
|
||||
}
|
||||
|
||||
ncclResult_t
|
||||
ncclCommSplit(ncclComm_t comm, int color, int key, ncclComm_t* newcomm,
|
||||
ncclConfig_t* config)
|
||||
@@ -672,3 +704,15 @@ ncclCommDeregister(const ncclComm_t comm, void* handle)
|
||||
{
|
||||
return ::rccl::RcclGetFunctionTable()->ncclCommDeregister_fn(comm, handle);
|
||||
}
|
||||
|
||||
ncclResult_t
|
||||
ncclCommWindowRegister(ncclComm_t comm, void* buff, size_t size, ncclWindow_t* win, int winFlags)
|
||||
{
|
||||
return ::rccl::RcclGetFunctionTable()->ncclCommWindowRegister_fn(comm, buff, size, win, winFlags);
|
||||
}
|
||||
|
||||
ncclResult_t
|
||||
ncclCommWindowDeregister(ncclComm_t comm, ncclWindow_t win)
|
||||
{
|
||||
return ::rccl::RcclGetFunctionTable()->ncclCommWindowDeregister_fn(comm, win);
|
||||
}
|
||||
|
||||
@@ -105,53 +105,53 @@ error:
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DECLARE_CUDA_PFN(symbol) PFN_##symbol pfn_##symbol = nullptr
|
||||
#define DECLARE_CUDA_PFN(symbol,version) PFN_##symbol##_v##version pfn_##symbol = nullptr
|
||||
|
||||
#if CUDART_VERSION >= 11030
|
||||
/* CUDA Driver functions loaded with cuGetProcAddress for versioning */
|
||||
DECLARE_CUDA_PFN(cuDeviceGet);
|
||||
DECLARE_CUDA_PFN(cuDeviceGetAttribute);
|
||||
DECLARE_CUDA_PFN(cuGetErrorString);
|
||||
DECLARE_CUDA_PFN(cuGetErrorName);
|
||||
DECLARE_CUDA_PFN(cuDeviceGet, 2000);
|
||||
DECLARE_CUDA_PFN(cuDeviceGetAttribute, 2000);
|
||||
DECLARE_CUDA_PFN(cuGetErrorString, 6000);
|
||||
DECLARE_CUDA_PFN(cuGetErrorName, 6000);
|
||||
/* enqueue.cc */
|
||||
DECLARE_CUDA_PFN(cuMemGetAddressRange);
|
||||
DECLARE_CUDA_PFN(cuLaunchKernel);
|
||||
DECLARE_CUDA_PFN(cuMemGetAddressRange, 3020);
|
||||
DECLARE_CUDA_PFN(cuLaunchKernel, 4000);
|
||||
#if CUDA_VERSION >= 11080
|
||||
DECLARE_CUDA_PFN(cuLaunchKernelEx);
|
||||
DECLARE_CUDA_PFN(cuLaunchKernelEx, 11060);
|
||||
#endif
|
||||
/* proxy.cc */
|
||||
DECLARE_CUDA_PFN(cuCtxCreate);
|
||||
DECLARE_CUDA_PFN(cuCtxDestroy);
|
||||
DECLARE_CUDA_PFN(cuCtxGetCurrent);
|
||||
DECLARE_CUDA_PFN(cuCtxSetCurrent);
|
||||
DECLARE_CUDA_PFN(cuCtxGetDevice);
|
||||
DECLARE_CUDA_PFN(cuCtxCreate, 11040);
|
||||
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);
|
||||
DECLARE_CUDA_PFN(cuMemAddressFree);
|
||||
DECLARE_CUDA_PFN(cuMemCreate);
|
||||
DECLARE_CUDA_PFN(cuMemGetAllocationGranularity);
|
||||
DECLARE_CUDA_PFN(cuMemExportToShareableHandle);
|
||||
DECLARE_CUDA_PFN(cuMemImportFromShareableHandle);
|
||||
DECLARE_CUDA_PFN(cuMemMap);
|
||||
DECLARE_CUDA_PFN(cuMemRelease);
|
||||
DECLARE_CUDA_PFN(cuMemRetainAllocationHandle);
|
||||
DECLARE_CUDA_PFN(cuMemSetAccess);
|
||||
DECLARE_CUDA_PFN(cuMemUnmap);
|
||||
DECLARE_CUDA_PFN(cuMemGetAllocationPropertiesFromHandle);
|
||||
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(cuMemRetainAllocationHandle, 11000);
|
||||
DECLARE_CUDA_PFN(cuMemSetAccess, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemUnmap, 10020);
|
||||
DECLARE_CUDA_PFN(cuMemGetAllocationPropertiesFromHandle, 10020);
|
||||
/* ncclMemAlloc/Free */
|
||||
DECLARE_CUDA_PFN(cuPointerGetAttribute);
|
||||
DECLARE_CUDA_PFN(cuPointerGetAttribute, 4000);
|
||||
#if CUDA_VERSION >= 11070
|
||||
/* transport/collNet.cc/net.cc*/
|
||||
DECLARE_CUDA_PFN(cuMemGetHandleForAddressRange); // DMA-BUF support
|
||||
DECLARE_CUDA_PFN(cuMemGetHandleForAddressRange, 11070); // DMA-BUF support
|
||||
#endif
|
||||
#if CUDA_VERSION >= 12010
|
||||
/* NVSwitch Multicast support */
|
||||
DECLARE_CUDA_PFN(cuMulticastAddDevice);
|
||||
DECLARE_CUDA_PFN(cuMulticastBindMem);
|
||||
DECLARE_CUDA_PFN(cuMulticastBindAddr);
|
||||
DECLARE_CUDA_PFN(cuMulticastCreate);
|
||||
DECLARE_CUDA_PFN(cuMulticastGetGranularity);
|
||||
DECLARE_CUDA_PFN(cuMulticastUnbind);
|
||||
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
|
||||
|
||||
@@ -162,8 +162,17 @@ bool ncclCudaLaunchBlocking = false;
|
||||
|
||||
#if CUDART_VERSION >= 11030
|
||||
|
||||
#if CUDART_VERSION >= 12000
|
||||
#define LOAD_SYM(symbol, ignore) do { \
|
||||
#if CUDART_VERSION >= 13000
|
||||
#define LOAD_SYM(symbol, version, ignore) do { \
|
||||
cudaDriverEntryPointQueryResult driverStatus = cudaDriverEntryPointSymbolNotFound; \
|
||||
res = cudaGetDriverEntryPointByVersion(#symbol, (void **) (&pfn_##symbol), version, cudaEnableDefault, &driverStatus); \
|
||||
if (res != cudaSuccess || driverStatus != cudaDriverEntryPointSuccess) { \
|
||||
if (!ignore) { \
|
||||
WARN("Retrieve %s version %d failed with %d status %d", #symbol, version, res, driverStatus); \
|
||||
return ncclSystemError; } \
|
||||
} } while(0)
|
||||
#elif CUDART_VERSION >= 12000
|
||||
#define LOAD_SYM(symbol, version, ignore) do { \
|
||||
cudaDriverEntryPointQueryResult driverStatus = cudaDriverEntryPointSymbolNotFound; \
|
||||
res = cudaGetDriverEntryPoint(#symbol, (void **) (&pfn_##symbol), cudaEnableDefault, &driverStatus); \
|
||||
if (res != cudaSuccess || driverStatus != cudaDriverEntryPointSuccess) { \
|
||||
@@ -172,7 +181,7 @@ bool ncclCudaLaunchBlocking = false;
|
||||
return ncclSystemError; } \
|
||||
} } while(0)
|
||||
#else
|
||||
#define LOAD_SYM(symbol, ignore) do { \
|
||||
#define LOAD_SYM(symbol, version, ignore) do { \
|
||||
res = cudaGetDriverEntryPoint(#symbol, (void **) (&pfn_##symbol), cudaEnableDefault); \
|
||||
if (res != cudaSuccess) { \
|
||||
if (!ignore) { \
|
||||
@@ -188,46 +197,46 @@ static ncclResult_t cudaPfnFuncLoader(void) {
|
||||
|
||||
cudaError_t res;
|
||||
|
||||
LOAD_SYM(cuGetErrorString, 0);
|
||||
LOAD_SYM(cuGetErrorName, 0);
|
||||
LOAD_SYM(cuDeviceGet, 0);
|
||||
LOAD_SYM(cuDeviceGetAttribute, 0);
|
||||
LOAD_SYM(cuMemGetAddressRange, 1);
|
||||
LOAD_SYM(cuCtxCreate, 1);
|
||||
LOAD_SYM(cuCtxDestroy, 1);
|
||||
LOAD_SYM(cuCtxGetCurrent, 1);
|
||||
LOAD_SYM(cuCtxSetCurrent, 1);
|
||||
LOAD_SYM(cuCtxGetDevice, 1);
|
||||
LOAD_SYM(cuLaunchKernel, 1);
|
||||
LOAD_SYM(cuGetErrorString, 6000, 0);
|
||||
LOAD_SYM(cuGetErrorName, 6000, 0);
|
||||
LOAD_SYM(cuDeviceGet, 2000, 0);
|
||||
LOAD_SYM(cuDeviceGetAttribute, 2000, 0);
|
||||
LOAD_SYM(cuMemGetAddressRange, 3020, 1);
|
||||
LOAD_SYM(cuCtxCreate, 11040, 1);
|
||||
LOAD_SYM(cuCtxDestroy, 4000, 1);
|
||||
LOAD_SYM(cuCtxGetCurrent, 4000, 1);
|
||||
LOAD_SYM(cuCtxSetCurrent, 4000, 1);
|
||||
LOAD_SYM(cuCtxGetDevice, 2000, 1);
|
||||
LOAD_SYM(cuLaunchKernel, 4000, 1);
|
||||
#if CUDA_VERSION >= 11080
|
||||
LOAD_SYM(cuLaunchKernelEx, 1);
|
||||
LOAD_SYM(cuLaunchKernelEx, 11060, 1);
|
||||
#endif
|
||||
/* cuMem API support */
|
||||
LOAD_SYM(cuMemAddressReserve, 1);
|
||||
LOAD_SYM(cuMemAddressFree, 1);
|
||||
LOAD_SYM(cuMemCreate, 1);
|
||||
LOAD_SYM(cuMemGetAllocationGranularity, 1);
|
||||
LOAD_SYM(cuMemExportToShareableHandle, 1);
|
||||
LOAD_SYM(cuMemImportFromShareableHandle, 1);
|
||||
LOAD_SYM(cuMemMap, 1);
|
||||
LOAD_SYM(cuMemRelease, 1);
|
||||
LOAD_SYM(cuMemRetainAllocationHandle, 1);
|
||||
LOAD_SYM(cuMemSetAccess, 1);
|
||||
LOAD_SYM(cuMemUnmap, 1);
|
||||
LOAD_SYM(cuMemGetAllocationPropertiesFromHandle, 1);
|
||||
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(cuMemRetainAllocationHandle, 11000, 1);
|
||||
LOAD_SYM(cuMemSetAccess, 10020, 1);
|
||||
LOAD_SYM(cuMemUnmap, 10020, 1);
|
||||
LOAD_SYM(cuMemGetAllocationPropertiesFromHandle, 10020, 1);
|
||||
/* ncclMemAlloc/Free */
|
||||
LOAD_SYM(cuPointerGetAttribute, 1);
|
||||
LOAD_SYM(cuPointerGetAttribute, 4000, 1);
|
||||
#if CUDA_VERSION >= 11070
|
||||
LOAD_SYM(cuMemGetHandleForAddressRange, 1); // DMA-BUF support
|
||||
LOAD_SYM(cuMemGetHandleForAddressRange, 11070, 1); // DMA-BUF support
|
||||
#endif
|
||||
#if CUDA_VERSION >= 12010
|
||||
/* NVSwitch Multicast support */
|
||||
LOAD_SYM(cuMulticastAddDevice, 1);
|
||||
LOAD_SYM(cuMulticastBindMem, 1);
|
||||
LOAD_SYM(cuMulticastBindAddr, 1);
|
||||
LOAD_SYM(cuMulticastCreate, 1);
|
||||
LOAD_SYM(cuMulticastGetGranularity, 1);
|
||||
LOAD_SYM(cuMulticastUnbind, 1);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef NCCL_BUILD_RDMA_CORE
|
||||
#include <infiniband/verbs.h>
|
||||
#else
|
||||
#include "ibvcore.h"
|
||||
#endif
|
||||
#include "ibvsymbols.h"
|
||||
|
||||
static pthread_once_t initOnceControl = PTHREAD_ONCE_INIT;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mlx5/mlx5dvsymbols.h"
|
||||
|
||||
#ifdef NCCL_BUILD_MLX5DV
|
||||
/* Mlx5dv linking mode. Symbols are pointers to linked MLX5 Direct Verbs */
|
||||
|
||||
#define ASSIGN_SYM(container, symbol, name) container->name= &symbol;
|
||||
|
||||
ncclResult_t buildMlx5dvSymbols(struct ncclMlx5dvSymbols* mlx5dvSymbols) {
|
||||
ASSIGN_SYM(mlx5dvSymbols, mlx5dv_is_supported, mlx5dv_internal_is_supported);
|
||||
ASSIGN_SYM(mlx5dvSymbols, mlx5dv_get_data_direct_sysfs_path, mlx5dv_internal_get_data_direct_sysfs_path);
|
||||
ASSIGN_SYM(mlx5dvSymbols, mlx5dv_reg_dmabuf_mr, mlx5dv_internal_reg_dmabuf_mr);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
#else
|
||||
/* Mlx5dv dynamic loading mode. Symbols are loaded from shared objects. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "core.h"
|
||||
|
||||
// MLX5DV Library versioning
|
||||
#define MLX5DV_VERSION "MLX5_1.8"
|
||||
|
||||
ncclResult_t buildMlx5dvSymbols(struct ncclMlx5dvSymbols* mlx5dvSymbols) {
|
||||
static void* mlx5dvhandle = NULL;
|
||||
void* tmp;
|
||||
void** cast;
|
||||
|
||||
mlx5dvhandle=dlopen("libmlx5.so", RTLD_NOW);
|
||||
if (!mlx5dvhandle) {
|
||||
mlx5dvhandle=dlopen("libmlx5.so.1", RTLD_NOW);
|
||||
if (!mlx5dvhandle) {
|
||||
INFO(NCCL_INIT, "Failed to open libmlx5.so[.1]");
|
||||
goto teardown;
|
||||
}
|
||||
}
|
||||
|
||||
#define LOAD_SYM(handle, symbol, funcptr) do { \
|
||||
cast = (void**)&funcptr; \
|
||||
tmp = dlvsym(handle, symbol, MLX5DV_VERSION); \
|
||||
if (tmp == NULL) { \
|
||||
WARN("dlvsym failed on %s - %s version %s", symbol, dlerror(), MLX5DV_VERSION); \
|
||||
goto teardown; \
|
||||
} \
|
||||
*cast = tmp; \
|
||||
} while (0)
|
||||
|
||||
// Attempt to load a specific symbol version - fail silently
|
||||
#define LOAD_SYM_VERSION(handle, symbol, funcptr, version) do { \
|
||||
cast = (void**)&funcptr; \
|
||||
*cast = dlvsym(handle, symbol, version); \
|
||||
} while (0)
|
||||
|
||||
LOAD_SYM(mlx5dvhandle, "mlx5dv_is_supported", mlx5dvSymbols->mlx5dv_internal_is_supported);
|
||||
// Cherry-pick the mlx5dv_get_data_direct_sysfs_path API from MLX5 1.25
|
||||
LOAD_SYM_VERSION(mlx5dvhandle, "mlx5dv_get_data_direct_sysfs_path", mlx5dvSymbols->mlx5dv_internal_get_data_direct_sysfs_path, "MLX5_1.25");
|
||||
// Cherry-pick the ibv_reg_dmabuf_mr API from MLX5 1.25
|
||||
LOAD_SYM_VERSION(mlx5dvhandle, "mlx5dv_reg_dmabuf_mr", mlx5dvSymbols->mlx5dv_internal_reg_dmabuf_mr, "MLX5_1.25");
|
||||
|
||||
return ncclSuccess;
|
||||
|
||||
teardown:
|
||||
mlx5dvSymbols->mlx5dv_internal_is_supported = NULL;
|
||||
mlx5dvSymbols->mlx5dv_internal_get_data_direct_sysfs_path = NULL;
|
||||
mlx5dvSymbols->mlx5dv_internal_reg_dmabuf_mr = NULL;
|
||||
|
||||
if (mlx5dvhandle != NULL) dlclose(mlx5dvhandle);
|
||||
return ncclSystemError;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*************************************************************************
|
||||
* Copyright (c) 2015-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* See LICENSE.txt for license information
|
||||
************************************************************************/
|
||||
|
||||
#include "mlx5/mlx5dvwrap.h"
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef NCCL_BUILD_MLX5DV
|
||||
#include <infiniband/mlx5dv.h>
|
||||
#else
|
||||
#include "mlx5/mlx5dvcore.h"
|
||||
#endif
|
||||
#include "mlx5/mlx5dvsymbols.h"
|
||||
|
||||
static pthread_once_t initOnceControl = PTHREAD_ONCE_INIT;
|
||||
static ncclResult_t initResult;
|
||||
struct ncclMlx5dvSymbols mlx5dvSymbols;
|
||||
|
||||
ncclResult_t wrap_mlx5dv_symbols(void) {
|
||||
pthread_once(&initOnceControl,
|
||||
[](){ initResult = buildMlx5dvSymbols(&mlx5dvSymbols); });
|
||||
return initResult;
|
||||
}
|
||||
|
||||
/* CHECK_NOT_NULL: helper macro to check for NULL symbol */
|
||||
#define CHECK_NOT_NULL(container, internal_name) \
|
||||
if (container.internal_name == NULL) { \
|
||||
WARN("lib wrapper not initialized."); \
|
||||
return ncclInternalError; \
|
||||
}
|
||||
|
||||
#define MLX5DV_PTR_CHECK_ERRNO(container, internal_name, call, retval, error_retval, name) \
|
||||
CHECK_NOT_NULL(container, internal_name); \
|
||||
retval = container.call; \
|
||||
if (retval == error_retval) { \
|
||||
WARN("Call to " name " failed with error %s", strerror(errno)); \
|
||||
return ncclSystemError; \
|
||||
} \
|
||||
return ncclSuccess;
|
||||
|
||||
#define MLX5DV_INT_CHECK_RET_ERRNO(container, internal_name, call, success_retval, name) \
|
||||
CHECK_NOT_NULL(container, internal_name); \
|
||||
int ret = container.call; \
|
||||
if (ret != success_retval) { \
|
||||
INFO(NCCL_NET, "Call to " name " failed with error %s errno %d", strerror(ret), ret); \
|
||||
return ncclSystemError; \
|
||||
} \
|
||||
return ncclSuccess;
|
||||
|
||||
bool wrap_mlx5dv_is_supported(struct ibv_device *device) {
|
||||
if (mlx5dvSymbols.mlx5dv_internal_is_supported == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return mlx5dvSymbols.mlx5dv_internal_is_supported(device);
|
||||
}
|
||||
|
||||
ncclResult_t wrap_mlx5dv_get_data_direct_sysfs_path(struct ibv_context *context, char *buf, size_t buf_len) {
|
||||
MLX5DV_INT_CHECK_RET_ERRNO(mlx5dvSymbols, mlx5dv_internal_get_data_direct_sysfs_path, mlx5dv_internal_get_data_direct_sysfs_path(context, buf, buf_len), 0, "mlx5dv_get_data_direct_sysfs_path");
|
||||
}
|
||||
|
||||
/* DMA-BUF support */
|
||||
ncclResult_t wrap_mlx5dv_reg_dmabuf_mr(struct ibv_mr **ret, struct ibv_pd *pd, uint64_t offset, size_t length, uint64_t iova, int fd, int access, int mlx5_access) {
|
||||
MLX5DV_PTR_CHECK_ERRNO(mlx5dvSymbols, mlx5dv_internal_reg_dmabuf_mr, mlx5dv_internal_reg_dmabuf_mr(pd, offset, length, iova, fd, access, mlx5_access), *ret, NULL, "mlx5dv_reg_dmabuf_mr");
|
||||
}
|
||||
|
||||
struct ibv_mr * wrap_direct_mlx5dv_reg_dmabuf_mr(struct ibv_pd *pd, uint64_t offset, size_t length, uint64_t iova, int fd, int access, int mlx5_access) {
|
||||
if (mlx5dvSymbols.mlx5dv_internal_reg_dmabuf_mr == NULL) {
|
||||
errno = EOPNOTSUPP; // ncclIbDmaBufSupport() requires this errno being set
|
||||
return NULL;
|
||||
}
|
||||
return mlx5dvSymbols.mlx5dv_internal_reg_dmabuf_mr(pd, offset, length, iova, fd, access, mlx5_access);
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "rocmwrap.h"
|
||||
#include "hsa/hsa.h"
|
||||
#include "param.h"
|
||||
#include "bootstrap.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <sys/utsname.h>
|
||||
@@ -24,9 +25,6 @@ DECLARE_ROCM_PFN(hsa_init);
|
||||
DECLARE_ROCM_PFN(hsa_system_get_info);
|
||||
DECLARE_ROCM_PFN(hsa_status_string);
|
||||
|
||||
// Handle type used for cuMemCreate()
|
||||
CUmemAllocationHandleType ncclCuMemHandleType = CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR;
|
||||
|
||||
static void *hsaLib;
|
||||
static uint16_t version_major, version_minor;
|
||||
bool ncclCudaLaunchBlocking = false;
|
||||
@@ -34,6 +32,52 @@ bool ncclCudaLaunchBlocking = false;
|
||||
static pthread_once_t initOnceControl = PTHREAD_ONCE_INIT;
|
||||
static ncclResult_t initResult;
|
||||
|
||||
// This env var (NCCL_CUMEM_ENABLE) toggles cuMem API usage
|
||||
NCCL_PARAM(CuMemEnable, "CUMEM_ENABLE", 0);
|
||||
NCCL_PARAM(CuMemHostEnable, "CUMEM_HOST_ENABLE", -1);
|
||||
// Handle type used for cuMemCreate()
|
||||
CUmemAllocationHandleType ncclCuMemHandleType = CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR;
|
||||
|
||||
static int ncclCuMemSupported = 0;
|
||||
|
||||
// Determine whether CUMEM & VMM RDMA is supported on this platform
|
||||
int ncclIsCuMemSupported() {
|
||||
#if defined(__HIP_PLATFORM_AMD__) || defined(__HIPCC__)
|
||||
return 0;
|
||||
#else
|
||||
CUdevice currentDev;
|
||||
int cudaDev;
|
||||
int cudaDriverVersion;
|
||||
int flag = 0;
|
||||
ncclResult_t ret = ncclSuccess;
|
||||
CUDACHECKGOTO(cudaDriverGetVersion(&cudaDriverVersion), ret, error);
|
||||
if (cudaDriverVersion < 12000) return 0; // Need CUDA_VISIBLE_DEVICES support
|
||||
CUDACHECKGOTO(cudaGetDevice(&cudaDev), ret, error);
|
||||
if (CUPFN(cuMemCreate) == NULL) return 0;
|
||||
CUCHECKGOTO(cuDeviceGet(¤tDev, cudaDev), ret, error);
|
||||
// Query device to see if CUMEM VMM support is available
|
||||
CUCHECKGOTO(cuDeviceGetAttribute(&flag, CU_DEVICE_ATTRIBUTE_VIRTUAL_MEMORY_MANAGEMENT_SUPPORTED, currentDev), ret, error);
|
||||
if (!flag) return 0;
|
||||
|
||||
error:
|
||||
return (ret == ncclSuccess);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ncclCuMemEnable() {
|
||||
#if defined(__HIP_PLATFORM_AMD__) || defined(__HIPCC__)
|
||||
return 0;
|
||||
#else
|
||||
// NCCL_CUMEM_ENABLE=-2 means auto-detect CUMEM support
|
||||
int param = ncclParamCuMemEnable();
|
||||
return param >= 0 ? param : (param == -2 && ncclCuMemSupported);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ncclCuMemHostEnable() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initOnceFunc() {
|
||||
do {
|
||||
char* val = getenv("CUDA_LAUNCH_BLOCKING");
|
||||
@@ -100,6 +144,9 @@ static void initOnceFunc() {
|
||||
//goto error;
|
||||
//}
|
||||
|
||||
// Determine whether we support the cuMem APIs or not
|
||||
ncclCuMemSupported = ncclIsCuMemSupported();
|
||||
|
||||
/* DMA-BUF support */
|
||||
//ROCm support
|
||||
if (ncclParamDmaBufEnable() == 0 ) {
|
||||
@@ -170,14 +217,6 @@ error:
|
||||
initResult = ncclSystemError;
|
||||
}
|
||||
|
||||
int ncclCuMemEnable() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncclCuMemHostEnable() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ncclResult_t rocmLibraryInit() {
|
||||
pthread_once(&initOnceControl, initOnceFunc);
|
||||
return initResult;
|
||||
|
||||
@@ -73,7 +73,8 @@ static ncclResult_t socketProgress(int op, struct ncclSocket* sock, void* ptr, i
|
||||
return ncclSuccess;
|
||||
} else {
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
WARN("socketProgress: Connection closed by remote peer %s", ncclSocketToString(&sock->addr, line, 0));
|
||||
WARN("socketProgress: Connection closed by remote peer %s",
|
||||
ncclSocketToString(&sock->addr, line, /*numericHostForm*/0));
|
||||
return ncclRemoteError;
|
||||
}
|
||||
}
|
||||
@@ -91,17 +92,22 @@ static ncclResult_t socketWait(int op, struct ncclSocket* sock, void* ptr, int s
|
||||
* Output: "IPv4/IPv6 address<port>"
|
||||
*/
|
||||
const char *ncclSocketToString(const union ncclSocketAddress *addr, char *buf, const int numericHostForm /*= 1*/) {
|
||||
if (buf == NULL || addr == NULL) return NULL;
|
||||
const struct sockaddr *saddr = &addr->sa;
|
||||
if (saddr->sa_family != AF_INET && saddr->sa_family != AF_INET6) { buf[0]='\0'; return buf; }
|
||||
const struct sockaddr *saddr;
|
||||
char host[NI_MAXHOST], service[NI_MAXSERV];
|
||||
int flag = NI_NUMERICSERV | (numericHostForm ? NI_NUMERICHOST : 0);
|
||||
if (buf == NULL || addr == NULL) goto fail;
|
||||
saddr = &addr->sa;
|
||||
if (saddr->sa_family != AF_INET && saddr->sa_family != AF_INET6) goto fail;
|
||||
/* NI_NUMERICHOST: If set, then the numeric form of the hostname is returned.
|
||||
* (When not set, this will still happen in case the node's name cannot be determined.)
|
||||
*/
|
||||
int flag = NI_NUMERICSERV | (numericHostForm ? NI_NUMERICHOST : 0);
|
||||
(void) getnameinfo(saddr, sizeof(union ncclSocketAddress), host, NI_MAXHOST, service, NI_MAXSERV, flag);
|
||||
if (getnameinfo(saddr, sizeof(union ncclSocketAddress), host, NI_MAXHOST, service, NI_MAXSERV, flag)) goto fail;
|
||||
sprintf(buf, "%s<%s>", host, service);
|
||||
return buf;
|
||||
fail:
|
||||
if (buf)
|
||||
buf[0] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static uint16_t socketToPort(union ncclSocketAddress *addr) {
|
||||
@@ -125,7 +131,8 @@ static int envSocketFamily(void) {
|
||||
return family;
|
||||
}
|
||||
|
||||
static int findInterfaces(const char* prefixList, char* names, union ncclSocketAddress *addrs, int sock_family, int maxIfNameSize, int maxIfs) {
|
||||
static ncclResult_t findInterfaces(const char* prefixList, char* names, union ncclSocketAddress *addrs, int sock_family,
|
||||
int maxIfNameSize, int maxIfs, int* found) {
|
||||
#ifdef ENABLE_TRACE
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
#endif
|
||||
@@ -136,10 +143,10 @@ static int findInterfaces(const char* prefixList, char* names, union ncclSocketA
|
||||
if (searchExact) prefixList++;
|
||||
int nUserIfs = parseStringList(prefixList, userIfs, MAX_IFS);
|
||||
|
||||
int found = 0;
|
||||
*found = 0;
|
||||
struct ifaddrs *interfaces, *interface;
|
||||
getifaddrs(&interfaces);
|
||||
for (interface = interfaces; interface && found < maxIfs; interface = interface->ifa_next) {
|
||||
SYSCHECK(getifaddrs(&interfaces), "getifaddrs");
|
||||
for (interface = interfaces; interface && *found < maxIfs; interface = interface->ifa_next) {
|
||||
if (interface->ifa_addr == NULL) continue;
|
||||
|
||||
/* We only support IPv4 & IPv6 */
|
||||
@@ -167,23 +174,23 @@ static int findInterfaces(const char* prefixList, char* names, union ncclSocketA
|
||||
// Check that this interface has not already been saved
|
||||
// getifaddrs() normal order appears to be; IPv4, IPv6 Global, IPv6 Link
|
||||
bool duplicate = false;
|
||||
for (int i = 0; i < found; i++) {
|
||||
for (int i = 0; i < *found; i++) {
|
||||
if (strcmp(interface->ifa_name, names+i*maxIfNameSize) == 0) { duplicate = true; break; }
|
||||
}
|
||||
|
||||
if (!duplicate) {
|
||||
// Store the interface name
|
||||
strncpy(names+found*maxIfNameSize, interface->ifa_name, maxIfNameSize);
|
||||
strncpy(names + (*found)*maxIfNameSize, interface->ifa_name, maxIfNameSize);
|
||||
// Store the IP address
|
||||
int salen = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
memset(addrs+found, '\0', sizeof(*addrs));
|
||||
memcpy(addrs+found, interface->ifa_addr, salen);
|
||||
found++;
|
||||
memset(addrs + *found, '\0', sizeof(*addrs));
|
||||
memcpy(addrs + *found, interface->ifa_addr, salen);
|
||||
(*found)++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(interfaces);
|
||||
return found;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static bool matchSubnet(struct ifaddrs local_if, union ncclSocketAddress* remote) {
|
||||
@@ -224,20 +231,21 @@ static bool matchSubnet(struct ifaddrs local_if, union ncclSocketAddress* remote
|
||||
same &= (local_addr->sin6_scope_id == remote_addr.sin6_scope_id);
|
||||
return same;
|
||||
} else {
|
||||
WARN("Net : Unsupported address family type");
|
||||
INFO(NCCL_NET, "Net : Unsupported address family type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int ncclFindInterfaceMatchSubnet(char* ifNames, union ncclSocketAddress* localAddrs, union ncclSocketAddress* remoteAddr, int ifNameMaxSize, int maxIfs) {
|
||||
ncclResult_t ncclFindInterfaceMatchSubnet(char* ifName, union ncclSocketAddress* localAddr,
|
||||
union ncclSocketAddress* remoteAddr, int ifNameMaxSize, int* found) {
|
||||
#ifdef ENABLE_TRACE
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
#endif
|
||||
char line_a[SOCKET_NAME_MAXLEN+1];
|
||||
int found = 0;
|
||||
#endif
|
||||
*found = 0;
|
||||
struct ifaddrs *interfaces, *interface;
|
||||
getifaddrs(&interfaces);
|
||||
for (interface = interfaces; interface && !found; interface = interface->ifa_next) {
|
||||
SYSCHECK(getifaddrs(&interfaces), "getifaddrs");
|
||||
for (interface = interfaces; interface && !*found; interface = interface->ifa_next) {
|
||||
if (interface->ifa_addr == NULL) continue;
|
||||
|
||||
/* We only support IPv4 & IPv6 */
|
||||
@@ -252,21 +260,18 @@ int ncclFindInterfaceMatchSubnet(char* ifNames, union ncclSocketAddress* localAd
|
||||
|
||||
// Store the local IP address
|
||||
int salen = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
memcpy(localAddrs+found, interface->ifa_addr, salen);
|
||||
memcpy(localAddr, interface->ifa_addr, salen);
|
||||
|
||||
// Store the interface name
|
||||
strncpy(ifNames+found*ifNameMaxSize, interface->ifa_name, ifNameMaxSize);
|
||||
strncpy(ifName, interface->ifa_name, ifNameMaxSize);
|
||||
|
||||
TRACE(NCCL_INIT|NCCL_NET,"NET : Found interface %s:%s in the same subnet as remote address %s", interface->ifa_name, ncclSocketToString(localAddrs+found, line), ncclSocketToString(remoteAddr, line_a));
|
||||
found++;
|
||||
if (found == maxIfs) break;
|
||||
TRACE(NCCL_INIT|NCCL_NET,"NET : Found interface %s:%s in the same subnet as remote address %s",
|
||||
interface->ifa_name, ncclSocketToString(localAddr, line), ncclSocketToString(remoteAddr, line_a));
|
||||
*found = 1;
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
WARN("Net : No interface found in the same subnet as remote address %s", ncclSocketToString(remoteAddr, line_a));
|
||||
}
|
||||
freeifaddrs(interfaces);
|
||||
return found;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclSocketGetAddrFromString(union ncclSocketAddress* ua, const char* ip_port_pair) {
|
||||
@@ -349,40 +354,41 @@ ncclResult_t ncclSocketGetAddrFromString(union ncclSocketAddress* ua, const char
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
int ncclFindInterfaces(char* ifNames, union ncclSocketAddress *ifAddrs, int ifNameMaxSize, int maxIfs) {
|
||||
ncclResult_t ncclFindInterfaces(char* ifNames, union ncclSocketAddress *ifAddrs, int ifNameMaxSize, int maxIfs,
|
||||
int* nIfs) {
|
||||
static int shownIfName = 0;
|
||||
int nIfs = 0;
|
||||
// Allow user to force the INET socket family selection
|
||||
int sock_family = envSocketFamily();
|
||||
// User specified interface
|
||||
const char* env = ncclGetEnv("NCCL_SOCKET_IFNAME");
|
||||
*nIfs = 0;
|
||||
if (env && strlen(env) > 1) {
|
||||
INFO(NCCL_ENV, "NCCL_SOCKET_IFNAME set by environment to %s", env);
|
||||
// Specified by user : find or fail
|
||||
if (shownIfName++ == 0) INFO(NCCL_NET, "NCCL_SOCKET_IFNAME set to %s", env);
|
||||
nIfs = findInterfaces(env, ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs);
|
||||
NCCLCHECK(findInterfaces(env, ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs, nIfs));
|
||||
} else {
|
||||
// Try to automatically pick the right one
|
||||
// Start with IB
|
||||
nIfs = findInterfaces("ib", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs);
|
||||
NCCLCHECK(findInterfaces("ib", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs, nIfs));
|
||||
// else see if we can get some hint from COMM ID
|
||||
if (nIfs == 0) {
|
||||
if (*nIfs == 0) {
|
||||
const char* commId = ncclGetEnv("NCCL_COMM_ID");
|
||||
if (commId && strlen(commId) > 1) {
|
||||
INFO(NCCL_ENV, "NCCL_COMM_ID set by environment to %s", commId);
|
||||
// Try to find interface that is in the same subnet as the IP in comm id
|
||||
union ncclSocketAddress idAddr;
|
||||
ncclSocketGetAddrFromString(&idAddr, commId);
|
||||
nIfs = ncclFindInterfaceMatchSubnet(ifNames, ifAddrs, &idAddr, ifNameMaxSize, maxIfs);
|
||||
NCCLCHECK(ncclSocketGetAddrFromString(&idAddr, commId));
|
||||
NCCLCHECK(ncclFindInterfaceMatchSubnet(ifNames, ifAddrs, &idAddr, ifNameMaxSize, nIfs));
|
||||
}
|
||||
}
|
||||
// Then look for anything else (but not docker or lo)
|
||||
if (nIfs == 0) nIfs = findInterfaces("^docker,lo", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs);
|
||||
if (*nIfs == 0) NCCLCHECK(findInterfaces("^docker,lo", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs, nIfs));
|
||||
// Finally look for docker, then lo.
|
||||
if (nIfs == 0) nIfs = findInterfaces("docker", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs);
|
||||
if (nIfs == 0) nIfs = findInterfaces("lo", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs);
|
||||
if (*nIfs == 0) NCCLCHECK(findInterfaces("docker", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs, nIfs));
|
||||
if (*nIfs == 0) NCCLCHECK(findInterfaces("lo", ifNames, ifAddrs, sock_family, ifNameMaxSize, maxIfs, nIfs));
|
||||
}
|
||||
return nIfs;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclResult_t ncclSocketListen(struct ncclSocket* sock) {
|
||||
@@ -444,17 +450,20 @@ static ncclResult_t socketTryAccept(struct ncclSocket* sock) {
|
||||
/* per accept's man page, for linux sockets, the following errors might be already pending errors
|
||||
* and should be considered as EAGAIN. To avoid infinite loop in case of errors, we use the retry count*/
|
||||
if (++sock->errorRetries == ncclParamRetryCnt()) {
|
||||
WARN("socketTryAccept: exceeded error retry count (%d), %s", sock->errorRetries, strerror(errno));
|
||||
WARN("socketTryAccept: exceeded error retry count after %d attempts, %s", sock->errorRetries, strerror(errno));
|
||||
return ncclSystemError;
|
||||
}
|
||||
INFO(NCCL_ALL, "Call to accept returned %s, retrying", strerror(errno));
|
||||
} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
INFO(NCCL_NET|NCCL_INIT, "Call to accept returned %s, retrying", strerror(errno));
|
||||
} else if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
WARN("socketTryAccept: Accept failed: %s", strerror(errno));
|
||||
return ncclSystemError;
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
NCCL_PARAM(SocketMaxRecvBuff, "SOCKET_RCVBUF", -1);
|
||||
NCCL_PARAM(SocketMaxSendBuff, "SOCKET_SNDBUF", -1);
|
||||
|
||||
static ncclResult_t socketSetFlags(struct ncclSocket* sock) {
|
||||
const int one = 1;
|
||||
/* Set socket as non-blocking if async or if we need to be able to abort */
|
||||
@@ -463,34 +472,55 @@ static ncclResult_t socketSetFlags(struct ncclSocket* sock) {
|
||||
SYSCHECK(flags = fcntl(sock->fd, F_GETFL), "fcntl");
|
||||
SYSCHECK(fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK), "fcntl");
|
||||
}
|
||||
SYSCHECK(setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int)), "setsockopt");
|
||||
SYSCHECK(setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int)), "setsockopt TCP NODELAY");
|
||||
// setsockopt should not fail even if the sizes are too large, do not change the default if unset by the user (=-1)
|
||||
int rcvBuf = ncclParamSocketMaxRecvBuff(), sndBuf = ncclParamSocketMaxSendBuff();
|
||||
if (sndBuf > 0) SYSCHECK(setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, (char*)&sndBuf, sizeof(int)), "setsockopt SO_SNDBUF");
|
||||
if (rcvBuf > 0) SYSCHECK(setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcvBuf, sizeof(int)), "setsockopt SO_RCVBUF");
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static void socketResetAccept(struct ncclSocket* sock) {
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
INFO(NCCL_NET|NCCL_INIT, "socketFinalizeAccept: didn't receive a valid magic from %s",
|
||||
ncclSocketToString(&sock->addr, line));
|
||||
// Ignore spurious connection and accept again
|
||||
(void)close(sock->fd);
|
||||
sock->fd = -1;
|
||||
sock->state = ncclSocketStateAccepting;
|
||||
sock->finalizeCounter = 0;
|
||||
}
|
||||
|
||||
static ncclResult_t socketFinalizeAccept(struct ncclSocket* sock) {
|
||||
uint64_t magic;
|
||||
enum ncclSocketType type;
|
||||
int received;
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
// once accepted, linux sockets do NOT inherit file status flags such as O_NONBLOCK (BSD ones do)
|
||||
NCCLCHECK(socketSetFlags(sock));
|
||||
|
||||
if (sock->asyncFlag == 0 || sock->finalizeCounter < sizeof(magic)) {
|
||||
if (sock->asyncFlag == 0) {
|
||||
received = 0;
|
||||
NCCLCHECK(socketWait(NCCL_SOCKET_RECV, sock, &magic, sizeof(magic), &received));
|
||||
if (socketWait(NCCL_SOCKET_RECV, sock, &magic, sizeof(magic), &received) != ncclSuccess) {
|
||||
socketResetAccept(sock);
|
||||
return ncclSuccess;
|
||||
}
|
||||
} else {
|
||||
int closed = 0;
|
||||
received = sock->finalizeCounter;
|
||||
NCCLCHECK(socketProgress(NCCL_SOCKET_RECV, sock, sock->finalizeBuffer, sizeof(magic), &received));
|
||||
NCCLCHECK(socketProgress(NCCL_SOCKET_RECV, sock, sock->finalizeBuffer, sizeof(magic), &received, &closed));
|
||||
sock->finalizeCounter = received;
|
||||
if (received < sizeof(magic)) return ncclSuccess;
|
||||
if (received < sizeof(magic)) {
|
||||
if (closed) {
|
||||
socketResetAccept(sock);
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
memcpy(&magic, sock->finalizeBuffer, sizeof(magic));
|
||||
}
|
||||
if (magic != sock->magic) {
|
||||
WARN("socketFinalizeAccept: wrong magic %lx != %lx", magic, sock->magic);
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
// Ignore spurious connection and accept again
|
||||
sock->state = ncclSocketStateAccepting;
|
||||
socketResetAccept(sock);
|
||||
return ncclSuccess;
|
||||
}
|
||||
}
|
||||
@@ -505,7 +535,7 @@ static ncclResult_t socketFinalizeAccept(struct ncclSocket* sock) {
|
||||
memcpy(&type, sock->finalizeBuffer, sizeof(type));
|
||||
}
|
||||
if (type != sock->type) {
|
||||
WARN("socketFinalizeAccept: wrong type %d != %d", type, sock->type);
|
||||
WARN("socketFinalizeAccept from %s: wrong type %d != %d", ncclSocketToString(&sock->addr, line), type, sock->type);
|
||||
sock->state = ncclSocketStateError;
|
||||
close(sock->fd);
|
||||
sock->fd = -1;
|
||||
@@ -537,32 +567,38 @@ cleanup:
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static ncclResult_t socketConnectCheck(struct ncclSocket* sock, int errCode, const char funcName[]) {
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
if (errCode == 0) {
|
||||
sock->state = ncclSocketStateConnected;
|
||||
} else if (errCode == EINPROGRESS) {
|
||||
sock->state = ncclSocketStateConnectPolling;
|
||||
} else if (errCode == ETIMEDOUT || errCode == EHOSTUNREACH || errCode == ECONNREFUSED) {
|
||||
} else if (errCode == EINTR || errCode == EWOULDBLOCK || errCode == EAGAIN || errCode == ETIMEDOUT ||
|
||||
errCode == EHOSTUNREACH || errCode == ECONNREFUSED) {
|
||||
if (sock->customRetry == 0) {
|
||||
if (sock->errorRetries++ == ncclParamRetryCnt()) {
|
||||
sock->state = ncclSocketStateError;
|
||||
WARN("%s: connect returned %s, exceeded error retry count (%d)", funcName, strerror(errCode), sock->errorRetries);
|
||||
WARN("%s: connect to %s returned %s, exceeded error retry count after %d attempts",
|
||||
funcName, ncclSocketToString(&sock->addr, line), strerror(errCode), sock->errorRetries);
|
||||
return ncclRemoteError;
|
||||
}
|
||||
unsigned int sleepTime = sock->errorRetries * ncclParamRetryTimeOut();
|
||||
INFO(NCCL_ALL, "%s: connect returned %s, retrying (%d/%ld) after sleep for %u msec", funcName, strerror(errCode), sock->errorRetries, ncclParamRetryCnt(), sleepTime);
|
||||
INFO(NCCL_NET|NCCL_INIT, "%s: connect to %s returned %s, retrying (%d/%ld) after sleep for %u msec",
|
||||
funcName, ncclSocketToString(&sock->addr, line), strerror(errCode),
|
||||
sock->errorRetries, ncclParamRetryCnt(), sleepTime);
|
||||
msleep(sleepTime);
|
||||
}
|
||||
NCCLCHECK(socketResetFd(sock)); /* in case of failure in connect, socket state is unspecified */
|
||||
sock->state = ncclSocketStateConnecting;
|
||||
} else {
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
sock->state = ncclSocketStateError;
|
||||
WARN("%s: Connect to %s failed : %s", funcName, ncclSocketToString(&sock->addr, line), strerror(errCode));
|
||||
WARN("%s: connect to %s failed : %s", funcName, ncclSocketToString(&sock->addr, line), strerror(errCode));
|
||||
return ncclSystemError;
|
||||
}
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
static ncclResult_t socketStartConnect(struct ncclSocket* sock) {
|
||||
/* blocking/non-blocking connect() is determined by asyncFlag. */
|
||||
int ret = connect(sock->fd, &sock->addr.sa, sock->salen);
|
||||
@@ -573,6 +609,7 @@ static ncclResult_t socketPollConnect(struct ncclSocket* sock) {
|
||||
struct pollfd pfd;
|
||||
int timeout = 1, ret;
|
||||
socklen_t rlen = sizeof(int);
|
||||
char line[SOCKET_NAME_MAXLEN+1];
|
||||
|
||||
memset(&pfd, 0, sizeof(struct pollfd));
|
||||
pfd.fd = sock->fd;
|
||||
@@ -582,10 +619,7 @@ static ncclResult_t socketPollConnect(struct ncclSocket* sock) {
|
||||
if (ret == 0 || (ret < 0 && errno == EINTR)) {
|
||||
return ncclSuccess;
|
||||
} else if (ret < 0) {
|
||||
WARN("socketPollConnect poll() failed with error %s", strerror(errno));
|
||||
return ncclRemoteError;
|
||||
} else if (ret != 1 || (pfd.revents & POLLOUT) == 0) {
|
||||
WARN("socketPollConnect poll() returned %d%s", ret, (pfd.revents & POLLOUT) ? "" : ", no POLLOUT events");
|
||||
WARN("socketPollConnect to %s failed with error %s", ncclSocketToString(&sock->addr, line), strerror(errno));
|
||||
return ncclSystemError;
|
||||
}
|
||||
|
||||
@@ -914,7 +948,7 @@ ncclResult_t ncclSocketTryRecv(struct ncclSocket* sock, void* ptr, int size, int
|
||||
ncclResult_t ncclSocketShutdown(struct ncclSocket* sock, int how) {
|
||||
if (sock != NULL) {
|
||||
if (sock->fd >= 0) {
|
||||
shutdown(sock->fd, how);
|
||||
SYSCHECK(shutdown(sock->fd, how), "shutdown");
|
||||
}
|
||||
sock->state = ncclSocketStateTerminating;
|
||||
}
|
||||
@@ -936,8 +970,8 @@ ncclResult_t ncclSocketClose(struct ncclSocket* sock, bool wait) {
|
||||
* 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);
|
||||
(void)shutdown(sock->fd, SHUT_RDWR);
|
||||
(void)close(sock->fd);
|
||||
}
|
||||
sock->state = ncclSocketStateClosed;
|
||||
sock->fd = -1;
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
#include "checks.h"
|
||||
#include "param.h"
|
||||
|
||||
#if CUDART_VERSION >= 13000
|
||||
#define cudaStreamGetCaptureInfo_v3 cudaStreamGetCaptureInfo
|
||||
#define cudaGraphAddDependencies_v2 cudaGraphAddDependencies
|
||||
#define cudaStreamUpdateCaptureDependencies_v2 cudaStreamUpdateCaptureDependencies
|
||||
#endif
|
||||
|
||||
// Tracks the captured work a given graph captured identified by its graph id.
|
||||
struct ncclStrongStreamCapture {
|
||||
struct ncclStrongStreamCapture* next;
|
||||
@@ -206,7 +212,11 @@ ncclResult_t ncclStrongStreamAcquire(
|
||||
CUDACHECK(cudaEventRecord(scratch, graph.origin));
|
||||
CUDACHECK(cudaStreamWaitEvent(cap->captureStream, scratch, 0));
|
||||
CUDACHECK(cudaEventDestroy(scratch));
|
||||
#if CUDART_VERSION >= 13000
|
||||
CUDACHECK(cudaStreamUpdateCaptureDependencies_v2(cap->captureStream, nullptr, nullptr, 0, cudaStreamSetCaptureDependencies));
|
||||
#else
|
||||
CUDACHECK(cudaStreamUpdateCaptureDependencies(cap->captureStream, nullptr, 0, cudaStreamSetCaptureDependencies));
|
||||
#endif
|
||||
|
||||
if (mixing && firstCapture) {
|
||||
CUDACHECK(cudaEventRecord(ss->serialEvent, ss->liveStream));
|
||||
@@ -266,7 +276,11 @@ ncclResult_t ncclStrongStreamRelease(
|
||||
|
||||
// Make this record order after previous record on this stream.
|
||||
if (cap->lastRecord != nullptr) {
|
||||
#if CUDART_VERSION >= 13000
|
||||
CUDACHECK(cudaGraphAddDependencies_v2(graph.graph, &cap->lastRecord, &recordNode, nullptr, 1));
|
||||
#else
|
||||
CUDACHECK(cudaGraphAddDependencies(graph.graph, &cap->lastRecord, &recordNode, 1));
|
||||
#endif
|
||||
}
|
||||
cap->lastRecord = recordNode;
|
||||
|
||||
@@ -274,7 +288,11 @@ ncclResult_t ncclStrongStreamRelease(
|
||||
cudaStreamCaptureStatus status;
|
||||
cudaGraphNode_t const* nodes;
|
||||
size_t count = 0;
|
||||
#if CUDART_VERSION >= 13000
|
||||
cudaError_t res = hipStreamGetCaptureInfo_v3(cap->captureStream, &status, nullptr, nullptr, &nodes, nullptr, &count);
|
||||
#else
|
||||
cudaError_t res = hipStreamGetCaptureInfo_v2(cap->captureStream, &status, nullptr, nullptr, &nodes, &count);
|
||||
#endif
|
||||
|
||||
#if CUDART_VERSION >= 12030
|
||||
if (res == cudaErrorLossyQuery) { // CUDA is telling us the dependencies have edge annotations.
|
||||
@@ -290,7 +308,11 @@ ncclResult_t ncclStrongStreamRelease(
|
||||
else {
|
||||
CUDACHECK(res /* = cudaStreamGetCaptureInfo_v2(...)*/);
|
||||
for (int i=0; i < (int)count; i++) {
|
||||
#if CUDART_VERSION >= 13000
|
||||
CUDACHECK(cudaGraphAddDependencies_v2(graph.graph, &nodes[i], &recordNode, nullptr, 1));
|
||||
#else
|
||||
CUDACHECK(cudaGraphAddDependencies(graph.graph, &nodes[i], &recordNode, 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +343,11 @@ ncclResult_t ncclStreamAdvanceToEvent(struct ncclCudaGraph g, cudaStream_t s, cu
|
||||
cudaStreamCaptureStatus status;
|
||||
cudaGraphNode_t const* nodes;
|
||||
size_t count = 0;
|
||||
#if CUDART_VERSION >= 13000
|
||||
cudaError_t res = hipStreamGetCaptureInfo_v3(tmp, &status, nullptr, nullptr, &nodes, nullptr, &count);
|
||||
#else
|
||||
cudaError_t res = hipStreamGetCaptureInfo_v2(tmp, &status, nullptr, nullptr, &nodes, &count);
|
||||
#endif
|
||||
|
||||
#if CUDART_VERSION >= 12030
|
||||
if (res == cudaErrorLossyQuery) { // CUDA is telling us the dependencies have edge annotations.
|
||||
@@ -334,7 +360,11 @@ ncclResult_t ncclStreamAdvanceToEvent(struct ncclCudaGraph g, cudaStream_t s, cu
|
||||
#endif
|
||||
else {
|
||||
CUDACHECK(res /* = cudaStreamGetCaptureInfo_v2(...)*/);
|
||||
#if CUDART_VERSION >= 13000
|
||||
CUDACHECK(cudaStreamUpdateCaptureDependencies_v2(s, (cudaGraphNode_t*)nodes, nullptr, count, cudaStreamSetCaptureDependencies));
|
||||
#else
|
||||
CUDACHECK(cudaStreamUpdateCaptureDependencies(s, (cudaGraphNode_t*)nodes, count, cudaStreamSetCaptureDependencies));
|
||||
#endif
|
||||
}
|
||||
|
||||
CUDACHECK(cudaStreamDestroy(tmp));
|
||||
|
||||
Reference in New Issue
Block a user