Files
project_6/cccl_upstream/cub/cub/block/block_reduce.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

712 lines
26 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::BlockReduce class provides :ref:`collective <collective-primitives>` methods for
//! computing a parallel reduction 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_reduce_raking.cuh>
#include <cub/block/specializations/block_reduce_raking_commutative_only.cuh>
#include <cub/block/specializations/block_reduce_warp_reductions.cuh>
#include <cub/thread/thread_operators.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
******************************************************************************/
//! BlockReduceAlgorithm enumerates alternative algorithms for parallel reduction across a CUDA thread
//! block.
enum BlockReduceAlgorithm
{
//! @rst
//! Overview
//! ++++++++++++++++++++++++++
//!
//! An efficient "raking" reduction algorithm that only supports commutative reduction operators
//! (true for most operations, e.g., addition).
//!
//! Execution is comprised of three phases:
//! #. Upsweep sequential reduction in registers (if threads contribute more than one input each).
//! Threads in warps other than the first warp place their partial reductions into shared
//! memory.
//! #. Upsweep sequential reduction in shared memory. Threads within the first warp continue to
//! accumulate by raking across segments of shared partial reductions
//! #. A warp-synchronous Kogge-Stone style reduction within the raking warp.
//!
//! Performance Considerations
//! ++++++++++++++++++++++++++
//!
//! - This variant performs less communication than BLOCK_REDUCE_RAKING_NON_COMMUTATIVE and is
//! preferable when the reduction operator is commutative. This variant applies fewer reduction
//! operators than BLOCK_REDUCE_WARP_REDUCTIONS, and can provide higher overall throughput across
//! the GPU when suitably occupied. However, turn-around latency may be higher than to
//! BLOCK_REDUCE_WARP_REDUCTIONS and thus less-desirable when the GPU is under-occupied.
//!
//! @endrst
BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY,
//! @rst
//! Overview
//! ++++++++++++++++++++++++++
//!
//! An efficient "raking" reduction algorithm that supports commutative (e.g., addition) and
//! non-commutative (e.g., string concatenation) reduction operators. @blocked.
//!
//! Execution is comprised of three 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 reduction within the raking warp.
//!
//! Performance Considerations
//! ++++++++++++++++++++++++++
//!
//! - This variant performs more communication than BLOCK_REDUCE_RAKING and is only preferable when
//! the reduction operator is non-commutative. This variant applies fewer reduction operators than
//! BLOCK_REDUCE_WARP_REDUCTIONS, and can provide higher overall throughput across the GPU when
//! suitably occupied. However, turn-around latency may be higher than to
//! BLOCK_REDUCE_WARP_REDUCTIONS and thus less-desirable when the GPU is under-occupied.
//!
//! @endrst
BLOCK_REDUCE_RAKING,
//! @rst
//! Overview
//! ++++++++++++++++++++++++++
//!
//! A quick "tiled warp-reductions" reduction algorithm that supports commutative (e.g., addition)
//! and non-commutative (e.g., string concatenation) reduction operators.
//!
//! 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 reduction within
//! each warp.
//! #. A propagation phase where the warp reduction outputs in each warp are updated with the
//! aggregate from each preceding warp.
//!
//! Performance Considerations
//! ++++++++++++++++++++++++++
//!
//! - This variant applies more reduction operators than BLOCK_REDUCE_RAKING or
//! BLOCK_REDUCE_RAKING_NON_COMMUTATIVE, which may result in lower overall throughput across the
//! GPU. However turn-around latency may be lower and thus useful when the GPU is under-occupied.
//!
//! @endrst
BLOCK_REDUCE_WARP_REDUCTIONS,
//! @rst
//! Overview
//! ++++++++++++++++++++++++++
//!
//! A quick "tiled warp-reductions" reduction algorithm that supports commutative (e.g., addition)
//! and non-commutative (e.g., string concatenation) reduction operators. This variant uses atomic
//! operations to reduce the warp-wide reduction results, making it non-deterministic, i.e. the
//! order of reduction operations is not guaranteed to be the same across different invocations of
//! the same kernel.
//!
//! Execution is comprised of three 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 non work-efficient warp-synchronous Kogge-Stone style reduction
//! within each warp.
//! #. Lane 0 of warp 0 stores its warp aggregate, while lane 0 of other warps use atomic
//! operations to accumulate their warp aggregates into a shared location, making the final
//! order non-deterministic.
//! #. The final block-wide result is available to all threads.
//!
//! Performance Considerations
//! ++++++++++++++++++++++++++
//!
//! - This variant applies more reduction operators than BLOCK_REDUCE_RAKING or
//! BLOCK_REDUCE_RAKING_NON_COMMUTATIVE, which may result in lower overall throughput across the
//! GPU. However turn-around latency may be lower and thus useful when the GPU is under-occupied.
//!
//! @endrst
BLOCK_REDUCE_WARP_REDUCTIONS_NONDETERMINISTIC,
};
#if _CCCL_HOSTED() && !defined(_CCCL_DOXYGEN_INVOKED)
namespace detail
{
[[nodiscard]] _CCCL_HOST_DEVICE_API constexpr const char* to_string(BlockReduceAlgorithm algo) noexcept
{
switch (algo)
{
case BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY:
return "BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY";
case BLOCK_REDUCE_RAKING:
return "BLOCK_REDUCE_RAKING";
case BLOCK_REDUCE_WARP_REDUCTIONS:
return "BLOCK_REDUCE_WARP_REDUCTIONS";
case BLOCK_REDUCE_WARP_REDUCTIONS_NONDETERMINISTIC:
return "BLOCK_REDUCE_WARP_REDUCTIONS_NONDETERMINISTIC";
}
return "<unknown BlockReduceAlgorithm>";
}
} // namespace detail
inline ::std::ostream& operator<<(::std::ostream& os, BlockReduceAlgorithm 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::BlockReduceAlgorithm, CharT> : formatter<const CharT*, CharT>
{
template <class FmtCtx>
auto format(const CUB_NS_QUALIFIER::BlockReduceAlgorithm& 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 BlockReduce class provides :ref:`collective <collective-primitives>` methods for computing a
//! parallel reduction of items partitioned across a CUDA thread block.
//!
//! Overview
//! +++++++++++++++++++++++++++++++++++++++++++++
//!
//! - A `reduction <http://en.wikipedia.org/wiki/Reduce_(higher-order_function)>`_ (or *fold*) uses a
//! binary combining operator to compute a single aggregate from a list of input elements.
//! - @rowmajor
//! - BlockReduce can be optionally specialized by algorithm to accommodate different
//! latency/throughput workload profiles:
//!
//! #. :cpp:enumerator:`cub::BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY`:
//! An efficient "raking" reduction algorithm that only supports commutative reduction operators.
//! #. :cpp:enumerator:`cub::BLOCK_REDUCE_RAKING`:
//! An efficient "raking" reduction algorithm that supports commutative and non-commutative
//! reduction operators.
//! #. :cpp:enumerator:`cub::BLOCK_REDUCE_WARP_REDUCTIONS`:
//! A quick "tiled warp-reductions" reduction algorithm that supports commutative and
//! non-commutative reduction operators.
//! #. :cpp:enumerator:`cub::BLOCK_REDUCE_WARP_REDUCTIONS_NONDETERMINISTIC`:
//! A quick "tiled warp-reductions" reduction algorithm that supports commutative and
//! non-commutative reduction operators. This variant uses atomic operations to reduce the
//! warp-wide reduction results, making it non-deterministic, i.e. the order of reduction
//! operations is not guaranteed to be the same across different invocations of the same
//! kernel.
//!
//! Performance Considerations
//! +++++++++++++++++++++++++++++++++++++++++++++
//!
//! - @granularity
//! - Very efficient (only one synchronization barrier).
//! - Incurs zero bank conflicts for most types
//! - Computation is slightly more efficient (i.e., having lower instruction overhead) for:
//! - Summation (vs. generic reduction)
//! - ``BLOCK_THREADS`` is a multiple of the architecture's warp size
//! - Every thread has a valid input (i.e., full vs. partial-tiles)
//! - See cub::BlockReduceAlgorithm for performance details regarding algorithmic alternatives
//!
//! A Simple Example
//! +++++++++++++++++++++++++++++++++++++++++++++
//!
//! @blockcollective{BlockReduce}
//!
//! The code snippet below illustrates a sum reduction 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_reduce.cuh>
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Compute the block-wide sum for thread0
//! int aggregate = BlockReduce(temp_storage).Sum(thread_data);
//! }
//!
//! 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.
//!
//! @endrst
//!
//! @tparam T
//! Data type being reduced
//!
//! @tparam BlockDimX
//! The thread block length in threads along the X dimension
//!
//! @tparam Algorithm
//! **[optional]** cub::BlockReduceAlgorithm enumerator specifying the underlying algorithm to use
//! (default: cub::BLOCK_REDUCE_WARP_REDUCTIONS)
//!
//! @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,
BlockReduceAlgorithm Algorithm = BLOCK_REDUCE_WARP_REDUCTIONS,
int BlockDimY = 1,
int BlockDimZ = 1>
class BlockReduce
{
private:
/// The thread block size in threads
static constexpr int BLOCK_THREADS = BlockDimX * BlockDimY * BlockDimZ;
using WarpReductions = detail::BlockReduceWarpReductions<T, BlockDimX, BlockDimY, BlockDimZ>;
using WarpReductionsNondeterministic = detail::BlockReduceWarpReductions<T, BlockDimX, BlockDimY, BlockDimZ, false>;
using RakingCommutativeOnly = detail::BlockReduceRakingCommutativeOnly<T, BlockDimX, BlockDimY, BlockDimZ>;
using Raking = detail::BlockReduceRaking<T, BlockDimX, BlockDimY, BlockDimZ>;
/// Internal specialization type
using InternalBlockReduce =
::cuda::std::_If<Algorithm == BLOCK_REDUCE_WARP_REDUCTIONS,
WarpReductions,
::cuda::std::_If<Algorithm == BLOCK_REDUCE_WARP_REDUCTIONS_NONDETERMINISTIC,
WarpReductionsNondeterministic,
::cuda::std::_If<Algorithm == BLOCK_REDUCE_RAKING_COMMUTATIVE_ONLY,
RakingCommutativeOnly,
Raking>>>; // BlockReduceRaking
/// Shared memory storage layout type for BlockReduce
using _TempStorage = typename InternalBlockReduce::TempStorage;
/// Internal storage allocator
_CCCL_DEVICE _CCCL_FORCEINLINE _TempStorage& PrivateStorage()
{
__shared__ _TempStorage private_storage;
return private_storage;
}
/// Shared storage reference
_TempStorage& temp_storage;
/// Linear thread-id
unsigned int linear_tid;
public:
/// @smemstorage{BlockReduce}
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 BlockReduce()
: 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 BlockReduce(TempStorage& temp_storage)
: temp_storage(temp_storage.Alias())
, linear_tid(RowMajorTid(BlockDimX, BlockDimY, BlockDimZ))
{}
//! @}
//! @name Generic reductions
//! @{
//! @rst
//! Computes a block-wide reduction for thread\ :sub:`0` using the specified binary reduction functor.
//! Each thread contributes one input element.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - The return value is undefined in threads other than thread\ :sub:`0`.
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates a max reduction of 128 integer items that are partitioned
//! across 128 threads.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Each thread obtains an input item
//! int thread_data;
//! ...
//!
//! // Compute the block-wide max for thread0
//! int aggregate = BlockReduce(temp_storage).Reduce(thread_data, cuda::maximum<>{});
//! }
//!
//! @endrst
//!
//! @tparam ReductionOp
//! **[inferred]** Binary reduction functor type having member `T operator()(const T &a, const T &b)`
//!
//! @param[in] input
//! Calling thread's input
//!
//! @param[in] reduction_op
//! Binary reduction functor
template <typename ReductionOp>
_CCCL_DEVICE _CCCL_FORCEINLINE T Reduce(T input, ReductionOp reduction_op)
{
return InternalBlockReduce(temp_storage).template Reduce<true>(input, BLOCK_THREADS, reduction_op);
}
//! @rst
//! Computes a block-wide reduction for thread\ :sub:`0` using the specified binary reduction
//! functor. Each thread contributes an array of consecutive input elements.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - The return value is undefined in threads other than thread\ :sub:`0`.
//! - @granularity
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates a max reduction 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_reduce.cuh>
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Compute the block-wide max for thread0
//! int aggregate = BlockReduce(temp_storage).Reduce(thread_data, cuda::maximum<>{});
//! }
//!
//! @endrst
//!
//! @tparam ITEMS_PER_THREAD
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @tparam ReductionOp
//! **[inferred]** Binary reduction functor type having member `T operator()(const T &a, const T &b)`
//!
//! @param[in] inputs
//! Calling thread's input segment
//!
//! @param[in] reduction_op
//! Binary reduction functor
template <int ITEMS_PER_THREAD, typename ReductionOp>
_CCCL_DEVICE _CCCL_FORCEINLINE T Reduce(T (&inputs)[ITEMS_PER_THREAD], ReductionOp reduction_op)
{
// Reduce partials
T partial = cub::ThreadReduce(inputs, reduction_op);
return Reduce(partial, reduction_op);
}
//! @rst
//! Computes a block-wide reduction for thread\ :sub:`0` using the specified binary reduction
//! functor. The first ``num_valid`` threads each contribute one input element.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - The return value is undefined in threads other than thread<sub>0</sub>.
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates a max reduction of a partially-full tile of integer items
//! that are partitioned across 128 threads.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
//!
//! __global__ void ExampleKernel(int num_valid, ...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Each thread obtains an input item
//! int thread_data;
//! if (threadIdx.x < num_valid) thread_data = ...
//!
//! // Compute the block-wide max for thread0
//! int aggregate = BlockReduce(temp_storage).Reduce(thread_data, cuda::maximum<>{}, num_valid);
//! }
//!
//! @endrst
//!
//! @tparam ReductionOp
//! **[inferred]** Binary reduction functor type having member `T operator()(const T &a, const T &b)`
//!
//! @param[in] input
//! Calling thread's input
//!
//! @param[in] reduction_op
//! Binary reduction functor
//!
//! @param[in] num_valid
//! Number of threads containing valid elements (may be less than BLOCK_THREADS)
template <typename ReductionOp>
_CCCL_DEVICE _CCCL_FORCEINLINE T Reduce(T input, ReductionOp reduction_op, int num_valid)
{
// Determine if we skip bounds checking
if (num_valid >= BLOCK_THREADS)
{
return InternalBlockReduce(temp_storage).template Reduce<true>(input, num_valid, reduction_op);
}
else
{
return InternalBlockReduce(temp_storage).template Reduce<false>(input, num_valid, reduction_op);
}
}
//! @}
//! @name Summation reductions
//! @{
//! @rst
//! Computes a block-wide reduction for thread\ :sub:`0` using addition (+) as the reduction operator.
//! Each thread contributes one input element.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - The return value is undefined in threads other than thread\ :sub:`0`.
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates a sum reduction of 128 integer items that are partitioned
//! across 128 threads.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Each thread obtains an input item
//! int thread_data;
//! ...
//!
//! // Compute the block-wide sum for thread0
//! int aggregate = BlockReduce(temp_storage).Sum(thread_data);
//! }
//!
//! @endrst
//!
//! @param[in] input
//! Calling thread's input
_CCCL_DEVICE _CCCL_FORCEINLINE T Sum(T input)
{
return InternalBlockReduce(temp_storage).template Sum<true>(input, BLOCK_THREADS);
}
//! @rst
//! Computes a block-wide reduction for thread<sub>0</sub> using addition (+) as the reduction
//! operator. Each thread contributes an array of consecutive input elements.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - The return value is undefined in threads other than thread\ :sub:`0`.
//! - @granularity
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates a sum reduction 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_reduce.cuh>
//!
//! __global__ void ExampleKernel(...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Obtain a segment of consecutive items that are blocked across threads
//! int thread_data[4];
//! ...
//!
//! // Compute the block-wide sum for thread0
//! int aggregate = BlockReduce(temp_storage).Sum(thread_data);
//! }
//!
//! @endrst
//!
//! @tparam ITEMS_PER_THREAD
//! **[inferred]** The number of consecutive items partitioned onto each thread.
//!
//! @param[in] inputs
//! Calling thread's input segment
template <int ITEMS_PER_THREAD>
_CCCL_DEVICE _CCCL_FORCEINLINE T Sum(T (&inputs)[ITEMS_PER_THREAD])
{
// Reduce partials
T partial = cub::ThreadReduce(inputs, ::cuda::std::plus<>{});
return Sum(partial);
}
//! @rst
//! Computes a block-wide reduction for thread\ :sub:`0` using addition (+) as the reduction
//! operator. The first ``num_valid`` threads each contribute one input element.
//!
//! .. versionadded:: 2.2.0
//! First appears in CUDA Toolkit 12.3.
//!
//! - The return value is undefined in threads other than thread\ :sub:`0`.
//! - @rowmajor
//! - @smemreuse
//!
//! Snippet
//! +++++++
//!
//! The code snippet below illustrates a sum reduction of a partially-full tile of integer items
//! that are partitioned across 128 threads.
//!
//! .. code-block:: c++
//!
//! #include <cub/cub.cuh> // or equivalently <cub/block/block_reduce.cuh>
//!
//! __global__ void ExampleKernel(int num_valid, ...)
//! {
//! // Specialize BlockReduce for a 1D block of 128 threads of type int
//! using BlockReduce = cub::BlockReduce<int, 128>;
//!
//! // Allocate shared memory for BlockReduce
//! __shared__ typename BlockReduce::TempStorage temp_storage;
//!
//! // Each thread obtains an input item (up to num_items)
//! int thread_data;
//! if (threadIdx.x < num_valid)
//! thread_data = ...
//!
//! // Compute the block-wide sum for thread0
//! int aggregate = BlockReduce(temp_storage).Sum(thread_data, num_valid);
//! }
//!
//! @endrst
//!
//! @param[in] input
//! Calling thread's input
//!
//! @param[in] num_valid
//! Number of threads containing valid elements (may be less than BLOCK_THREADS)
_CCCL_DEVICE _CCCL_FORCEINLINE T Sum(T input, int num_valid)
{
// Determine if we skip bounds checking
if (num_valid >= BLOCK_THREADS)
{
return InternalBlockReduce(temp_storage).template Sum<true>(input, num_valid);
}
else
{
return InternalBlockReduce(temp_storage).template Sum<false>(input, num_valid);
}
}
//! @}
};
CUB_NAMESPACE_END