Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
agent_reduce.cuh485 linesDownload Raw Back to agent
1/******************************************************************************2 * Copyright (c) 2011, Duane Merrill.  All rights reserved.3 * Copyright (c) 2011-2022, NVIDIA CORPORATION.  All rights reserved.4 *5 * Redistribution and use in source and binary forms, with or without6 * modification, are permitted provided that the following conditions are met:7 *     * Redistributions of source code must retain the above copyright8 *       notice, this list of conditions and the following disclaimer.9 *     * Redistributions in binary form must reproduce the above copyright10 *       notice, this list of conditions and the following disclaimer in the11 *       documentation and/or other materials provided with the distribution.12 *     * Neither the name of the NVIDIA CORPORATION nor the13 *       names of its contributors may be used to endorse or promote products14 *       derived from this software without specific prior written permission.15 *16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19 * ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.26 *27 ******************************************************************************/28 29/**30 * @file cub::AgentReduce implements a stateful abstraction of CUDA thread31 *       blocks for participating in device-wide reduction.32 */33 34#pragma once35 36#include <cub/config.cuh>37 38#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)39#  pragma GCC system_header40#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)41#  pragma clang system_header42#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)43#  pragma system_header44#endif // no system header45 46#include <iterator>47 48#include <cub/block/block_load.cuh>49#include <cub/block/block_reduce.cuh>50#include <cub/detail/type_traits.cuh>51#include <cub/grid/grid_even_share.cuh>52#include <cub/grid/grid_mapping.cuh>53#include <cub/iterator/cache_modified_input_iterator.cuh>54#include <cub/util_type.cuh>55 56CUB_NAMESPACE_BEGIN57 58/******************************************************************************59 * Tuning policy types60 ******************************************************************************/61 62/**63 * Parameterizable tuning policy type for AgentReduce64 * @tparam NOMINAL_BLOCK_THREADS_4B Threads per thread block65 * @tparam NOMINAL_ITEMS_PER_THREAD_4B Items per thread (per tile of input)66 * @tparam ComputeT Dominant compute type67 * @tparam _VECTOR_LOAD_LENGTH Number of items per vectorized load68 * @tparam _BLOCK_ALGORITHM Cooperative block-wide reduction algorithm to use69 * @tparam _LOAD_MODIFIER Cache load modifier for reading input elements70 */71template <int NOMINAL_BLOCK_THREADS_4B,72          int NOMINAL_ITEMS_PER_THREAD_4B,73          typename ComputeT,74          int _VECTOR_LOAD_LENGTH,75          BlockReduceAlgorithm _BLOCK_ALGORITHM,76          CacheLoadModifier _LOAD_MODIFIER,77          typename ScalingType = MemBoundScaling<NOMINAL_BLOCK_THREADS_4B,78                                                 NOMINAL_ITEMS_PER_THREAD_4B,79                                                 ComputeT>>80struct AgentReducePolicy : ScalingType81{82  /// Number of items per vectorized load83  static constexpr int VECTOR_LOAD_LENGTH = _VECTOR_LOAD_LENGTH;84 85  /// Cooperative block-wide reduction algorithm to use86  static constexpr BlockReduceAlgorithm BLOCK_ALGORITHM = _BLOCK_ALGORITHM;87 88  /// Cache load modifier for reading input elements89  static constexpr CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER;90};91 92/******************************************************************************93 * Thread block abstractions94 ******************************************************************************/95 96/**97 * @brief AgentReduce implements a stateful abstraction of CUDA thread blocks98 *        for participating in device-wide reduction .99 *100 * Each thread reduces only the values it loads. If `FIRST_TILE`, this partial101 * reduction is stored into `thread_aggregate`. Otherwise it is accumulated102 * into `thread_aggregate`.103 *104 * @tparam AgentReducePolicy105 *   Parameterized AgentReducePolicy tuning policy type106 *107 * @tparam InputIteratorT108 *   Random-access iterator type for input109 *110 * @tparam OutputIteratorT111 *   Random-access iterator type for output112 *113 * @tparam OffsetT114 *   Signed integer type for global offsets115 *116 * @tparam ReductionOp117 *   Binary reduction operator type having member118 *   `auto operator()(T &&a, U &&b)`119 *120 * @tparam AccumT121 *   The type of intermediate accumulator (according to P2322R6)122 */123template <typename AgentReducePolicy,124          typename InputIteratorT,125          typename OutputIteratorT,126          typename OffsetT,127          typename ReductionOp,128          typename AccumT>129struct AgentReduce130{131  //---------------------------------------------------------------------132  // Types and constants133  //---------------------------------------------------------------------134 135  /// The input value type136  using InputT = cub::detail::value_t<InputIteratorT>;137 138  /// Vector type of InputT for data movement139  using VectorT =140    typename CubVector<InputT, AgentReducePolicy::VECTOR_LOAD_LENGTH>::Type;141 142  /// Input iterator wrapper type (for applying cache modifier)143  // Wrap the native input pointer with CacheModifiedInputIterator144  // or directly use the supplied input iterator type145  using WrappedInputIteratorT = cub::detail::conditional_t<146    std::is_pointer<InputIteratorT>::value,147    CacheModifiedInputIterator<AgentReducePolicy::LOAD_MODIFIER, InputT, OffsetT>,148    InputIteratorT>;149 150  /// Constants151  static constexpr int BLOCK_THREADS      = AgentReducePolicy::BLOCK_THREADS;152  static constexpr int ITEMS_PER_THREAD   = AgentReducePolicy::ITEMS_PER_THREAD;153  static constexpr int TILE_ITEMS         = BLOCK_THREADS * ITEMS_PER_THREAD;154  static constexpr int VECTOR_LOAD_LENGTH =155    CUB_MIN(ITEMS_PER_THREAD, AgentReducePolicy::VECTOR_LOAD_LENGTH);156 157  // Can vectorize according to the policy if the input iterator is a native158  // pointer to a primitive type159  static constexpr bool ATTEMPT_VECTORIZATION = (VECTOR_LOAD_LENGTH > 1) &&160                            (ITEMS_PER_THREAD % VECTOR_LOAD_LENGTH == 0) &&161                            (std::is_pointer<InputIteratorT>::value) &&162                            Traits<InputT>::PRIMITIVE;163 164  static constexpr CacheLoadModifier LOAD_MODIFIER =165    AgentReducePolicy::LOAD_MODIFIER;166 167  static constexpr BlockReduceAlgorithm BLOCK_ALGORITHM =168    AgentReducePolicy::BLOCK_ALGORITHM;169 170  /// Parameterized BlockReduce primitive171  using BlockReduceT =172    BlockReduce<AccumT, BLOCK_THREADS, AgentReducePolicy::BLOCK_ALGORITHM>;173 174  /// Shared memory type required by this thread block175  struct _TempStorage176  {177    typename BlockReduceT::TempStorage reduce;178  };179 180  /// Alias wrapper allowing storage to be unioned181  struct TempStorage : Uninitialized<_TempStorage>182  {};183 184  //---------------------------------------------------------------------185  // Per-thread fields186  //---------------------------------------------------------------------187 188  _TempStorage &temp_storage;         ///< Reference to temp_storage189  InputIteratorT d_in;                ///< Input data to reduce190  WrappedInputIteratorT d_wrapped_in; ///< Wrapped input data to reduce191  ReductionOp reduction_op;           ///< Binary reduction operator192 193  //---------------------------------------------------------------------194  // Utility195  //---------------------------------------------------------------------196 197  // Whether or not the input is aligned with the vector type (specialized for198  // types we can vectorize)199  template <typename Iterator>200  static __device__ __forceinline__ bool201  IsAligned(Iterator d_in, Int2Type<true> /*can_vectorize*/)202  {203    return (size_t(d_in) & (sizeof(VectorT) - 1)) == 0;204  }205 206  // Whether or not the input is aligned with the vector type (specialized for207  // types we cannot vectorize)208  template <typename Iterator>209  static __device__ __forceinline__ bool210  IsAligned(Iterator /*d_in*/, Int2Type<false> /*can_vectorize*/)211  {212    return false;213  }214 215  //---------------------------------------------------------------------216  // Constructor217  //---------------------------------------------------------------------218 219  /**220   * @brief Constructor221   * @param temp_storage Reference to temp_storage222   * @param d_in Input data to reduce223   * @param reduction_op Binary reduction operator224   */225  __device__ __forceinline__ AgentReduce(TempStorage &temp_storage,226                                         InputIteratorT d_in,227                                         ReductionOp reduction_op)228      : temp_storage(temp_storage.Alias())229      , d_in(d_in)230      , d_wrapped_in(d_in)231      , reduction_op(reduction_op)232  {}233 234  //---------------------------------------------------------------------235  // Tile consumption236  //---------------------------------------------------------------------237 238  /**239   * @brief Consume a full tile of input (non-vectorized)240   * @param block_offset The offset the tile to consume241   * @param valid_items The number of valid items in the tile242   * @param is_full_tile Whether or not this is a full tile243   * @param can_vectorize Whether or not we can vectorize loads244   */245  template <int IS_FIRST_TILE>246  __device__ __forceinline__ void ConsumeTile(AccumT &thread_aggregate,247                                              OffsetT block_offset,248                                              int /*valid_items*/,249                                              Int2Type<true> /*is_full_tile*/,250                                              Int2Type<false> /*can_vectorize*/)251  {252    AccumT items[ITEMS_PER_THREAD];253 254    // Load items in striped fashion255    LoadDirectStriped<BLOCK_THREADS>(threadIdx.x,256                                     d_wrapped_in + block_offset,257                                     items);258 259    // Reduce items within each thread stripe260    thread_aggregate =261      (IS_FIRST_TILE)262        ? internal::ThreadReduce(items, reduction_op)263        : internal::ThreadReduce(items, reduction_op, thread_aggregate);264  }265 266  /**267   * Consume a full tile of input (vectorized)268   * @param block_offset The offset the tile to consume269   * @param valid_items The number of valid items in the tile270   * @param is_full_tile Whether or not this is a full tile271   * @param can_vectorize Whether or not we can vectorize loads272   */273  template <int IS_FIRST_TILE>274  __device__ __forceinline__ void ConsumeTile(AccumT &thread_aggregate,275                                              OffsetT block_offset,276                                              int /*valid_items*/,277                                              Int2Type<true> /*is_full_tile*/,278                                              Int2Type<true> /*can_vectorize*/)279  {280    // Alias items as an array of VectorT and load it in striped fashion281    enum282    {283      WORDS = ITEMS_PER_THREAD / VECTOR_LOAD_LENGTH284    };285 286    // Fabricate a vectorized input iterator287    InputT *d_in_unqualified = const_cast<InputT *>(d_in) + block_offset +288                               (threadIdx.x * VECTOR_LOAD_LENGTH);289    CacheModifiedInputIterator<AgentReducePolicy::LOAD_MODIFIER, VectorT, OffsetT>290      d_vec_in(reinterpret_cast<VectorT *>(d_in_unqualified));291 292    // Load items as vector items293    InputT input_items[ITEMS_PER_THREAD];294    VectorT *vec_items = reinterpret_cast<VectorT *>(input_items);295#pragma unroll296    for (int i = 0; i < WORDS; ++i)297    {298      vec_items[i] = d_vec_in[BLOCK_THREADS * i];299    }300 301    // Convert from input type to output type302    AccumT items[ITEMS_PER_THREAD];303#pragma unroll304    for (int i = 0; i < ITEMS_PER_THREAD; ++i)305    {306      items[i] = input_items[i];307    }308 309    // Reduce items within each thread stripe310    thread_aggregate =311      (IS_FIRST_TILE)312        ? internal::ThreadReduce(items, reduction_op)313        : internal::ThreadReduce(items, reduction_op, thread_aggregate);314  }315 316  /**317   * Consume a partial tile of input318   * @param block_offset The offset the tile to consume319   * @param valid_items The number of valid items in the tile320   * @param is_full_tile Whether or not this is a full tile321   * @param can_vectorize Whether or not we can vectorize loads322   */323  template <int IS_FIRST_TILE, int CAN_VECTORIZE>324  __device__ __forceinline__ void325  ConsumeTile(AccumT &thread_aggregate,326              OffsetT block_offset,327              int valid_items,328              Int2Type<false> /*is_full_tile*/,329              Int2Type<CAN_VECTORIZE> /*can_vectorize*/)330  {331    // Partial tile332    int thread_offset = threadIdx.x;333 334    // Read first item335    if ((IS_FIRST_TILE) && (thread_offset < valid_items))336    {337      thread_aggregate = d_wrapped_in[block_offset + thread_offset];338      thread_offset += BLOCK_THREADS;339    }340 341    // Continue reading items (block-striped)342    while (thread_offset < valid_items)343    {344      InputT item(d_wrapped_in[block_offset + thread_offset]);345 346      thread_aggregate = reduction_op(thread_aggregate, item);347      thread_offset += BLOCK_THREADS;348    }349  }350 351  //---------------------------------------------------------------352  // Consume a contiguous segment of tiles353  //---------------------------------------------------------------------354 355  /**356   * @brief Reduce a contiguous segment of input tiles357   * @param even_share GridEvenShare descriptor358   * @param can_vectorize Whether or not we can vectorize loads359   */360  template <int CAN_VECTORIZE>361  __device__ __forceinline__ AccumT362  ConsumeRange(GridEvenShare<OffsetT> &even_share,363               Int2Type<CAN_VECTORIZE> can_vectorize)364  {365    AccumT thread_aggregate{};366 367    if (even_share.block_end - even_share.block_offset < TILE_ITEMS)368    {369      // First tile isn't full (not all threads have valid items)370      int valid_items = even_share.block_end - even_share.block_offset;371      ConsumeTile<true>(thread_aggregate,372                        even_share.block_offset,373                        valid_items,374                        Int2Type<false>(),375                        can_vectorize);376      return BlockReduceT(temp_storage.reduce)377        .Reduce(thread_aggregate, reduction_op, valid_items);378    }379 380    // Extracting this into a function saves 8% of generated kernel size by allowing to reuse381    // the block reduction below. This also workaround hang in nvcc.382    ConsumeFullTileRange(thread_aggregate, even_share, can_vectorize);383 384    // Compute block-wide reduction (all threads have valid items)385    return BlockReduceT(temp_storage.reduce)386      .Reduce(thread_aggregate, reduction_op);387  }388 389  /**390   * @brief Reduce a contiguous segment of input tiles391   * @param[in] block_offset Threadblock begin offset (inclusive)392   * @param[in] block_end Threadblock end offset (exclusive)393   */394  __device__ __forceinline__ AccumT ConsumeRange(OffsetT block_offset,395                                                 OffsetT block_end)396  {397    GridEvenShare<OffsetT> even_share;398    even_share.template BlockInit<TILE_ITEMS>(block_offset, block_end);399 400    return (IsAligned(d_in + block_offset, Int2Type<ATTEMPT_VECTORIZATION>()))401             ? ConsumeRange(even_share,402                            Int2Type < true && ATTEMPT_VECTORIZATION > ())403             : ConsumeRange(even_share,404                            Int2Type < false && ATTEMPT_VECTORIZATION > ());405  }406 407  /**408   * Reduce a contiguous segment of input tiles409   * @param[in] even_share GridEvenShare descriptor410   */411  __device__ __forceinline__ AccumT412  ConsumeTiles(GridEvenShare<OffsetT> &even_share)413  {414    // Initialize GRID_MAPPING_STRIP_MINE even-share descriptor for this thread block415    even_share.template BlockInit<TILE_ITEMS, GRID_MAPPING_STRIP_MINE>();416 417    return (IsAligned(d_in, Int2Type<ATTEMPT_VECTORIZATION>()))418             ? ConsumeRange(even_share,419                            Int2Type < true && ATTEMPT_VECTORIZATION > ())420             : ConsumeRange(even_share,421                            Int2Type < false && ATTEMPT_VECTORIZATION > ());422  }423 424private:425  /**426   * @brief Reduce a contiguous segment of input tiles with more than `TILE_ITEMS` elements427   * @param even_share GridEvenShare descriptor428   * @param can_vectorize Whether or not we can vectorize loads429   */430  template <int CAN_VECTORIZE>431  __device__ __forceinline__ void432  ConsumeFullTileRange(AccumT &thread_aggregate,433                       GridEvenShare<OffsetT> &even_share,434                       Int2Type<CAN_VECTORIZE> can_vectorize)435  {436    // At least one full block437    ConsumeTile<true>(thread_aggregate,438                      even_share.block_offset,439                      TILE_ITEMS,440                      Int2Type<true>(),441                      can_vectorize);442 443    if (even_share.block_end - even_share.block_offset < even_share.block_stride)444    {445      // Exit early to handle offset overflow446      return;447    }448 449    even_share.block_offset += even_share.block_stride;450 451    // Consume subsequent full tiles of input, at least one full tile was processed, so452    // `even_share.block_end >= TILE_ITEMS`453    while (even_share.block_offset <= even_share.block_end - TILE_ITEMS)454    {455      ConsumeTile<false>(thread_aggregate,456                         even_share.block_offset,457                         TILE_ITEMS,458                         Int2Type<true>(),459                         can_vectorize);460 461      if (even_share.block_end - even_share.block_offset < even_share.block_stride)462      {463        // Exit early to handle offset overflow464        return;465      }466 467      even_share.block_offset += even_share.block_stride;468    }469 470    // Consume a partially-full tile471    if (even_share.block_offset < even_share.block_end)472    {473      int valid_items = even_share.block_end - even_share.block_offset;474      ConsumeTile<false>(thread_aggregate,475                         even_share.block_offset,476                         valid_items,477                         Int2Type<false>(),478                         can_vectorize);479    }480  }481};482 483CUB_NAMESPACE_END484 485 
codekingpro/portable-devtools · Team Ai