Files
project_6/cccl_upstream/cub/cub/block/block_load.cuh
EngineX CI 56fd68e7dd [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
2026-07-30 09:35:51 +00:00

1193 lines
42 KiB
Plaintext

// SPDX-FileCopyrightText: Copyright (c) 2011, Duane Merrill. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2011-2016, NVIDIA CORPORATION. All rights reserved.
// SPDX-License-Identifier: BSD-3
//! @file
//! block_load.cuh Operations for reading linear tiles of data into the CUDA thread block.
#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_exchange.cuh>
#include <cub/iterator/cache_modified_input_iterator.cuh>
#include <cub/util_ptx.cuh>
#include <cub/util_type.cuh>
#include <cuda/std/__concepts/same_as.h>
#include <cuda/std/__fwd/format.h>
#include <cuda/std/__host_stdlib/ostream>
#include <cuda/std/__memory/is_sufficiently_aligned.h>
#include <cuda/std/__new/device_new.h>
CUB_NAMESPACE_BEGIN
//! @name Blocked arrangement I/O (direct)
//! @{
//! @rst
//! Load a linear segment of items into a blocked arrangement across the thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @blocked
//!
//! @endrst
//!
//! @tparam T
//! **[inferred]** The data type to load.
//!
//! @tparam ItemsPerThread
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **[inferred]** The random-access iterator type for input iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) + linear_tid` for 2D
//! thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base input iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
template <typename T, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void
LoadDirectBlocked(int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread])
{
// Load directly in thread-blocked order
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] = block_src_it[linear_tid * ItemsPerThread + i]; // NOLINT(bugprone-misplaced-widening-cast)
}
}
//! @rst
//! Load a linear segment of items into a blocked arrangement across the thread block, guarded by range.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @blocked
//!
//! @endrst
//!
//! @tparam T
//! **[inferred]** The data type to load.
//!
//! @tparam ItemsPerThread
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **[inferred]** The random-access iterator type for input iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) + linear_tid` for 2D
//! thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! First out-of-bounds index when loading from block_src_it
template <typename T, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void LoadDirectBlocked(
int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread], int block_items_end)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
const auto src_pos = linear_tid * ItemsPerThread + i;
if (src_pos < block_items_end)
{
dst_items[i] = block_src_it[src_pos];
}
}
}
//! @rst
//! Load a linear segment of items into a blocked arrangement across the thread block, guarded
//! by range, with a fall-back assignment of out-of-bound elements.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @blocked
//!
//! @endrst
//!
//! @tparam T
//! **[inferred]** The data type to load.
//!
//! @tparam ItemsPerThread
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **[inferred]** The random-access iterator type for input \iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) + linear_tid` for 2D
//! thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base input iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! First out-of-bounds index when loading from block_src_it
//!
//! @param[in] oob_default
//! Default value to assign out-of-bound items
template <typename T, typename DefaultT, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void LoadDirectBlocked(
int linear_tid,
RandomAccessIterator block_src_it,
T (&dst_items)[ItemsPerThread],
int block_items_end,
DefaultT oob_default)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] = oob_default;
}
LoadDirectBlocked(linear_tid, block_src_it, dst_items, block_items_end);
}
#ifndef _CCCL_DOXYGEN_INVOKED // Do not document
//! @brief Internal implementation for load vectorization
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) + linear_tid` for 2D
//! thread blocks)
//!
//! @param[in] block_src_ptr
//! Input pointer for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
template <CacheLoadModifier MODIFIER, typename T, int ItemsPerThread>
_CCCL_DEVICE _CCCL_FORCEINLINE void
InternalLoadDirectBlockedVectorized(int linear_tid, const T* block_src_ptr, T (&dst_items)[ItemsPerThread])
{
// Find biggest memory access word that T is a whole multiple of
using device_word_t = typename UnitWord<T>::DeviceWord;
_CCCL_DIAG_PUSH
# if _CCCL_COMPILER(CLANG, >=, 10)
_CCCL_DIAG_SUPPRESS_CLANG("-Wsizeof-array-div")
# endif // _CCCL_COMPILER(CLANG, >=, 10)
// NOLINTNEXTLINE(bugprone-sizeof-expression)
constexpr int total_words = static_cast<int>(sizeof(dst_items) / sizeof(device_word_t));
_CCCL_DIAG_POP
constexpr int vector_size = (total_words % 4 == 0) ? 4 : (total_words % 2 == 0) ? 2 : 1;
constexpr int vectors_per_thread = total_words / vector_size;
// Load into an array of vectors in thread-blocked order
using vector_t = typename CubVector<device_word_t, vector_size>::Type;
// Add the alignment check to ensure the vectorized loading can proceed.
if (::cuda::std::is_sufficiently_aligned<alignof(vector_t)>(block_src_ptr))
{
vector_t vec_items[vectors_per_thread];
// Load into an array of vectors in thread-blocked order
const vector_t* vec_ptr = reinterpret_cast<const vector_t*>(block_src_ptr) + linear_tid * vectors_per_thread;
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < vectors_per_thread; i++)
{
vec_items[i] = ThreadLoad<MODIFIER>(vec_ptr + i);
}
// Copy to destination
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] = *(reinterpret_cast<T*>(vec_items) + i);
}
}
else
{
LoadDirectBlocked(linear_tid, block_src_ptr, dst_items);
}
}
#endif // _CCCL_DOXYGEN_INVOKED
//! @rst
//! Load a linear segment of items into a blocked arrangement across the thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @blocked
//!
//! The input offset (``block_ptr + block_offset``) must be quad-item aligned
//!
//! The following conditions will prevent vectorization and loading will fall back to cub::BLOCK_LOAD_DIRECT:
//!
//! - ``ItemsPerThread`` is odd
//! - The data type ``T`` is not a built-in primitive or CUDA vector type
//! (e.g., ``short``, ``int2``, ``double``, ``float2``, etc.)
//!
//! @endrst
//!
//! @tparam T
//! **[inferred]** The data type to load.
//!
//! @tparam ItemsPerThread
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) +
//! linear_tid` for 2D thread blocks)
//!
//! @param[in] block_src_ptr
//! The thread block's base pointer for loading from
//!
//! @param[out] dst_items
//! destination to load data into
template <typename T, int ItemsPerThread>
_CCCL_DEVICE _CCCL_FORCEINLINE void
LoadDirectBlockedVectorized(int linear_tid, T* block_src_ptr, T (&dst_items)[ItemsPerThread])
{
InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, block_src_ptr, dst_items);
}
//! @}
//! @name Striped arrangement I/O (direct)
//! @{
//! @rst
//! Load a linear segment of items into a striped arrangement across the thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @striped
//!
//! @endrst
//!
//! @tparam ThreadsPerBlock
//! The thread block size in threads
//!
//! @tparam T
//! **[inferred]** The data type to load.
//!
//! @tparam ItemsPerThread
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **[inferred]** The random-access iterator type for input iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) + linear_tid` for 2D
//! thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
template <int ThreadsPerBlock, typename T, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void
LoadDirectStriped(int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread])
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] = block_src_it[linear_tid + i * ThreadsPerBlock]; // NOLINT(bugprone-misplaced-widening-cast)
}
}
namespace detail
{
template <int ThreadsPerBlock, typename T, int ItemsPerThread, typename RandomAccessIterator, typename TransformOpT>
_CCCL_DEVICE _CCCL_FORCEINLINE void load_transform_direct_striped(
int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread], TransformOpT transform_op)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] =
transform_op(block_src_it[linear_tid + i * ThreadsPerBlock]); // NOLINT(bugprone-misplaced-widening-cast)
}
}
} // namespace detail
//! @rst
//! Load a linear segment of items into a striped arrangement across the thread block, guarded by range
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @striped
//!
//! @endrst
//!
//! @tparam ThreadsPerBlock
//! The thread block size in threads
//!
//! @tparam T
//! **inferred** The data type to load.
//!
//! @tparam ItemsPerThread
//! **inferred** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **inferred** The random-access iterator type for input iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., <tt>(threadIdx.y * blockDim.x) +
//! linear_tid</tt> for 2D thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! Number of valid items to load
template <int ThreadsPerBlock, typename T, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void LoadDirectStriped(
int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread], int block_items_end)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
const auto src_pos = linear_tid + i * ThreadsPerBlock;
if (src_pos < block_items_end)
{
dst_items[i] = block_src_it[src_pos];
}
}
}
//! @rst
//! Load a linear segment of items into a striped arrangement across the thread block, guarded
//! by range, with a fall-back assignment of out-of-bound elements.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @striped
//!
//! @endrst
//!
//! @tparam ThreadsPerBlock
//! The thread block size in threads
//!
//! @tparam T
//! **inferred** The data type to load.
//!
//! @tparam ItemsPerThread
//! **inferred** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **inferred** The random-access iterator type for input \iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) +
//! linear_tid` for 2D thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! Number of valid items to load
//!
//! @param[in] oob_default
//! Default value to assign out-of-bound items
template <int ThreadsPerBlock, typename T, typename DefaultT, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void LoadDirectStriped(
int linear_tid,
RandomAccessIterator block_src_it,
T (&dst_items)[ItemsPerThread],
int block_items_end,
DefaultT oob_default)
{
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] = oob_default;
}
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items, block_items_end);
}
//! @}
//! @name Warp-striped arrangement I/O (direct)
//! @{
//! @rst
//! Load a linear segment of items into a warp-striped arrangement across the thread block.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @warpstriped
//!
//! Usage Considerations
//! ++++++++++++++++++++
//!
//! The number of threads in the thread block must be a multiple of the architecture's warp size.
//!
//! @endrst
//!
//! @tparam T
//! **inferred** The data type to load.
//!
//! @tparam ItemsPerThread
//! **inferred** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **inferred** The random-access iterator type for input iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) +
//! linear_tid` for 2D thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
template <typename T, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void
LoadDirectWarpStriped(int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread])
{
const int tid = linear_tid & (detail::warp_threads - 1);
const int wid = linear_tid >> detail::log2_warp_threads;
const int warp_offset = wid * detail::warp_threads * ItemsPerThread;
// Load directly in warp-striped order
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
new (&dst_items[i])
T(block_src_it[warp_offset + tid + (i * detail::warp_threads)]); // NOLINT(bugprone-misplaced-widening-cast)
}
}
//! @rst
//! Load a linear segment of items into a warp-striped arrangement across the thread block, guarded by range
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @warpstriped
//!
//! Usage Considerations
//! ++++++++++++++++++++
//!
//! The number of threads in the thread block must be a multiple of the architecture's warp size.
//!
//! @endrst
//!
//! @tparam T
//! **inferred** The data type to load.
//!
//! @tparam ItemsPerThread
//! **inferred** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **inferred** The random-access iterator type for input \iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) +
//! linear_tid` for 2D thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! Number of valid items to load
template <typename T, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void LoadDirectWarpStriped(
int linear_tid, RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread], int block_items_end)
{
const int tid = linear_tid & (detail::warp_threads - 1);
const int wid = linear_tid >> detail::log2_warp_threads;
const int warp_offset = wid * detail::warp_threads * ItemsPerThread;
// Load directly in warp-striped order
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
const auto src_pos = warp_offset + tid + (i * detail::warp_threads);
if (src_pos < block_items_end)
{
new (&dst_items[i]) T(block_src_it[src_pos]);
}
}
}
//! @rst
//! Load a linear segment of items into a warp-striped arrangement across the thread block,
//! guarded by range, with a fall-back assignment of out-of-bound elements.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! @warpstriped
//!
//! @endrst
//!
//! Usage Considerations
//! ++++++++++++++++++++
//!
//! The number of threads in the thread block must be a multiple of the architecture's warp size.
//!
//! @tparam T
//! **inferred** The data type to load.
//!
//! @tparam ItemsPerThread
//! **inferred** The number of consecutive items partitioned onto each thread.
//!
//! @tparam RandomAccessIterator
//! **inferred** The random-access iterator type for input \iterator.
//!
//! @param[in] linear_tid
//! A suitable 1D thread-identifier for the calling thread (e.g., `(threadIdx.y * blockDim.x) +
//! linear_tid` for 2D thread blocks)
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! Number of valid items to load
//!
//! @param[in] oob_default
//! Default value to assign out-of-bound items
template <typename T, typename DefaultT, int ItemsPerThread, typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void LoadDirectWarpStriped(
int linear_tid,
RandomAccessIterator block_src_it,
T (&dst_items)[ItemsPerThread],
int block_items_end,
DefaultT oob_default)
{
// Load directly in warp-striped order
_CCCL_PRAGMA_UNROLL_FULL()
for (int i = 0; i < ItemsPerThread; i++)
{
dst_items[i] = oob_default;
}
LoadDirectWarpStriped(linear_tid, block_src_it, dst_items, block_items_end);
}
//! @}
//! @brief cub::BlockLoadAlgorithm enumerates alternative algorithms for cub::BlockLoad to read a linear segment of data
//! from memory into a blocked arrangement across a CUDA thread block.
enum BlockLoadAlgorithm
{
//! @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
BLOCK_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
BLOCK_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 ``ItemsPerThread % 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::BLOCK_LOAD_DIRECT:
//!
//! - ``ItemsPerThread`` is odd
//! - The ``RandomAccessIterator`` 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
BLOCK_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::BLOCK_LOAD_DIRECT and
//! cub::BLOCK_LOAD_VECTORIZE alternatives.
//!
//! @endrst
BLOCK_LOAD_TRANSPOSE,
//! @rst
//! Overview
//! ++++++++++++++++++++++++++
//!
//! A :ref:`warp-striped arrangement <flexible-data-arrangement>` of data is read efficiently from memory and then
//! locally transposed into a :ref:`blocked arrangement <flexible-data-arrangement>`.
//!
//! Usage Considerations
//! ++++++++++++++++++++++++++
//!
//! - ThreadsPerBlock must be a multiple of WARP_THREADS
//!
//! Performance Considerations
//! ++++++++++++++++++++++++++
//!
//! - The utilization of memory transactions (coalescing) remains high regardless of items loaded per thread.
//! - The local reordering incurs slightly larger latencies than the direct cub::BLOCK_LOAD_DIRECT and
//! cub::BLOCK_LOAD_VECTORIZE alternatives.
//! - Provisions more shared storage, but incurs smaller latencies than the
//! BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED alternative.
//!
//! @endrst
BLOCK_LOAD_WARP_TRANSPOSE,
//! @rst
//! Overview
//! ++++++++++++++++++++++++++
//!
//! Like ``BLOCK_LOAD_WARP_TRANSPOSE``, a :ref:`warp-striped arrangement <flexible-data-arrangement>` of data is read
//! directly from memory and then is locally transposed into a :ref:`blocked arrangement <flexible-data-arrangement>`.
//! To reduce the shared memory requirement, only one warp's worth of shared memory is provisioned and is subsequently
//! time-sliced among warps.
//!
//! Usage Considerations
//! ++++++++++++++++++++++++++
//!
//! - ThreadsPerBlock must be a multiple of WARP_THREADS
//!
//! Performance Considerations
//! ++++++++++++++++++++++++++
//!
//! - The utilization of memory transactions (coalescing) remains high regardless of items loaded per thread.
//! - Provisions less shared memory temporary storage, but incurs larger latencies than the BLOCK_LOAD_WARP_TRANSPOSE
//! alternative.
//!
//! @endrst
BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED,
};
#if _CCCL_HOSTED() && !defined(_CCCL_DOXYGEN_INVOKED)
namespace detail
{
[[nodiscard]] _CCCL_HOST_DEVICE_API constexpr const char* to_string(BlockLoadAlgorithm algo) noexcept
{
switch (algo)
{
case BLOCK_LOAD_DIRECT:
return "BLOCK_LOAD_DIRECT";
case BLOCK_LOAD_STRIPED:
return "BLOCK_LOAD_STRIPED";
case BLOCK_LOAD_VECTORIZE:
return "BLOCK_LOAD_VECTORIZE";
case BLOCK_LOAD_TRANSPOSE:
return "BLOCK_LOAD_TRANSPOSE";
case BLOCK_LOAD_WARP_TRANSPOSE:
return "BLOCK_LOAD_WARP_TRANSPOSE";
case BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED:
return "BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED";
}
return "<unknown BlockLoadAlgorithm>";
}
} // namespace detail
inline ::std::ostream& operator<<(::std::ostream& os, BlockLoadAlgorithm 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::BlockLoadAlgorithm, CharT> : formatter<const CharT*, CharT>
{
template <class FmtCtx>
auto format(const CUB_NS_QUALIFIER::BlockLoadAlgorithm& 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 BlockLoad 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
//! block.
//!
//! Overview
//! +++++++++++++++++++++++++++++++++++++++++++++
//!
//! - The BlockLoad class provides a single data movement abstraction that can be specialized to implement different
//! cub::BlockLoadAlgorithm strategies. This facilitates different performance policies for different architectures,
//! data types, granularity sizes, etc.
//! - BlockLoad can be optionally specialized by different data movement strategies:
//!
//! #. :cpp:enumerator:`cub::BLOCK_LOAD_DIRECT`:
//! A :ref:`blocked arrangement <flexible-data-arrangement>` of data is read directly from memory.
//! #. :cpp:enumerator:`cub::BLOCK_LOAD_STRIPED`:
//! A :ref:`striped arrangement <flexible-data-arrangement>` of data is read directly from memory.
//! #. :cpp:enumerator:`cub::BLOCK_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::BLOCK_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>`.
//! #. :cpp:enumerator:`cub::BLOCK_LOAD_WARP_TRANSPOSE`:
//! A :ref:`warp-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>`.
//! #. :cpp:enumerator:`cub::BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED`:
//! A :ref:`warp-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>` one warp at a time.
//!
//! - @rowmajor
//!
//! A Simple Example
//! +++++++++++++++++++++++++++++++++++++++++++++
//!
//! @blockcollective{BlockLoad}
//!
//! The code snippet below illustrates the loading of a linear segment of 512 integers into a "blocked" arrangement
//! across 128 threads where each thread owns 4 consecutive items. The load is specialized for
//! ``BLOCK_LOAD_WARP_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/block/block_load.cuh>
//!
//! __global__ void ExampleKernel(int *d_data, ...)
//! {
//! // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
//! using BlockLoad = cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE>;
//!
//! // Allocate shared memory for BlockLoad
//! __shared__ typename BlockLoad::TempStorage temp_storage;
//!
//! // Load a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! BlockLoad(temp_storage).Load(d_data, thread_data);
//! }
//!
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, ...``. The set of ``thread_data`` across the block of threads in
//! those threads will be ``{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }``.
//!
//! Re-using dynamically allocating shared memory
//! +++++++++++++++++++++++++++++++++++++++++++++
//!
//! The ``block/example_block_reduce_dyn_smem.cu`` example illustrates usage of dynamically shared memory with
//! BlockReduce and how to re-purpose the same memory region. This example can be easily adapted to the storage required
//! by BlockLoad.
//!
//! @endrst
//!
//! @tparam T
//! The data type to read into (which must be convertible from the input iterator's value type).
//!
//! @tparam BlockDimX
//! The thread block length in threads along the X dimension
//!
//! @tparam ItemsPerThread
//! The number of consecutive items partitioned onto each thread.
//!
//! @tparam Algorithm
//! **[optional]** cub::BlockLoadAlgorithm tuning policy. default: ``cub::BLOCK_LOAD_DIRECT``.
//!
//! @tparam BlockDimY
//! **[optional]** The thread block length in threads along the Y dimension (default: 1)
//!
//! @tparam BlockDimZ
//! **[optional]** The thread block length in threads along the Z dimension (default: 1)
//!
template <typename T,
int BlockDimX,
int ItemsPerThread,
BlockLoadAlgorithm Algorithm = BLOCK_LOAD_DIRECT,
int BlockDimY = 1,
int BlockDimZ = 1>
class BlockLoad
{
static constexpr int ThreadsPerBlock = BlockDimX * BlockDimY * BlockDimZ; // total threads in the block
// transposing load algorithms need a BlockExchange
using block_exchange =
BlockExchange<T,
BlockDimX,
ItemsPerThread,
/* WarpTimeSlicing = */ Algorithm == BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED,
BlockDimY,
BlockDimZ>;
static_assert((Algorithm != BLOCK_LOAD_WARP_TRANSPOSE && Algorithm != BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED)
|| (ThreadsPerBlock % detail::warp_threads == 0),
"ThreadsPerBlock must be a multiple of warp_threads for this BlockLoadAlgorithm");
_CCCL_HOST_DEVICE_API static constexpr auto temp_storage_helper()
{
if constexpr (Algorithm == BLOCK_LOAD_DIRECT || Algorithm == BLOCK_LOAD_STRIPED
|| Algorithm == BLOCK_LOAD_VECTORIZE)
{
return NullType{};
}
else if constexpr (Algorithm == BLOCK_LOAD_TRANSPOSE || Algorithm == BLOCK_LOAD_WARP_TRANSPOSE
|| Algorithm == BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED)
{
return typename block_exchange::TempStorage{};
}
}
using _TempStorage = decltype(temp_storage_helper());
// Internal storage allocator
_CCCL_DEVICE _CCCL_FORCEINLINE _TempStorage& PrivateStorage()
{
__shared__ _TempStorage private_storage;
return private_storage;
}
_TempStorage& temp_storage;
int linear_tid;
public:
/// @smemstorage{BlockLoad}
using TempStorage = Uninitialized<_TempStorage>;
//! @name Collective constructors
//! @{
//! @brief Collective constructor using a private static allocation of shared memory as temporary storage.
//!
//! @rst
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//! @endrst
_CCCL_DEVICE _CCCL_FORCEINLINE BlockLoad()
: temp_storage(PrivateStorage())
, linear_tid(RowMajorTid(BlockDimX, BlockDimY, BlockDimZ))
{}
//! @brief Collective constructor using the specified memory allocation as temporary storage.
//!
//! @rst
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//! @endrst
//!
//! @param[in] temp_storage Reference to memory allocation having layout type TempStorage
_CCCL_DEVICE _CCCL_FORCEINLINE BlockLoad(TempStorage& temp_storage)
: temp_storage(temp_storage.Alias())
, linear_tid(RowMajorTid(BlockDimX, BlockDimY, BlockDimZ))
{}
//! @}
//! @name Data movement
//! @{
//! @rst
//! Load a linear segment of items from memory.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @blocked
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates the loading of a linear segment of 512 integers into a "blocked" arrangement
//! across 128 threads where each thread owns 4 consecutive items. The load is specialized for
//! ``BLOCK_LOAD_WARP_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/block/block_load.cuh>
//!
//! __global__ void ExampleKernel(int *d_data, ...)
//! {
//! // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
//! using BlockLoad = cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE>;
//!
//! // Allocate shared memory for BlockLoad
//! __shared__ typename BlockLoad::TempStorage temp_storage;
//!
//! // Load a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! BlockLoad(temp_storage).Load(d_data, thread_data);
//! }
//!
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, ...``. The set of ``thread_data`` across the block of threads
//! in those threads will be ``{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }``.
//!
//! @endrst
//!
//! @param[in] block_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
template <typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void Load(RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread])
{
if constexpr (Algorithm == BLOCK_LOAD_DIRECT)
{
LoadDirectBlocked(linear_tid, block_src_it, dst_items);
}
else if constexpr (Algorithm == BLOCK_LOAD_STRIPED)
{
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items);
}
else if constexpr (Algorithm == BLOCK_LOAD_VECTORIZE)
{
if constexpr (detail::is_CacheModifiedInputIterator<RandomAccessIterator>)
{
InternalLoadDirectBlockedVectorized<RandomAccessIterator::__modifier>(linear_tid, block_src_it.ptr, dst_items);
}
else if constexpr (::cuda::std::contiguous_iterator<RandomAccessIterator>
&& ::cuda::std::__can_to_address<RandomAccessIterator>)
{
InternalLoadDirectBlockedVectorized<LOAD_DEFAULT>(linear_tid, ::cuda::std::to_address(block_src_it), dst_items);
}
else
{
LoadDirectBlocked(linear_tid, block_src_it, dst_items);
}
}
else if constexpr (Algorithm == BLOCK_LOAD_TRANSPOSE)
{
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items);
block_exchange(temp_storage).StripedToBlocked(dst_items, dst_items);
}
else if constexpr (Algorithm == BLOCK_LOAD_WARP_TRANSPOSE || Algorithm == BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED)
{
LoadDirectWarpStriped(linear_tid, block_src_it, dst_items);
block_exchange(temp_storage).WarpStripedToBlocked(dst_items, dst_items);
}
}
//! @rst
//! Load a linear segment of items from memory, guarded by range.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @blocked
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates the guarded loading of a linear segment of 512 integers into a "blocked"
//! arrangement across 128 threads where each thread owns 4 consecutive items. The load is specialized for
//! ``BLOCK_LOAD_WARP_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/block/block_load.cuh>
//!
//! __global__ void ExampleKernel(int *d_data, int block_items_end, ...)
//! {
//! // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
//! using BlockLoad = cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE>;
//!
//! // Allocate shared memory for BlockLoad
//! __shared__ typename BlockLoad::TempStorage temp_storage;
//!
//! // Load a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! BlockLoad(temp_storage).Load(d_data, thread_data, block_items_end);
//! }
//!
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, 6...`` and ``block_items_end`` is ``5``. The set of
//! ``thread_data`` across the block 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_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! Number of valid items to load
template <typename RandomAccessIterator>
_CCCL_DEVICE _CCCL_FORCEINLINE void
Load(RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread], int block_items_end)
{
if constexpr (Algorithm == BLOCK_LOAD_DIRECT || Algorithm == BLOCK_LOAD_VECTORIZE)
{
LoadDirectBlocked(linear_tid, block_src_it, dst_items, block_items_end);
}
else if constexpr (Algorithm == BLOCK_LOAD_STRIPED)
{
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items, block_items_end);
}
else if constexpr (Algorithm == BLOCK_LOAD_TRANSPOSE)
{
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items, block_items_end);
block_exchange(temp_storage).StripedToBlocked(dst_items, dst_items);
}
else if constexpr (Algorithm == BLOCK_LOAD_WARP_TRANSPOSE || Algorithm == BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED)
{
LoadDirectWarpStriped(linear_tid, block_src_it, dst_items, block_items_end);
block_exchange(temp_storage).WarpStripedToBlocked(dst_items, dst_items);
}
}
//! @rst
//! Load a linear segment of items from memory, guarded by range, with a fall-back assignment of out-of-bound elements
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - @blocked
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates the guarded loading of a linear segment of 512 integers into a "blocked"
//! arrangement across 128 threads where each thread owns 4 consecutive items. The load is specialized for
//! ``BLOCK_LOAD_WARP_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/block/block_load.cuh>
//!
//! __global__ void ExampleKernel(int *d_data, int block_items_end, ...)
//! {
//! // Specialize BlockLoad for a 1D block of 128 threads owning 4 integer items each
//! using BlockLoad = cub::BlockLoad<int, 128, 4, BLOCK_LOAD_WARP_TRANSPOSE>;
//!
//! // Allocate shared memory for BlockLoad
//! __shared__ typename BlockLoad::TempStorage temp_storage;
//!
//! // Load a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! BlockLoad(temp_storage).Load(d_data, thread_data, block_items_end, -1);
//! }
//!
//! Suppose the input ``d_data`` is ``0, 1, 2, 3, 4, 5, 6...``, ``block_items_end`` is ``5``, and the out-of-bounds
//! default is ``-1``. The set of ``thread_data`` across the block 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_src_it
//! The thread block's base iterator for loading from
//!
//! @param[out] dst_items
//! Destination to load data into
//!
//! @param[in] block_items_end
//! Number of valid items to load
//!
//! @param[in] oob_default
//! Default value to assign out-of-bound items
template <typename RandomAccessIterator, typename DefaultT>
_CCCL_DEVICE _CCCL_FORCEINLINE void
Load(RandomAccessIterator block_src_it, T (&dst_items)[ItemsPerThread], int block_items_end, DefaultT oob_default)
{
if constexpr (Algorithm == BLOCK_LOAD_DIRECT || Algorithm == BLOCK_LOAD_VECTORIZE)
{
LoadDirectBlocked(linear_tid, block_src_it, dst_items, block_items_end, oob_default);
}
else if constexpr (Algorithm == BLOCK_LOAD_STRIPED)
{
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items, block_items_end, oob_default);
}
else if constexpr (Algorithm == BLOCK_LOAD_TRANSPOSE)
{
LoadDirectStriped<ThreadsPerBlock>(linear_tid, block_src_it, dst_items, block_items_end, oob_default);
block_exchange(temp_storage).StripedToBlocked(dst_items, dst_items);
}
else if constexpr (Algorithm == BLOCK_LOAD_WARP_TRANSPOSE || Algorithm == BLOCK_LOAD_WARP_TRANSPOSE_TIMESLICED)
{
LoadDirectWarpStriped(linear_tid, block_src_it, dst_items, block_items_end, oob_default);
block_exchange(temp_storage).WarpStripedToBlocked(dst_items, dst_items);
}
}
//! @}
};
template <class Policy, class It, class T = cub::detail::it_value_t<It>>
struct BlockLoadType
{
using type = cub::BlockLoad<T, Policy::BLOCK_THREADS, Policy::ITEMS_PER_THREAD, Policy::LOAD_ALGORITHM>;
};
CUB_NAMESPACE_END