[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:
muh-bot
2026-08-03 12:39:26 +00:00
parent a2a5dd8f00
commit 24ef6a91b5
5439 changed files with 0 additions and 719516 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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