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
2278 lines
86 KiB
Plaintext
2278 lines
86 KiB
Plaintext
// SPDX-FileCopyrightText: Copyright (c) 2011, Duane Merrill. All rights reserved.
|
|
// SPDX-FileCopyrightText: Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
|
|
// SPDX-License-Identifier: BSD-3
|
|
|
|
//! @file
|
|
//! The cub::BlockScan class provides :ref:`collective <collective-primitives>` methods for computing a parallel prefix
|
|
//! sum/scan of items partitioned across a 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/specializations/block_scan_raking.cuh>
|
|
#include <cub/block/specializations/block_scan_warp_scans.cuh>
|
|
#include <cub/util_ptx.cuh>
|
|
#include <cub/util_type.cuh>
|
|
|
|
#include <cuda/std/__concepts/same_as.h>
|
|
#include <cuda/std/__functional/operations.h>
|
|
#include <cuda/std/__fwd/format.h>
|
|
#include <cuda/std/__host_stdlib/ostream>
|
|
#include <cuda/std/__type_traits/conditional.h>
|
|
|
|
CUB_NAMESPACE_BEGIN
|
|
|
|
/******************************************************************************
|
|
* Algorithmic variants
|
|
******************************************************************************/
|
|
|
|
//! @brief BlockScanAlgorithm enumerates alternative algorithms for cub::BlockScan to compute a
|
|
//! parallel prefix scan across a CUDA thread block.
|
|
enum BlockScanAlgorithm
|
|
{
|
|
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! An efficient "raking reduce-then-scan" prefix scan algorithm. Execution is comprised of five phases:
|
|
//!
|
|
//! #. Upsweep sequential reduction in registers (if threads contribute more than one input each).
|
|
//! Each thread then places the partial reduction of its item(s) into shared memory.
|
|
//! #. Upsweep sequential reduction in shared memory.
|
|
//! Threads within a single warp rake across segments of shared partial reductions.
|
|
//! #. A warp-synchronous Kogge-Stone style exclusive scan within the raking warp.
|
|
//! #. Downsweep sequential exclusive scan in shared memory.
|
|
//! Threads within a single warp rake across segments of shared partial reductions,
|
|
//! seeded with the warp-scan output.
|
|
//! #. Downsweep sequential scan in registers (if threads contribute more than one input),
|
|
//! seeded with the raking scan output.
|
|
//!
|
|
//! Performance Considerations
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! - Although this variant may suffer longer turnaround latencies when the
|
|
//! GPU is under-occupied, it can often provide higher overall throughput
|
|
//! across the GPU when suitably occupied.
|
|
//!
|
|
//! @endrst
|
|
BLOCK_SCAN_RAKING,
|
|
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! Similar to cub::BLOCK_SCAN_RAKING, but with fewer shared memory reads at the expense of higher
|
|
//! register pressure. Raking threads preserve their "upsweep" segment of values in registers while performing
|
|
//! warp-synchronous scan, allowing the "downsweep" not to re-read them from shared memory.
|
|
//!
|
|
//! @endrst
|
|
BLOCK_SCAN_RAKING_MEMOIZE,
|
|
|
|
//! @rst
|
|
//! Overview
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! A quick "tiled warpscans" prefix scan algorithm. Execution is comprised of four phases:
|
|
//! #. Upsweep sequential reduction in registers (if threads contribute more than one input each).
|
|
//! Each thread then places the partial reduction of its item(s) into shared memory.
|
|
//! #. Compute a shallow, but inefficient warp-synchronous Kogge-Stone style scan within each warp.
|
|
//! #. A propagation phase where the warp scan outputs in each warp are updated with the aggregate
|
|
//! from each preceding warp.
|
|
//! #. Downsweep sequential scan in registers (if threads contribute more than one input),
|
|
//! seeded with the raking scan output.
|
|
//!
|
|
//! Performance Considerations
|
|
//! ++++++++++++++++++++++++++
|
|
//!
|
|
//! - Although this variant may suffer lower overall throughput across the
|
|
//! GPU because due to a heavy reliance on inefficient warpscans, it can
|
|
//! often provide lower turnaround latencies when the GPU is under-occupied.
|
|
//!
|
|
//! @endrst
|
|
BLOCK_SCAN_WARP_SCANS,
|
|
};
|
|
|
|
#if _CCCL_HOSTED() && !defined(_CCCL_DOXYGEN_INVOKED)
|
|
namespace detail
|
|
{
|
|
[[nodiscard]] _CCCL_HOST_DEVICE_API constexpr const char* to_string(BlockScanAlgorithm algo) noexcept
|
|
{
|
|
switch (algo)
|
|
{
|
|
case BLOCK_SCAN_RAKING:
|
|
return "BLOCK_SCAN_RAKING";
|
|
case BLOCK_SCAN_RAKING_MEMOIZE:
|
|
return "BLOCK_SCAN_RAKING_MEMOIZE";
|
|
case BLOCK_SCAN_WARP_SCANS:
|
|
return "BLOCK_SCAN_WARP_SCANS";
|
|
}
|
|
return "<unknown BlockScanAlgorithm>";
|
|
}
|
|
} // namespace detail
|
|
|
|
inline ::std::ostream& operator<<(::std::ostream& os, BlockScanAlgorithm 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::BlockScanAlgorithm, CharT> : formatter<const CharT*, CharT>
|
|
{
|
|
template <class FmtCtx>
|
|
auto format(const CUB_NS_QUALIFIER::BlockScanAlgorithm& 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 BlockScan class provides :ref:`collective <collective-primitives>` methods for computing a parallel prefix
|
|
//! sum/scan of items partitioned across a CUDA thread block.
|
|
//!
|
|
//! Overview
|
|
//! +++++++++++++++++++++++++++++++++++++++++++++
|
|
//!
|
|
//! - Given a list of input elements and a binary reduction operator, a
|
|
//! `prefix scan <http://en.wikipedia.org/wiki/Prefix_sum>`_ produces an output list where each element is computed
|
|
//! to be the reduction of the elements occurring earlier in the input list. *Prefix sum* connotes a prefix scan with
|
|
//! the addition operator. The term *inclusive indicates* that the *i*\ :sup:`th` output reduction incorporates
|
|
//! the *i*\ :sup:`th` input. The term *exclusive* indicates the *i*\ :sup:`th` input is not incorporated into
|
|
//! the *i*\ :sup:`th` output reduction.
|
|
//! - @rowmajor
|
|
//! - BlockScan can be optionally specialized by algorithm to accommodate different workload profiles:
|
|
//!
|
|
//! #. :cpp:enumerator:`cub::BLOCK_SCAN_RAKING`:
|
|
//! An efficient (high throughput) "raking reduce-then-scan" prefix scan algorithm.
|
|
//! #. :cpp:enumerator:`cub::BLOCK_SCAN_RAKING_MEMOIZE`:
|
|
//! Similar to cub::BLOCK_SCAN_RAKING, but having higher throughput at the expense of additional
|
|
//! register pressure for intermediate storage.
|
|
//! #. :cpp:enumerator:`cub::BLOCK_SCAN_WARP_SCANS`:
|
|
//! A quick (low latency) "tiled warpscans" prefix scan algorithm.
|
|
//!
|
|
//! Performance Considerations
|
|
//! +++++++++++++++++++++++++++++++++++++++++++++
|
|
//!
|
|
//! - @granularity
|
|
//! - Uses special instructions when applicable (e.g., warp ``SHFL``)
|
|
//! - Uses synchronization-free communication between warp lanes when applicable
|
|
//! - Invokes a minimal number of minimal block-wide synchronization barriers (only
|
|
//! one or two depending on algorithm selection)
|
|
//! - Incurs zero bank conflicts for most types
|
|
//! - Computation is slightly more efficient (i.e., having lower instruction overhead) for:
|
|
//!
|
|
//! - Prefix sum variants (vs. generic scan)
|
|
//! - @blocksize
|
|
//!
|
|
//! - See cub::BlockScanAlgorithm for performance details regarding algorithmic alternatives
|
|
//!
|
|
//! A Simple Example
|
|
//! +++++++++++++++++++++++++++++++++++++++++++++
|
|
//!
|
|
//! @blockcollective{BlockScan}
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix sum of 512 integer items that
|
|
//! are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>` across 128 threads
|
|
//! where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-array
|
|
//! :end-before: example-end exclusive-sum-array
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{[1,1,1,1], [1,1,1,1], ..., [1,1,1,1]}``.
|
|
//! The corresponding output ``thread_data`` 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 BlockScan.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam T
|
|
//! Data type being scanned
|
|
//!
|
|
//! @tparam BlockDimX
|
|
//! The thread block length in threads along the X dimension
|
|
//!
|
|
//! @tparam Algorithm
|
|
//! **[optional]** cub::BlockScanAlgorithm enumerator specifying the underlying algorithm to use
|
|
//! (default: cub::BLOCK_SCAN_RAKING)
|
|
//!
|
|
//! @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, BlockScanAlgorithm Algorithm = BLOCK_SCAN_RAKING, int BlockDimY = 1, int BlockDimZ = 1>
|
|
class BlockScan
|
|
{
|
|
private:
|
|
/// The thread block size in threads
|
|
static constexpr int BLOCK_THREADS = BlockDimX * BlockDimY * BlockDimZ;
|
|
|
|
/**
|
|
* Ensure the template parameterization meets the requirements of the
|
|
* specified algorithm. Currently, the BLOCK_SCAN_WARP_SCANS policy
|
|
* cannot be used with thread block sizes not a multiple of the
|
|
* architectural warp size.
|
|
*/
|
|
static constexpr BlockScanAlgorithm SAFE_ALGORITHM =
|
|
((Algorithm == BLOCK_SCAN_WARP_SCANS) && (BLOCK_THREADS % detail::warp_threads != 0))
|
|
? BLOCK_SCAN_RAKING
|
|
: Algorithm;
|
|
|
|
using WarpScans = detail::BlockScanWarpScans<T, BlockDimX, BlockDimY, BlockDimZ>;
|
|
using Raking =
|
|
detail::BlockScanRaking<T, BlockDimX, BlockDimY, BlockDimZ, (SAFE_ALGORITHM == BLOCK_SCAN_RAKING_MEMOIZE)>;
|
|
|
|
/// Define the delegate type for the desired algorithm
|
|
using InternalBlockScan = ::cuda::std::_If<SAFE_ALGORITHM == BLOCK_SCAN_WARP_SCANS, WarpScans, Raking>;
|
|
|
|
/// Shared memory storage layout type for BlockScan
|
|
using _TempStorage = typename InternalBlockScan::TempStorage;
|
|
|
|
/// Shared storage reference
|
|
_TempStorage& temp_storage;
|
|
|
|
/// Linear thread-id
|
|
unsigned int linear_tid;
|
|
|
|
/// Internal storage allocator
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE _TempStorage& PrivateStorage()
|
|
{
|
|
__shared__ _TempStorage private_storage;
|
|
return private_storage;
|
|
}
|
|
|
|
public:
|
|
/// @smemstorage{BlockScan}
|
|
struct 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 BlockScan()
|
|
: 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 BlockScan(TempStorage& temp_storage)
|
|
: temp_storage(temp_storage.Alias())
|
|
, linear_tid(RowMajorTid(BlockDimX, BlockDimY, BlockDimZ))
|
|
{}
|
|
|
|
//! @}
|
|
//! @name Exclusive prefix sum operations
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes one input element. The value of 0 is applied as the initial value, and is assigned
|
|
//! to ``output`` in *thread*\ :sub:`0`.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @identityzero
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix sum of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-single
|
|
//! :end-before: example-end exclusive-sum-single
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is ``1, 1, ..., 1``.
|
|
//! The corresponding output ``thread_data`` in those threads will be ``0, 1, ..., 127``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveSum(T input, T& output)
|
|
{
|
|
T initial_value{};
|
|
|
|
ExclusiveScan(input, output, initial_value, ::cuda::std::plus<>{});
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes one input element.
|
|
//! The value of 0 is applied as the initial value, and is assigned to ``output`` in *thread*\ :sub:`0`.
|
|
//! Also provides every thread with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @identityzero
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix sum of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-aggregate
|
|
//! :end-before: example-end exclusive-sum-aggregate
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is ``1, 1, ..., 1``.
|
|
//! The corresponding output ``thread_data`` in those threads will be ``0, 1, ..., 127``.
|
|
//! Furthermore the value ``128`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveSum(T input, T& output, T& block_aggregate)
|
|
{
|
|
T initial_value{};
|
|
|
|
ExclusiveScan(input, output, initial_value, ::cuda::std::plus<>{}, block_aggregate);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes one input element. Instead of using 0 as the block-wide prefix, the call-back functor
|
|
//! ``block_prefix_callback_op`` is invoked by the first warp in the block, and the value returned by
|
|
//! *lane*\ :sub:`0` in that warp is used as the "seed" value that logically prefixes the thread block's
|
|
//! scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @identityzero
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function
|
|
//! ``T operator()(T block_aggregate)``. The functor will be invoked by the first warp of threads in the block,
|
|
//! however only the return value from *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an exclusive prefix sum over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans. Each tile consists
|
|
//! of 128 integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin block-prefix-callback-op
|
|
//! :end-before: example-end block-prefix-callback-op
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-single-prefix-callback
|
|
//! :end-before: example-end exclusive-sum-single-prefix-callback
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``1, 1, 1, 1, 1, 1, 1, 1, ...``.
|
|
//! The corresponding output for the first segment will be ``0, 1, ..., 127``.
|
|
//! The output for the second segment will be ``128, 129, ..., 255``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to
|
|
//! the logical input sequence.
|
|
//! @endrst
|
|
template <typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveSum(T input, T& output, BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
ExclusiveScan(input, output, ::cuda::std::plus<>{}, block_prefix_callback_op);
|
|
}
|
|
|
|
//! @}
|
|
//! @name Exclusive prefix sum operations (multiple data per thread)
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! The value of 0 is applied as the initial value, and is assigned to ``output[0]`` in *thread*\ :sub:`0`.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @identityzero
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix sum of 512 integer items that
|
|
//! are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>` across 128 threads
|
|
//! where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-array
|
|
//! :end-before: example-end exclusive-sum-array
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }``.
|
|
//! The corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
template <int ITEMS_PER_THREAD>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveSum(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD])
|
|
{
|
|
T initial_value{};
|
|
|
|
ExclusiveScan(input, output, initial_value, ::cuda::std::plus<>{});
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! The value of 0 is applied as the initial value, and is assigned to ``output[0]`` in *thread*\ :sub:`0`.
|
|
//! Also provides every thread with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @identityzero
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix sum of 512 integer items that are partitioned in
|
|
//! a :ref:`blocked arrangement <flexible-data-arrangement>` across 128 threads where each thread owns
|
|
//! 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-array-aggregate
|
|
//! :end-before: example-end exclusive-sum-array-aggregate
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }``.
|
|
//! The corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [0,1,2,3], [4,5,6,7], ..., [508,509,510,511] }``.
|
|
//! Furthermore the value ``512`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
template <int ITEMS_PER_THREAD>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
ExclusiveSum(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], T& block_aggregate)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T initial_value{};
|
|
|
|
ExclusiveScan(input, output, initial_value, ::cuda::std::plus<>{}, block_aggregate);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! Instead of using 0 as the block-wide prefix, the call-back functor ``block_prefix_callback_op`` is invoked by
|
|
//! the first warp in the block, and the value returned by *lane*\ :sub:`0` in that warp is used as the "seed"
|
|
//! value that logically prefixes the thread block's scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @identityzero
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function ``T operator()(T block_aggregate)``.
|
|
//! The functor will be invoked by the first warp of threads in the block, however only the return value from
|
|
//! *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an exclusive prefix sum over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans. Each tile consists
|
|
//! of 512 integer items that are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>`
|
|
//! across 128 threads where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin block-prefix-callback-op
|
|
//! :end-before: example-end block-prefix-callback-op
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-sum-prefix-callback
|
|
//! :end-before: example-end exclusive-sum-prefix-callback
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``1, 1, 1, 1, 1, 1, 1, 1, ...``.
|
|
//! The corresponding output for the first segment will be ``0, 1, 2, 3, ..., 510, 511``.
|
|
//! The output for the second segment will be ``512, 513, 514, 515, ..., 1022, 1023``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member
|
|
//! `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to
|
|
//! the logical input sequence.
|
|
//! @endrst
|
|
template <int ITEMS_PER_THREAD, typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveSum(
|
|
T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
ExclusiveScan(input, output, ::cuda::std::plus<>{}, block_prefix_callback_op);
|
|
}
|
|
|
|
//! @}
|
|
//! @name Exclusive prefix scan operations
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix max scan of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-scan-single
|
|
//! :end-before: example-end exclusive-scan-single
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is ``0, -1, 2, -3, ..., 126, -127``.
|
|
//! The corresponding output ``thread_data`` in those threads will be ``INT_MIN, 0, 0, 2, ..., 124, 126``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] initial_value
|
|
//! @rst
|
|
//! Initial value to seed the exclusive scan (and is assigned to `output[0]` in *thread*\ :sub:`0`)
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveScan(T input, T& output, T initial_value, ScanOp scan_op)
|
|
{
|
|
InternalBlockScan(temp_storage).ExclusiveScan(input, output, initial_value, scan_op);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element.
|
|
//! Also provides every thread with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix max scan of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-scan-aggregate
|
|
//! :end-before: example-end exclusive-scan-aggregate
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is ``0, -1, 2, -3, ..., 126, -127``.
|
|
//! The corresponding output ``thread_data`` in those threads will be ``INT_MIN, 0, 0, 2, ..., 124, 126``.
|
|
//! Furthermore the value ``126`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! .. note::
|
|
//!
|
|
//! ``initial_value`` is not applied to the block-wide aggregate.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member ``T operator()(const T &a, const T &b)``
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to ``input``)
|
|
//!
|
|
//! @param[in] initial_value
|
|
//! @rst
|
|
//! Initial value to seed the exclusive scan (and is assigned to ``output[0]`` in *thread*\ :sub:`0`). It is not
|
|
//! taken into account for ``block_aggregate``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
template <typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
ExclusiveScan(T input, T& output, T initial_value, ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
InternalBlockScan(temp_storage).ExclusiveScan(input, output, initial_value, scan_op, block_aggregate);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element. The call-back functor ``block_prefix_callback_op`` is invoked by
|
|
//! the first warp in the block, and the value returned by *lane*\ :sub:`0` in that warp is used as
|
|
//! the "seed" value that logically prefixes the thread block's scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function ``T operator()(T block_aggregate)``.
|
|
//! The functor will be invoked by the first warp of threads in the block, however only the return value from
|
|
//! *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an exclusive prefix max scan over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans.
|
|
//! Each tile consists of 128 integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
|
|
//!
|
|
//! // A stateful callback functor that maintains a running prefix to be applied
|
|
//! // during consecutive scan operations.
|
|
//! struct BlockPrefixCallbackOp
|
|
//! {
|
|
//! // Running prefix
|
|
//! int running_total;
|
|
//!
|
|
//! // Constructor
|
|
//! __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
|
|
//!
|
|
//! // Callback operator to be entered by the first warp of threads in the block.
|
|
//! // Thread-0 is responsible for returning a value for seeding the block-wide scan.
|
|
//! __device__ int operator()(int block_aggregate)
|
|
//! {
|
|
//! int old_prefix = running_total;
|
|
//! running_total = (block_aggregate > old_prefix) ? block_aggregate : old_prefix;
|
|
//! return old_prefix;
|
|
//! }
|
|
//! };
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, int num_items, ...)
|
|
//! {
|
|
//! // Specialize BlockScan for a 1D block of 128 threads
|
|
//! using BlockScan = cub::BlockScan<int, 128>;
|
|
//!
|
|
//! // Allocate shared memory for BlockScan
|
|
//! __shared__ typename BlockScan::TempStorage temp_storage;
|
|
//!
|
|
//! // Initialize running total
|
|
//! BlockPrefixCallbackOp prefix_op(INT_MIN);
|
|
//!
|
|
//! // Have the block iterate over segments of items
|
|
//! for (int block_offset = 0; block_offset < num_items; block_offset += 128)
|
|
//! {
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data = d_data[block_offset + threadIdx.x];
|
|
//!
|
|
//! // Collectively compute the block-wide exclusive prefix max scan
|
|
//! BlockScan(temp_storage).ExclusiveScan(
|
|
//! thread_data, thread_data, INT_MIN, cuda::maximum<>{}, prefix_op);
|
|
//! __syncthreads();
|
|
//!
|
|
//! // Store scanned items to output segment
|
|
//! d_data[block_offset + threadIdx.x] = thread_data;
|
|
//! }
|
|
//! }
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, -1, 2, -3, 4, -5, ...``.
|
|
//! The corresponding output for the first segment will be ``INT_MIN, 0, 0, 2, ..., 124, 126``.
|
|
//! The output for the second segment will be ``126, 128, 128, 130, ..., 252, 254``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to
|
|
//! the logical input sequence.
|
|
//! @endrst
|
|
template <typename ScanOp, typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
ExclusiveScan(T input, T& output, ScanOp scan_op, BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
InternalBlockScan(temp_storage).ExclusiveScan(input, output, scan_op, block_prefix_callback_op);
|
|
}
|
|
|
|
//! @}
|
|
//! @name Exclusive prefix scan operations (multiple data per thread)
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix max scan of 512 integer
|
|
//! items that are partitioned in a [<em>blocked arrangement</em>](../index.html#sec5sec3)
|
|
//! across 128 threads where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-scan-array
|
|
//! :end-before: example-end exclusive-scan-array
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }``.
|
|
//! The corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [INT_MIN,0,0,2], [2,4,4,6], ..., [506,508,508,510] }``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member
|
|
//! `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] initial_value
|
|
//! @rst
|
|
//! Initial value to seed the exclusive scan (and is assigned to `output[0]` in *thread*\ :sub:`0`)
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
ExclusiveScan(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], T initial_value, ScanOp scan_op)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, initial_value, scan_op);
|
|
|
|
// Exclusive scan in registers with prefix as seed
|
|
detail::ThreadScanExclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! Also provides every thread with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an exclusive prefix max scan of 512 integer items that are partitioned in
|
|
//! a :ref:`blocked arrangement <flexible-data-arrangement>` across 128 threads where each thread owns
|
|
//! 4 consecutive items.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(...)
|
|
//! {
|
|
//! // Specialize BlockScan for a 1D block of 128 threads of type int
|
|
//! using BlockScan = cub::BlockScan<int, 128>;
|
|
//!
|
|
//! // Allocate shared memory for BlockScan
|
|
//! __shared__ typename BlockScan::TempStorage temp_storage;
|
|
//!
|
|
//! // Obtain a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[4];
|
|
//! ...
|
|
//!
|
|
//! // Collectively compute the block-wide exclusive prefix max scan
|
|
//! int block_aggregate;
|
|
//! BlockScan(temp_storage).ExclusiveScan(
|
|
//! thread_data, thread_data, INT_MIN, cuda::maximum<>{}, block_aggregate);
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }``.
|
|
//! The corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [INT_MIN,0,0,2], [2,4,4,6], ..., [506,508,508,510] }``.
|
|
//! Furthermore the value ``510`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! .. note::
|
|
//!
|
|
//! ``initial_value`` is not applied to the block-wide aggregate.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] initial_value
|
|
//! @rst
|
|
//! Initial value to seed the exclusive scan (and is assigned to `output[0]` in *thread*\ :sub:`0`). It is not taken
|
|
//! into account for ``block_aggregate``.
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveScan(
|
|
T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], T initial_value, ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, initial_value, scan_op, block_aggregate);
|
|
|
|
// Exclusive scan in registers with prefix as seed
|
|
detail::ThreadScanExclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! The call-back functor ``block_prefix_callback_op`` is invoked by the first warp in the block, and the value
|
|
//! returned by *lane*\ :sub:`0` in that warp is used as the "seed" value that logically prefixes the thread
|
|
//! block's scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function
|
|
//! ``T operator()(T block_aggregate)``. The functor will be invoked by the
|
|
//! first warp of threads in the block, however only the return value from
|
|
//! *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an exclusive prefix max scan over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans. Each tile consists
|
|
//! of 128 integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin block-prefix-callback-max-op
|
|
//! :end-before: example-end block-prefix-callback-max-op
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin exclusive-scan-prefix-callback
|
|
//! :end-before: example-end exclusive-scan-prefix-callback
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, -1, 2, -3, 4, -5, ...``.
|
|
//! The corresponding output for the first segment will be
|
|
//! ``INT_MIN, 0, 0, 2, 2, 4, ..., 508, 510``.
|
|
//! The output for the second segment will be
|
|
//! ``510, 512, 512, 514, 514, 516, ..., 1020, 1022``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to
|
|
//! the logical input sequence.
|
|
//! @endrst
|
|
template <int ITEMS_PER_THREAD, typename ScanOp, typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveScan(
|
|
T (&input)[ITEMS_PER_THREAD],
|
|
T (&output)[ITEMS_PER_THREAD],
|
|
ScanOp scan_op,
|
|
BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, scan_op, block_prefix_callback_op);
|
|
|
|
// Exclusive scan in registers with prefix as seed
|
|
detail::ThreadScanExclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
|
|
//! @}
|
|
#ifndef _CCCL_DOXYGEN_INVOKED // Do not document no-initial-value scans
|
|
|
|
//! @name Exclusive prefix scan operations (no initial value, single datum per thread)
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element.
|
|
//! With no initial value, the output computed for *thread*\ :sub:`0` is undefined.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveScan(T input, T& output, ScanOp scan_op)
|
|
{
|
|
InternalBlockScan(temp_storage).ExclusiveScan(input, output, scan_op);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element. Also provides every thread with the block-wide
|
|
//! ``block_aggregate`` of all inputs. With no initial value, the output computed for
|
|
//! *thread*\ :sub:`0` is undefined.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
template <typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void ExclusiveScan(T input, T& output, ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
InternalBlockScan(temp_storage).ExclusiveScan(input, output, scan_op, block_aggregate);
|
|
}
|
|
|
|
//! @}
|
|
//! @name Exclusive prefix scan operations (no initial value, multiple data per thread)
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements. With no initial value, the
|
|
//! output computed for *thread*\ :sub:`0` is undefined.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
ExclusiveScan(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], ScanOp scan_op)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_partial = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_partial, thread_partial, scan_op);
|
|
|
|
// Exclusive scan in registers with prefix
|
|
detail::ThreadScanExclusive(input, output, scan_op, thread_partial, (linear_tid != 0));
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an exclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements. Also provides every thread
|
|
//! with the block-wide ``block_aggregate`` of all inputs.
|
|
//! With no initial value, the output computed for *thread*\ :sub:`0` is undefined.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
ExclusiveScan(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_partial = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_partial, thread_partial, scan_op, block_aggregate);
|
|
|
|
// Exclusive scan in registers with prefix
|
|
detail::ThreadScanExclusive(input, output, scan_op, thread_partial, (linear_tid != 0));
|
|
}
|
|
|
|
//! @}
|
|
#endif // _CCCL_DOXYGEN_INVOKED // Do not document no-initial-value scans
|
|
|
|
//! @name Inclusive prefix sum operations
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using addition (+)
|
|
//! as the scan operator. Each thread contributes one input element.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix sum of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-sum-single
|
|
//! :end-before: example-end inclusive-sum-single
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is ``1, 1, ..., 1``.
|
|
//! The corresponding output ``thread_data`` in those threads will be ``1, 2, ..., 128``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveSum(T input, T& output)
|
|
{
|
|
InclusiveScan(input, output, ::cuda::std::plus<>{});
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes one input element.
|
|
//! Also provides every thread with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix sum of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-sum-single-aggregate
|
|
//! :end-before: example-end inclusive-sum-single-aggregate
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is ``1, 1, ..., 1``.
|
|
//! The corresponding output ``thread_data`` in those threads will be ``1, 2, ..., 128``.
|
|
//! Furthermore the value ``128`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveSum(T input, T& output, T& block_aggregate)
|
|
{
|
|
InclusiveScan(input, output, ::cuda::std::plus<>{}, block_aggregate);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes one input element. Instead of using 0 as the block-wide prefix, the call-back functor
|
|
//! ``block_prefix_callback_op`` is invoked by the first warp in the block, and the value returned by
|
|
//! *lane*\ :sub:`0` in that warp is used as the "seed" value that logically prefixes the thread block's
|
|
//! scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function
|
|
//! ``T operator()(T block_aggregate)``. The functor will be invoked by the first warp of threads in the block,
|
|
//! however only the return value from *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an inclusive prefix sum over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans.
|
|
//! Each tile consists of 128 integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
|
|
//!
|
|
//! // A stateful callback functor that maintains a running prefix to be applied
|
|
//! // during consecutive scan operations.
|
|
//! struct BlockPrefixCallbackOp
|
|
//! {
|
|
//! // Running prefix
|
|
//! int running_total;
|
|
//!
|
|
//! // Constructor
|
|
//! __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
|
|
//!
|
|
//! // Callback operator to be entered by the first warp of threads in the block.
|
|
//! // Thread-0 is responsible for returning a value for seeding the block-wide scan.
|
|
//! __device__ int operator()(int block_aggregate)
|
|
//! {
|
|
//! int old_prefix = running_total;
|
|
//! running_total += block_aggregate;
|
|
//! return old_prefix;
|
|
//! }
|
|
//! };
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, int num_items, ...)
|
|
//! {
|
|
//! // Specialize BlockScan for a 1D block of 128 threads
|
|
//! using BlockScan = cub::BlockScan<int, 128>;
|
|
//!
|
|
//! // Allocate shared memory for BlockScan
|
|
//! __shared__ typename BlockScan::TempStorage temp_storage;
|
|
//!
|
|
//! // Initialize running total
|
|
//! BlockPrefixCallbackOp prefix_op(0);
|
|
//!
|
|
//! // Have the block iterate over segments of items
|
|
//! for (int block_offset = 0; block_offset < num_items; block_offset += 128)
|
|
//! {
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data = d_data[block_offset + threadIdx.x];
|
|
//!
|
|
//! // Collectively compute the block-wide inclusive prefix sum
|
|
//! BlockScan(temp_storage).InclusiveSum(
|
|
//! thread_data, thread_data, prefix_op);
|
|
//! __syncthreads();
|
|
//!
|
|
//! // Store scanned items to output segment
|
|
//! d_data[block_offset + threadIdx.x] = thread_data;
|
|
//! }
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``1, 1, 1, 1, 1, 1, 1, 1, ...``.
|
|
//! The corresponding output for the first segment will be ``1, 2, ..., 128``.
|
|
//! The output for the second segment will be ``129, 130, ..., 256``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied
|
|
//! to the logical input sequence.
|
|
//! @endrst
|
|
template <typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveSum(T input, T& output, BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
InclusiveScan(input, output, ::cuda::std::plus<>{}, block_prefix_callback_op);
|
|
}
|
|
|
|
//! @}
|
|
//! @name Inclusive prefix sum operations (multiple data per thread)
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix sum of 512 integer items that
|
|
//! are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>` across 128 threads
|
|
//! where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-sum-array
|
|
//! :end-before: example-end inclusive-sum-array
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }``. The corresponding output
|
|
//! ``thread_data`` in those threads will be ``{ [1,2,3,4], [5,6,7,8], ..., [509,510,511,512] }``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
template <int ITEMS_PER_THREAD>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveSum(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD])
|
|
{
|
|
if constexpr (ITEMS_PER_THREAD == 1)
|
|
{
|
|
InclusiveSum(input[0], output[0]);
|
|
}
|
|
else
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
::cuda::std::plus<> scan_op;
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveSum(thread_prefix, thread_prefix);
|
|
|
|
// Inclusive scan in registers with prefix as seed
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
|
|
}
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! Also provides every thread with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix sum of 512 integer items that
|
|
//! are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>` across 128 threads
|
|
//! where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-sum-array-aggregate
|
|
//! :end-before: example-end inclusive-sum-array-aggregate
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [1,1,1,1], [1,1,1,1], ..., [1,1,1,1] }``. The
|
|
//! corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [1,2,3,4], [5,6,7,8], ..., [509,510,511,512] }``.
|
|
//! Furthermore the value ``512`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! block-wide aggregate reduction of input items
|
|
template <int ITEMS_PER_THREAD>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
InclusiveSum(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], T& block_aggregate)
|
|
{
|
|
if constexpr (ITEMS_PER_THREAD == 1)
|
|
{
|
|
InclusiveSum(input[0], output[0], block_aggregate);
|
|
}
|
|
else
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
::cuda::std::plus<> scan_op;
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveSum(thread_prefix, thread_prefix, block_aggregate);
|
|
|
|
// Inclusive scan in registers with prefix as seed
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
|
|
}
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using addition (+) as the scan operator.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! Instead of using 0 as the block-wide prefix, the call-back functor ``block_prefix_callback_op`` is invoked by
|
|
//! the first warp in the block, and the value returned by *lane*\ :sub:`0` in that warp is used as the "seed"
|
|
//! value that logically prefixes the thread block's scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function
|
|
//! ``T operator()(T block_aggregate)``. The functor will be invoked by the first warp of threads in the block,
|
|
//! however only the return value from *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an inclusive prefix sum over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans. Each tile consists
|
|
//! of 512 integer items that are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>`
|
|
//! across 128 threads where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin block-prefix-callback-op
|
|
//! :end-before: example-end block-prefix-callback-op
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-scan-prefix-callback
|
|
//! :end-before: example-end inclusive-scan-prefix-callback
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``1, 1, 1, 1, 1, 1, 1, 1, ...``.
|
|
//! The corresponding output for the first segment will be
|
|
//! ``1, 2, 3, 4, ..., 511, 512``. The output for the second segment will be
|
|
//! ``513, 514, 515, 516, ..., 1023, 1024``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to the
|
|
//! logical input sequence.
|
|
//! @endrst
|
|
template <int ITEMS_PER_THREAD, typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveSum(
|
|
T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
if constexpr (ITEMS_PER_THREAD == 1)
|
|
{
|
|
InclusiveSum(input[0], output[0], block_prefix_callback_op);
|
|
}
|
|
else
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
::cuda::std::plus<> scan_op;
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveSum(thread_prefix, thread_prefix, block_prefix_callback_op);
|
|
|
|
// Inclusive scan in registers with prefix as seed
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
}
|
|
|
|
//! @}
|
|
//! @name Inclusive prefix scan operations
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix max scan of 128 integer items that
|
|
//! are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-scan-single
|
|
//! :end-before: example-end inclusive-scan-single
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``0, -1, 2, -3, ..., 126, -127``. The corresponding output ``thread_data``
|
|
//! in those threads will be ``0, 0, 2, 2, ..., 126, 126``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveScan(T input, T& output, ScanOp scan_op)
|
|
{
|
|
InternalBlockScan(temp_storage).InclusiveScan(input, output, scan_op);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element. Also provides every thread with the block-wide
|
|
//! ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix max scan of 128
|
|
//! integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(...)
|
|
//! {
|
|
//! // Specialize BlockScan for a 1D block of 128 threads of type int
|
|
//! using BlockScan = cub::BlockScan<int, 128>;
|
|
//!
|
|
//! // Allocate shared memory for BlockScan
|
|
//! __shared__ typename BlockScan::TempStorage temp_storage;
|
|
//!
|
|
//! // Obtain input item for each thread
|
|
//! int thread_data;
|
|
//! ...
|
|
//!
|
|
//! // Collectively compute the block-wide inclusive prefix max scan
|
|
//! int block_aggregate;
|
|
//! BlockScan(temp_storage).InclusiveScan(thread_data, thread_data, cuda::maximum<>{}, block_aggregate);
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``0, -1, 2, -3, ..., 126, -127``. The corresponding output ``thread_data``
|
|
//! in those threads will be ``0, 0, 2, 2, ..., 126, 126``. Furthermore the value
|
|
//! ``126`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! Block-wide aggregate reduction of input items
|
|
template <typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveScan(T input, T& output, ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
InternalBlockScan(temp_storage).InclusiveScan(input, output, scan_op, block_aggregate);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes one input element. The call-back functor ``block_prefix_callback_op``
|
|
//! is invoked by the first warp in the block, and the value returned by *lane*\ :sub:`0` in that warp is used as
|
|
//! the "seed" value that logically prefixes the thread block's scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function
|
|
//! ``T operator()(T block_aggregate)``. The functor's input parameter
|
|
//! The functor will be invoked by the first warp of threads in the block,
|
|
//! however only the return value from *lane*\ :sub:`0` is applied
|
|
//! as the block-wide prefix. Can be stateful.
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @rowmajor
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an inclusive prefix max scan over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans. Each tile consists
|
|
//! of 128 integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin block-prefix-callback-max-op
|
|
//! :end-before: example-end block-prefix-callback-max-op
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-scan-prefix-callback-max
|
|
//! :end-before: example-end inclusive-scan-prefix-callback-max
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, -1, 2, -3, 4, -5, ...``.
|
|
//! The corresponding output for the first segment will be
|
|
//! ``0, 0, 2, 2, ..., 126, 126``. The output for the second segment
|
|
//! will be ``128, 128, 130, 130, ..., 254, 254``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input item
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output item (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to
|
|
//! the logical input sequence.
|
|
//! @endrst
|
|
template <typename ScanOp, typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
InclusiveScan(T input, T& output, ScanOp scan_op, BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
InternalBlockScan(temp_storage).InclusiveScan(input, output, scan_op, block_prefix_callback_op);
|
|
}
|
|
|
|
//! @}
|
|
//! @name Inclusive prefix scan operations (multiple data per thread)
|
|
//! @{
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix max scan of 512 integer items that
|
|
//! are partitioned in a [<em>blocked arrangement</em>](../index.html#sec5sec3) across 128 threads
|
|
//! where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/examples/block/example_block_scan.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-scan-array
|
|
//! :end-before: example-end inclusive-scan-array
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }``.
|
|
//! The corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [0,0,2,2], [4,4,6,6], ..., [508,508,510,510] }``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
InclusiveScan(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], ScanOp scan_op)
|
|
{
|
|
if constexpr (ITEMS_PER_THREAD == 1)
|
|
{
|
|
InclusiveScan(input[0], output[0], scan_op);
|
|
}
|
|
else
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, scan_op);
|
|
|
|
// Inclusive scan in registers with prefix as seed (first thread does not seed)
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
|
|
}
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix max scan of 128 integer items that
|
|
//! are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>` across 64 threads
|
|
//! where each thread owns 2 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/test/catch2_test_block_scan_api.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-scan-array-init-value
|
|
//! :end-before: example-end inclusive-scan-array-init-value
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] initial_value
|
|
//! Initial value to seed the inclusive scan (uniform across block)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
InclusiveScan(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], T initial_value, ScanOp scan_op)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, initial_value, scan_op);
|
|
|
|
// Exclusive scan in registers with prefix as seed
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements. Also provides every thread
|
|
//! with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix max scan of 512 integer items that
|
|
//! are partitioned in a [<em>blocked arrangement</em>](../index.html#sec5sec3) across 128 threads
|
|
//! where each thread owns 4 consecutive items.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
|
|
//!
|
|
//! __global__ void ExampleKernel(...)
|
|
//! {
|
|
//! // Specialize BlockScan for a 1D block of 128 threads of type int
|
|
//! using BlockScan = cub::BlockScan<int, 128>;
|
|
//!
|
|
//! // Allocate shared memory for BlockScan
|
|
//! __shared__ typename BlockScan::TempStorage temp_storage;
|
|
//!
|
|
//! // Obtain a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[4];
|
|
//! ...
|
|
//!
|
|
//! // Collectively compute the block-wide inclusive prefix max scan
|
|
//! int block_aggregate;
|
|
//! BlockScan(temp_storage).InclusiveScan(thread_data, thread_data, cuda::maximum<>{}, block_aggregate);
|
|
//!
|
|
//! Suppose the set of input ``thread_data`` across the block of threads is
|
|
//! ``{ [0,-1,2,-3], [4,-5,6,-7], ..., [508,-509,510,-511] }``.
|
|
//! The corresponding output ``thread_data`` in those threads will be
|
|
//! ``{ [0,0,2,2], [4,4,6,6], ..., [508,508,510,510] }``.
|
|
//! Furthermore the value ``510`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! Block-wide aggregate reduction of input items
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void
|
|
InclusiveScan(T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
if (ITEMS_PER_THREAD == 1)
|
|
{
|
|
InclusiveScan(input[0], output[0], scan_op, block_aggregate);
|
|
}
|
|
else
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan (with no initial value)
|
|
ExclusiveScan(thread_prefix, thread_prefix, scan_op, block_aggregate);
|
|
|
|
// Inclusive scan in registers with prefix as seed (first thread does not seed)
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix, (linear_tid != 0));
|
|
}
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements. Also provides every thread
|
|
//! with the block-wide ``block_aggregate`` of all inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates an inclusive prefix max scan of 128 integer items that
|
|
//! are partitioned in a :ref:`blocked arrangement <flexible-data-arrangement>` across 64 threads
|
|
//! where each thread owns 2 consecutive items.
|
|
//!
|
|
//! .. literalinclude:: ../../../cub/test/catch2_test_block_scan_api.cu
|
|
//! :language: c++
|
|
//! :dedent:
|
|
//! :start-after: example-begin inclusive-scan-array-aggregate-init-value
|
|
//! :end-before: example-end inclusive-scan-array-aggregate-init-value
|
|
//!
|
|
//! The value ``126`` will be stored in ``block_aggregate`` for all threads.
|
|
//!
|
|
//! .. note::
|
|
//!
|
|
//! ``initial_value`` is not applied to the block-wide aggregate.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] initial_value
|
|
//! Initial value to seed the inclusive scan (uniform across block). It is not taken
|
|
//! into account for ``block_aggregate``.
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[out] block_aggregate
|
|
//! Block-wide aggregate reduction of input items
|
|
template <int ITEMS_PER_THREAD, typename ScanOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveScan(
|
|
T (&input)[ITEMS_PER_THREAD], T (&output)[ITEMS_PER_THREAD], T initial_value, ScanOp scan_op, T& block_aggregate)
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, initial_value, scan_op, block_aggregate);
|
|
|
|
// Exclusive scan in registers with prefix as seed
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
|
|
//! @rst
|
|
//! Computes an inclusive block-wide prefix scan using the specified binary ``scan_op`` functor.
|
|
//! Each thread contributes an array of consecutive input elements.
|
|
//! The call-back functor ``block_prefix_callback_op`` is invoked by the first warp in the block,
|
|
//! and the value returned by *lane*\ :sub:`0` in that warp is used as the "seed" value that logically prefixes the
|
|
//! thread block's scan inputs.
|
|
//!
|
|
//! .. versionadded:: 2.2.0
|
|
//! First appears in CUDA Toolkit 12.3.
|
|
//!
|
|
//! - The ``block_prefix_callback_op`` functor must implement a member function ``T operator()(T block_aggregate)``.
|
|
//! The functor will be invoked by the first warp of threads in the block, however only the return value
|
|
//! from *lane*\ :sub:`0` is applied as the block-wide prefix. Can be stateful.
|
|
//! - Supports non-commutative scan operators.
|
|
//! - @blocked
|
|
//! - @granularity
|
|
//! - @smemreuse
|
|
//!
|
|
//! Snippet
|
|
//! +++++++
|
|
//!
|
|
//! The code snippet below illustrates a single thread block that progressively
|
|
//! computes an inclusive prefix max scan over multiple "tiles" of input using a
|
|
//! prefix functor to maintain a running total between block-wide scans. Each tile consists
|
|
//! of 128 integer items that are partitioned across 128 threads.
|
|
//!
|
|
//! .. code-block:: c++
|
|
//!
|
|
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_scan.cuh>
|
|
//!
|
|
//! // A stateful callback functor that maintains a running prefix to be applied
|
|
//! // during consecutive scan operations.
|
|
//! struct BlockPrefixCallbackOp
|
|
//! {
|
|
//! // Running prefix
|
|
//! int running_total;
|
|
//!
|
|
//! // Constructor
|
|
//! __device__ BlockPrefixCallbackOp(int running_total) : running_total(running_total) {}
|
|
//!
|
|
//! // Callback operator to be entered by the first warp of threads in the block.
|
|
//! // Thread-0 is responsible for returning a value for seeding the block-wide scan.
|
|
//! __device__ int operator()(int block_aggregate)
|
|
//! {
|
|
//! int old_prefix = running_total;
|
|
//! running_total = (block_aggregate > old_prefix) ? block_aggregate : old_prefix;
|
|
//! return old_prefix;
|
|
//! }
|
|
//! };
|
|
//!
|
|
//! __global__ void ExampleKernel(int *d_data, int num_items, ...)
|
|
//! {
|
|
//! // Specialize BlockLoad, BlockStore, and BlockScan for a 1D block of 128 threads, 4 ints per thread
|
|
//! using BlockLoad = cub::BlockLoad<int*, 128, 4, BLOCK_LOAD_TRANSPOSE> ;
|
|
//! using BlockStore = cub::BlockStore<int, 128, 4, BLOCK_STORE_TRANSPOSE> ;
|
|
//! using BlockScan = cub::BlockScan<int, 128> ;
|
|
//!
|
|
//! // Allocate aliased shared memory for BlockLoad, BlockStore, and BlockScan
|
|
//! __shared__ union {
|
|
//! typename BlockLoad::TempStorage load;
|
|
//! typename BlockScan::TempStorage scan;
|
|
//! typename BlockStore::TempStorage store;
|
|
//! } temp_storage;
|
|
//!
|
|
//! // Initialize running total
|
|
//! BlockPrefixCallbackOp prefix_op(0);
|
|
//!
|
|
//! // Have the block iterate over segments of items
|
|
//! for (int block_offset = 0; block_offset < num_items; block_offset += 128 * 4)
|
|
//! {
|
|
//! // Load a segment of consecutive items that are blocked across threads
|
|
//! int thread_data[4];
|
|
//! BlockLoad(temp_storage.load).Load(d_data + block_offset, thread_data);
|
|
//! __syncthreads();
|
|
//!
|
|
//! // Collectively compute the block-wide inclusive prefix max scan
|
|
//! BlockScan(temp_storage.scan).InclusiveScan(
|
|
//! thread_data, thread_data, cuda::maximum<>{}, prefix_op);
|
|
//! __syncthreads();
|
|
//!
|
|
//! // Store scanned items to output segment
|
|
//! BlockStore(temp_storage.store).Store(d_data + block_offset, thread_data);
|
|
//! __syncthreads();
|
|
//! }
|
|
//!
|
|
//! Suppose the input ``d_data`` is ``0, -1, 2, -3, 4, -5, ...``.
|
|
//! The corresponding output for the first segment will be
|
|
//! ``0, 0, 2, 2, 4, 4, ..., 510, 510``. The output for the second
|
|
//! segment will be ``512, 512, 514, 514, 516, 516, ..., 1022, 1022``.
|
|
//!
|
|
//! @endrst
|
|
//!
|
|
//! @tparam ITEMS_PER_THREAD
|
|
//! **[inferred]** The number of consecutive items partitioned onto each thread.
|
|
//!
|
|
//! @tparam ScanOp
|
|
//! **[inferred]** Binary scan functor type having member `T operator()(const T &a, const T &b)`
|
|
//!
|
|
//! @tparam BlockPrefixCallbackOp
|
|
//! **[inferred]** Call-back functor type having member `T operator()(T block_aggregate)`
|
|
//!
|
|
//! @param[in] input
|
|
//! Calling thread's input items
|
|
//!
|
|
//! @param[out] output
|
|
//! Calling thread's output items (may be aliased to `input`)
|
|
//!
|
|
//! @param[in] scan_op
|
|
//! Binary scan functor
|
|
//!
|
|
//! @param[in,out] block_prefix_callback_op
|
|
//! @rst
|
|
//! *warp*\ :sub:`0` only call-back functor for specifying a block-wide prefix to be applied to
|
|
//! the logical input sequence.
|
|
//! @endrst
|
|
template <int ITEMS_PER_THREAD, typename ScanOp, typename BlockPrefixCallbackOp>
|
|
_CCCL_DEVICE _CCCL_FORCEINLINE void InclusiveScan(
|
|
T (&input)[ITEMS_PER_THREAD],
|
|
T (&output)[ITEMS_PER_THREAD],
|
|
ScanOp scan_op,
|
|
BlockPrefixCallbackOp& block_prefix_callback_op)
|
|
{
|
|
if (ITEMS_PER_THREAD == 1)
|
|
{
|
|
InclusiveScan(input[0], output[0], scan_op, block_prefix_callback_op);
|
|
}
|
|
else
|
|
{
|
|
// Reduce consecutive thread items in registers
|
|
T thread_prefix = cub::ThreadReduce(input, scan_op);
|
|
|
|
// Exclusive thread block-scan
|
|
ExclusiveScan(thread_prefix, thread_prefix, scan_op, block_prefix_callback_op);
|
|
|
|
// Inclusive scan in registers with prefix as seed
|
|
detail::ThreadScanInclusive(input, output, scan_op, thread_prefix);
|
|
}
|
|
}
|
|
|
|
//! @}
|
|
};
|
|
|
|
CUB_NAMESPACE_END
|