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
648 lines
24 KiB
Plaintext
648 lines
24 KiB
Plaintext
// SPDX-FileCopyrightText: Copyright (c) 2011-2021, NVIDIA CORPORATION. All rights reserved.
|
|
// SPDX-License-Identifier: BSD-3
|
|
|
|
//! @file
|
|
//! Operations for reading linear tiles of data into the CUDA warp.
|
|
|
|
#pragma once
|
|
|
|
#include <cub/config.cuh>
|
|
|
|
#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 <cub/block/block_load.cuh>
|
|
#include <cub/iterator/cache_modified_input_iterator.cuh>
|
|
#include <cub/util_ptx.cuh>
|
|
#include <cub/util_type.cuh>
|
|
#include <cub/warp/warp_exchange.cuh>
|
|
|
|
#include <cuda/__cmath/pow2.h>
|
|
#include <cuda/__ptx/instructions/get_sreg.h>
|
|
#include <cuda/std/__concepts/same_as.h>
|
|
#include <cuda/std/__fwd/format.h>
|
|
#include <cuda/std/__host_stdlib/ostream>
|
|
|
|
CUB_NAMESPACE_BEGIN
|
|
|
|
//! @rst
|
|
//! ``cub::WarpLoadAlgorithm`` enumerates alternative algorithms for :cpp:struct:`cub::WarpLoad` to
|
|
//! read a linear segment of data from memory into a CUDA warp.
|
|
//! @endrst
|
|
enum WarpLoadAlgorithm
|
|
{
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! A :ref:`blocked arrangement <flexible-data-arrangement>` of data is read directly from memory.
|
|
//!
|
|
//! Performance Considerations
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! The utilization of memory transactions (coalescing) decreases as the
|
|
//! access stride between threads increases (i.e., the number items per thread).
|
|
//! @endrst
|
|
WARP_LOAD_DIRECT,
|
|
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! A :ref:`striped arrangement <flexible-data-arrangement>` of data is read directly from memory.
|
|
//!
|
|
//! Performance Considerations
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! The utilization of memory transactions (coalescing) doesn't depend on
|
|
//! the number of items per thread.
|
|
//! @endrst
|
|
WARP_LOAD_STRIPED,
|
|
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! A :ref:`blocked arrangement <flexible-data-arrangement>` of data is read from memory using
|
|
//! CUDA's built-in vectorized loads as a coalescing optimization.
|
|
//! For example, ``ld.global.v4.s32`` instructions will be generated when ``T = int`` and
|
|
//! ``ITEMS_PER_THREAD % 4 == 0``.
|
|
//!
|
|
//! Performance Considerations
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! - The utilization of memory transactions (coalescing) remains high until the the
|
|
//! access stride between threads (i.e., the number items per thread) exceeds the
|
|
//! maximum vector load width (typically 4 items or 64B, whichever is lower).
|
|
//! - The following conditions will prevent vectorization and loading will fall
|
|
//! back to cub::WARP_LOAD_DIRECT:
|
|
//!
|
|
//! - ``ITEMS_PER_THREAD`` is odd
|
|
//! - The ``InputIteratorT`` is not a simple pointer type
|
|
//! - The block input offset is not quadword-aligned
|
|
//! - The data type ``T`` is not a built-in primitive or CUDA vector type
|
|
//! (e.g., ``short``, ``int2``, ``double``, ``float2``, etc.)
|
|
//! @endrst
|
|
WARP_LOAD_VECTORIZE,
|
|
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! A :ref:`striped arrangement <flexible-data-arrangement>` of data is read efficiently from
|
|
//! memory and then locally transposed into a
|
|
//! :ref:`blocked arrangement <flexible-data-arrangement>`.
|
|
//!
|
|
//! Performance Considerations
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! - The utilization of memory transactions (coalescing) remains high
|
|
//! regardless of items loaded per thread.
|
|
//! - The local reordering incurs slightly longer latencies and throughput than the direct
|
|
//! ``cub::WARP_LOAD_DIRECT`` and ``cub::WARP_LOAD_VECTORIZE`` alternatives.
|
|
//! @endrst
|
|
WARP_LOAD_TRANSPOSE
|
|
};
|
|
|
|
#if _CCCL_HOSTED()
|
|
namespace detail
|
|
{
|
|
[[nodiscard]] _CCCL_HOST_DEVICE_API constexpr const char* to_string(WarpLoadAlgorithm algo) noexcept
|
|
{
|
|
switch (algo)
|
|
{
|
|
case WARP_LOAD_DIRECT:
|
|
return "WARP_LOAD_DIRECT";
|
|
case WARP_LOAD_STRIPED:
|
|
return "WARP_LOAD_STRIPED";
|
|
case WARP_LOAD_VECTORIZE:
|
|
return "WARP_LOAD_VECTORIZE";
|
|
case WARP_LOAD_TRANSPOSE:
|
|
return "WARP_LOAD_TRANSPOSE";
|
|
}
|
|
return "<unknown WarpLoadAlgorithm>";
|
|
}
|
|
} // namespace detail
|
|
#endif // _CCCL_HOSTED()
|
|
|
|
#if _CCCL_HOSTED()
|
|
inline ::std::ostream& operator<<(::std::ostream& os, WarpLoadAlgorithm algo)
|
|
{
|
|
return os << CUB_NS_QUALIFIER::detail::to_string(algo);
|
|
}
|
|
#endif // _CCCL_HOSTED() && !_CCCL_DOXYGEN_INVOKED
|
|
|
|
CUB_NAMESPACE_END
|
|
|
|
#if __cpp_lib_format >= 201907L && !defined(_CCCL_DOXYGEN_INVOKED)
|
|
template <::cuda::std::same_as<char> CharT>
|
|
struct std::formatter<CUB_NS_QUALIFIER::WarpLoadAlgorithm, CharT> : formatter<const CharT*, CharT>
|
|
{
|
|
template <class FmtCtx>
|
|
auto format(const CUB_NS_QUALIFIER::WarpLoadAlgorithm& algo, FmtCtx& ctx) const
|
|
{
|
|
return formatter<const CharT*, CharT>::format(CUB_NS_QUALIFIER::detail::to_string(algo), ctx);
|
|
}
|
|
};
|
|
#endif // __cpp_lib_format >= 201907L && !defined(_CCCL_DOXYGEN_INVOKED)
|
|
|
|
CUB_NAMESPACE_BEGIN
|
|
|
|
//! @rst
|
|
//! The WarpLoad class provides :ref:`collective <collective-primitives>` data movement methods for
|
|
//! loading a linear segment of items from memory into a
|
|
//! :ref:`blocked arrangement <flexible-data-arrangement>` across a CUDA thread warp.
|
|
//!
|
|
//! Overview
|
|
//! ++++++++++++++++
|
|
//!
|
|
//! - The WarpLoad class provides a single data movement abstraction that can be
|
|
//! specialized to implement different cub::WarpLoadAlgorithm strategies. This
|
|
//! facilitates different performance policies for different architectures, data
|
|
//! types, granularity sizes, etc.
|
|
//! - WarpLoad can be optionally specialized by different data movement strategies:
|
|
//!
|
|
//! #. :cpp:enumerator:`cub::WARP_LOAD_DIRECT`:
|
|
//! a :ref:`blocked arrangement <flexible-data-arrangement>` of data is read directly from
|
|
//! memory.
|
|
//! #. :cpp:enumerator:`cub::WARP_LOAD_STRIPED`:
|
|
//! a :ref:`striped arrangement <flexible-data-arrangement>` of data is read directly from
|
|
//! memory.
|
|
//! #. :cpp:enumerator:`cub::WARP_LOAD_VECTORIZE`:
|
|
//! a :ref:`blocked arrangement <flexible-data-arrangement>` of data is read directly from
|
|
//! memory using CUDA's built-in vectorized loads as a coalescing optimization.
|
|
//! #. :cpp:enumerator:`cub::WARP_LOAD_TRANSPOSE`:
|
|
//! a :ref:`striped arrangement <flexible-data-arrangement>` of data is read directly from
|
|
//! memory and is then locally transposed into a
|
|
//! :ref:`blocked arrangement <flexible-data-arrangement>`.
|
|
//!
|
|
//! A Simple Example
|
|
//! ++++++++++++++++
|
|
//!
|
|
//! The code snippet below illustrates the loading of a linear segment of 64
|
|
//! integers into a "blocked" arrangement across 16 threads where each thread
|
|
//! owns 4 consecutive items. The load is specialized for ``WARP_LOAD_TRANSPOSE``,
|
|
//! meaning memory references are efficiently coalesced using a warp-striped access
|
|
//! pattern (after which items are locally reordered among threads).
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/warp/warp_load.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, ...)
|
|
//! {
|
|
//! constexpr int warp_threads = 16;
|
|
//! constexpr int threads_per_block = 256;
|
|
//! constexpr int items_per_thread = 4;
|
|
//!
|
|
//! // Specialize WarpLoad for a warp of 16 threads owning 4 integer items each
|
|
//! using WarpLoadT = WarpLoad<int,
|
|
//! items_per_thread,
|
|
//! cub::WARP_LOAD_TRANSPOSE,
|
|
//! warp_threads>;
|
|
//!
|
|
//! constexpr int warps_in_block = threads_per_block / warp_threads;
|
|
//! constexpr int tile_size = items_per_thread * warp_threads;
|
|
//! const int warp_id = static_cast<int>(threadIdx.x) / warp_threads;
|
|
//!
|
|
//! // Allocate shared memory for WarpLoad
|
|
//! __shared__ typename WarpLoadT::TempStorage temp_storage[warps_in_block];
|
|
//!
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[items_per_thread];
|
|
//! WarpLoadT(temp_storage[warp_id]).Load(d_data + warp_id * tile_size, thread_data);
|
|
//! }
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, ...``.
|
|
//! The set of ``thread_data`` across the first logical warp of threads in those
|
|
//! threads will be: ``{ [0,1,2,3], [4,5,6,7], ..., [60,61,62,63] }``.
|
|
//! @endrst
|
|
//!
|
|
//! @tparam InputT
|
|
//! The data type to read into (which must be convertible from the input
|
|
//! iterator's value type).
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ALGORITHM
|
|
//! <b>[optional]</b> cub::WarpLoadAlgorithm tuning policy.
|
|
//! default: cub::WARP_LOAD_DIRECT.
|
|
//!
|
|
//! @tparam LOGICAL_WARP_THREADS
|
|
//! <b>[optional]</b> The number of threads per "logical" warp (may be less
|
|
//! than the number of hardware warp threads). Default is the warp size of the
|
|
//! targeted CUDA compute-capability (e.g., 32 threads for SM86). Must be a
|
|
//! power of two.
|
|
//!
|
|
template <typename InputT,
|
|
int ITEMS_PER_THREAD,
|
|
WarpLoadAlgorithm ALGORITHM = WARP_LOAD_DIRECT,
|
|
int LOGICAL_WARP_THREADS = detail::warp_threads>
|
|
class WarpLoad
|
|
{
|
|
static constexpr bool IS_ARCH_WARP = LOGICAL_WARP_THREADS == detail::warp_threads;
|
|
|
|
static_assert(::cuda::is_power_of_two(LOGICAL_WARP_THREADS), "LOGICAL_WARP_THREADS must be a power of two");
|
|
|
|
private:
|
|
/*****************************************************************************
|
|
* Algorithmic variants
|
|
****************************************************************************/
|
|
|
|
/// Load helper
|
|
template <WarpLoadAlgorithm _POLICY, int DUMMY>
|
|
struct LoadInternal;
|
|
|
|
template <int DUMMY>
|
|
struct LoadInternal<WARP_LOAD_DIRECT, DUMMY>
|
|
{
|
|
using TempStorage = NullType;
|
|
|
|
int linear_tid;
|
|
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE LoadInternal(TempStorage& /*temp_storage*/, int linear_tid)
|
|
: linear_tid(linear_tid)
|
|
{}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
LoadDirectBlocked(linear_tid, block_itr, items);
|
|
}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items)
|
|
{
|
|
LoadDirectBlocked(linear_tid, block_itr, items, valid_items);
|
|
}
|
|
|
|
template <typename InputIteratorT, typename DefaultT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items, DefaultT oob_default)
|
|
{
|
|
LoadDirectBlocked(linear_tid, block_itr, items, valid_items, oob_default);
|
|
}
|
|
};
|
|
|
|
template <int DUMMY>
|
|
struct LoadInternal<WARP_LOAD_STRIPED, DUMMY>
|
|
{
|
|
using TempStorage = NullType;
|
|
|
|
int linear_tid;
|
|
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE LoadInternal(TempStorage& /*temp_storage*/, int linear_tid)
|
|
: linear_tid(linear_tid)
|
|
{}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
LoadDirectStriped<LOGICAL_WARP_THREADS>(linear_tid, block_itr, items);
|
|
}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items)
|
|
{
|
|
LoadDirectStriped<LOGICAL_WARP_THREADS>(linear_tid, block_itr, items, valid_items);
|
|
}
|
|
|
|
template <typename InputIteratorT, typename DefaultT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items, DefaultT oob_default)
|
|
{
|
|
LoadDirectStriped<LOGICAL_WARP_THREADS>(linear_tid, block_itr, items, valid_items, oob_default);
|
|
}
|
|
};
|
|
|
|
template <int DUMMY>
|
|
struct LoadInternal<WARP_LOAD_VECTORIZE, DUMMY>
|
|
{
|
|
using TempStorage = NullType;
|
|
|
|
int linear_tid;
|
|
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE LoadInternal(TempStorage& /*temp_storage*/, int linear_tid)
|
|
: linear_tid(linear_tid)
|
|
{}
|
|
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(InputT* block_ptr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, block_ptr, items);
|
|
}
|
|
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(const InputT* block_ptr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, block_ptr, items);
|
|
}
|
|
|
|
template <CacheLoadModifier MODIFIER, typename ValueType, typename OffsetT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(CacheModifiedInputIterator<MODIFIER, ValueType, OffsetT> block_itr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
InternalLoadDirectBlockedVectorized<MODIFIER>(linear_tid, block_itr.ptr, items);
|
|
}
|
|
|
|
template <typename _InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(_InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
LoadDirectBlocked(linear_tid, block_itr, items);
|
|
}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items)
|
|
{
|
|
LoadDirectBlocked(linear_tid, block_itr, items, valid_items);
|
|
}
|
|
|
|
template <typename InputIteratorT, typename DefaultT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items, DefaultT oob_default)
|
|
{
|
|
LoadDirectBlocked(linear_tid, block_itr, items, valid_items, oob_default);
|
|
}
|
|
};
|
|
|
|
template <int DUMMY>
|
|
struct LoadInternal<WARP_LOAD_TRANSPOSE, DUMMY>
|
|
{
|
|
using WarpExchangeT = WarpExchange<InputT, ITEMS_PER_THREAD, LOGICAL_WARP_THREADS>;
|
|
|
|
struct _TempStorage : WarpExchangeT::TempStorage
|
|
{};
|
|
|
|
struct TempStorage : Uninitialized<_TempStorage>
|
|
{};
|
|
|
|
_TempStorage& temp_storage;
|
|
|
|
int linear_tid;
|
|
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE LoadInternal(TempStorage& temp_storage, int linear_tid)
|
|
: temp_storage(temp_storage.Alias())
|
|
, linear_tid(linear_tid)
|
|
{}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
LoadDirectStriped<LOGICAL_WARP_THREADS>(linear_tid, block_itr, items);
|
|
WarpExchangeT(temp_storage).StripedToBlocked(items, items);
|
|
}
|
|
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items)
|
|
{
|
|
LoadDirectStriped<LOGICAL_WARP_THREADS>(linear_tid, block_itr, items, valid_items);
|
|
WarpExchangeT(temp_storage).StripedToBlocked(items, items);
|
|
}
|
|
|
|
template <typename InputIteratorT, typename DefaultT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items, DefaultT oob_default)
|
|
{
|
|
LoadDirectStriped<LOGICAL_WARP_THREADS>(linear_tid, block_itr, items, valid_items, oob_default);
|
|
WarpExchangeT(temp_storage).StripedToBlocked(items, items);
|
|
}
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* Type definitions
|
|
****************************************************************************/
|
|
|
|
/// Internal load implementation to use
|
|
using InternalLoad = LoadInternal<ALGORITHM, 0>;
|
|
|
|
/// Shared memory storage layout type
|
|
using _TempStorage = typename InternalLoad::TempStorage;
|
|
|
|
/*****************************************************************************
|
|
* Utility methods
|
|
****************************************************************************/
|
|
|
|
/// Internal storage allocator
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE _TempStorage& PrivateStorage()
|
|
{
|
|
__shared__ _TempStorage private_storage;
|
|
return private_storage;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Thread fields
|
|
****************************************************************************/
|
|
|
|
/// Thread reference to shared storage
|
|
_TempStorage& temp_storage;
|
|
|
|
/// Linear thread-id
|
|
int linear_tid;
|
|
|
|
public:
|
|
/// @smemstorage{WarpLoad}
|
|
struct TempStorage : Uninitialized<_TempStorage>
|
|
{};
|
|
|
|
//! @name Collective constructors
|
|
//! @{
|
|
|
|
//! @brief Collective constructor using a private static allocation of
|
|
//! shared memory as temporary storage.
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE WarpLoad()
|
|
: temp_storage(PrivateStorage())
|
|
, linear_tid(
|
|
IS_ARCH_WARP ? ::cuda::ptx::get_sreg_laneid() : (::cuda::ptx::get_sreg_laneid() % LOGICAL_WARP_THREADS))
|
|
{}
|
|
|
|
//! @brief Collective constructor using the specified memory allocation as
|
|
//! temporary storage.
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE WarpLoad(TempStorage& temp_storage)
|
|
: temp_storage(temp_storage.Alias())
|
|
, linear_tid(
|
|
IS_ARCH_WARP ? ::cuda::ptx::get_sreg_laneid() : (::cuda::ptx::get_sreg_laneid() % LOGICAL_WARP_THREADS))
|
|
{}
|
|
|
|
//! @}
|
|
//! @name Data movement
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Load a linear segment of items from memory.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! @smemwarpreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/warp/warp_load.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, ...)
|
|
//! {
|
|
//! constexpr int warp_threads = 16;
|
|
//! constexpr int threads_per_block = 256;
|
|
//! constexpr int items_per_thread = 4;
|
|
//!
|
|
//! // Specialize WarpLoad for a warp of 16 threads owning 4 integer items each
|
|
//! using WarpLoadT = WarpLoad<int,
|
|
//! items_per_thread,
|
|
//! cub::WARP_LOAD_TRANSPOSE,
|
|
//! warp_threads>;
|
|
//!
|
|
//! constexpr int warps_in_block = threads_per_block / warp_threads;
|
|
//! constexpr int tile_size = items_per_thread * warp_threads;
|
|
//! const int warp_id = static_cast<int>(threadIdx.x) / warp_threads;
|
|
//!
|
|
//! // Allocate shared memory for WarpLoad
|
|
//! __shared__ typename WarpLoadT::TempStorage temp_storage[warps_in_block];
|
|
//!
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[items_per_thread];
|
|
//! WarpLoadT(temp_storage[warp_id]).Load(d_data + warp_id * tile_size, thread_data);
|
|
//! }
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, ...``,
|
|
//! The set of ``thread_data`` across the first logical warp of threads in those
|
|
//! threads will be: ``{ [0,1,2,3], [4,5,6,7], ..., [60,61,62,63] }``.
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] block_itr The thread block's base input iterator for loading from
|
|
//! @param[out] items Data to load
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD])
|
|
{
|
|
InternalLoad(temp_storage, linear_tid).Load(block_itr, items);
|
|
}
|
|
|
|
//! @rst
|
|
//! Load a linear segment of items from memory, guarded by range.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! @smemwarpreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/warp/warp_load.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, int valid_items, ...)
|
|
//! {
|
|
//! constexpr int warp_threads = 16;
|
|
//! constexpr int threads_per_block = 256;
|
|
//! constexpr int items_per_thread = 4;
|
|
//!
|
|
//! // Specialize WarpLoad for a warp of 16 threads owning 4 integer items each
|
|
//! using WarpLoadT = WarpLoad<int,
|
|
//! items_per_thread,
|
|
//! cub::WARP_LOAD_TRANSPOSE,
|
|
//! warp_threads>;
|
|
//!
|
|
//! constexpr int warps_in_block = threads_per_block / warp_threads;
|
|
//! constexpr int tile_size = items_per_thread * warp_threads;
|
|
//! const int warp_id = static_cast<int>(threadIdx.x) / warp_threads;
|
|
//!
|
|
//! // Allocate shared memory for WarpLoad
|
|
//! __shared__ typename WarpLoadT::TempStorage temp_storage[warps_in_block];
|
|
//!
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[items_per_thread];
|
|
//! WarpLoadT(temp_storage[warp_id]).Load(d_data + warp_id * tile_size, thread_data,
|
|
//! valid_items);
|
|
//! }
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, ...`` and ``valid_items`` is ``5``.
|
|
//! The set of ``thread_data`` across the first logical warp of threads in those threads will be:
|
|
//! ``{ [0,1,2,3], [4,?,?,?], ..., [?,?,?,?] }`` with only the first two threads being unmasked to
|
|
//! load portions of valid data (and other items remaining unassigned).
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] block_itr The thread block's base input iterator for loading from
|
|
//! @param[out] items Data to load
|
|
//! @param[in] valid_items Number of valid items to load
|
|
template <typename InputIteratorT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items)
|
|
{
|
|
InternalLoad(temp_storage, linear_tid).Load(block_itr, items, valid_items);
|
|
}
|
|
|
|
//! @rst
|
|
//! Load a linear segment of items from memory, guarded by range.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! @smemwarpreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/warp/warp_load.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, int valid_items, ...)
|
|
//! {
|
|
//! constexpr int warp_threads = 16;
|
|
//! constexpr int threads_per_block = 256;
|
|
//! constexpr int items_per_thread = 4;
|
|
//!
|
|
//! // Specialize WarpLoad for a warp of 16 threads owning 4 integer items each
|
|
//! using WarpLoadT = WarpLoad<int,
|
|
//! items_per_thread,
|
|
//! cub::WARP_LOAD_TRANSPOSE,
|
|
//! warp_threads>;
|
|
//!
|
|
//! constexpr int warps_in_block = threads_per_block / warp_threads;
|
|
//! constexpr int tile_size = items_per_thread * warp_threads;
|
|
//! const int warp_id = static_cast<int>(threadIdx.x) / warp_threads;
|
|
//!
|
|
//! // Allocate shared memory for WarpLoad
|
|
//! __shared__ typename WarpLoadT::TempStorage temp_storage[warps_in_block];
|
|
//!
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[items_per_thread];
|
|
//! WarpLoadT(temp_storage[warp_id]).Load(d_data + warp_id * tile_size,
|
|
//! thread_data,
|
|
//! valid_items,
|
|
//! -1);
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, ...``, ``valid_items`` is ``5``, and the
|
|
//! out-of-bounds default is ``-1``. The set of ``thread_data`` across the first logical warp of
|
|
//! threads in those threads will be: ``{ [0,1,2,3], [4,-1,-1,-1], ..., [-1,-1,-1,-1] }`` with
|
|
//! only the first two threads being unmasked to load portions of valid data (and other items
|
|
//! are assigned ``-1``).
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] block_itr The thread block's base input iterator for loading from
|
|
//! @param[out] items Data to load
|
|
//! @param[in] valid_items Number of valid items to load
|
|
//! @param[in] oob_default Default value to assign out-of-bound items
|
|
template <typename InputIteratorT, typename DefaultT>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
Load(InputIteratorT block_itr, InputT (&items)[ITEMS_PER_THREAD], int valid_items, DefaultT oob_default)
|
|
{
|
|
InternalLoad(temp_storage, linear_tid).Load(block_itr, items, valid_items, oob_default);
|
|
}
|
|
|
|
//! @}
|
|
};
|
|
|
|
CUB_NAMESPACE_END
|