[INFRA] Import NVIDIA/CCCL upstream as optimization reference library
CCCL (CUDA C++ Core Libraries) provides: - CUB: device/block/warp-level GPU primitives (reduce, scan, sort, topk) - Thrust: high-level parallel algorithms (transform_reduce, sort, scan) - libcudacxx: CUDA C++ standard library (atomics, barriers, memory) - cudax: experimental features (memory resources, allocators) - Tuning policies: per-SM hardware-specific algorithm parameters Competition optimization vectors mapped to CCCL: - Output TPS (83% weight): warp_reduce, block_reduce, device_topk - Input TPS (14% weight): device_scan, block_load, prefetch - Cache TPS (3% weight): prefix caching strategy patterns - Memory (0.9 util): pooled/cached/buddy allocators Source: https://github.com/NVIDIA/cccl (shallow clone, HEAD only) License: Apache-2.0
This commit is contained in:
1203
cccl_upstream/libcudacxx/include/cuda/__container/buffer.h
Normal file
1203
cccl_upstream/libcudacxx/include/cuda/__container/buffer.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,439 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __CUDAX__CONTAINERS_HETEROGENEOUS_ITERATOR_CUH
|
||||
#define __CUDAX__CONTAINERS_HETEROGENEOUS_ITERATOR_CUH
|
||||
|
||||
#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
|
||||
|
||||
#if _CCCL_HAS_CTK()
|
||||
|
||||
# include <cuda/__memory_resource/properties.h>
|
||||
# include <cuda/std/__iterator/iterator_traits.h>
|
||||
# include <cuda/std/__memory/addressof.h>
|
||||
# include <cuda/std/__memory/pointer_traits.h>
|
||||
# include <cuda/std/__type_traits/is_const.h>
|
||||
# include <cuda/std/__type_traits/is_same.h>
|
||||
# include <cuda/std/__type_traits/maybe_const.h>
|
||||
# include <cuda/std/__type_traits/remove_const.h>
|
||||
# include <cuda/std/cstdint>
|
||||
|
||||
# include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
//! @file
|
||||
//! @brief The \c heterogeneous_iterator class is an iterator that provides typed execution space safety.
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
|
||||
enum class __is_heterogeneous_const_iter
|
||||
{
|
||||
__no,
|
||||
__yes,
|
||||
};
|
||||
//! @rst
|
||||
//! .. _libcudacxx-containers-heterogeneous-iterator:
|
||||
//!
|
||||
//! Type safe iterator over heterogeneous memory
|
||||
//! ---------------------------------------------
|
||||
//!
|
||||
//! ``heterogeneous_iterator`` provides a type safe access over heterogeneous memory. Depending on whether the memory is
|
||||
//! tagged as host-accessible and / or device-accessible the iterator restricts memory access.
|
||||
//! All operations that do not require memory access are always available on host and device.
|
||||
//!
|
||||
//! @endrst
|
||||
//! @tparam _Tp The underlying type of the elements the \c heterogeneous_iterator points at.
|
||||
//! @tparam _IsConst Enumeration choosing whether the \c heterogeneous_iterator allows mutating the element pointed to.
|
||||
//! @tparam _Properties The properties that the \c heterogeneous_iterator is tagged with.
|
||||
template <class _CvTp, class... _Properties>
|
||||
class heterogeneous_iterator;
|
||||
|
||||
// We restrict all accessors of the iterator based on the execution space
|
||||
template <class _Tp, __is_heterogeneous_const_iter _IsConst, ::cuda::mr::__memory_accessibility _Space>
|
||||
class __heterogeneous_iterator_access;
|
||||
|
||||
template <class _Tp, __is_heterogeneous_const_iter _IsConst>
|
||||
class __heterogeneous_iterator_access<_Tp, _IsConst, ::cuda::mr::__memory_accessibility ::__host>
|
||||
{
|
||||
public:
|
||||
using iterator_concept = ::cuda::std::contiguous_iterator_tag;
|
||||
using iterator_category = ::cuda::std::random_access_iterator_tag;
|
||||
using value_type = _Tp;
|
||||
using difference_type = ::cuda::std::ptrdiff_t;
|
||||
using pointer = ::cuda::std::__maybe_const<_IsConst == __is_heterogeneous_const_iter::__yes, _Tp>*;
|
||||
using reference = ::cuda::std::__maybe_const<_IsConst == __is_heterogeneous_const_iter::__yes, _Tp>&;
|
||||
|
||||
_CCCL_HIDE_FROM_ABI __heterogeneous_iterator_access() = default;
|
||||
|
||||
_CCCL_API explicit constexpr __heterogeneous_iterator_access(pointer __ptr) noexcept
|
||||
: __ptr_(__ptr)
|
||||
{}
|
||||
|
||||
//! @brief Dereference a \c heterogeneous_iterator
|
||||
//! @return A reference to the element the iterator points to
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr reference operator*() const noexcept
|
||||
{
|
||||
return *__ptr_;
|
||||
}
|
||||
|
||||
//! @brief Operator arrow on a \c heterogeneous_iterator
|
||||
//! @return A pointer to the element the iterator points to
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr pointer operator->() const noexcept
|
||||
{
|
||||
return __ptr_;
|
||||
}
|
||||
|
||||
//! @brief Dereference a \c heterogeneous_iterator
|
||||
//! @param __count The offset at which we want to dereference
|
||||
//! @return A reference of the \p __count th element after the one the iterator points to
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr reference operator[](const difference_type __count) const noexcept
|
||||
{
|
||||
return *(__ptr_ + __count);
|
||||
}
|
||||
|
||||
protected:
|
||||
pointer __ptr_ = nullptr;
|
||||
|
||||
template <class, class...>
|
||||
friend class heterogeneous_iterator;
|
||||
};
|
||||
|
||||
template <class _Tp, __is_heterogeneous_const_iter _IsConst>
|
||||
class __heterogeneous_iterator_access<_Tp, _IsConst, ::cuda::mr::__memory_accessibility ::__device>
|
||||
{
|
||||
public:
|
||||
using iterator_concept = ::cuda::std::contiguous_iterator_tag;
|
||||
using iterator_category = ::cuda::std::random_access_iterator_tag;
|
||||
using value_type = _Tp;
|
||||
using difference_type = ::cuda::std::ptrdiff_t;
|
||||
using pointer = ::cuda::std::__maybe_const<_IsConst == __is_heterogeneous_const_iter::__yes, _Tp>*;
|
||||
using reference = ::cuda::std::__maybe_const<_IsConst == __is_heterogeneous_const_iter::__yes, _Tp>&;
|
||||
|
||||
_CCCL_HIDE_FROM_ABI __heterogeneous_iterator_access() = default;
|
||||
|
||||
_CCCL_API explicit constexpr __heterogeneous_iterator_access(pointer __ptr) noexcept
|
||||
: __ptr_(__ptr)
|
||||
{}
|
||||
|
||||
//! @brief Dereference a \c heterogeneous_iterator
|
||||
//! @return A reference to the element the iterator points to
|
||||
[[nodiscard]] _CCCL_DEVICE_API constexpr reference operator*() const noexcept
|
||||
{
|
||||
return *__ptr_;
|
||||
}
|
||||
|
||||
//! @brief Operator arrow on a \c heterogeneous_iterator
|
||||
//! @return A pointer to the element the iterator points to
|
||||
[[nodiscard]] _CCCL_DEVICE_API constexpr pointer operator->() const noexcept
|
||||
{
|
||||
return __ptr_;
|
||||
}
|
||||
|
||||
//! @brief Dereference a \c heterogeneous_iterator
|
||||
//! @param __count The offset at which we want to dereference
|
||||
//! @return A reference of the \p __count th element after the one the iterator points to
|
||||
[[nodiscard]] _CCCL_DEVICE_API constexpr reference operator[](const difference_type __count) const noexcept
|
||||
{
|
||||
return *(__ptr_ + __count);
|
||||
}
|
||||
|
||||
protected:
|
||||
pointer __ptr_ = nullptr;
|
||||
|
||||
template <class, class...>
|
||||
friend class heterogeneous_iterator;
|
||||
};
|
||||
|
||||
template <class _Tp, __is_heterogeneous_const_iter _IsConst>
|
||||
class __heterogeneous_iterator_access<_Tp, _IsConst, ::cuda::mr::__memory_accessibility ::__host_device>
|
||||
{
|
||||
public:
|
||||
using iterator_concept = ::cuda::std::contiguous_iterator_tag;
|
||||
using iterator_category = ::cuda::std::random_access_iterator_tag;
|
||||
using value_type = _Tp;
|
||||
using difference_type = ::cuda::std::ptrdiff_t;
|
||||
using pointer = ::cuda::std::__maybe_const<_IsConst == __is_heterogeneous_const_iter::__yes, _Tp>*;
|
||||
using reference = ::cuda::std::__maybe_const<_IsConst == __is_heterogeneous_const_iter::__yes, _Tp>&;
|
||||
|
||||
_CCCL_HIDE_FROM_ABI __heterogeneous_iterator_access() = default;
|
||||
|
||||
_CCCL_API explicit constexpr __heterogeneous_iterator_access(pointer __ptr) noexcept
|
||||
: __ptr_(__ptr)
|
||||
{}
|
||||
|
||||
//! @brief Dereference a \c heterogeneous_iterator
|
||||
//! @return A reference to the element the iterator points to
|
||||
[[nodiscard]] _CCCL_API constexpr reference operator*() const noexcept
|
||||
{
|
||||
return *__ptr_;
|
||||
}
|
||||
|
||||
//! @brief Operator arrow on a \c heterogeneous_iterator
|
||||
//! @return A pointer to the element the iterator points to
|
||||
[[nodiscard]] _CCCL_API constexpr pointer operator->() const noexcept
|
||||
{
|
||||
return __ptr_;
|
||||
}
|
||||
|
||||
//! @brief Dereference a \c heterogeneous_iterator
|
||||
//! @param __count The offset at which we want to dereference
|
||||
//! @return A reference to the `__count` element after the one the iterator points to
|
||||
[[nodiscard]] _CCCL_API constexpr reference operator[](const difference_type __count) const noexcept
|
||||
{
|
||||
return *(__ptr_ + __count);
|
||||
}
|
||||
|
||||
protected:
|
||||
pointer __ptr_ = nullptr;
|
||||
|
||||
template <class, class...>
|
||||
friend class heterogeneous_iterator;
|
||||
};
|
||||
|
||||
template <class _CvTp, class... _Properties>
|
||||
class heterogeneous_iterator
|
||||
: public __heterogeneous_iterator_access<
|
||||
::cuda::std::remove_const_t<_CvTp>,
|
||||
::cuda::std::is_const_v<_CvTp> ? __is_heterogeneous_const_iter::__yes : __is_heterogeneous_const_iter::__no,
|
||||
::cuda::mr::__memory_accessibility_from_properties<_Properties...>::value>
|
||||
{
|
||||
using __base = __heterogeneous_iterator_access<
|
||||
::cuda::std::remove_const_t<_CvTp>,
|
||||
::cuda::std::is_const_v<_CvTp> ? __is_heterogeneous_const_iter::__yes : __is_heterogeneous_const_iter::__no,
|
||||
::cuda::mr::__memory_accessibility_from_properties<_Properties...>::value>;
|
||||
|
||||
public:
|
||||
using iterator_concept = ::cuda::std::contiguous_iterator_tag;
|
||||
using iterator_category = ::cuda::std::random_access_iterator_tag;
|
||||
using value_type = ::cuda::std::remove_const_t<_CvTp>;
|
||||
using difference_type = ::cuda::std::ptrdiff_t;
|
||||
using pointer = _CvTp*;
|
||||
using reference = _CvTp&;
|
||||
|
||||
_CCCL_HIDE_FROM_ABI heterogeneous_iterator() = default;
|
||||
|
||||
//! @brief Construct a \c heterogeneous_iterator from a pointer to the underlying memory
|
||||
_CCCL_API constexpr heterogeneous_iterator(pointer __ptr) noexcept
|
||||
: __base(__ptr)
|
||||
{}
|
||||
|
||||
//! @brief Constructs an immutable \c heterogeneous_iterator from a mutable one
|
||||
//! @param __other The mutable \c heterogeneous_iterator
|
||||
_CCCL_TEMPLATE(class _OtherTp, class _CvTp2 = _CvTp)
|
||||
_CCCL_REQUIRES((::cuda::std::is_same_v<_OtherTp, value_type>) _CCCL_AND(::cuda::std::is_const_v<_CvTp2>))
|
||||
_CCCL_API constexpr heterogeneous_iterator(heterogeneous_iterator<_OtherTp, _Properties...> __other) noexcept
|
||||
: __base(__other.__ptr_)
|
||||
{}
|
||||
|
||||
//! @brief Increment of a \c heterogeneous_iterator
|
||||
//! @return The heterogeneous_iterator pointing to the next element
|
||||
_CCCL_API constexpr heterogeneous_iterator& operator++() noexcept
|
||||
{
|
||||
++this->__ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Post-increment of a \c heterogeneous_iterator
|
||||
//! @return A copy of the heterogeneous_iterator pointing to the next element
|
||||
_CCCL_API constexpr heterogeneous_iterator operator++(int) noexcept
|
||||
{
|
||||
heterogeneous_iterator __temp = *this;
|
||||
++this->__ptr_;
|
||||
return __temp;
|
||||
}
|
||||
|
||||
//! @brief Decrement of a \c heterogeneous_iterator
|
||||
//! @return The heterogeneous_iterator pointing to the previous element
|
||||
_CCCL_API constexpr heterogeneous_iterator& operator--() noexcept
|
||||
{
|
||||
--this->__ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Post-decrement of a \c heterogeneous_iterator
|
||||
//! @return A copy of the heterogeneous_iterator pointing to the previous element
|
||||
_CCCL_API constexpr heterogeneous_iterator operator--(int) noexcept
|
||||
{
|
||||
heterogeneous_iterator __temp = *this;
|
||||
--this->__ptr_;
|
||||
return __temp;
|
||||
}
|
||||
|
||||
//! @brief Advance a \c heterogeneous_iterator
|
||||
//! @param __count The number of elements to advance.
|
||||
//! @return The heterogeneous_iterator advanced by \p __count
|
||||
_CCCL_API constexpr heterogeneous_iterator& operator+=(const difference_type __count) noexcept
|
||||
{
|
||||
this->__ptr_ += __count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Advance a \c heterogeneous_iterator
|
||||
//! @param __count The number of elements to advance.
|
||||
//! @return A copy of this heterogeneous_iterator advanced by \p __count
|
||||
[[nodiscard]] _CCCL_API constexpr heterogeneous_iterator operator+(const difference_type __count) const noexcept
|
||||
{
|
||||
heterogeneous_iterator __temp = *this;
|
||||
__temp += __count;
|
||||
return __temp;
|
||||
}
|
||||
|
||||
# ifndef _CCCL_DOXYGEN_INVOKED // Do not document
|
||||
//! @brief Advance a \c heterogeneous_iterator
|
||||
//! @param __count The number of elements to advance.
|
||||
//! @param __other A heterogeneous_iterator.
|
||||
//! @return \p __other advanced by \p __count
|
||||
[[nodiscard]] _CCCL_API friend constexpr heterogeneous_iterator
|
||||
operator+(const difference_type __count, heterogeneous_iterator __other) noexcept
|
||||
{
|
||||
__other += __count;
|
||||
return __other;
|
||||
}
|
||||
# endif // _CCCL_DOXYGEN_INVOKED
|
||||
|
||||
//! @brief Advance a \c heterogeneous_iterator by the negative value of \p __count
|
||||
//! @param __count The number of elements to advance.
|
||||
//! @return The heterogeneous_iterator advanced by the negative value of \p __count
|
||||
_CCCL_API constexpr heterogeneous_iterator& operator-=(const difference_type __count) noexcept
|
||||
{
|
||||
this->__ptr_ -= __count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Advance a \c heterogeneous_iterator by the negative value of \p __count
|
||||
//! @param __count The number of elements to advance.
|
||||
//! @return A copy of this heterogeneous_iterator advanced by the negative value of \p __count
|
||||
[[nodiscard]] _CCCL_API constexpr heterogeneous_iterator operator-(const difference_type __count) const noexcept
|
||||
{
|
||||
heterogeneous_iterator __temp = *this;
|
||||
__temp -= __count;
|
||||
return __temp;
|
||||
}
|
||||
|
||||
//! @brief Distance between two heterogeneous_iterator
|
||||
//! @param __other The other heterogeneous_iterator.
|
||||
//! @return The distance between the two elements the heterogeneous_iterator point to
|
||||
[[nodiscard]] _CCCL_API constexpr difference_type operator-(const heterogeneous_iterator& __other) const noexcept
|
||||
{
|
||||
return static_cast<difference_type>(this->__ptr_ - __other.__ptr_);
|
||||
}
|
||||
|
||||
# ifndef _CCCL_DOXYGEN_INVOKED // Do not document
|
||||
//! @brief Equality comparison between two heterogeneous_iterator
|
||||
//! @param __lhs A heterogeneous_iterator.
|
||||
//! @param __rhs Another heterogeneous_iterator.
|
||||
//! @return true, if both heterogeneous_iterator point to the same element
|
||||
[[nodiscard]] _CCCL_API friend constexpr bool
|
||||
operator==(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ == __rhs.__ptr_;
|
||||
}
|
||||
# if _CCCL_STD_VER <= 2017
|
||||
//! @brief Inequality comparison between two heterogeneous_iterator
|
||||
//! @param __lhs A heterogeneous_iterator.
|
||||
//! @param __rhs Another heterogeneous_iterator.
|
||||
//! @return false, if both heterogeneous_iterator point to the same element
|
||||
[[nodiscard]] _CCCL_API friend constexpr bool
|
||||
operator!=(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ != __rhs.__ptr_;
|
||||
}
|
||||
# endif // _CCCL_STD_VER <= 2017
|
||||
|
||||
# if _LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
|
||||
[[nodiscard]] _CCCL_API friend constexpr ::cuda::std::strong_ordering
|
||||
operator<=>(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ <=> __rhs.__ptr_;
|
||||
}
|
||||
# else // ^^^ _LIBCUDACXX_HAS_SPACESHIP_OPERATOR() ^^^ / vvv !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR() vvv
|
||||
//! @brief Less than relation between two heterogeneous_iterator
|
||||
//! @param __lhs A heterogeneous_iterator.
|
||||
//! @param __rhs Another heterogeneous_iterator.
|
||||
//! @return true, if the address of the element pointed to by \p __lhs is less then the address of the one pointed to
|
||||
//! by \p __rhs
|
||||
[[nodiscard]] _CCCL_API friend constexpr bool
|
||||
operator<(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ < __rhs.__ptr_;
|
||||
}
|
||||
//! @brief Less equal relation between two heterogeneous_iterator
|
||||
//! @param __lhs A heterogeneous_iterator.
|
||||
//! @param __rhs Another heterogeneous_iterator.
|
||||
//! @return true, if the address of the element pointed to by \p __lhs is less then or equal to the address of the one
|
||||
//! pointed to by \p __rhs
|
||||
[[nodiscard]] _CCCL_API friend constexpr bool
|
||||
operator<=(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ <= __rhs.__ptr_;
|
||||
}
|
||||
//! @brief Greater then relation between two heterogeneous_iterator
|
||||
//! @param __lhs A heterogeneous_iterator.
|
||||
//! @param __rhs Another heterogeneous_iterator.
|
||||
//! @return true, if the address of the element pointed to by \p __lhs is greater then the address of the one
|
||||
//! pointed to by \p __rhs
|
||||
[[nodiscard]] _CCCL_API friend constexpr bool
|
||||
operator>(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ > __rhs.__ptr_;
|
||||
}
|
||||
//! @brief Greater equal relation between two heterogeneous_iterator
|
||||
//! @param __lhs A heterogeneous_iterator.
|
||||
//! @param __rhs Another heterogeneous_iterator.
|
||||
//! @return true, if the address of the element pointed to by \p __lhs is greater then or equal to the address of the
|
||||
//! one pointed to by \p __rhs
|
||||
[[nodiscard]] _CCCL_API friend constexpr bool
|
||||
operator>=(const heterogeneous_iterator& __lhs, const heterogeneous_iterator& __rhs) noexcept
|
||||
{
|
||||
return __lhs.__ptr_ >= __rhs.__ptr_;
|
||||
}
|
||||
# endif // !_LIBCUDACXX_HAS_SPACESHIP_OPERATOR()
|
||||
# endif // _CCCL_DOXYGEN_INVOKED
|
||||
|
||||
_CCCL_API constexpr pointer __unwrap() const noexcept
|
||||
{
|
||||
return this->__ptr_;
|
||||
}
|
||||
};
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA_STD
|
||||
|
||||
// Here be dragons: We need to ensure that the iterator can work with legacy interfaces that take a pointer.
|
||||
// This will obviously eat all of our execution checks
|
||||
template <class _Tp, class... _Properties>
|
||||
struct pointer_traits<::cuda::heterogeneous_iterator<_Tp, _Properties...>>
|
||||
{
|
||||
using pointer = ::cuda::heterogeneous_iterator<_Tp, _Properties...>;
|
||||
using element_type = _Tp;
|
||||
using difference_type = ::cuda::std::ptrdiff_t;
|
||||
|
||||
//! @brief Retrieve the address of the element pointed at by an heterogeneous_iterator
|
||||
//! @param __iter A heterogeneous_iterator.
|
||||
//! @return A pointer to the element pointed to by the heterogeneous_iterator
|
||||
[[nodiscard]] _CCCL_API static constexpr element_type* to_address(const pointer __iter) noexcept
|
||||
{
|
||||
return ::cuda::std::to_address(__iter.__unwrap());
|
||||
}
|
||||
};
|
||||
|
||||
_CCCL_END_NAMESPACE_CUDA_STD
|
||||
|
||||
# include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CCCL_HAS_CTK()
|
||||
|
||||
#endif //__CUDAX__CONTAINERS_HETEROGENEOUS_ITERATOR_CUH
|
||||
@@ -0,0 +1,127 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of libcu++, the C++ Standard Library for your entire system,
|
||||
// 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___CONTAINER_MAKE_BUFFER_WITH_POOL_H
|
||||
#define _CUDA___CONTAINER_MAKE_BUFFER_WITH_POOL_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
|
||||
|
||||
#if _CCCL_HAS_CTK()
|
||||
|
||||
# include <cuda/__container/buffer.h>
|
||||
# include <cuda/__memory_pool/device_memory_pool.h>
|
||||
|
||||
# if _CCCL_CTK_AT_LEAST(12, 9)
|
||||
# include <cuda/__memory_pool/pinned_memory_pool.h>
|
||||
# endif // _CCCL_CTK_AT_LEAST(12, 9)
|
||||
|
||||
# if _CCCL_CTK_AT_LEAST(13, 0)
|
||||
# include <cuda/__memory_pool/managed_memory_pool.h>
|
||||
# endif // _CCCL_CTK_AT_LEAST(13, 0)
|
||||
|
||||
# include <cuda/std/__execution/env.h>
|
||||
# include <cuda/std/__utility/forward.h>
|
||||
# include <cuda/std/initializer_list>
|
||||
|
||||
# include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
|
||||
//! @brief Creates a buffer backed by the default device memory pool.
|
||||
//! @param __stream The stream used for allocation.
|
||||
//! @param __device The device whose default memory pool will be used.
|
||||
//! @param __args Remaining arguments forwarded to `make_buffer`.
|
||||
//! @see make_buffer for the full set of supported argument combinations.
|
||||
template <class _Tp, class... _Args>
|
||||
_CCCL_HOST_API auto make_device_buffer(stream_ref __stream, device_ref __device, _Args&&... __args)
|
||||
{
|
||||
return ::cuda::make_buffer<_Tp>(
|
||||
__stream, ::cuda::device_default_memory_pool(__device), ::cuda::std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
//! @brief Creates a buffer backed by the default device memory pool from an initializer_list.
|
||||
//! @param __stream The stream used for allocation.
|
||||
//! @param __device The device whose default memory pool will be used.
|
||||
//! @param __ilist The initializer_list being copied into the buffer.
|
||||
//! @param __env The environment providing additional configuration.
|
||||
template <class _Tp, class _Env = ::cuda::std::execution::env<>>
|
||||
_CCCL_HOST_API auto make_device_buffer(
|
||||
stream_ref __stream, device_ref __device, ::cuda::std::initializer_list<_Tp> __ilist, const _Env& __env = {})
|
||||
{
|
||||
return ::cuda::make_buffer<_Tp>(__stream, ::cuda::device_default_memory_pool(__device), __ilist, __env);
|
||||
}
|
||||
|
||||
# if _CCCL_CTK_AT_LEAST(12, 9)
|
||||
|
||||
//! @brief Creates a buffer backed by the default pinned memory pool.
|
||||
//! @param __stream The stream used for allocation.
|
||||
//! @param __args Remaining arguments forwarded to `make_buffer`.
|
||||
//! @see make_buffer for the full set of supported argument combinations.
|
||||
template <class _Tp, class... _Args>
|
||||
_CCCL_HOST_API auto make_pinned_buffer(stream_ref __stream, _Args&&... __args)
|
||||
{
|
||||
return ::cuda::make_buffer<_Tp>(
|
||||
__stream, ::cuda::pinned_default_memory_pool(), ::cuda::std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
//! @brief Creates a buffer backed by the default pinned memory pool from an initializer_list.
|
||||
//! @param __stream The stream used for allocation.
|
||||
//! @param __ilist The initializer_list being copied into the buffer.
|
||||
//! @param __env The environment providing additional configuration.
|
||||
template <class _Tp, class _Env = ::cuda::std::execution::env<>>
|
||||
_CCCL_HOST_API auto
|
||||
make_pinned_buffer(stream_ref __stream, ::cuda::std::initializer_list<_Tp> __ilist, const _Env& __env = {})
|
||||
{
|
||||
return ::cuda::make_buffer<_Tp>(__stream, ::cuda::pinned_default_memory_pool(), __ilist, __env);
|
||||
}
|
||||
|
||||
# endif // _CCCL_CTK_AT_LEAST(12, 9)
|
||||
|
||||
# if _CCCL_CTK_AT_LEAST(13, 0)
|
||||
|
||||
//! @brief Creates a buffer backed by the default managed memory pool.
|
||||
//! @param __stream The stream used for allocation.
|
||||
//! @param __args Remaining arguments forwarded to `make_buffer`.
|
||||
//! @see make_buffer for the full set of supported argument combinations.
|
||||
template <class _Tp, class... _Args>
|
||||
_CCCL_HOST_API auto make_managed_buffer(stream_ref __stream, _Args&&... __args)
|
||||
{
|
||||
return ::cuda::make_buffer<_Tp>(
|
||||
__stream, ::cuda::managed_default_memory_pool(), ::cuda::std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
//! @brief Creates a buffer backed by the default managed memory pool from an initializer_list.
|
||||
//! @param __stream The stream used for allocation.
|
||||
//! @param __ilist The initializer_list being copied into the buffer.
|
||||
//! @param __env The environment providing additional configuration.
|
||||
template <class _Tp, class _Env = ::cuda::std::execution::env<>>
|
||||
_CCCL_HOST_API auto
|
||||
make_managed_buffer(stream_ref __stream, ::cuda::std::initializer_list<_Tp> __ilist, const _Env& __env = {})
|
||||
{
|
||||
return ::cuda::make_buffer<_Tp>(__stream, ::cuda::managed_default_memory_pool(), __ilist, __env);
|
||||
}
|
||||
|
||||
# endif // _CCCL_CTK_AT_LEAST(13, 0)
|
||||
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
# include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CCCL_HAS_CTK()
|
||||
|
||||
#endif // _CUDA___CONTAINER_MAKE_BUFFER_WITH_POOL_H
|
||||
@@ -0,0 +1,211 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of libcu++, the C++ Standard Library for your entire system,
|
||||
// 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___CONTAINER_RESIZABLE_BUFFER_H
|
||||
#define _CUDA___CONTAINER_RESIZABLE_BUFFER_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
|
||||
|
||||
#if _CCCL_HAS_CTK()
|
||||
|
||||
# include <cuda/__container/buffer.h>
|
||||
# include <cuda/std/__host_stdlib/stdexcept>
|
||||
# include <cuda/std/__memory/addressof.h>
|
||||
# include <cuda/std/__utility/exchange.h>
|
||||
# include <cuda/std/__utility/move.h>
|
||||
# include <cuda/std/__utility/swap.h>
|
||||
|
||||
# include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
_CCCL_BEGIN_NAMESPACE_ABI_VER4_BUMP
|
||||
|
||||
//! @brief Internal buffer adapter that tracks allocation capacity separately
|
||||
//! from logical size.
|
||||
//!
|
||||
//! `cuda::__resizable_buffer` preserves the `cuda::buffer` interface through
|
||||
//! public inheritance. The inherited `size()` remains the logical number of
|
||||
//! elements, while `capacity()` is the number of elements that can be addressed
|
||||
//! without reallocating.
|
||||
template <class _Tp, class... _Properties>
|
||||
class __resizable_buffer : public buffer<_Tp, _Properties...>
|
||||
{
|
||||
using __base_t = buffer<_Tp, _Properties...>;
|
||||
|
||||
public:
|
||||
using size_type = typename __base_t::size_type;
|
||||
|
||||
private:
|
||||
size_type __capacity_ = static_cast<const __base_t&>(*this).size();
|
||||
|
||||
_CCCL_HOST_API void __replace_allocation(::cuda::stream_ref __stream, size_type __new_capacity)
|
||||
{
|
||||
const auto __old_size = this->size();
|
||||
const auto __old_capacity = __capacity_;
|
||||
_CCCL_ASSERT(__old_size <= __new_capacity,
|
||||
"cuda::__resizable_buffer reallocation capacity must be at least the current size");
|
||||
|
||||
auto __old_buffer = __base_t::__replace_allocation(__stream, __new_capacity);
|
||||
__capacity_ = __new_capacity;
|
||||
__old_buffer.__set_size_unsynchronized(__old_capacity);
|
||||
|
||||
if (__old_size != 0)
|
||||
{
|
||||
::cuda::__copy_cross_buffers(__stream, *this, __old_buffer, __old_size);
|
||||
// Free on the copy stream so the stream-ordered deallocation happens
|
||||
// after the read from the old allocation.
|
||||
__old_buffer.destroy(__stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
__old_buffer.destroy();
|
||||
}
|
||||
|
||||
__base_t::__set_size_unsynchronized(__old_size);
|
||||
}
|
||||
|
||||
_CCCL_HOST_API void __replace_allocation_discard(::cuda::stream_ref __stream, size_type __new_capacity)
|
||||
{
|
||||
const auto __old_capacity = ::cuda::std::exchange(__capacity_, 0);
|
||||
__base_t::__replace_allocation_discard(__stream, __new_capacity, __old_capacity);
|
||||
__capacity_ = __new_capacity;
|
||||
}
|
||||
|
||||
public:
|
||||
using __base_t::__base_t;
|
||||
|
||||
//! @brief Constructs a resizable buffer by taking over an existing
|
||||
//! `cuda::buffer` allocation.
|
||||
//!
|
||||
//! The initial capacity is the source buffer size.
|
||||
_CCCL_HOST_API explicit __resizable_buffer(__base_t&& __buffer) noexcept
|
||||
: __base_t(::cuda::std::move(__buffer))
|
||||
{}
|
||||
|
||||
__resizable_buffer(const __resizable_buffer&) = delete;
|
||||
__resizable_buffer& operator=(const __resizable_buffer&) = delete;
|
||||
|
||||
_CCCL_HOST_API __resizable_buffer(__resizable_buffer&& __other) noexcept
|
||||
: __base_t(::cuda::std::move(__other))
|
||||
, __capacity_(::cuda::std::exchange(__other.__capacity_, 0))
|
||||
{}
|
||||
|
||||
_CCCL_HOST_API __resizable_buffer& operator=(__resizable_buffer&& __other) noexcept
|
||||
{
|
||||
if (this != ::cuda::std::addressof(__other))
|
||||
{
|
||||
__base_t::__set_size_unsynchronized(__capacity_);
|
||||
__base_t::operator=(::cuda::std::move(__other));
|
||||
__capacity_ = ::cuda::std::exchange(__other.__capacity_, 0);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_CCCL_HOST_API ~__resizable_buffer() noexcept
|
||||
{
|
||||
__base_t::__set_size_unsynchronized(__capacity_);
|
||||
}
|
||||
|
||||
//! @brief Returns the number of elements that fit in the current allocation
|
||||
//! without reallocating.
|
||||
[[nodiscard]] _CCCL_HOST_API size_type capacity() const noexcept
|
||||
{
|
||||
return __capacity_;
|
||||
}
|
||||
|
||||
//! @brief Returns `capacity() * sizeof(value_type)`.
|
||||
[[nodiscard]] _CCCL_HOST_API size_type capacity_bytes() const noexcept
|
||||
{
|
||||
return __capacity_ * sizeof(_Tp);
|
||||
}
|
||||
|
||||
//! @brief Changes the logical size without stream ordering or reallocating.
|
||||
//!
|
||||
//! This member only updates the host-side logical size. It can shrink or grow
|
||||
//! within `capacity()`, and throws if growth would require reallocation.
|
||||
_CCCL_HOST_API void resize_unsynchronized(size_type __new_size, ::cuda::no_init_t)
|
||||
{
|
||||
if (__new_size > __capacity_)
|
||||
{
|
||||
_CCCL_THROW(::std::invalid_argument,
|
||||
"cuda::__resizable_buffer::resize_unsynchronized cannot grow beyond capacity");
|
||||
}
|
||||
__base_t::__set_size_unsynchronized(__new_size);
|
||||
}
|
||||
|
||||
//! @brief Changes the logical size, reallocating on \p __stream if needed.
|
||||
//!
|
||||
//! If reallocation is needed, existing logical elements are copied to the new
|
||||
//! allocation and newly exposed elements are left uninitialized.
|
||||
_CCCL_HOST_API void resize(::cuda::stream_ref __stream, size_type __new_size, ::cuda::no_init_t)
|
||||
{
|
||||
if (__new_size > __capacity_)
|
||||
{
|
||||
__replace_allocation(__stream, __new_size);
|
||||
}
|
||||
__base_t::__set_size_unsynchronized(__new_size);
|
||||
}
|
||||
|
||||
//! @brief Changes the logical size, reallocating on \p __stream if needed,
|
||||
//! without preserving existing contents.
|
||||
//!
|
||||
//! All elements in the resulting logical range are left uninitialized.
|
||||
_CCCL_HOST_API void resize_discard(::cuda::stream_ref __stream, size_type __new_size, ::cuda::no_init_t)
|
||||
{
|
||||
if (__new_size > __capacity_)
|
||||
{
|
||||
__replace_allocation_discard(__stream, __new_size);
|
||||
}
|
||||
__base_t::__set_size_unsynchronized(__new_size);
|
||||
}
|
||||
|
||||
//! @brief Swaps the allocation, logical size, stream, memory resource, and
|
||||
//! capacity with \p __other.
|
||||
_CCCL_HOST_API void swap(__resizable_buffer& __other) noexcept
|
||||
{
|
||||
__base_t::swap(__other);
|
||||
::cuda::std::swap(__capacity_, __other.__capacity_);
|
||||
}
|
||||
|
||||
_CCCL_HOST_API friend void swap(__resizable_buffer& __lhs, __resizable_buffer& __rhs) noexcept
|
||||
{
|
||||
__lhs.swap(__rhs);
|
||||
}
|
||||
|
||||
//! @brief Destroys the allocation using capacity rather than logical size.
|
||||
_CCCL_HOST_API void destroy(::cuda::stream_ref __stream) noexcept
|
||||
{
|
||||
__base_t::__set_size_unsynchronized(__capacity_);
|
||||
__base_t::destroy(__stream);
|
||||
__capacity_ = 0;
|
||||
}
|
||||
|
||||
_CCCL_HOST_API void destroy() noexcept
|
||||
{
|
||||
destroy(this->stream());
|
||||
}
|
||||
};
|
||||
|
||||
_CCCL_END_NAMESPACE_ABI_VER4_BUMP
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
# include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CCCL_HAS_CTK()
|
||||
|
||||
#endif // _CUDA___CONTAINER_RESIZABLE_BUFFER_H
|
||||
@@ -0,0 +1,477 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __CUDAX__CONTAINERS_UNINITIALIZED_ASYNC_BUFFER_H
|
||||
#define __CUDAX__CONTAINERS_UNINITIALIZED_ASYNC_BUFFER_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
|
||||
|
||||
#if _CCCL_HAS_CTK()
|
||||
|
||||
# include <cuda/__memory_resource/allocation_alignment.h>
|
||||
# include <cuda/__memory_resource/any_resource.h>
|
||||
# include <cuda/__memory_resource/properties.h>
|
||||
# include <cuda/__stream/stream_ref.h>
|
||||
# include <cuda/std/__memory/addressof.h>
|
||||
# include <cuda/std/__memory/align.h>
|
||||
# include <cuda/std/__new/launder.h>
|
||||
# include <cuda/std/__type_traits/type_set.h>
|
||||
# include <cuda/std/__utility/exchange.h>
|
||||
# include <cuda/std/__utility/move.h>
|
||||
# include <cuda/std/__utility/swap.h>
|
||||
# include <cuda/std/span>
|
||||
|
||||
# include <cuda/std/__cccl/prologue.h>
|
||||
|
||||
//! @file
|
||||
//! The \c __uninitialized_async_buffer class provides a typed buffer allocated
|
||||
//! in stream-order from a given memory resource.
|
||||
_CCCL_BEGIN_NAMESPACE_CUDA
|
||||
|
||||
//! @rst
|
||||
//! .. _libcudacxx-containers-uninitialized-async-buffer:
|
||||
//!
|
||||
//! Uninitialized stream-ordered type-safe memory storage
|
||||
//! ------------------------------------------------------
|
||||
//!
|
||||
//! ``__uninitialized_async_buffer`` provides a typed buffer allocated in stream
|
||||
//! order from a given :ref:`async memory resource
|
||||
//! <libcudacxx-extended-api-memory-resources-resource>`. It handles alignment
|
||||
//! and release of the allocation. The memory is uninitialized, so that a user
|
||||
//! needs to ensure elements are properly constructed.
|
||||
//!
|
||||
//! In addition to being type safe, ``__uninitialized_async_buffer`` also takes
|
||||
//! a set of :ref:`properties
|
||||
//! <libcudacxx-extended-api-memory-resources-properties>` to ensure that e.g.
|
||||
//! execution space constraints are checked at compile time. However, only
|
||||
//! stateless properties can be forwarded. To use a stateful property, implement
|
||||
//! :ref:`get_property(const __uninitialized_async_buffer&, Property)
|
||||
//! <libcudacxx-extended-api-memory-resources-properties>`.
|
||||
//!
|
||||
//! .. warning::
|
||||
//!
|
||||
//! ``__uninitialized_async_buffer`` uses `stream-ordered allocation
|
||||
//! <https://developer.nvidia.com/blog/using-cuda-stream-ordered-memory-allocator-part-1/>`__.
|
||||
//! It is the user's responsibility to ensure the lifetime of both the
|
||||
//! provided async resource and the stream exceed the lifetime of the buffer.
|
||||
//!
|
||||
//! @endrst
|
||||
//! @tparam _Tp the type to be stored in the buffer
|
||||
//! @tparam _Properties... The properties the allocated memory satisfies
|
||||
template <class _Tp, class... _Properties>
|
||||
class __uninitialized_async_buffer
|
||||
{
|
||||
private:
|
||||
static_assert(::cuda::mr::__contains_execution_space_property<_Properties...>,
|
||||
"The properties of cuda::__uninitialized_async_buffer must contain at least one execution space "
|
||||
"property!");
|
||||
|
||||
using __async_resource = ::cuda::mr::any_resource<_Properties...>;
|
||||
|
||||
__async_resource __mr_;
|
||||
::cuda::stream_ref __stream_ = {::cudaStream_t{}};
|
||||
size_t __count_ = 0;
|
||||
size_t __alignment_ = alignof(_Tp);
|
||||
void* __buf_ = nullptr;
|
||||
|
||||
template <class, class...>
|
||||
friend class __uninitialized_async_buffer;
|
||||
|
||||
//! @brief Helper to check whether a different buffer still satisfies all
|
||||
//! properties of this one
|
||||
template <class... _OtherProperties>
|
||||
static constexpr bool __properties_match =
|
||||
!::cuda::std::is_same_v<::cuda::std::__make_type_set<_Properties...>,
|
||||
::cuda::std::__make_type_set<_OtherProperties...>>
|
||||
&& ::cuda::std::__type_set_contains_v<::cuda::std::__make_type_set<_OtherProperties...>, _Properties...>;
|
||||
|
||||
//! @brief Determines the allocation size given the alignment and size of `T`
|
||||
[[nodiscard]] _CCCL_HOST_API size_t __get_allocation_size(const size_t __count) const noexcept
|
||||
{
|
||||
return (__count * sizeof(_Tp) + (__alignment_ - 1)) & ~(__alignment_ - 1);
|
||||
}
|
||||
|
||||
//! @brief Determines the properly aligned start of the buffer given the
|
||||
//! alignment and size of `T`
|
||||
[[nodiscard]] _CCCL_HOST_API _Tp* __get_data() const noexcept
|
||||
{
|
||||
size_t __space = __get_allocation_size(__count_);
|
||||
void* __ptr = __buf_;
|
||||
return ::cuda::std::launder(
|
||||
static_cast<_Tp*>(::cuda::std::align(__alignment_, __count_ * sizeof(_Tp), __ptr, __space)));
|
||||
}
|
||||
|
||||
//! @brief Causes the buffer to be treated as a span when passed to
|
||||
//! cuda::launch.
|
||||
//! @pre The buffer must have the cuda::mr::device_accessible property.
|
||||
template <class _Tp2 = _Tp>
|
||||
[[nodiscard]] _CCCL_HOST_API friend auto
|
||||
transform_launch_argument(::cuda::stream_ref, __uninitialized_async_buffer& __self) noexcept
|
||||
_CCCL_TRAILING_REQUIRES(::cuda::std::span<_Tp>)(
|
||||
::cuda::std::same_as<_Tp, _Tp2>&& ::cuda::std::__is_included_in_v<::cuda::mr::device_accessible, _Properties...>)
|
||||
{
|
||||
return {__self.__get_data(), __self.size()};
|
||||
}
|
||||
|
||||
//! @brief Causes the buffer to be treated as a span when passed to
|
||||
//! cuda::launch
|
||||
//! @pre The buffer must have the cuda::mr::device_accessible property.
|
||||
template <class _Tp2 = _Tp>
|
||||
[[nodiscard]] _CCCL_HOST_API friend auto
|
||||
transform_launch_argument(::cuda::stream_ref, const __uninitialized_async_buffer& __self) noexcept
|
||||
_CCCL_TRAILING_REQUIRES(::cuda::std::span<const _Tp>)(
|
||||
::cuda::std::same_as<_Tp, _Tp2>&& ::cuda::std::__is_included_in_v<::cuda::mr::device_accessible, _Properties...>)
|
||||
{
|
||||
return {__self.__get_data(), __self.size()};
|
||||
}
|
||||
|
||||
# ifndef _CCCL_DOXYGEN_INVOKED
|
||||
// This is needed to ensure that we do not do a deep copy in
|
||||
// __replace_allocation
|
||||
struct __fake_resource_ref
|
||||
{
|
||||
__async_resource* __resource_;
|
||||
|
||||
void* allocate_sync(std::size_t __size, std::size_t __alignment)
|
||||
{
|
||||
return __resource_->allocate_sync(__size, __alignment);
|
||||
}
|
||||
|
||||
void deallocate_sync(void* __ptr, std::size_t __size, std::size_t __alignment) noexcept
|
||||
{
|
||||
__resource_->deallocate_sync(__ptr, __size, __alignment);
|
||||
}
|
||||
|
||||
void* allocate(::cuda::stream_ref __stream, std::size_t __size, std::size_t __alignment)
|
||||
{
|
||||
return __resource_->allocate(__stream, __size, __alignment);
|
||||
}
|
||||
|
||||
void deallocate(::cuda::stream_ref __stream, void* __ptr, std::size_t __size, std::size_t __alignment) noexcept
|
||||
{
|
||||
__resource_->deallocate(__stream, __ptr, __size, __alignment);
|
||||
}
|
||||
|
||||
friend bool operator==(const __fake_resource_ref& __lhs, const __fake_resource_ref& __rhs) noexcept
|
||||
{
|
||||
return *__lhs.__resource_ == *__rhs.__resource_;
|
||||
}
|
||||
friend bool operator!=(const __fake_resource_ref& __lhs, const __fake_resource_ref& __rhs) noexcept
|
||||
{
|
||||
return *__lhs.__resource_ != *__rhs.__resource_;
|
||||
}
|
||||
|
||||
//! @brief Forwards the passed properties
|
||||
_CCCL_TEMPLATE(class _Property)
|
||||
_CCCL_REQUIRES(::cuda::std::__is_included_in_v<_Property, _Properties...>)
|
||||
_CCCL_HOST_API friend constexpr void get_property(const __fake_resource_ref&, _Property) noexcept {}
|
||||
};
|
||||
# endif // _CCCL_DOXYGEN_INVOKED
|
||||
|
||||
public:
|
||||
using value_type = _Tp;
|
||||
using reference = _Tp&;
|
||||
using const_reference = const _Tp&;
|
||||
using pointer = _Tp*;
|
||||
using const_pointer = const _Tp*;
|
||||
using size_type = size_t;
|
||||
|
||||
//! @brief Constructs an \c __uninitialized_async_buffer, allocating
|
||||
//! sufficient storage for \p __count elements through
|
||||
//! \p __mr
|
||||
//! @param __mr The async memory resource to allocate the buffer with.
|
||||
//! @param __stream The CUDA stream used for stream-ordered allocation.
|
||||
//! @param __count The desired size of the buffer.
|
||||
//! @note Depending on the alignment requirements of `T` the size of the
|
||||
//! underlying allocation might be larger than `count * sizeof(T)`. Only
|
||||
//! allocates memory when \p __count > 0
|
||||
_CCCL_HOST_API __uninitialized_async_buffer(
|
||||
__async_resource __mr,
|
||||
const ::cuda::stream_ref __stream,
|
||||
const size_t __count,
|
||||
const size_t __alignment = alignof(_Tp))
|
||||
: __mr_(::cuda::std::move(__mr))
|
||||
, __stream_(__stream)
|
||||
, __count_(__count)
|
||||
, __alignment_(__validate_alignment_param(__alignment))
|
||||
, __buf_(__count_ == 0 ? nullptr : __mr_.allocate(__stream_, __get_allocation_size(__count_), __alignment_))
|
||||
{}
|
||||
|
||||
private:
|
||||
static size_t __validate_alignment_param(size_t __a)
|
||||
{
|
||||
::cuda::__validate_allocation_alignment(__a, alignof(_Tp));
|
||||
return __a;
|
||||
}
|
||||
|
||||
public:
|
||||
__uninitialized_async_buffer(const __uninitialized_async_buffer&) = delete;
|
||||
__uninitialized_async_buffer& operator=(const __uninitialized_async_buffer&) = delete;
|
||||
|
||||
//! @brief Move-constructs a \c __uninitialized_async_buffer from \p __other
|
||||
//! @param __other Another \c __uninitialized_async_buffer
|
||||
//! Takes ownership of the allocation in \p __other and resets it
|
||||
_CCCL_HOST_API __uninitialized_async_buffer(__uninitialized_async_buffer&& __other) noexcept
|
||||
: __mr_(::cuda::std::move(__other.__mr_))
|
||||
, __stream_(::cuda::std::exchange(__other.__stream_, ::cuda::stream_ref{::cudaStream_t{}}))
|
||||
, __count_(::cuda::std::exchange(__other.__count_, 0))
|
||||
, __alignment_(::cuda::std::exchange(__other.__alignment_, alignof(_Tp)))
|
||||
, __buf_(::cuda::std::exchange(__other.__buf_, nullptr))
|
||||
{}
|
||||
|
||||
//! @brief Move-constructs a \c __uninitialized_async_buffer from \p __other
|
||||
//! @param __other Another \c __uninitialized_async_buffer with matching
|
||||
//! properties Takes ownership of the allocation in \p __other and resets it
|
||||
_CCCL_TEMPLATE(class... _OtherProperties)
|
||||
_CCCL_REQUIRES(__properties_match<_OtherProperties...>)
|
||||
_CCCL_HOST_API __uninitialized_async_buffer(__uninitialized_async_buffer<_Tp, _OtherProperties...>&& __other) noexcept
|
||||
: __mr_(::cuda::std::move(__other.__mr_))
|
||||
, __stream_(::cuda::std::exchange(__other.__stream_, ::cuda::stream_ref{::cudaStream_t{}}))
|
||||
, __count_(::cuda::std::exchange(__other.__count_, 0))
|
||||
, __alignment_(::cuda::std::exchange(__other.__alignment_, alignof(_Tp)))
|
||||
, __buf_(::cuda::std::exchange(__other.__buf_, nullptr))
|
||||
{}
|
||||
|
||||
//! @brief Move-assigns a \c __uninitialized_async_buffer from \p __other
|
||||
//! @param __other Another \c __uninitialized_async_buffer
|
||||
//! Deallocates the current allocation and then takes ownership of the
|
||||
//! allocation in \p __other and resets it
|
||||
_CCCL_HOST_API __uninitialized_async_buffer& operator=(__uninitialized_async_buffer&& __other) noexcept
|
||||
{
|
||||
if (this == ::cuda::std::addressof(__other))
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (__buf_)
|
||||
{
|
||||
__mr_.deallocate(__stream_, __buf_, __get_allocation_size(__count_), __alignment_);
|
||||
}
|
||||
__mr_ = ::cuda::std::move(__other.__mr_);
|
||||
__stream_ = ::cuda::std::exchange(__other.__stream_, ::cuda::stream_ref{::cudaStream_t{}});
|
||||
__count_ = ::cuda::std::exchange(__other.__count_, 0);
|
||||
__alignment_ = ::cuda::std::exchange(__other.__alignment_, alignof(_Tp));
|
||||
__buf_ = ::cuda::std::exchange(__other.__buf_, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! @brief Destroys an \c __uninitialized_async_buffer, deallocates the buffer
|
||||
//! in stream order on the stream that is stored in the buffer and destroys
|
||||
//! the memory resource.
|
||||
//! @param __stream The stream to deallocate the buffer on.
|
||||
//! @warning destroy does not destroy any objects that may or may not reside
|
||||
//! within the buffer. It is the user's responsibility to ensure that all
|
||||
//! objects within the buffer have been properly destroyed.
|
||||
_CCCL_HOST_API void destroy(::cuda::stream_ref __stream) noexcept
|
||||
{
|
||||
if (__buf_)
|
||||
{
|
||||
__mr_.deallocate(__stream, __buf_, __get_allocation_size(__count_), __alignment_);
|
||||
__buf_ = nullptr;
|
||||
__count_ = 0;
|
||||
}
|
||||
// TODO should we make sure we move the mr only once by moving it to the if
|
||||
// above? It won't work for 0 count buffers, so we would probably need a
|
||||
// separate bool to track it
|
||||
auto __tmp_mr = ::cuda::std::move(__mr_);
|
||||
}
|
||||
|
||||
//! @brief Destroys an \c __uninitialized_async_buffer, deallocates the buffer
|
||||
//! in stream order on the stream that is stored in the buffer and destroys
|
||||
//! the memory resource.
|
||||
//! @warning destroy does not destroy any objects that may or may not reside
|
||||
//! within the buffer. It is the user's responsibility to ensure that all
|
||||
//! objects within the buffer have been properly destroyed.
|
||||
_CCCL_HOST_API void destroy() noexcept
|
||||
{
|
||||
destroy(__stream_);
|
||||
}
|
||||
|
||||
# ifndef _CCCL_DOXYGEN_INVOKED
|
||||
_CCCL_HOST_API constexpr void __set_size(const size_t __count) noexcept
|
||||
{
|
||||
__count_ = __count;
|
||||
}
|
||||
# endif // _CCCL_DOXYGEN_INVOKED
|
||||
|
||||
//! @brief Destroys an \c __uninitialized_async_buffer and deallocates the
|
||||
//! buffer in stream order on the stream that was used to create the buffer.
|
||||
//! @warning The destructor does not destroy any objects that may or may not
|
||||
//! reside within the buffer. It is the user's responsibility to ensure that
|
||||
//! all objects within the buffer have been properly destroyed.
|
||||
_CCCL_HOST_API ~__uninitialized_async_buffer()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
//! @brief Returns an aligned pointer to the first element in the buffer
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr pointer begin() noexcept
|
||||
{
|
||||
return __get_data();
|
||||
}
|
||||
|
||||
//! @overload
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr const_pointer begin() const noexcept
|
||||
{
|
||||
return __get_data();
|
||||
}
|
||||
|
||||
//! @brief Returns an aligned pointer to the element following the last
|
||||
//! element of the buffer. This element acts as a placeholder; attempting to
|
||||
//! access it results in undefined behavior.
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr pointer end() noexcept
|
||||
{
|
||||
return __get_data() + __count_;
|
||||
}
|
||||
|
||||
//! @overload
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr const_pointer end() const noexcept
|
||||
{
|
||||
return __get_data() + __count_;
|
||||
}
|
||||
|
||||
//! @brief Returns an aligned pointer to the first element in the buffer
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr pointer data() noexcept
|
||||
{
|
||||
return __get_data();
|
||||
}
|
||||
|
||||
//! @overload
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr const_pointer data() const noexcept
|
||||
{
|
||||
return __get_data();
|
||||
}
|
||||
|
||||
//! @brief Returns the size of the buffer
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr size_type size() const noexcept
|
||||
{
|
||||
return __count_;
|
||||
}
|
||||
|
||||
//! @brief Returns the alignment used for the allocation
|
||||
[[nodiscard]] _CCCL_HIDE_FROM_ABI constexpr size_type alignment() const noexcept
|
||||
{
|
||||
return __alignment_;
|
||||
}
|
||||
|
||||
//! @brief Returns the size of the buffer in bytes
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr size_type size_bytes() const noexcept
|
||||
{
|
||||
return __count_ * sizeof(_Tp);
|
||||
}
|
||||
|
||||
//! @rst
|
||||
//! Returns a \c const reference to the :ref:`any_resource
|
||||
//! <cuda-memory-resource-any-async-resource>` that holds the memory resource
|
||||
//! used to allocate the buffer
|
||||
//! @endrst
|
||||
[[nodiscard]] _CCCL_HOST_API const __async_resource& memory_resource() const noexcept
|
||||
{
|
||||
return __mr_;
|
||||
}
|
||||
|
||||
//! @brief Returns the stored stream
|
||||
//! @note Stream used to allocate the buffer is initially stored in the
|
||||
//! buffer, but can be changed with `set_stream`
|
||||
[[nodiscard]] _CCCL_HOST_API constexpr ::cuda::stream_ref stream() const noexcept
|
||||
{
|
||||
return __stream_;
|
||||
}
|
||||
|
||||
//! @brief Replaces the stored stream
|
||||
//! @param __new_stream the new stream
|
||||
//! @note Always synchronizes with the old stream
|
||||
_CCCL_HOST_API constexpr void set_stream(::cuda::stream_ref __new_stream)
|
||||
{
|
||||
if (__new_stream != __stream_)
|
||||
{
|
||||
__stream_.sync();
|
||||
}
|
||||
__stream_ = __new_stream;
|
||||
}
|
||||
|
||||
//! @brief Replaces the stored stream
|
||||
//! @param __new_stream the new stream
|
||||
//! @warning This does not synchronize between \p __new_stream and the current
|
||||
//! stream. It is the user's responsibility to ensure proper stream order
|
||||
//! going forward
|
||||
_CCCL_HOST_API constexpr void set_stream_unsynchronized(::cuda::stream_ref __new_stream) noexcept
|
||||
{
|
||||
__stream_ = __new_stream;
|
||||
}
|
||||
|
||||
//! @brief Forwards the passed properties
|
||||
_CCCL_TEMPLATE(class _Property)
|
||||
_CCCL_REQUIRES((!property_with_value<_Property>) _CCCL_AND ::cuda::std::__is_included_in_v<_Property, _Properties...>)
|
||||
_CCCL_HOST_API friend constexpr void get_property(const __uninitialized_async_buffer&, _Property) noexcept {}
|
||||
|
||||
# ifndef _CCCL_DOXYGEN_INVOKED
|
||||
//! @brief Internal method to grow the allocation to a new size \p __count.
|
||||
//! @param __stream The stream to allocate the new allocation on.
|
||||
//! @param __count The new size of the allocation.
|
||||
//! @return An \c __uninitialized_async_buffer that holds the previous
|
||||
//! allocation
|
||||
//! @warning This buffer must outlive the returned buffer
|
||||
_CCCL_HOST_API __uninitialized_async_buffer __replace_allocation(::cuda::stream_ref __stream, const size_t __count)
|
||||
{
|
||||
// Create a new buffer with a reference to the stored memory resource and
|
||||
// swap allocation information
|
||||
__uninitialized_async_buffer __ret{
|
||||
__fake_resource_ref{::cuda::std::addressof(__mr_)}, __stream, __count, __alignment_};
|
||||
::cuda::std::swap(__count_, __ret.__count_);
|
||||
::cuda::std::swap(__alignment_, __ret.__alignment_);
|
||||
::cuda::std::swap(__buf_, __ret.__buf_);
|
||||
__ret.__stream_ = ::cuda::std::exchange(__stream_, __stream);
|
||||
return __ret;
|
||||
}
|
||||
|
||||
//! @overload
|
||||
_CCCL_HOST_API __uninitialized_async_buffer __replace_allocation(const size_t __count)
|
||||
{
|
||||
return __replace_allocation(__stream_, __count);
|
||||
}
|
||||
|
||||
_CCCL_HOST_API void
|
||||
__replace_allocation_discard(::cuda::stream_ref __stream, const size_t __count, const size_t __old_capacity)
|
||||
{
|
||||
if (__buf_)
|
||||
{
|
||||
__mr_.deallocate(__stream_, __buf_, __get_allocation_size(__old_capacity), __alignment_);
|
||||
__buf_ = nullptr;
|
||||
__count_ = 0;
|
||||
}
|
||||
|
||||
__stream_ = __stream;
|
||||
if (__count != 0)
|
||||
{
|
||||
__buf_ = __mr_.allocate(__stream_, __get_allocation_size(__count), __alignment_);
|
||||
}
|
||||
__count_ = __count;
|
||||
}
|
||||
# endif // _CCCL_DOXYGEN_INVOKED
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
using uninitialized_async_device_buffer = __uninitialized_async_buffer<_Tp, ::cuda::mr::device_accessible>;
|
||||
_CCCL_END_NAMESPACE_CUDA
|
||||
|
||||
# include <cuda/std/__cccl/epilogue.h>
|
||||
|
||||
#endif // _CCCL_HAS_CTK()
|
||||
|
||||
#endif //__CUDAX__CONTAINERS_UNINITIALIZED_ASYNC_BUFFER_H
|
||||
Reference in New Issue
Block a user