[CCCL] 瘦身 + 补全: 移除 cudax/python/libcudacxx-tests 冗余文件, 新增 c2h 测试助手 + cmake 构建系统 + 8 个 CUDA thrust examples
变更摘要:
- 删除: cudax/ (783 files, 7.2M) — 实验性组件,竞赛不需要
- 删除: python/ (226 files, 2.0M) — Python 绑定,竞赛不需要
- 删除: libcudacxx/{test,benchmarks,codegen,cmake,share} (4432 files, 31M)
保留: libcudacxx/include/ (1463 headers, cuda::std 编译依赖)
- 新增: c2h/ (27 files) — CUB Catch2 测试辅助头文件,编译 243 个测试必需
- 新增: cmake/ (29 files) — CCCL 原生 CMake 构建系统
- 新增: thrust/examples/cuda/ (7 files) + cpp_integration/ (1 file)
async_reduce, custom_temporary_allocation, explicit_cuda_stream,
global_device_vector, range_view, unwrap_pointer, wrap_pointer, device
结果: cccl_upstream 从 74M→35M (瘦身 53%), 核心内容 100% 保留:
27/27 tuning headers, 78 benchmarks, 243 tests,
60 thrust examples, 18 CUB examples, 全部编译头文件
This commit is contained in:
@@ -1,151 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of CUDA Experimental in CUDA C++ Core Libraries,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _CUDA_EXPERIMENTAL___NCCL_ABI_COMPATIBLE_H
|
||||
#define _CUDA_EXPERIMENTAL___NCCL_ABI_COMPATIBLE_H
|
||||
|
||||
#include <cuda/std/detail/__config>
|
||||
|
||||
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
|
||||
# pragma GCC system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
|
||||
# pragma clang system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
|
||||
# pragma system_header
|
||||
#endif // no system header
|
||||
|
||||
#include <cuda/std/__type_traits/decay.h>
|
||||
#include <cuda/std/__type_traits/is_enum.h>
|
||||
#include <cuda/std/__type_traits/is_function.h>
|
||||
#include <cuda/std/__type_traits/is_pointer.h>
|
||||
#include <cuda/std/__type_traits/is_same.h>
|
||||
#include <cuda/std/__type_traits/remove_cv.h>
|
||||
#include <cuda/std/__type_traits/remove_pointer.h>
|
||||
#include <cuda/std/__type_traits/underlying_type.h>
|
||||
|
||||
#include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
// NOLINTBEGIN(bugprone-reserved-identifier)
|
||||
|
||||
#ifndef _CCCL_DOXYGEN_INVOKED // do not document
|
||||
|
||||
namespace cuda::experimental::__nccl::__abi_detail
|
||||
{
|
||||
//! @brief A helper that checks at compile-time whether two types are ABI compatible.
|
||||
//!
|
||||
//! @tparam _Tp The left type to check.
|
||||
//! @tparam _Up The right type to check.
|
||||
//!
|
||||
//! @return `true` if `_Tp` and `_Up` are considered to be ABI compatible, `false` otherwise.
|
||||
//!
|
||||
//! ABI compatibility is stricter than type compatibility because it cannot allow conversions of any
|
||||
//! kind, implicit or otherwise. The mental test is essentially "are _Tp and _Up bitwise convertible
|
||||
//! through void *?":
|
||||
//!
|
||||
//! ```c++
|
||||
//! void *opaque_function()
|
||||
//! {
|
||||
//! _Tp inner = ...;
|
||||
//!
|
||||
//! return &inner;
|
||||
//! }
|
||||
//!
|
||||
//! _Up value = *(_Up *)opaque_function(); // is this OK?
|
||||
//! ```
|
||||
//! If `__abi_compatible<_Tp, _Up>()` is `true`, then this conversion is legal and always correct.
|
||||
//!
|
||||
//! For most types, we must have an exact type match for this to be legal. The only exception is
|
||||
//! enums, where we only need to ensure that the underlying types of the enums are identical. This
|
||||
//! rule therefore makes it possible to approximate an enum using just the raw underlying type. For
|
||||
//! example:
|
||||
//!
|
||||
//! ```c++
|
||||
//! enum OpaqueEnum : int8_t { FOO };
|
||||
//!
|
||||
//! void *opaque_function()
|
||||
//! {
|
||||
//! OpaqueEnum inner = FOO;
|
||||
//!
|
||||
//! return &inner;
|
||||
//! }
|
||||
//!
|
||||
//! // Assignment is OK, the underlying type is int8_t
|
||||
//! int8_t value = *(int8_t *)opaque_function();
|
||||
//! ```
|
||||
template <class _Tp, class _Up>
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr bool __abi_compatible() noexcept;
|
||||
|
||||
template <class _R1, class... _Args1, class _R2, class... _Args2>
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr bool __abi_compatible_func(_R1 (*)(_Args1...), _R2 (*)(_Args2...)) noexcept
|
||||
{
|
||||
if constexpr (::cuda::experimental::__nccl::__abi_detail::__abi_compatible<_R1, _R2>()
|
||||
&& (sizeof...(_Args1) == sizeof...(_Args2)))
|
||||
{
|
||||
return (::cuda::experimental::__nccl::__abi_detail::__abi_compatible<_Args1, _Args2>() && ...);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr bool __abi_compatible() noexcept
|
||||
{
|
||||
// Note, only remove_cv not remove_cvref. References are absolutely part of the type
|
||||
using _UnqualTp = ::cuda::std::remove_cv_t<_Tp>;
|
||||
using _UnqualUp = ::cuda::std::remove_cv_t<_Up>;
|
||||
|
||||
if constexpr (::cuda::std::is_same_v<_UnqualTp, _UnqualUp>)
|
||||
{
|
||||
// Equal types are obviously ABI compatible
|
||||
return true;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_function_v<_UnqualTp> && ::cuda::std::is_function_v<_UnqualUp>)
|
||||
{
|
||||
// Functions need all arguments checked
|
||||
return ::cuda::experimental::__nccl::__abi_detail::__abi_compatible_func(
|
||||
::cuda::std::decay_t<_UnqualTp>{}, ::cuda::std::decay_t<_UnqualUp>{});
|
||||
}
|
||||
else if constexpr (::cuda::std::is_enum_v<_UnqualTp> || ::cuda::std::is_enum_v<_UnqualUp>)
|
||||
{
|
||||
// If either side is an enum, we need to unwrap to check whether the underlying types
|
||||
// match. These must match *exactly*, otherwise we perform the moral equivalent of a
|
||||
// bitcast when we reinterpret them
|
||||
if constexpr (::cuda::std::is_enum_v<_UnqualTp> && ::cuda::std::is_enum_v<_UnqualUp>)
|
||||
{
|
||||
return ::cuda::experimental::__nccl::__abi_detail::__abi_compatible<::cuda::std::underlying_type_t<_UnqualTp>,
|
||||
::cuda::std::underlying_type_t<_UnqualUp>>();
|
||||
}
|
||||
else if constexpr (::cuda::std::is_enum_v<_UnqualTp>)
|
||||
{
|
||||
return ::cuda::experimental::__nccl::__abi_detail::__abi_compatible<::cuda::std::underlying_type_t<_UnqualTp>,
|
||||
_UnqualUp>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::cuda::experimental::__nccl::__abi_detail::__abi_compatible<_UnqualTp,
|
||||
::cuda::std::underlying_type_t<_UnqualUp>>();
|
||||
}
|
||||
}
|
||||
else if constexpr (::cuda::std::is_pointer_v<_UnqualTp> && ::cuda::std::is_pointer_v<_UnqualUp>)
|
||||
{
|
||||
// Note the &&. If one is a pointer but the other is not, that's an error
|
||||
return ::cuda::experimental::__nccl::__abi_detail::__abi_compatible<::cuda::std::remove_pointer_t<_UnqualTp>,
|
||||
::cuda::std::remove_pointer_t<_UnqualUp>>();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace cuda::experimental::__nccl::__abi_detail
|
||||
|
||||
#endif // _CCCL_DOXYGEN_INVOKED
|
||||
|
||||
// NOLINTEND(bugprone-reserved-identifier)
|
||||
|
||||
#include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CUDA_EXPERIMENTAL___NCCL_ABI_COMPATIBLE_H
|
||||
@@ -1,767 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of CUDA Experimental in CUDA C++ Core Libraries,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _CUDA_EXPERIMENTAL___NCCL_NCCL_API_H
|
||||
#define _CUDA_EXPERIMENTAL___NCCL_NCCL_API_H
|
||||
|
||||
#include <cuda/std/detail/__config>
|
||||
|
||||
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
|
||||
# pragma GCC system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
|
||||
# pragma clang system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
|
||||
# pragma system_header
|
||||
#endif // no system header
|
||||
|
||||
#include <cuda/__device/device_ref.h>
|
||||
#include <cuda/__functional/operator_properties.h>
|
||||
#include <cuda/__stream/stream_ref.h>
|
||||
#include <cuda/std/__cstddef/types.h>
|
||||
#include <cuda/std/__exception/msg_storage.h>
|
||||
#include <cuda/std/__functional/operations_traits.h>
|
||||
#include <cuda/std/__host_stdlib/cstdio> // snprintf
|
||||
#include <cuda/std/__host_stdlib/stdexcept>
|
||||
#include <cuda/std/__type_traits/is_same.h>
|
||||
#include <cuda/std/__type_traits/remove_cvref.h>
|
||||
#include <cuda/std/__utility/to_underlying.h>
|
||||
#include <cuda/std/cstdint>
|
||||
#include <cuda/std/source_location>
|
||||
|
||||
#include <cuda/experimental/__nccl/shared_library.h>
|
||||
#if _CCCL_HOSTED()
|
||||
# include <exception> // uncaught_exceptions
|
||||
#endif // _CCCL_HOSTED()
|
||||
|
||||
#define _CCCL_NCCL() _CCCL_VERSION_INVALID()
|
||||
#define _CCCL_HAS_NCCL() 0
|
||||
|
||||
#if __has_include(<nccl.h>)
|
||||
# include <nccl.h>
|
||||
|
||||
# undef _CCCL_HAS_NCCL
|
||||
# define _CCCL_HAS_NCCL() 1
|
||||
|
||||
# if !defined(NCCL_MAJOR) || !defined(NCCL_MINOR)
|
||||
# error "Unsupported NCCL version which doesn't define NCCL_MAJOR and/or NCCL_MINOR"
|
||||
# endif // No NCCL_MAJOR or NCCL_MINOR
|
||||
|
||||
# undef _CCCL_NCCL
|
||||
# define _CCCL_NCCL() (NCCL_MAJOR, NCCL_MINOR)
|
||||
|
||||
# include <cuda/experimental/__nccl/abi_compatible.h>
|
||||
#endif // __has_include(<nccl.h>)
|
||||
|
||||
#include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
// NOLINTBEGIN(bugprone-reserved-identifier)
|
||||
|
||||
extern "C" {
|
||||
struct ncclComm;
|
||||
} // extern "C"
|
||||
|
||||
// Taken from nccl.h.in
|
||||
#define _CCCL_NCCL_MAKE_VERSION(_MAJOR, _MINOR) \
|
||||
(((_MAJOR) <= 2 && (_MINOR) <= 8) ? (_MAJOR) * 1000 + (_MINOR) * 100 : (_MAJOR) * 10000 + (_MINOR) * 100)
|
||||
#define _CCCL_NCCL_VERSION(...) _CCCL_VERSION_COMPARE(_CCCL_NCCL_, _CCCL_NCCL, __VA_ARGS__)
|
||||
|
||||
namespace cuda::experimental::__nccl
|
||||
{
|
||||
[[nodiscard]] _CCCL_HOST_API inline __shared_library& __nccl_lib()
|
||||
{
|
||||
static auto __lib = __shared_library{
|
||||
#if _CCCL_OS(WINDOWS)
|
||||
/*__lib_path=*/"nccl.dll"
|
||||
#elif _CCCL_OS(APPLE)
|
||||
/*__lib_path=*/"libnccl.dylib"
|
||||
#elif _CCCL_OS(LINUX)
|
||||
/*__lib_path=*/"libnccl.so"
|
||||
#else
|
||||
# error "Unknown nccl library name for platform, please report a bug at https://github.com/NVIDIA/cccl/issues"
|
||||
#endif
|
||||
};
|
||||
|
||||
return __lib;
|
||||
}
|
||||
|
||||
#if _CCCL_HAS_NCCL()
|
||||
# define _CCCL_LOAD_NCCL_SYMBOL_ENABLE_ABI_CHECK_IF(__cond, __symbol, ...) \
|
||||
::cuda::experimental::__nccl::__nccl_lib().load_symbol<__VA_ARGS__>(#__symbol); \
|
||||
static_assert( \
|
||||
_CCCL_PP_IIF(__cond)( \
|
||||
(::cuda::experimental::__nccl::__abi_detail::__abi_compatible<decltype(&::__symbol), __VA_ARGS__>()), true), \
|
||||
#__symbol " and " #__VA_ARGS__ " are not ABI compatible")
|
||||
|
||||
# define _CCCL_LOAD_NCCL_SYMBOL(__symbol, ...) \
|
||||
::cuda::experimental::__nccl::__nccl_lib().load_symbol<__VA_ARGS__>(#__symbol); \
|
||||
static_assert(::cuda::experimental::__nccl::__abi_detail::__abi_compatible<decltype(&::__symbol), __VA_ARGS__>(), \
|
||||
#__symbol " and " #__VA_ARGS__ " are not ABI compatible")
|
||||
|
||||
#else // ^^^ _CCCL_HAS_NCCL() ^^^ / vvv !_CCCL_HAS_NCCL() vvv
|
||||
|
||||
# define _CCCL_LOAD_NCCL_SYMBOL_ENABLE_ABI_CHECK_IF(__cond, __symbol, ...) \
|
||||
::cuda::experimental::__nccl::__nccl_lib().load_symbol<__VA_ARGS__>(#__symbol)
|
||||
|
||||
# define _CCCL_LOAD_NCCL_SYMBOL(__symbol, ...) \
|
||||
::cuda::experimental::__nccl::__nccl_lib().load_symbol<__VA_ARGS__>(#__symbol)
|
||||
|
||||
#endif // ^^^ !_CCCL_HAS_NCCL() ^^^
|
||||
|
||||
#if _CCCL_NCCL_VERSION(>=, 2, 28)
|
||||
# define _CCCL_HAS_NCCL_2_28() 1
|
||||
#else // ^^^ nccl 2.28+ ^^^ / vvv nccl.2.27- vvv
|
||||
# define _CCCL_HAS_NCCL_2_28() 0
|
||||
#endif // ^^^ nccl 2.27- ^^^
|
||||
|
||||
// NCCL forward decls
|
||||
// ==========================================================================================
|
||||
|
||||
enum __ncclResult_t // NOLINT(performance-enum-size)
|
||||
{
|
||||
__ncclSuccess,
|
||||
__ncclUnhandledCudaError,
|
||||
__ncclSystemError,
|
||||
__ncclInternalError,
|
||||
__ncclInvalidArgument,
|
||||
__ncclInvalidUsage,
|
||||
__ncclRemoteError,
|
||||
__ncclInProgress,
|
||||
__ncclTimeout,
|
||||
__ncclNumResults
|
||||
};
|
||||
|
||||
#if _CCCL_HAS_NCCL()
|
||||
static_assert(::cuda::std::to_underlying(__ncclSuccess) == ::ncclSuccess);
|
||||
static_assert(::cuda::std::to_underlying(__ncclUnhandledCudaError) == ::ncclUnhandledCudaError);
|
||||
static_assert(::cuda::std::to_underlying(__ncclSystemError) == ::ncclSystemError);
|
||||
static_assert(::cuda::std::to_underlying(__ncclInternalError) == ::ncclInternalError);
|
||||
static_assert(::cuda::std::to_underlying(__ncclInvalidArgument) == ::ncclInvalidArgument);
|
||||
static_assert(::cuda::std::to_underlying(__ncclInvalidUsage) == ::ncclInvalidUsage);
|
||||
# if _CCCL_NCCL_VERSION(>=, 2, 13)
|
||||
static_assert(::cuda::std::to_underlying(__ncclRemoteError) == ::ncclRemoteError);
|
||||
# endif // NCCL 2.13+
|
||||
# if _CCCL_NCCL_VERSION(>=, 2, 14)
|
||||
static_assert(::cuda::std::to_underlying(__ncclInProgress) == ::ncclInProgress);
|
||||
# endif // NCCL 2.14+
|
||||
# if _CCCL_NCCL_VERSION(>=, 2, 30)
|
||||
static_assert(::cuda::std::to_underlying(__ncclTimeout) == ::ncclTimeout);
|
||||
# endif // NCCL 2.30+
|
||||
#endif // _CCCL_HAS_NCCL
|
||||
|
||||
enum __ncclDataType_t // NOLINT(performance-enum-size)
|
||||
{
|
||||
__ncclInt8 = 0,
|
||||
__ncclChar = __ncclInt8,
|
||||
__ncclUint8 = 1,
|
||||
__ncclInt32 = 2,
|
||||
__ncclInt = __ncclInt32,
|
||||
__ncclUint32 = 3,
|
||||
__ncclInt64 = 4,
|
||||
__ncclUint64 = 5,
|
||||
__ncclFloat16 = 6,
|
||||
__ncclHalf = __ncclFloat16,
|
||||
__ncclFloat32 = 7,
|
||||
__ncclFloat = __ncclFloat32,
|
||||
__ncclFloat64 = 8,
|
||||
__ncclDouble = __ncclFloat64,
|
||||
__ncclBfloat16 = 9,
|
||||
__ncclFloat8e4m3 = 10,
|
||||
__ncclFloat8e5m2 = 11,
|
||||
__ncclNumTypes = 12
|
||||
};
|
||||
|
||||
#if _CCCL_HAS_NCCL()
|
||||
// Do not check NumTypes. If NCCL adds new types after these values, we don't care (until we
|
||||
// support them)
|
||||
static_assert(::cuda::std::to_underlying(__ncclInt8) == ::ncclInt8);
|
||||
static_assert(::cuda::std::to_underlying(__ncclChar) == ::ncclChar);
|
||||
static_assert(::cuda::std::to_underlying(__ncclUint8) == ::ncclUint8);
|
||||
static_assert(::cuda::std::to_underlying(__ncclInt32) == ::ncclInt32);
|
||||
static_assert(::cuda::std::to_underlying(__ncclInt) == ::ncclInt);
|
||||
static_assert(::cuda::std::to_underlying(__ncclUint32) == ::ncclUint32);
|
||||
static_assert(::cuda::std::to_underlying(__ncclInt64) == ::ncclInt64);
|
||||
static_assert(::cuda::std::to_underlying(__ncclUint64) == ::ncclUint64);
|
||||
static_assert(::cuda::std::to_underlying(__ncclFloat16) == ::ncclFloat16);
|
||||
static_assert(::cuda::std::to_underlying(__ncclHalf) == ::ncclHalf);
|
||||
static_assert(::cuda::std::to_underlying(__ncclFloat32) == ::ncclFloat32);
|
||||
static_assert(::cuda::std::to_underlying(__ncclFloat) == ::ncclFloat);
|
||||
static_assert(::cuda::std::to_underlying(__ncclFloat64) == ::ncclFloat64);
|
||||
static_assert(::cuda::std::to_underlying(__ncclDouble) == ::ncclDouble);
|
||||
# if (_CCCL_NCCL_VERSION(>=, 2, 10) && defined(__CUDA_BF16_TYPES_EXIST__)) || _CCCL_NCCL_VERSION(>=, 2, 24)
|
||||
static_assert(::cuda::std::to_underlying(__ncclBfloat16) == ::ncclBfloat16);
|
||||
# endif // NCCL [2.10 - 2.24) and cuda_bf16. included, or NCCL 2.24+
|
||||
# if _CCCL_NCCL_VERSION(>=, 2, 24)
|
||||
static_assert(::cuda::std::to_underlying(__ncclFloat8e4m3) == ::ncclFloat8e4m3);
|
||||
static_assert(::cuda::std::to_underlying(__ncclFloat8e5m2) == ::ncclFloat8e5m2);
|
||||
# endif // NCCL 2.24+
|
||||
#endif // _CCCL_HAS_NCCL
|
||||
|
||||
enum __ncclRedOp_dummy_t // NOLINT(performance-enum-size)
|
||||
{
|
||||
__ncclNumOps_dummy = 5
|
||||
};
|
||||
|
||||
enum __ncclRedOp_t // NOLINT(performance-enum-size)
|
||||
{
|
||||
__ncclSum = 0,
|
||||
__ncclProd = 1,
|
||||
__ncclMax = 2,
|
||||
__ncclMin = 3,
|
||||
__ncclAvg = 4,
|
||||
/* ncclNumOps: The number of built-in ncclRedOp_t values. Also
|
||||
* serves as the least possible value for dynamic ncclRedOp_t's
|
||||
* as constructed by ncclRedOpCreate*** functions. */
|
||||
__ncclNumOps = 5,
|
||||
/* ncclMaxRedOp: The largest valid value for ncclRedOp_t.
|
||||
* It is defined to be the largest signed value (since compilers
|
||||
* are permitted to use signed enums) that won't grow
|
||||
* sizeof(ncclRedOp_t) when compared to previous NCCL versions to
|
||||
* maintain ABI compatibility. */
|
||||
__ncclMaxRedOp = 0x7fffffff >> (32 - (8 * sizeof(__ncclRedOp_dummy_t)))
|
||||
};
|
||||
|
||||
#if _CCCL_HAS_NCCL()
|
||||
// Do not check NumOps or MaxRedOp. These aren't guaranteed to be in older versions
|
||||
static_assert(::cuda::std::to_underlying(__ncclSum) == ::ncclSum);
|
||||
static_assert(::cuda::std::to_underlying(__ncclProd) == ::ncclProd);
|
||||
static_assert(::cuda::std::to_underlying(__ncclMax) == ::ncclMax);
|
||||
static_assert(::cuda::std::to_underlying(__ncclMin) == ::ncclMin);
|
||||
static_assert(::cuda::std::to_underlying(__ncclAvg) == ::ncclAvg);
|
||||
#endif // _CCCL_HAS_NCCL
|
||||
|
||||
using __ncclComm_t = ::ncclComm*;
|
||||
|
||||
inline constexpr __ncclComm_t __NCCL_COMM_NULL = static_cast<__ncclComm_t>(nullptr);
|
||||
|
||||
#if _CCCL_HAS_NCCL()
|
||||
static_assert(__NCCL_COMM_NULL == NCCL_COMM_NULL);
|
||||
#endif
|
||||
|
||||
// Helpers and concepts
|
||||
// ==========================================================================================
|
||||
|
||||
struct __no_nccl_type
|
||||
{};
|
||||
|
||||
template <class _Tp>
|
||||
[[nodiscard]] _CCCL_API _CCCL_CONSTEVAL auto __nccl_type_of() noexcept
|
||||
{
|
||||
if constexpr (::cuda::std::is_same_v<_Tp, bool>)
|
||||
{
|
||||
if constexpr (sizeof(bool) == sizeof(char))
|
||||
{
|
||||
return __ncclChar;
|
||||
}
|
||||
else if constexpr (sizeof(bool) == sizeof(::cuda::std::int32_t))
|
||||
{
|
||||
// Apparently ancient Visual studio used int
|
||||
return __ncclInt32;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(!::cuda::std::is_same_v<_Tp, _Tp>, "Unknown platform boolean size");
|
||||
}
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::cuda::std::int8_t>)
|
||||
{
|
||||
return __ncclInt8;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, char> && !::cuda::std::is_same_v<char, ::cuda::std::int8_t>)
|
||||
{
|
||||
return __ncclChar;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::cuda::std::uint8_t>)
|
||||
{
|
||||
return __ncclUint8;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::cuda::std::int32_t>)
|
||||
{
|
||||
return __ncclInt32;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::cuda::std::uint32_t>)
|
||||
{
|
||||
return __ncclUint32;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::cuda::std::int64_t>)
|
||||
{
|
||||
return __ncclInt64;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::cuda::std::uint64_t>)
|
||||
{ // NOLINT(bugprone-branch-clone)
|
||||
return __ncclUint64;
|
||||
}
|
||||
// On some platforms size_t != uint64_t
|
||||
else if constexpr ((sizeof(::cuda::std::size_t) == sizeof(::cuda::std::uint64_t))
|
||||
&& (alignof(::cuda::std::size_t) == alignof(::cuda::std::uint64_t))
|
||||
&& ::cuda::std::is_same_v<_Tp, ::cuda::std::size_t>)
|
||||
{
|
||||
return __ncclUint64;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, float>)
|
||||
{
|
||||
return __ncclFloat;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, double>)
|
||||
{
|
||||
return __ncclDouble;
|
||||
}
|
||||
#if _CCCL_HAS_NVFP16()
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::__half>)
|
||||
{
|
||||
return __ncclHalf;
|
||||
}
|
||||
#endif // _CCCL_HAS_NVFP16()
|
||||
#if _CCCL_HAS_NVBF16()
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::__nv_bfloat16>)
|
||||
{
|
||||
return __ncclBfloat16;
|
||||
}
|
||||
#endif // _CCCL_HAS_NVBF16()
|
||||
#if _CCCL_HAS_NVFP8()
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::__nv_fp8_e4m3>)
|
||||
{
|
||||
return __ncclFloat8e4m3;
|
||||
}
|
||||
else if constexpr (::cuda::std::is_same_v<_Tp, ::__nv_fp8_e5m2>)
|
||||
{
|
||||
return __ncclFloat8e5m2;
|
||||
}
|
||||
#endif // _CCCL_HAS_NVFP8()
|
||||
else
|
||||
{
|
||||
return __no_nccl_type{};
|
||||
}
|
||||
_CCCL_UNREACHABLE();
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline constexpr __ncclDataType_t __nccl_type_of_v =
|
||||
::cuda::experimental::__nccl::__nccl_type_of<::cuda::std::remove_cvref_t<_Tp>>();
|
||||
|
||||
template <class _Tp>
|
||||
_CCCL_CONCEPT __has_nccl_type_of = _CCCL_REQUIRES_EXPR((_Tp), )(
|
||||
_Same_as(__ncclDataType_t)::cuda::experimental::__nccl::__nccl_type_of<::cuda::std::remove_cvref_t<_Tp>>());
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
struct __no_nccl_redop
|
||||
{};
|
||||
|
||||
template <class _Op>
|
||||
[[nodiscard]] _CCCL_API _CCCL_CONSTEVAL auto __nccl_redop_of() noexcept
|
||||
{
|
||||
if constexpr (::cuda::std::__is_plus_op_v<_Op>)
|
||||
{
|
||||
return __ncclSum;
|
||||
}
|
||||
else if constexpr (::cuda::std::__is_multiplies_op_v<_Op>)
|
||||
{
|
||||
return __ncclProd;
|
||||
}
|
||||
else if constexpr (::cuda::__is_cuda_maximum_v<_Op>)
|
||||
{
|
||||
return __ncclMax;
|
||||
}
|
||||
else if constexpr (::cuda::__is_cuda_minimum_v<_Op>)
|
||||
{
|
||||
return __ncclMin;
|
||||
}
|
||||
else
|
||||
{
|
||||
return __no_nccl_redop{};
|
||||
}
|
||||
_CCCL_UNREACHABLE();
|
||||
}
|
||||
|
||||
template <class _Op>
|
||||
inline constexpr __ncclRedOp_t __nccl_redop_of_v =
|
||||
::cuda::experimental::__nccl::__nccl_redop_of<::cuda::std::remove_cvref_t<_Op>>();
|
||||
|
||||
template <class _Op>
|
||||
_CCCL_CONCEPT __has_nccl_redop_of = _CCCL_REQUIRES_EXPR((_Op), )(
|
||||
_Same_as(__ncclRedOp_t)::cuda::experimental::__nccl::__nccl_redop_of<::cuda::std::remove_cvref_t<_Op>>());
|
||||
|
||||
// API wrappers
|
||||
// ==========================================================================================
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline const char* __ncclGetLastErrorNoThrow(__ncclComm_t __comm) noexcept
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclGetLastError, const char* (*) (__ncclComm_t));
|
||||
|
||||
return __fn(__comm);
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline const char* __ncclGetErrorStringNoThrow(__ncclResult_t __result) noexcept
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclGetErrorString, const char* (*) (__ncclResult_t));
|
||||
|
||||
return __fn(__result);
|
||||
}
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
#if _CCCL_HOSTED()
|
||||
|
||||
class nccl_error final : public ::std::runtime_error
|
||||
{
|
||||
[[nodiscard]] _CCCL_HOST_API static const char* __format_nccl_error(
|
||||
::cuda::__msg_storage& __msg_buffer,
|
||||
__ncclResult_t __result,
|
||||
const char* __msg,
|
||||
const char* __api,
|
||||
const ::cuda::std::source_location& __loc) noexcept
|
||||
{
|
||||
static_cast<void>(::snprintf(
|
||||
__msg_buffer.__buffer,
|
||||
::cuda::__msg_storage::__size,
|
||||
"%s:%d %s%s%s(%d): %s",
|
||||
__loc.file_name(),
|
||||
__loc.line(),
|
||||
__api ? __api : "",
|
||||
__api ? " " : "",
|
||||
::cuda::experimental::__nccl::__ncclGetErrorStringNoThrow(__result),
|
||||
static_cast<::cuda::std::int32_t>(__result),
|
||||
__msg));
|
||||
|
||||
return __msg_buffer.__buffer;
|
||||
}
|
||||
|
||||
public:
|
||||
_CCCL_HOST_API nccl_error(
|
||||
__ncclResult_t __result,
|
||||
const char* __msg,
|
||||
const char* __api = nullptr,
|
||||
::cuda::std::source_location __loc = ::cuda::std::source_location::current(),
|
||||
::cuda::__msg_storage __msg_buffer = {}) noexcept
|
||||
: ::std::runtime_error{__format_nccl_error(__msg_buffer, __result, __msg, __api, __loc)}
|
||||
, __result_{__result}
|
||||
{}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr __ncclResult_t status() const noexcept
|
||||
{
|
||||
return __result_;
|
||||
}
|
||||
|
||||
private:
|
||||
__ncclResult_t __result_;
|
||||
};
|
||||
|
||||
#else // ^^^ _CCCL_HOSTED() ^^^ / vvv !_CCCL_HOSTED() vvv
|
||||
|
||||
class nccl_error final
|
||||
{};
|
||||
|
||||
#endif // ^^^ !_CCCL_HOSTED() ^^^
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline __ncclResult_t __ncclCommDestroyNoThrow(__ncclComm_t __comm) noexcept
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclCommDestroy, __ncclResult_t (*)(__ncclComm_t));
|
||||
|
||||
return __fn(__comm);
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclCommDestroy(__ncclComm_t __comm)
|
||||
{
|
||||
if (const auto __ret = ::cuda::experimental::__nccl::__ncclCommDestroyNoThrow(__comm); __ret != __ncclSuccess)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclCommDestroy", "ncclCommDestroy");
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline int __ncclCommCount(__ncclComm_t __comm)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclCommCount, __ncclResult_t (*)(__ncclComm_t, int*));
|
||||
|
||||
int __count{};
|
||||
|
||||
if (const auto __ret = __fn(__comm, &__count); __ret != __ncclSuccess)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclCommCount", "ncclCommCount");
|
||||
}
|
||||
return __count;
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline int __ncclCommUserRank(__ncclComm_t __comm)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclCommUserRank, __ncclResult_t (*)(__ncclComm_t, int*));
|
||||
|
||||
int __rank{};
|
||||
|
||||
if (const auto __ret = __fn(__comm, &__rank); __ret != __ncclSuccess)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclCommUserRank", "ncclCommUserRank");
|
||||
}
|
||||
return __rank;
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline ::cuda::device_ref __ncclCommCuDevice(__ncclComm_t __comm)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclCommCuDevice, __ncclResult_t (*)(__ncclComm_t, int*));
|
||||
|
||||
int __device{};
|
||||
|
||||
if (const auto __ret = __fn(__comm, &__device); __ret != __ncclSuccess)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclCommCuDevice", "ncclCommCuDevice");
|
||||
}
|
||||
|
||||
return {__device};
|
||||
}
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
_CCCL_HOST_API inline void __ncclGroupStart()
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclGroupStart, __ncclResult_t (*)());
|
||||
|
||||
if (const auto __ret = __fn(); __ret != __ncclSuccess)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclGroupStart", "ncclGroupStart");
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API inline __ncclResult_t __ncclGroupEndNoThrow() noexcept
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(ncclGroupEnd, __ncclResult_t (*)());
|
||||
|
||||
return __fn();
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclGroupEnd()
|
||||
{
|
||||
if (const auto __ret = ::cuda::experimental::__nccl::__ncclGroupEndNoThrow();
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclGroupEnd", "ncclGroupEnd");
|
||||
}
|
||||
}
|
||||
|
||||
class __ensure_nccl_group
|
||||
{
|
||||
public:
|
||||
_CCCL_HOST_API __ensure_nccl_group()
|
||||
: __uncaught_on_entry_{::std::uncaught_exceptions()}
|
||||
{
|
||||
::cuda::experimental::__nccl::__ncclGroupStart();
|
||||
}
|
||||
|
||||
_CCCL_HIDE_FROM_ABI __ensure_nccl_group(const __ensure_nccl_group&) = delete;
|
||||
_CCCL_HIDE_FROM_ABI void operator=(const __ensure_nccl_group&) = delete;
|
||||
_CCCL_HIDE_FROM_ABI __ensure_nccl_group(__ensure_nccl_group&&) = delete;
|
||||
_CCCL_HIDE_FROM_ABI void operator=(__ensure_nccl_group&&) = delete;
|
||||
|
||||
_CCCL_HOST_API ~__ensure_nccl_group() noexcept(false)
|
||||
{
|
||||
if (::std::uncaught_exceptions() > __uncaught_on_entry_)
|
||||
{
|
||||
static_cast<void>(::cuda::experimental::__nccl::__ncclGroupEndNoThrow());
|
||||
}
|
||||
else
|
||||
{
|
||||
::cuda::experimental::__nccl::__ncclGroupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// This is needed in case __ensure_nccl_group is constructed *inside* a catch block (or
|
||||
// anywhere an exception is already in the process of being handled). We need to identify
|
||||
// exactly the situation where we are unwinding as a result of a new exception during the
|
||||
// lifetime of this object.
|
||||
int __uncaught_on_entry_{};
|
||||
};
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
_CCCL_HOST_API inline void __ncclAllReduce(
|
||||
const void* __sendbuff,
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __count,
|
||||
__ncclDataType_t __datatype,
|
||||
__ncclRedOp_t __op,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(
|
||||
ncclAllReduce,
|
||||
__ncclResult_t (*)(
|
||||
const void*, void*, ::cuda::std::size_t, __ncclDataType_t, __ncclRedOp_t, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __recvbuff, __count, __datatype, __op, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclAllReduce", "ncclAllReduce");
|
||||
}
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclReduce(
|
||||
const void* __sendbuff,
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __count,
|
||||
__ncclDataType_t __datatype,
|
||||
__ncclRedOp_t __op,
|
||||
int __root,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(
|
||||
ncclReduce,
|
||||
__ncclResult_t (*)(
|
||||
const void*, void*, ::cuda::std::size_t, __ncclDataType_t, __ncclRedOp_t, int, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __recvbuff, __count, __datatype, __op, __root, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclReduce", "ncclReduce");
|
||||
}
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclAllGather(
|
||||
const void* __sendbuff,
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __sendcount,
|
||||
__ncclDataType_t __datatype,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(
|
||||
ncclAllGather,
|
||||
__ncclResult_t (*)(const void*, void*, ::cuda::std::size_t, __ncclDataType_t, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __recvbuff, __sendcount, __datatype, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclAllGather", "ncclAllGather");
|
||||
}
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclBroadcast(
|
||||
const void* __sendbuff,
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __count,
|
||||
__ncclDataType_t __datatype,
|
||||
int __root,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(
|
||||
ncclBroadcast,
|
||||
__ncclResult_t (*)(const void*, void*, ::cuda::std::size_t, __ncclDataType_t, int, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __recvbuff, __count, __datatype, __root, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclBroadcast", "ncclBroadcast");
|
||||
}
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclGather(
|
||||
const void* __sendbuff,
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __sendcount,
|
||||
__ncclDataType_t __datatype,
|
||||
int __root,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
// ncclGather only since 2.28.
|
||||
//
|
||||
// TODO(jfaibussowit): If gather doesn't exist, we could try and implement it ourselves. The
|
||||
// NCCL docs show an example implementation
|
||||
// https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/p2p.html#all-to-one-gather
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL_ENABLE_ABI_CHECK_IF(
|
||||
_CCCL_HAS_NCCL_2_28(),
|
||||
ncclGather,
|
||||
__ncclResult_t (*)(const void*, void*, ::cuda::std::size_t, __ncclDataType_t, int, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __recvbuff, __sendcount, __datatype, __root, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclGather", "ncclGather");
|
||||
}
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclAlltoAll(
|
||||
const void* __sendbuff,
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __count,
|
||||
__ncclDataType_t __datatype,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
// ncclAllToAll only since 2.28
|
||||
//
|
||||
// TODO(jfaibussowit): If all-to-all doesn't exist, we could try and implement it
|
||||
// ourselves. The NCCL docs show an example implementation
|
||||
// https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/p2p.html#all-to-all
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL_ENABLE_ABI_CHECK_IF(
|
||||
_CCCL_HAS_NCCL_2_28(),
|
||||
ncclAlltoAll,
|
||||
__ncclResult_t (*)(const void*, void*, ::cuda::std::size_t, __ncclDataType_t, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __recvbuff, __count, __datatype, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclAlltoAll", "ncclAlltoAll");
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
_CCCL_HOST_API inline void __ncclSend(
|
||||
const void* __sendbuff,
|
||||
::cuda::std::size_t __count,
|
||||
__ncclDataType_t __datatype,
|
||||
int __peer,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(
|
||||
ncclSend, __ncclResult_t (*)(const void*, ::cuda::std::size_t, __ncclDataType_t, int, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__sendbuff, __count, __datatype, __peer, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclSend", "ncclSend");
|
||||
}
|
||||
}
|
||||
|
||||
_CCCL_HOST_API inline void __ncclRecv(
|
||||
void* __recvbuff,
|
||||
::cuda::std::size_t __count,
|
||||
__ncclDataType_t __datatype,
|
||||
int __peer,
|
||||
__ncclComm_t __comm,
|
||||
::cuda::stream_ref __stream)
|
||||
{
|
||||
static auto* const __fn = _CCCL_LOAD_NCCL_SYMBOL(
|
||||
ncclRecv, __ncclResult_t (*)(void*, ::cuda::std::size_t, __ncclDataType_t, int, __ncclComm_t, ::CUstream));
|
||||
|
||||
if (const auto __ret = __fn(__recvbuff, __count, __datatype, __peer, __comm, __stream.get());
|
||||
__ret != __ncclSuccess && __ret != __ncclInProgress)
|
||||
{
|
||||
_CCCL_THROW(::cuda::experimental::__nccl::nccl_error, __ret, "Error in ncclRecv", "ncclRecv");
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
#undef _CCCL_LOAD_NCCL_SYMBOL
|
||||
#undef _CCCL_LOAD_NCCL_SYMBOL_ENABLE_ABI_CHECK_IF
|
||||
#undef _CCCL_HAS_NCCL_2_28
|
||||
} // namespace cuda::experimental::__nccl
|
||||
|
||||
// NOLINTEND(bugprone-reserved-identifier)
|
||||
|
||||
#include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CUDA_EXPERIMENTAL___NCCL_NCCL_API_H
|
||||
@@ -1,203 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of CUDA Experimental in CUDA C++ Core Libraries,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _CUDA_EXPERIMENTAL___NCCL_SHARED_LIBRARY_H
|
||||
#define _CUDA_EXPERIMENTAL___NCCL_SHARED_LIBRARY_H
|
||||
|
||||
#include <cuda/std/detail/__config>
|
||||
|
||||
#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
|
||||
# pragma GCC system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
|
||||
# pragma clang system_header
|
||||
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
|
||||
# pragma system_header
|
||||
#endif // no system header
|
||||
|
||||
#include <cuda/std/__exception/exception_macros.h>
|
||||
#include <cuda/std/__host_stdlib/stdexcept>
|
||||
#include <cuda/std/__memory/unique_ptr.h>
|
||||
#include <cuda/std/__type_traits/decay.h>
|
||||
#include <cuda/std/__type_traits/remove_pointer.h>
|
||||
#include <cuda/std/cstdint>
|
||||
|
||||
#if _CCCL_OS(WINDOWS)
|
||||
# include <windows.h>
|
||||
#else // ^^^ _CCCL_OS(WINDOWS) ^^^ / vvv !_CCCL_OS(WINDOWS) vvv
|
||||
# include <dlfcn.h>
|
||||
#endif // ^^^ !_CCCL_OS(WINDOWS) ^^^
|
||||
|
||||
#include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
#ifndef _CCCL_DOXYGEN_INVOKED // Do not document
|
||||
|
||||
// NOLINTBEGIN(bugprone-reserved-identifier)
|
||||
|
||||
namespace cuda::experimental
|
||||
{
|
||||
# if _CCCL_OS(WINDOWS)
|
||||
class __shared_library_base
|
||||
{
|
||||
struct __platform_deleter
|
||||
{
|
||||
using pointer _CCCL_NODEBUG_ALIAS = HMODULE;
|
||||
|
||||
_CCCL_HOST_API void operator()(HMODULE __mod) const noexcept
|
||||
{
|
||||
static_cast<void>(::FreeLibrary(__mod));
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
static constexpr ::cuda::std::int32_t __platform_default_flags = LOAD_LIBRARY_SEARCH_SYSTEM32;
|
||||
|
||||
using __platform_handle_t _CCCL_NODEBUG_ALIAS =
|
||||
::cuda::std::unique_ptr<::cuda::std::remove_pointer_t<HMODULE>, __platform_deleter>;
|
||||
|
||||
_CCCL_HOST_API __shared_library_base(const char* const __lib_path, const ::cuda::std::int32_t __flags)
|
||||
: __handle_{::LoadLibraryExA(__lib_path, /*hFile=*/nullptr, static_cast<DWORD>(__flags))}
|
||||
{}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API void* __load_symbol_platform(const char* const __sym_name, const bool __can_fail) const
|
||||
{
|
||||
void* const __sym = ::GetProcAddress(__handle_.get(), __sym_name);
|
||||
|
||||
if (__sym == nullptr && !__can_fail)
|
||||
{
|
||||
_CCCL_THROW(::std::invalid_argument, "Failed to locate the symbol in the shared library");
|
||||
}
|
||||
return __sym;
|
||||
}
|
||||
|
||||
__platform_handle_t __handle_{};
|
||||
};
|
||||
# elif _CCCL_OS(LINUX) || _CCCL_OS(APPLE) // ^^^ _CCCL_OS(WINDOWS) ^^^ / vvv _CCCL_OS(LINUX) vvv
|
||||
class __shared_library_base
|
||||
{
|
||||
struct __platform_deleter
|
||||
{
|
||||
_CCCL_HOST_API void operator()(void* const __mod) const noexcept
|
||||
{
|
||||
static_cast<void>(::dlclose(__mod));
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
using __platform_handle_t _CCCL_NODEBUG_ALIAS = ::cuda::std::unique_ptr<void, __platform_deleter>;
|
||||
|
||||
private:
|
||||
[[nodiscard]] _CCCL_HOST_API static __platform_handle_t
|
||||
__load_lib_platform(const char* const __lib_name, const ::cuda::std::int32_t __flags)
|
||||
{
|
||||
static_cast<void>(::dlerror());
|
||||
|
||||
return __platform_handle_t{::dlopen(__lib_name, __flags)};
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr ::cuda::std::int32_t __platform_default_flags = RTLD_LAZY | RTLD_LOCAL;
|
||||
|
||||
_CCCL_HOST_API __shared_library_base(const char* const __lib_path, const ::cuda::std::int32_t __flags)
|
||||
: __handle_{__load_lib_platform(__lib_path, __flags)}
|
||||
{}
|
||||
|
||||
[[nodiscard]] _CCCL_HOST_API void* __load_symbol_platform(const char* const __sym_name, const bool __can_fail) const
|
||||
{
|
||||
static_cast<void>(::dlerror());
|
||||
|
||||
auto* __sym = ::dlsym(__handle_.get(), __sym_name);
|
||||
|
||||
if (const char* const __error = ::dlerror(); __error || !__sym)
|
||||
{
|
||||
if (__can_fail)
|
||||
{
|
||||
// Ensure it is null
|
||||
__sym = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
_CCCL_THROW(::std::runtime_error, "Failed to locate the symbol in the shared library");
|
||||
}
|
||||
}
|
||||
return __sym;
|
||||
}
|
||||
|
||||
__platform_handle_t __handle_{};
|
||||
};
|
||||
# else // ^^^ _CCCL_OS(LINUX) ^^^ / vvv unknown arch vvv
|
||||
# error "Unsupported system architecture. Please file a bug report at https://github.com/NVIDIA/cccl/issues"
|
||||
# endif // ^^^ unknown arch ^^^
|
||||
|
||||
class __shared_library : __shared_library_base
|
||||
{
|
||||
public:
|
||||
using native_handle_type = typename __shared_library_base::__platform_handle_t::pointer;
|
||||
|
||||
/**
|
||||
* @brief __shared_library may not be default constructed
|
||||
*/
|
||||
_CCCL_HIDE_FROM_ABI __shared_library() = delete;
|
||||
|
||||
/**
|
||||
* @brief Construct and load a named shared library with the provided flags
|
||||
*
|
||||
* @param __lib_path The path used to find the shared library object. If absolute, then the
|
||||
* specified path will be attempted to be loaded. If relative, or without path prefixes, then
|
||||
* loading is platform dependent.
|
||||
*
|
||||
* @param __flags Platform dependent flags to pass to the module loading functions. At
|
||||
* present should probably be left unspecified.
|
||||
*
|
||||
* @throw std::runtime_error if the library could not be loaded.
|
||||
*/
|
||||
_CCCL_HOST_API explicit __shared_library(
|
||||
const char* __lib_path, ::cuda::std::int32_t __flags = __shared_library_base::__platform_default_flags)
|
||||
: __shared_library_base{__lib_path, __flags}
|
||||
{
|
||||
if (!__handle_)
|
||||
{
|
||||
_CCCL_THROW(::std::runtime_error, "Failed to load dynamic shared object");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Pointer to the platform-specific library handle.
|
||||
*/
|
||||
[[nodiscard]] _CCCL_HOST_API native_handle_type handle() const
|
||||
{
|
||||
return __handle_.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load a named symbol from the library.
|
||||
*
|
||||
* @tparam _Tp The type of the symbol to load.
|
||||
*
|
||||
* @param __symbol_name The name of the symbol to load.
|
||||
* @param __can_fail `true` if the function is allowed to fail, false otherwise.
|
||||
*
|
||||
* @return A pointer to the loaded symbol casted to `_Tp`.
|
||||
*/
|
||||
template <class _Tp>
|
||||
[[nodiscard]] _CCCL_HOST_API ::cuda::std::decay_t<_Tp>
|
||||
load_symbol(const char* __symbol_name, bool __can_fail = false) const
|
||||
{
|
||||
return reinterpret_cast<::cuda::std::decay_t<_Tp>>(__load_symbol_platform(__symbol_name, __can_fail));
|
||||
}
|
||||
};
|
||||
} // namespace cuda::experimental
|
||||
|
||||
// NOLINTEND(bugprone-reserved-identifier)
|
||||
|
||||
#endif // _CCCL_DOXYGEN_INVOKED
|
||||
|
||||
#include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CUDA_EXPERIMENTAL___NCCL_SHARED_LIBRARY_H
|
||||
Reference in New Issue
Block a user