a46ea10583
Add support for CUDA graphs. Fuse BCM Gen4 switches to avoid suboptimal performance on some platforms. Issue #439. Fix bootstrap issue caused by connection reordering. Fix CPU locking block. Improve CollNet algorithm. Improve performance on DGX A100 for communicators with only one GPU per node.
247 lines
8.5 KiB
C++
247 lines
8.5 KiB
C++
/*************************************************************************
|
|
* Copyright (c) 2020-2021, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* See LICENSE.txt for license information
|
|
************************************************************************/
|
|
|
|
#include "gdrwrap.h"
|
|
|
|
#ifndef GDR_DIRECT
|
|
#include "core.h"
|
|
|
|
static enum { gdrUninitialized, gdrInitializing, gdrInitialized, gdrError } gdrState = gdrUninitialized;
|
|
|
|
/* Function pointers assigned from dlopen() */
|
|
static gdr_t (*gdr_internal_open)(void);
|
|
static int (*gdr_internal_close)(gdr_t g);
|
|
static int (*gdr_internal_pin_buffer)(gdr_t g, unsigned long addr, size_t size, uint64_t p2p_token, uint32_t va_space, gdr_mh_t *handle);
|
|
static int (*gdr_internal_unpin_buffer)(gdr_t g, gdr_mh_t handle);
|
|
static int (*gdr_internal_get_info)(gdr_t g, gdr_mh_t handle, gdr_info_t *info);
|
|
static int (*gdr_internal_map)(gdr_t g, gdr_mh_t handle, void **va, size_t size);
|
|
static int (*gdr_internal_unmap)(gdr_t g, gdr_mh_t handle, void *va, size_t size);
|
|
static void (*gdr_internal_runtime_get_version)(int *major, int *minor);
|
|
static void (*gdr_internal_driver_get_version)(gdr_t g, int *major, int *minor);
|
|
static int (*gdr_internal_copy_to_mapping)(gdr_mh_t handle, void *map_d_ptr, const void *h_ptr, size_t size);
|
|
static int (*gdr_internal_copy_from_mapping)(gdr_mh_t handle, void *h_ptr, const void *map_d_ptr, size_t size);
|
|
|
|
|
|
// Used to make the GDR library calls thread safe
|
|
pthread_mutex_t gdrLock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
#define GDRAPI_LIBNAME "libgdrapi.so"
|
|
|
|
#define LOAD_SYM(handle, symbol, funcptr) do { \
|
|
cast = (void**)&funcptr; \
|
|
tmp = dlsym(handle, symbol); \
|
|
if (tmp == NULL) { \
|
|
WARN("dlsym failed on %s - %s", symbol, dlerror());\
|
|
goto teardown; \
|
|
} \
|
|
*cast = tmp; \
|
|
} while (0)
|
|
|
|
#define LOAD_SYM_OPTIONAL(handle, symbol, funcptr) do {\
|
|
cast = (void**)&funcptr; \
|
|
tmp = dlsym(handle, symbol); \
|
|
if (tmp == NULL) { \
|
|
INFO(NCCL_INIT,"dlsym failed on %s, ignoring", symbol); \
|
|
} \
|
|
*cast = tmp; \
|
|
} while (0)
|
|
|
|
ncclResult_t wrap_gdr_symbols(void) {
|
|
if (gdrState == gdrInitialized)
|
|
return ncclSuccess;
|
|
if (gdrState == gdrError)
|
|
return ncclSystemError;
|
|
|
|
if (__sync_bool_compare_and_swap(&gdrState, gdrUninitialized, gdrInitializing) == false) {
|
|
// Another thread raced in front of us. Wait for it to be done.
|
|
while (gdrState == gdrInitializing) pthread_yield();
|
|
return (gdrState == gdrInitialized) ? ncclSuccess : ncclSystemError;
|
|
}
|
|
|
|
static void* gdrhandle = NULL;
|
|
void* tmp;
|
|
void** cast;
|
|
|
|
gdrhandle=dlopen(GDRAPI_LIBNAME, RTLD_NOW);
|
|
if (!gdrhandle) {
|
|
WARN("Failed to open %s", GDRAPI_LIBNAME);
|
|
goto teardown;
|
|
}
|
|
|
|
/* Load the function pointers from the DL library image */
|
|
LOAD_SYM(gdrhandle, "gdr_open", gdr_internal_open);
|
|
LOAD_SYM(gdrhandle, "gdr_close", gdr_internal_close);
|
|
LOAD_SYM(gdrhandle, "gdr_pin_buffer", gdr_internal_pin_buffer);
|
|
LOAD_SYM(gdrhandle, "gdr_unpin_buffer", gdr_internal_unpin_buffer);
|
|
LOAD_SYM(gdrhandle, "gdr_get_info", gdr_internal_get_info);
|
|
LOAD_SYM(gdrhandle, "gdr_map", gdr_internal_map);
|
|
LOAD_SYM(gdrhandle, "gdr_unmap", gdr_internal_unmap);
|
|
LOAD_SYM(gdrhandle, "gdr_runtime_get_version", gdr_internal_runtime_get_version);
|
|
LOAD_SYM(gdrhandle, "gdr_driver_get_version", gdr_internal_driver_get_version);
|
|
LOAD_SYM(gdrhandle, "gdr_copy_to_mapping", gdr_internal_copy_to_mapping);
|
|
LOAD_SYM(gdrhandle, "gdr_copy_from_mapping", gdr_internal_copy_from_mapping);
|
|
|
|
gdrState = gdrInitialized;
|
|
return ncclSuccess;
|
|
|
|
teardown:
|
|
gdr_internal_open = NULL;
|
|
gdr_internal_close = NULL;
|
|
gdr_internal_pin_buffer = NULL;
|
|
gdr_internal_unpin_buffer = NULL;
|
|
gdr_internal_get_info = NULL;
|
|
gdr_internal_map = NULL;
|
|
gdr_internal_unmap = NULL;
|
|
gdr_internal_runtime_get_version = NULL;
|
|
gdr_internal_driver_get_version = NULL;
|
|
gdr_internal_copy_to_mapping = NULL;
|
|
gdr_internal_copy_from_mapping = NULL;
|
|
|
|
if (gdrhandle != NULL) dlclose(gdrhandle);
|
|
gdrState = gdrError;
|
|
return ncclSystemError;
|
|
}
|
|
|
|
|
|
gdr_t wrap_gdr_open(void) {
|
|
if (gdr_internal_open == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return NULL;
|
|
}
|
|
return gdr_internal_open();
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_close(gdr_t g) {
|
|
if (gdr_internal_close == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret = gdr_internal_close(g);
|
|
if (ret != 0) {
|
|
WARN("gdr_close() failed: %d", ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_pin_buffer(gdr_t g, unsigned long addr, size_t size, uint64_t p2p_token, uint32_t va_space, gdr_mh_t *handle) {
|
|
if (gdr_internal_pin_buffer == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_pin_buffer(g, addr, size, p2p_token, va_space, handle), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_pin_buffer(addr %lx, size %zi) failed: %d", addr, size, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_unpin_buffer(gdr_t g, gdr_mh_t handle) {
|
|
if (gdr_internal_unpin_buffer == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_unpin_buffer(g, handle), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_unpin_buffer(handle %lx) failed: %d", handle.h, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_get_info(gdr_t g, gdr_mh_t handle, gdr_info_t *info) {
|
|
if (gdr_internal_get_info == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_get_info(g, handle, info), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_get_info(handle %lx) failed: %d", handle.h, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_map(gdr_t g, gdr_mh_t handle, void **va, size_t size) {
|
|
if (gdr_internal_map == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_map(g, handle, va, size), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_map(handle %lx, size %zi) failed: %d", handle.h, size, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_unmap(gdr_t g, gdr_mh_t handle, void *va, size_t size) {
|
|
if (gdr_internal_unmap == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_unmap(g, handle, va, size), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_unmap(handle %lx, va %p, size %zi) failed: %d", handle.h, va, size, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_runtime_get_version(int *major, int *minor) {
|
|
if (gdr_internal_runtime_get_version == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
gdr_internal_runtime_get_version(major, minor);
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_driver_get_version(gdr_t g, int *major, int *minor) {
|
|
if (gdr_internal_driver_get_version == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
gdr_internal_driver_get_version(g, major, minor);
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_copy_to_mapping(gdr_mh_t handle, void *map_d_ptr, const void *h_ptr, size_t size) {
|
|
if (gdr_internal_copy_to_mapping == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_copy_to_mapping(handle, map_d_ptr, h_ptr, size), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_copy_to_mapping(handle %lx, map_d_ptr %p, h_ptr %p, size %zi) failed: %d", handle.h, map_d_ptr, h_ptr, size, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
ncclResult_t wrap_gdr_copy_from_mapping(gdr_mh_t handle, void *h_ptr, const void *map_d_ptr, size_t size) {
|
|
if (gdr_internal_copy_from_mapping == NULL) {
|
|
WARN("GDRCOPY lib wrapper not initialized.");
|
|
return ncclInternalError;
|
|
}
|
|
int ret;
|
|
GDRLOCKCALL(gdr_internal_copy_from_mapping(handle, h_ptr, map_d_ptr, size), ret);
|
|
if (ret != 0) {
|
|
WARN("gdr_copy_from_mapping(handle %lx, h_ptr %p, map_d_ptr %p, size %zi) failed: %d", handle.h, h_ptr, map_d_ptr, size, ret);
|
|
return ncclSystemError;
|
|
}
|
|
return ncclSuccess;
|
|
}
|
|
|
|
#endif /* !GDR_DIRECT */
|