summaryrefslogtreecommitdiff
path: root/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch')
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_histogram.cuh1096
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_radix_sort.cuh1619
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce.cuh882
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce_by_key.cuh554
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_rle.cuh538
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_scan.cuh563
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_select_if.cuh542
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_spmv_orig.cuh834
8 files changed, 6628 insertions, 0 deletions
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_histogram.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_histogram.cuh
new file mode 100644
index 0000000..ab08e8e
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_histogram.cuh
@@ -0,0 +1,1096 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceHistogram provides device-wide parallel operations for constructing histogram(s) from a sequence of samples data residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+#include <limits>
+
+#include "../../agent/agent_histogram.cuh"
+#include "../../util_debug.cuh"
+#include "../../util_device.cuh"
+#include "../../thread/thread_search.cuh"
+#include "../../grid/grid_queue.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+
+/******************************************************************************
+ * Histogram kernel entry points
+ *****************************************************************************/
+
+/**
+ * Histogram initialization kernel entry point
+ */
+template <
+ int NUM_ACTIVE_CHANNELS, ///< Number of channels actively being histogrammed
+ typename CounterT, ///< Integer type for counting sample occurrences per histogram bin
+ typename OffsetT> ///< Signed integer type for global offsets
+__global__ void DeviceHistogramInitKernel(
+ ArrayWrapper<int, NUM_ACTIVE_CHANNELS> num_output_bins_wrapper, ///< Number of output histogram bins per channel
+ ArrayWrapper<CounterT*, NUM_ACTIVE_CHANNELS> d_output_histograms_wrapper, ///< Histogram counter data having logical dimensions <tt>CounterT[NUM_ACTIVE_CHANNELS][num_bins.array[CHANNEL]]</tt>
+ GridQueue<int> tile_queue) ///< Drain queue descriptor for dynamically mapping tile data onto thread blocks
+{
+ if ((threadIdx.x == 0) && (blockIdx.x == 0))
+ tile_queue.ResetDrain();
+
+ int output_bin = (blockIdx.x * blockDim.x) + threadIdx.x;
+
+ #pragma unroll
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ {
+ if (output_bin < num_output_bins_wrapper.array[CHANNEL])
+ d_output_histograms_wrapper.array[CHANNEL][output_bin] = 0;
+ }
+}
+
+
+/**
+ * Histogram privatized sweep kernel entry point (multi-block). Computes privatized histograms, one per thread block.
+ */
+template <
+ typename AgentHistogramPolicyT, ///< Parameterized AgentHistogramPolicy tuning policy type
+ int PRIVATIZED_SMEM_BINS, ///< Maximum number of histogram bins per channel (e.g., up to 256)
+ int NUM_CHANNELS, ///< Number of channels interleaved in the input data (may be greater than the number of channels being actively histogrammed)
+ int NUM_ACTIVE_CHANNELS, ///< Number of channels actively being histogrammed
+ typename SampleIteratorT, ///< The input iterator type. \iterator.
+ typename CounterT, ///< Integer type for counting sample occurrences per histogram bin
+ typename PrivatizedDecodeOpT, ///< The transform operator type for determining privatized counter indices from samples, one for each channel
+ typename OutputDecodeOpT, ///< The transform operator type for determining output bin-ids from privatized counter indices, one for each channel
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int(AgentHistogramPolicyT::BLOCK_THREADS))
+__global__ void DeviceHistogramSweepKernel(
+ SampleIteratorT d_samples, ///< Input data to reduce
+ ArrayWrapper<int, NUM_ACTIVE_CHANNELS> num_output_bins_wrapper, ///< The number bins per final output histogram
+ ArrayWrapper<int, NUM_ACTIVE_CHANNELS> num_privatized_bins_wrapper, ///< The number bins per privatized histogram
+ ArrayWrapper<CounterT*, NUM_ACTIVE_CHANNELS> d_output_histograms_wrapper, ///< Reference to final output histograms
+ ArrayWrapper<CounterT*, NUM_ACTIVE_CHANNELS> d_privatized_histograms_wrapper, ///< Reference to privatized histograms
+ ArrayWrapper<OutputDecodeOpT, NUM_ACTIVE_CHANNELS> output_decode_op_wrapper, ///< The transform operator for determining output bin-ids from privatized counter indices, one for each channel
+ ArrayWrapper<PrivatizedDecodeOpT, NUM_ACTIVE_CHANNELS> privatized_decode_op_wrapper, ///< The transform operator for determining privatized counter indices from samples, one for each channel
+ OffsetT num_row_pixels, ///< The number of multi-channel pixels per row in the region of interest
+ OffsetT num_rows, ///< The number of rows in the region of interest
+ OffsetT row_stride_samples, ///< The number of samples between starts of consecutive rows in the region of interest
+ int tiles_per_row, ///< Number of image tiles per row
+ GridQueue<int> tile_queue) ///< Drain queue descriptor for dynamically mapping tile data onto thread blocks
+{
+ // Thread block type for compositing input tiles
+ typedef AgentHistogram<
+ AgentHistogramPolicyT,
+ PRIVATIZED_SMEM_BINS,
+ NUM_CHANNELS,
+ NUM_ACTIVE_CHANNELS,
+ SampleIteratorT,
+ CounterT,
+ PrivatizedDecodeOpT,
+ OutputDecodeOpT,
+ OffsetT>
+ AgentHistogramT;
+
+ // Shared memory for AgentHistogram
+ __shared__ typename AgentHistogramT::TempStorage temp_storage;
+
+ AgentHistogramT agent(
+ temp_storage,
+ d_samples,
+ num_output_bins_wrapper.array,
+ num_privatized_bins_wrapper.array,
+ d_output_histograms_wrapper.array,
+ d_privatized_histograms_wrapper.array,
+ output_decode_op_wrapper.array,
+ privatized_decode_op_wrapper.array);
+
+ // Initialize counters
+ agent.InitBinCounters();
+
+ // Consume input tiles
+ agent.ConsumeTiles(
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ tiles_per_row,
+ tile_queue);
+
+ // Store output to global (if necessary)
+ agent.StoreOutput();
+
+}
+
+
+
+
+
+
+/******************************************************************************
+ * Dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for DeviceHistogram
+ */
+template <
+ int NUM_CHANNELS, ///< Number of channels interleaved in the input data (may be greater than the number of channels being actively histogrammed)
+ int NUM_ACTIVE_CHANNELS, ///< Number of channels actively being histogrammed
+ typename SampleIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename CounterT, ///< Integer type for counting sample occurrences per histogram bin
+ typename LevelT, ///< Type for specifying bin level boundaries
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DipatchHistogram
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// The sample value type of the input iterator
+ typedef typename std::iterator_traits<SampleIteratorT>::value_type SampleT;
+
+ enum
+ {
+ // Maximum number of bins per channel for which we will use a privatized smem strategy
+ MAX_PRIVATIZED_SMEM_BINS = 256
+ };
+
+
+ //---------------------------------------------------------------------
+ // Transform functors for converting samples to bin-ids
+ //---------------------------------------------------------------------
+
+ // Searches for bin given a list of bin-boundary levels
+ template <typename LevelIteratorT>
+ struct SearchTransform
+ {
+ LevelIteratorT d_levels; // Pointer to levels array
+ int num_output_levels; // Number of levels in array
+
+ // Initializer
+ __host__ __device__ __forceinline__ void Init(
+ LevelIteratorT d_levels, // Pointer to levels array
+ int num_output_levels) // Number of levels in array
+ {
+ this->d_levels = d_levels;
+ this->num_output_levels = num_output_levels;
+ }
+
+ // Method for converting samples to bin-ids
+ template <CacheLoadModifier LOAD_MODIFIER, typename _SampleT>
+ __host__ __device__ __forceinline__ void BinSelect(_SampleT sample, int &bin, bool valid)
+ {
+ /// Level iterator wrapper type
+ typedef typename If<IsPointer<LevelIteratorT>::VALUE,
+ CacheModifiedInputIterator<LOAD_MODIFIER, LevelT, OffsetT>, // Wrap the native input pointer with CacheModifiedInputIterator
+ LevelIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedLevelIteratorT;
+
+ WrappedLevelIteratorT wrapped_levels(d_levels);
+
+ int num_bins = num_output_levels - 1;
+ if (valid)
+ {
+ bin = UpperBound(wrapped_levels, num_output_levels, (LevelT) sample) - 1;
+ if (bin >= num_bins)
+ bin = -1;
+ }
+ }
+ };
+
+
+ // Scales samples to evenly-spaced bins
+ struct ScaleTransform
+ {
+ int num_bins; // Number of levels in array
+ LevelT max; // Max sample level (exclusive)
+ LevelT min; // Min sample level (inclusive)
+ LevelT scale; // Bin scaling factor
+
+ // Initializer
+ template <typename _LevelT>
+ __host__ __device__ __forceinline__ void Init(
+ int num_output_levels, // Number of levels in array
+ _LevelT max, // Max sample level (exclusive)
+ _LevelT min, // Min sample level (inclusive)
+ _LevelT scale) // Bin scaling factor
+ {
+ this->num_bins = num_output_levels - 1;
+ this->max = max;
+ this->min = min;
+ this->scale = scale;
+ }
+
+ // Initializer (float specialization)
+ __host__ __device__ __forceinline__ void Init(
+ int num_output_levels, // Number of levels in array
+ float max, // Max sample level (exclusive)
+ float min, // Min sample level (inclusive)
+ float scale) // Bin scaling factor
+ {
+ this->num_bins = num_output_levels - 1;
+ this->max = max;
+ this->min = min;
+ this->scale = float(1.0) / scale;
+ }
+
+ // Initializer (double specialization)
+ __host__ __device__ __forceinline__ void Init(
+ int num_output_levels, // Number of levels in array
+ double max, // Max sample level (exclusive)
+ double min, // Min sample level (inclusive)
+ double scale) // Bin scaling factor
+ {
+ this->num_bins = num_output_levels - 1;
+ this->max = max;
+ this->min = min;
+ this->scale = double(1.0) / scale;
+ }
+
+ // Method for converting samples to bin-ids
+ template <CacheLoadModifier LOAD_MODIFIER, typename _SampleT>
+ __host__ __device__ __forceinline__ void BinSelect(_SampleT sample, int &bin, bool valid)
+ {
+ LevelT level_sample = (LevelT) sample;
+
+ if (valid && (level_sample >= min) && (level_sample < max))
+ bin = (int) ((level_sample - min) / scale);
+ }
+
+ // Method for converting samples to bin-ids (float specialization)
+ template <CacheLoadModifier LOAD_MODIFIER>
+ __host__ __device__ __forceinline__ void BinSelect(float sample, int &bin, bool valid)
+ {
+ LevelT level_sample = (LevelT) sample;
+
+ if (valid && (level_sample >= min) && (level_sample < max))
+ bin = (int) ((level_sample - min) * scale);
+ }
+
+ // Method for converting samples to bin-ids (double specialization)
+ template <CacheLoadModifier LOAD_MODIFIER>
+ __host__ __device__ __forceinline__ void BinSelect(double sample, int &bin, bool valid)
+ {
+ LevelT level_sample = (LevelT) sample;
+
+ if (valid && (level_sample >= min) && (level_sample < max))
+ bin = (int) ((level_sample - min) * scale);
+ }
+ };
+
+
+ // Pass-through bin transform operator
+ struct PassThruTransform
+ {
+ // Method for converting samples to bin-ids
+ template <CacheLoadModifier LOAD_MODIFIER, typename _SampleT>
+ __host__ __device__ __forceinline__ void BinSelect(_SampleT sample, int &bin, bool valid)
+ {
+ if (valid)
+ bin = (int) sample;
+ }
+ };
+
+
+
+ //---------------------------------------------------------------------
+ // Tuning policies
+ //---------------------------------------------------------------------
+
+ template <int NOMINAL_ITEMS_PER_THREAD>
+ struct TScale
+ {
+ enum
+ {
+ V_SCALE = (sizeof(SampleT) + sizeof(int) - 1) / sizeof(int),
+ VALUE = CUB_MAX((NOMINAL_ITEMS_PER_THREAD / NUM_ACTIVE_CHANNELS / V_SCALE), 1)
+ };
+ };
+
+
+ /// SM11
+ struct Policy110
+ {
+ // HistogramSweepPolicy
+ typedef AgentHistogramPolicy<
+ 512,
+ (NUM_CHANNELS == 1) ? 8 : 2,
+ BLOCK_LOAD_DIRECT,
+ LOAD_DEFAULT,
+ true,
+ GMEM,
+ false>
+ HistogramSweepPolicy;
+ };
+
+ /// SM20
+ struct Policy200
+ {
+ // HistogramSweepPolicy
+ typedef AgentHistogramPolicy<
+ (NUM_CHANNELS == 1) ? 256 : 128,
+ (NUM_CHANNELS == 1) ? 8 : 3,
+ (NUM_CHANNELS == 1) ? BLOCK_LOAD_DIRECT : BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ true,
+ SMEM,
+ false>
+ HistogramSweepPolicy;
+ };
+
+ /// SM30
+ struct Policy300
+ {
+ // HistogramSweepPolicy
+ typedef AgentHistogramPolicy<
+ 512,
+ (NUM_CHANNELS == 1) ? 8 : 2,
+ BLOCK_LOAD_DIRECT,
+ LOAD_DEFAULT,
+ true,
+ GMEM,
+ false>
+ HistogramSweepPolicy;
+ };
+
+ /// SM35
+ struct Policy350
+ {
+ // HistogramSweepPolicy
+ typedef AgentHistogramPolicy<
+ 128,
+ TScale<8>::VALUE,
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ true,
+ BLEND,
+ true>
+ HistogramSweepPolicy;
+ };
+
+ /// SM50
+ struct Policy500
+ {
+ // HistogramSweepPolicy
+ typedef AgentHistogramPolicy<
+ 384,
+ TScale<16>::VALUE,
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ true,
+ SMEM,
+ false>
+ HistogramSweepPolicy;
+ };
+
+
+
+ //---------------------------------------------------------------------
+ // Tuning policies of current PTX compiler pass
+ //---------------------------------------------------------------------
+
+#if (CUB_PTX_ARCH >= 500)
+ typedef Policy500 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 350)
+ typedef Policy350 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 300)
+ typedef Policy300 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 200)
+ typedef Policy200 PtxPolicy;
+
+#else
+ typedef Policy110 PtxPolicy;
+
+#endif
+
+ // "Opaque" policies (whose parameterizations aren't reflected in the type signature)
+ struct PtxHistogramSweepPolicy : PtxPolicy::HistogramSweepPolicy {};
+
+
+ //---------------------------------------------------------------------
+ // Utilities
+ //---------------------------------------------------------------------
+
+ /**
+ * Initialize kernel dispatch configurations with the policies corresponding to the PTX assembly we will use
+ */
+ template <typename KernelConfig>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t InitConfigs(
+ int ptx_version,
+ KernelConfig &histogram_sweep_config)
+ {
+ #if (CUB_PTX_ARCH > 0)
+
+ // We're on the device, so initialize the kernel dispatch configurations with the current PTX policy
+ return histogram_sweep_config.template Init<PtxHistogramSweepPolicy>();
+
+ #else
+
+ // We're on the host, so lookup and initialize the kernel dispatch configurations with the policies that match the device's PTX version
+ if (ptx_version >= 500)
+ {
+ return histogram_sweep_config.template Init<typename Policy500::HistogramSweepPolicy>();
+ }
+ else if (ptx_version >= 350)
+ {
+ return histogram_sweep_config.template Init<typename Policy350::HistogramSweepPolicy>();
+ }
+ else if (ptx_version >= 300)
+ {
+ return histogram_sweep_config.template Init<typename Policy300::HistogramSweepPolicy>();
+ }
+ else if (ptx_version >= 200)
+ {
+ return histogram_sweep_config.template Init<typename Policy200::HistogramSweepPolicy>();
+ }
+ else if (ptx_version >= 110)
+ {
+ return histogram_sweep_config.template Init<typename Policy110::HistogramSweepPolicy>();
+ }
+ else
+ {
+ // No global atomic support
+ return cudaErrorNotSupported;
+ }
+
+ #endif
+ }
+
+
+ /**
+ * Kernel kernel dispatch configuration
+ */
+ struct KernelConfig
+ {
+ int block_threads;
+ int pixels_per_thread;
+
+ template <typename BlockPolicy>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t Init()
+ {
+ block_threads = BlockPolicy::BLOCK_THREADS;
+ pixels_per_thread = BlockPolicy::PIXELS_PER_THREAD;
+
+ return cudaSuccess;
+ }
+ };
+
+
+ //---------------------------------------------------------------------
+ // Dispatch entrypoints
+ //---------------------------------------------------------------------
+
+ /**
+ * Privatization-based dispatch routine
+ */
+ template <
+ typename PrivatizedDecodeOpT, ///< The transform operator type for determining privatized counter indices from samples, one for each channel
+ typename OutputDecodeOpT, ///< The transform operator type for determining output bin-ids from privatized counter indices, one for each channel
+ typename DeviceHistogramInitKernelT, ///< Function type of cub::DeviceHistogramInitKernel
+ typename DeviceHistogramSweepKernelT> ///< Function type of cub::DeviceHistogramSweepKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t PrivatizedDispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SampleIteratorT d_samples, ///< [in] The pointer to the input sequence of sample items. The samples from different channels are assumed to be interleaved (e.g., an array of 32-bit pixels where each pixel consists of four RGBA 8-bit samples).
+ CounterT* d_output_histograms[NUM_ACTIVE_CHANNELS], ///< [out] The pointers to the histogram counter output arrays, one for each active channel. For channel<sub><em>i</em></sub>, the allocation length of <tt>d_histograms[i]</tt> should be <tt>num_output_levels[i]</tt> - 1.
+ int num_privatized_levels[NUM_ACTIVE_CHANNELS], ///< [in] The number of bin level boundaries for delineating histogram samples in each active channel. Implies that the number of bins for channel<sub><em>i</em></sub> is <tt>num_output_levels[i]</tt> - 1.
+ PrivatizedDecodeOpT privatized_decode_op[NUM_ACTIVE_CHANNELS], ///< [in] Transform operators for determining bin-ids from samples, one for each channel
+ int num_output_levels[NUM_ACTIVE_CHANNELS], ///< [in] The number of bin level boundaries for delineating histogram samples in each active channel. Implies that the number of bins for channel<sub><em>i</em></sub> is <tt>num_output_levels[i]</tt> - 1.
+ OutputDecodeOpT output_decode_op[NUM_ACTIVE_CHANNELS], ///< [in] Transform operators for determining bin-ids from samples, one for each channel
+ int max_num_output_bins, ///< [in] Maximum number of output bins in any channel
+ OffsetT num_row_pixels, ///< [in] The number of multi-channel pixels per row in the region of interest
+ OffsetT num_rows, ///< [in] The number of rows in the region of interest
+ OffsetT row_stride_samples, ///< [in] The number of samples between starts of consecutive rows in the region of interest
+ DeviceHistogramInitKernelT histogram_init_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceHistogramInitKernel
+ DeviceHistogramSweepKernelT histogram_sweep_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceHistogramSweepKernel
+ KernelConfig histogram_sweep_config, ///< [in] Dispatch parameters that match the policy that \p histogram_sweep_kernel was compiled for
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. May cause significant slowdown. Default is \p false.
+ {
+ #ifndef CUB_RUNTIME_ENABLED
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported);
+
+ #else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Get SM occupancy for histogram_sweep_kernel
+ int histogram_sweep_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ histogram_sweep_sm_occupancy,
+ histogram_sweep_kernel,
+ histogram_sweep_config.block_threads))) break;
+
+ // Get device occupancy for histogram_sweep_kernel
+ int histogram_sweep_occupancy = histogram_sweep_sm_occupancy * sm_count;
+
+ if (num_row_pixels * NUM_CHANNELS == row_stride_samples)
+ {
+ // Treat as a single linear array of samples
+ num_row_pixels *= num_rows;
+ num_rows = 1;
+ row_stride_samples = num_row_pixels * NUM_CHANNELS;
+ }
+
+ // Get grid dimensions, trying to keep total blocks ~histogram_sweep_occupancy
+ int pixels_per_tile = histogram_sweep_config.block_threads * histogram_sweep_config.pixels_per_thread;
+ int tiles_per_row = int(num_row_pixels + pixels_per_tile - 1) / pixels_per_tile;
+ int blocks_per_row = CUB_MIN(histogram_sweep_occupancy, tiles_per_row);
+ int blocks_per_col = (blocks_per_row > 0) ?
+ int(CUB_MIN(histogram_sweep_occupancy / blocks_per_row, num_rows)) :
+ 0;
+ int num_thread_blocks = blocks_per_row * blocks_per_col;
+
+ dim3 sweep_grid_dims;
+ sweep_grid_dims.x = (unsigned int) blocks_per_row;
+ sweep_grid_dims.y = (unsigned int) blocks_per_col;
+ sweep_grid_dims.z = 1;
+
+ // Temporary storage allocation requirements
+ const int NUM_ALLOCATIONS = NUM_ACTIVE_CHANNELS + 1;
+ void* allocations[NUM_ALLOCATIONS];
+ size_t allocation_sizes[NUM_ALLOCATIONS];
+
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ allocation_sizes[CHANNEL] = size_t(num_thread_blocks) * (num_privatized_levels[CHANNEL] - 1) * sizeof(CounterT);
+
+ allocation_sizes[NUM_ALLOCATIONS - 1] = GridQueue<int>::AllocationSize();
+
+ // Alias the temporary allocations from the single storage blob (or compute the necessary size of the blob)
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ break;
+ }
+
+ // Construct the grid queue descriptor
+ GridQueue<int> tile_queue(allocations[NUM_ALLOCATIONS - 1]);
+
+ // Setup array wrapper for histogram channel output (because we can't pass static arrays as kernel parameters)
+ ArrayWrapper<CounterT*, NUM_ACTIVE_CHANNELS> d_output_histograms_wrapper;
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ d_output_histograms_wrapper.array[CHANNEL] = d_output_histograms[CHANNEL];
+
+ // Setup array wrapper for privatized per-block histogram channel output (because we can't pass static arrays as kernel parameters)
+ ArrayWrapper<CounterT*, NUM_ACTIVE_CHANNELS> d_privatized_histograms_wrapper;
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ d_privatized_histograms_wrapper.array[CHANNEL] = (CounterT*) allocations[CHANNEL];
+
+ // Setup array wrapper for sweep bin transforms (because we can't pass static arrays as kernel parameters)
+ ArrayWrapper<PrivatizedDecodeOpT, NUM_ACTIVE_CHANNELS> privatized_decode_op_wrapper;
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ privatized_decode_op_wrapper.array[CHANNEL] = privatized_decode_op[CHANNEL];
+
+ // Setup array wrapper for aggregation bin transforms (because we can't pass static arrays as kernel parameters)
+ ArrayWrapper<OutputDecodeOpT, NUM_ACTIVE_CHANNELS> output_decode_op_wrapper;
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ output_decode_op_wrapper.array[CHANNEL] = output_decode_op[CHANNEL];
+
+ // Setup array wrapper for num privatized bins (because we can't pass static arrays as kernel parameters)
+ ArrayWrapper<int, NUM_ACTIVE_CHANNELS> num_privatized_bins_wrapper;
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ num_privatized_bins_wrapper.array[CHANNEL] = num_privatized_levels[CHANNEL] - 1;
+
+ // Setup array wrapper for num output bins (because we can't pass static arrays as kernel parameters)
+ ArrayWrapper<int, NUM_ACTIVE_CHANNELS> num_output_bins_wrapper;
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ num_output_bins_wrapper.array[CHANNEL] = num_output_levels[CHANNEL] - 1;
+
+ int histogram_init_block_threads = 256;
+ int histogram_init_grid_dims = (max_num_output_bins + histogram_init_block_threads - 1) / histogram_init_block_threads;
+
+ // Log DeviceHistogramInitKernel configuration
+ if (debug_synchronous) _CubLog("Invoking DeviceHistogramInitKernel<<<%d, %d, 0, %lld>>>()\n",
+ histogram_init_grid_dims, histogram_init_block_threads, (long long) stream);
+
+ // Invoke histogram_init_kernel
+ histogram_init_kernel<<<histogram_init_grid_dims, histogram_init_block_threads, 0, stream>>>(
+ num_output_bins_wrapper,
+ d_output_histograms_wrapper,
+ tile_queue);
+
+ // Return if empty problem
+ if ((blocks_per_row == 0) || (blocks_per_col == 0))
+ break;
+
+ // Log histogram_sweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking histogram_sweep_kernel<<<{%d, %d, %d}, %d, 0, %lld>>>(), %d pixels per thread, %d SM occupancy\n",
+ sweep_grid_dims.x, sweep_grid_dims.y, sweep_grid_dims.z,
+ histogram_sweep_config.block_threads, (long long) stream, histogram_sweep_config.pixels_per_thread, histogram_sweep_sm_occupancy);
+
+ // Invoke histogram_sweep_kernel
+ histogram_sweep_kernel<<<sweep_grid_dims, histogram_sweep_config.block_threads, 0, stream>>>(
+ d_samples,
+ num_output_bins_wrapper,
+ num_privatized_bins_wrapper,
+ d_output_histograms_wrapper,
+ d_privatized_histograms_wrapper,
+ output_decode_op_wrapper,
+ privatized_decode_op_wrapper,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ tiles_per_row,
+ tile_queue);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ }
+ while (0);
+
+ return error;
+
+ #endif // CUB_RUNTIME_ENABLED
+ }
+
+
+
+ /**
+ * Dispatch routine for HistogramRange, specialized for sample types larger than 8bit
+ */
+ CUB_RUNTIME_FUNCTION
+ static cudaError_t DispatchRange(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SampleIteratorT d_samples, ///< [in] The pointer to the multi-channel input sequence of data samples. The samples from different channels are assumed to be interleaved (e.g., an array of 32-bit pixels where each pixel consists of four RGBA 8-bit samples).
+ CounterT* d_output_histograms[NUM_ACTIVE_CHANNELS], ///< [out] The pointers to the histogram counter output arrays, one for each active channel. For channel<sub><em>i</em></sub>, the allocation length of <tt>d_histograms[i]</tt> should be <tt>num_output_levels[i]</tt> - 1.
+ int num_output_levels[NUM_ACTIVE_CHANNELS], ///< [in] The number of boundaries (levels) for delineating histogram samples in each active channel. Implies that the number of bins for channel<sub><em>i</em></sub> is <tt>num_output_levels[i]</tt> - 1.
+ LevelT *d_levels[NUM_ACTIVE_CHANNELS], ///< [in] The pointers to the arrays of boundaries (levels), one for each active channel. Bin ranges are defined by consecutive boundary pairings: lower sample value boundaries are inclusive and upper sample value boundaries are exclusive.
+ OffsetT num_row_pixels, ///< [in] The number of multi-channel pixels per row in the region of interest
+ OffsetT num_rows, ///< [in] The number of rows in the region of interest
+ OffsetT row_stride_samples, ///< [in] The number of samples between starts of consecutive rows in the region of interest
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. May cause significant slowdown. Default is \p false.
+ Int2Type<false> is_byte_sample) ///< [in] Marker type indicating whether or not SampleT is a 8b type
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel dispatch configurations
+ KernelConfig histogram_sweep_config;
+ if (CubDebug(error = InitConfigs(ptx_version, histogram_sweep_config)))
+ break;
+
+ // Use the search transform op for converting samples to privatized bins
+ typedef SearchTransform<LevelT*> PrivatizedDecodeOpT;
+
+ // Use the pass-thru transform op for converting privatized bins to output bins
+ typedef PassThruTransform OutputDecodeOpT;
+
+ PrivatizedDecodeOpT privatized_decode_op[NUM_ACTIVE_CHANNELS];
+ OutputDecodeOpT output_decode_op[NUM_ACTIVE_CHANNELS];
+ int max_levels = num_output_levels[0];
+
+ for (int channel = 0; channel < NUM_ACTIVE_CHANNELS; ++channel)
+ {
+ privatized_decode_op[channel].Init(d_levels[channel], num_output_levels[channel]);
+ if (num_output_levels[channel] > max_levels)
+ max_levels = num_output_levels[channel];
+ }
+ int max_num_output_bins = max_levels - 1;
+
+ // Dispatch
+ if (max_num_output_bins > MAX_PRIVATIZED_SMEM_BINS)
+ {
+ // Too many bins to keep in shared memory.
+ const int PRIVATIZED_SMEM_BINS = 0;
+
+ if (CubDebug(error = PrivatizedDispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_samples,
+ d_output_histograms,
+ num_output_levels,
+ privatized_decode_op,
+ num_output_levels,
+ output_decode_op,
+ max_num_output_bins,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ DeviceHistogramInitKernel<NUM_ACTIVE_CHANNELS, CounterT, OffsetT>,
+ DeviceHistogramSweepKernel<PtxHistogramSweepPolicy, PRIVATIZED_SMEM_BINS, NUM_CHANNELS, NUM_ACTIVE_CHANNELS, SampleIteratorT, CounterT, PrivatizedDecodeOpT, OutputDecodeOpT, OffsetT>,
+ histogram_sweep_config,
+ stream,
+ debug_synchronous))) break;
+ }
+ else
+ {
+ // Dispatch shared-privatized approach
+ const int PRIVATIZED_SMEM_BINS = MAX_PRIVATIZED_SMEM_BINS;
+
+ if (CubDebug(error = PrivatizedDispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_samples,
+ d_output_histograms,
+ num_output_levels,
+ privatized_decode_op,
+ num_output_levels,
+ output_decode_op,
+ max_num_output_bins,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ DeviceHistogramInitKernel<NUM_ACTIVE_CHANNELS, CounterT, OffsetT>,
+ DeviceHistogramSweepKernel<PtxHistogramSweepPolicy, PRIVATIZED_SMEM_BINS, NUM_CHANNELS, NUM_ACTIVE_CHANNELS, SampleIteratorT, CounterT, PrivatizedDecodeOpT, OutputDecodeOpT, OffsetT>,
+ histogram_sweep_config,
+ stream,
+ debug_synchronous))) break;
+ }
+
+ } while (0);
+
+ return error;
+ }
+
+
+ /**
+ * Dispatch routine for HistogramRange, specialized for 8-bit sample types (computes 256-bin privatized histograms and then reduces to user-specified levels)
+ */
+ CUB_RUNTIME_FUNCTION
+ static cudaError_t DispatchRange(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SampleIteratorT d_samples, ///< [in] The pointer to the multi-channel input sequence of data samples. The samples from different channels are assumed to be interleaved (e.g., an array of 32-bit pixels where each pixel consists of four RGBA 8-bit samples).
+ CounterT* d_output_histograms[NUM_ACTIVE_CHANNELS], ///< [out] The pointers to the histogram counter output arrays, one for each active channel. For channel<sub><em>i</em></sub>, the allocation length of <tt>d_histograms[i]</tt> should be <tt>num_output_levels[i]</tt> - 1.
+ int num_output_levels[NUM_ACTIVE_CHANNELS], ///< [in] The number of boundaries (levels) for delineating histogram samples in each active channel. Implies that the number of bins for channel<sub><em>i</em></sub> is <tt>num_output_levels[i]</tt> - 1.
+ LevelT *d_levels[NUM_ACTIVE_CHANNELS], ///< [in] The pointers to the arrays of boundaries (levels), one for each active channel. Bin ranges are defined by consecutive boundary pairings: lower sample value boundaries are inclusive and upper sample value boundaries are exclusive.
+ OffsetT num_row_pixels, ///< [in] The number of multi-channel pixels per row in the region of interest
+ OffsetT num_rows, ///< [in] The number of rows in the region of interest
+ OffsetT row_stride_samples, ///< [in] The number of samples between starts of consecutive rows in the region of interest
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. May cause significant slowdown. Default is \p false.
+ Int2Type<true> is_byte_sample) ///< [in] Marker type indicating whether or not SampleT is a 8b type
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel dispatch configurations
+ KernelConfig histogram_sweep_config;
+ if (CubDebug(error = InitConfigs(ptx_version, histogram_sweep_config)))
+ break;
+
+ // Use the pass-thru transform op for converting samples to privatized bins
+ typedef PassThruTransform PrivatizedDecodeOpT;
+
+ // Use the search transform op for converting privatized bins to output bins
+ typedef SearchTransform<LevelT*> OutputDecodeOpT;
+
+ int num_privatized_levels[NUM_ACTIVE_CHANNELS];
+ PrivatizedDecodeOpT privatized_decode_op[NUM_ACTIVE_CHANNELS];
+ OutputDecodeOpT output_decode_op[NUM_ACTIVE_CHANNELS];
+ int max_levels = num_output_levels[0]; // Maximum number of levels in any channel
+
+ for (int channel = 0; channel < NUM_ACTIVE_CHANNELS; ++channel)
+ {
+ num_privatized_levels[channel] = 257;
+ output_decode_op[channel].Init(d_levels[channel], num_output_levels[channel]);
+
+ if (num_output_levels[channel] > max_levels)
+ max_levels = num_output_levels[channel];
+ }
+ int max_num_output_bins = max_levels - 1;
+
+ const int PRIVATIZED_SMEM_BINS = 256;
+
+ if (CubDebug(error = PrivatizedDispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_samples,
+ d_output_histograms,
+ num_privatized_levels,
+ privatized_decode_op,
+ num_output_levels,
+ output_decode_op,
+ max_num_output_bins,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ DeviceHistogramInitKernel<NUM_ACTIVE_CHANNELS, CounterT, OffsetT>,
+ DeviceHistogramSweepKernel<PtxHistogramSweepPolicy, PRIVATIZED_SMEM_BINS, NUM_CHANNELS, NUM_ACTIVE_CHANNELS, SampleIteratorT, CounterT, PrivatizedDecodeOpT, OutputDecodeOpT, OffsetT>,
+ histogram_sweep_config,
+ stream,
+ debug_synchronous))) break;
+
+ } while (0);
+
+ return error;
+ }
+
+
+ /**
+ * Dispatch routine for HistogramEven, specialized for sample types larger than 8-bit
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t DispatchEven(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SampleIteratorT d_samples, ///< [in] The pointer to the input sequence of sample items. The samples from different channels are assumed to be interleaved (e.g., an array of 32-bit pixels where each pixel consists of four RGBA 8-bit samples).
+ CounterT* d_output_histograms[NUM_ACTIVE_CHANNELS], ///< [out] The pointers to the histogram counter output arrays, one for each active channel. For channel<sub><em>i</em></sub>, the allocation length of <tt>d_histograms[i]</tt> should be <tt>num_output_levels[i]</tt> - 1.
+ int num_output_levels[NUM_ACTIVE_CHANNELS], ///< [in] The number of bin level boundaries for delineating histogram samples in each active channel. Implies that the number of bins for channel<sub><em>i</em></sub> is <tt>num_output_levels[i]</tt> - 1.
+ LevelT lower_level[NUM_ACTIVE_CHANNELS], ///< [in] The lower sample value bound (inclusive) for the lowest histogram bin in each active channel.
+ LevelT upper_level[NUM_ACTIVE_CHANNELS], ///< [in] The upper sample value bound (exclusive) for the highest histogram bin in each active channel.
+ OffsetT num_row_pixels, ///< [in] The number of multi-channel pixels per row in the region of interest
+ OffsetT num_rows, ///< [in] The number of rows in the region of interest
+ OffsetT row_stride_samples, ///< [in] The number of samples between starts of consecutive rows in the region of interest
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. May cause significant slowdown. Default is \p false.
+ Int2Type<false> is_byte_sample) ///< [in] Marker type indicating whether or not SampleT is a 8b type
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel dispatch configurations
+ KernelConfig histogram_sweep_config;
+ if (CubDebug(error = InitConfigs(ptx_version, histogram_sweep_config)))
+ break;
+
+ // Use the scale transform op for converting samples to privatized bins
+ typedef ScaleTransform PrivatizedDecodeOpT;
+
+ // Use the pass-thru transform op for converting privatized bins to output bins
+ typedef PassThruTransform OutputDecodeOpT;
+
+ PrivatizedDecodeOpT privatized_decode_op[NUM_ACTIVE_CHANNELS];
+ OutputDecodeOpT output_decode_op[NUM_ACTIVE_CHANNELS];
+ int max_levels = num_output_levels[0];
+
+ for (int channel = 0; channel < NUM_ACTIVE_CHANNELS; ++channel)
+ {
+ int bins = num_output_levels[channel] - 1;
+ LevelT scale = (upper_level[channel] - lower_level[channel]) / bins;
+
+ privatized_decode_op[channel].Init(num_output_levels[channel], upper_level[channel], lower_level[channel], scale);
+
+ if (num_output_levels[channel] > max_levels)
+ max_levels = num_output_levels[channel];
+ }
+ int max_num_output_bins = max_levels - 1;
+
+ if (max_num_output_bins > MAX_PRIVATIZED_SMEM_BINS)
+ {
+ // Dispatch shared-privatized approach
+ const int PRIVATIZED_SMEM_BINS = 0;
+
+ if (CubDebug(error = PrivatizedDispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_samples,
+ d_output_histograms,
+ num_output_levels,
+ privatized_decode_op,
+ num_output_levels,
+ output_decode_op,
+ max_num_output_bins,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ DeviceHistogramInitKernel<NUM_ACTIVE_CHANNELS, CounterT, OffsetT>,
+ DeviceHistogramSweepKernel<PtxHistogramSweepPolicy, PRIVATIZED_SMEM_BINS, NUM_CHANNELS, NUM_ACTIVE_CHANNELS, SampleIteratorT, CounterT, PrivatizedDecodeOpT, OutputDecodeOpT, OffsetT>,
+ histogram_sweep_config,
+ stream,
+ debug_synchronous))) break;
+ }
+ else
+ {
+ // Dispatch shared-privatized approach
+ const int PRIVATIZED_SMEM_BINS = MAX_PRIVATIZED_SMEM_BINS;
+
+ if (CubDebug(error = PrivatizedDispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_samples,
+ d_output_histograms,
+ num_output_levels,
+ privatized_decode_op,
+ num_output_levels,
+ output_decode_op,
+ max_num_output_bins,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ DeviceHistogramInitKernel<NUM_ACTIVE_CHANNELS, CounterT, OffsetT>,
+ DeviceHistogramSweepKernel<PtxHistogramSweepPolicy, PRIVATIZED_SMEM_BINS, NUM_CHANNELS, NUM_ACTIVE_CHANNELS, SampleIteratorT, CounterT, PrivatizedDecodeOpT, OutputDecodeOpT, OffsetT>,
+ histogram_sweep_config,
+ stream,
+ debug_synchronous))) break;
+ }
+ }
+ while (0);
+
+ return error;
+ }
+
+
+ /**
+ * Dispatch routine for HistogramEven, specialized for 8-bit sample types (computes 256-bin privatized histograms and then reduces to user-specified levels)
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t DispatchEven(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SampleIteratorT d_samples, ///< [in] The pointer to the input sequence of sample items. The samples from different channels are assumed to be interleaved (e.g., an array of 32-bit pixels where each pixel consists of four RGBA 8-bit samples).
+ CounterT* d_output_histograms[NUM_ACTIVE_CHANNELS], ///< [out] The pointers to the histogram counter output arrays, one for each active channel. For channel<sub><em>i</em></sub>, the allocation length of <tt>d_histograms[i]</tt> should be <tt>num_output_levels[i]</tt> - 1.
+ int num_output_levels[NUM_ACTIVE_CHANNELS], ///< [in] The number of bin level boundaries for delineating histogram samples in each active channel. Implies that the number of bins for channel<sub><em>i</em></sub> is <tt>num_output_levels[i]</tt> - 1.
+ LevelT lower_level[NUM_ACTIVE_CHANNELS], ///< [in] The lower sample value bound (inclusive) for the lowest histogram bin in each active channel.
+ LevelT upper_level[NUM_ACTIVE_CHANNELS], ///< [in] The upper sample value bound (exclusive) for the highest histogram bin in each active channel.
+ OffsetT num_row_pixels, ///< [in] The number of multi-channel pixels per row in the region of interest
+ OffsetT num_rows, ///< [in] The number of rows in the region of interest
+ OffsetT row_stride_samples, ///< [in] The number of samples between starts of consecutive rows in the region of interest
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. May cause significant slowdown. Default is \p false.
+ Int2Type<true> is_byte_sample) ///< [in] Marker type indicating whether or not SampleT is a 8b type
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel dispatch configurations
+ KernelConfig histogram_sweep_config;
+ if (CubDebug(error = InitConfigs(ptx_version, histogram_sweep_config)))
+ break;
+
+ // Use the pass-thru transform op for converting samples to privatized bins
+ typedef PassThruTransform PrivatizedDecodeOpT;
+
+ // Use the scale transform op for converting privatized bins to output bins
+ typedef ScaleTransform OutputDecodeOpT;
+
+ int num_privatized_levels[NUM_ACTIVE_CHANNELS];
+ PrivatizedDecodeOpT privatized_decode_op[NUM_ACTIVE_CHANNELS];
+ OutputDecodeOpT output_decode_op[NUM_ACTIVE_CHANNELS];
+ int max_levels = num_output_levels[0];
+
+ for (int channel = 0; channel < NUM_ACTIVE_CHANNELS; ++channel)
+ {
+ num_privatized_levels[channel] = 257;
+
+ int bins = num_output_levels[channel] - 1;
+ LevelT scale = (upper_level[channel] - lower_level[channel]) / bins;
+ output_decode_op[channel].Init(num_output_levels[channel], upper_level[channel], lower_level[channel], scale);
+
+ if (num_output_levels[channel] > max_levels)
+ max_levels = num_output_levels[channel];
+ }
+ int max_num_output_bins = max_levels - 1;
+
+ const int PRIVATIZED_SMEM_BINS = 256;
+
+ if (CubDebug(error = PrivatizedDispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_samples,
+ d_output_histograms,
+ num_privatized_levels,
+ privatized_decode_op,
+ num_output_levels,
+ output_decode_op,
+ max_num_output_bins,
+ num_row_pixels,
+ num_rows,
+ row_stride_samples,
+ DeviceHistogramInitKernel<NUM_ACTIVE_CHANNELS, CounterT, OffsetT>,
+ DeviceHistogramSweepKernel<PtxHistogramSweepPolicy, PRIVATIZED_SMEM_BINS, NUM_CHANNELS, NUM_ACTIVE_CHANNELS, SampleIteratorT, CounterT, PrivatizedDecodeOpT, OutputDecodeOpT, OffsetT>,
+ histogram_sweep_config,
+ stream,
+ debug_synchronous))) break;
+
+ }
+ while (0);
+
+ return error;
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_radix_sort.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_radix_sort.cuh
new file mode 100644
index 0000000..d1a992d
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_radix_sort.cuh
@@ -0,0 +1,1619 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceRadixSort provides device-wide, parallel operations for computing a radix sort across a sequence of data items residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "../../agent/agent_radix_sort_upsweep.cuh"
+#include "../../agent/agent_radix_sort_downsweep.cuh"
+#include "../../agent/agent_scan.cuh"
+#include "../../block/block_radix_sort.cuh"
+#include "../../grid/grid_even_share.cuh"
+#include "../../util_type.cuh"
+#include "../../util_debug.cuh"
+#include "../../util_device.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/******************************************************************************
+ * Kernel entry points
+ *****************************************************************************/
+
+/**
+ * Upsweep digit-counting kernel entry point (multi-block). Computes privatized digit histograms, one per block.
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ bool ALT_DIGIT_BITS, ///< Whether or not to use the alternate (lower-bits) policy
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< Key type
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int((ALT_DIGIT_BITS) ?
+ ChainedPolicyT::ActivePolicy::AltUpsweepPolicy::BLOCK_THREADS :
+ ChainedPolicyT::ActivePolicy::UpsweepPolicy::BLOCK_THREADS))
+__global__ void DeviceRadixSortUpsweepKernel(
+ const KeyT *d_keys, ///< [in] Input keys buffer
+ OffsetT *d_spine, ///< [out] Privatized (per block) digit histograms (striped, i.e., 0s counts from each block, then 1s counts from each block, etc.)
+ OffsetT /*num_items*/, ///< [in] Total number of input data items
+ int current_bit, ///< [in] Bit position of current radix digit
+ int num_bits, ///< [in] Number of bits of current radix digit
+ GridEvenShare<OffsetT> even_share) ///< [in] Even-share descriptor for mapan equal number of tiles onto each thread block
+{
+ enum {
+ TILE_ITEMS = ChainedPolicyT::ActivePolicy::AltUpsweepPolicy::BLOCK_THREADS *
+ ChainedPolicyT::ActivePolicy::AltUpsweepPolicy::ITEMS_PER_THREAD
+ };
+
+ // Parameterize AgentRadixSortUpsweep type for the current configuration
+ typedef AgentRadixSortUpsweep<
+ typename If<(ALT_DIGIT_BITS),
+ typename ChainedPolicyT::ActivePolicy::AltUpsweepPolicy,
+ typename ChainedPolicyT::ActivePolicy::UpsweepPolicy>::Type,
+ KeyT,
+ OffsetT>
+ AgentRadixSortUpsweepT;
+
+ // Shared memory storage
+ __shared__ typename AgentRadixSortUpsweepT::TempStorage temp_storage;
+
+ // Initialize GRID_MAPPING_RAKE even-share descriptor for this thread block
+ even_share.template BlockInit<TILE_ITEMS, GRID_MAPPING_RAKE>();
+
+ AgentRadixSortUpsweepT upsweep(temp_storage, d_keys, current_bit, num_bits);
+
+ upsweep.ProcessRegion(even_share.block_offset, even_share.block_end);
+
+ CTA_SYNC();
+
+ // Write out digit counts (striped)
+ upsweep.template ExtractCounts<IS_DESCENDING>(d_spine, gridDim.x, blockIdx.x);
+}
+
+
+/**
+ * Spine scan kernel entry point (single-block). Computes an exclusive prefix sum over the privatized digit histograms
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int(ChainedPolicyT::ActivePolicy::ScanPolicy::BLOCK_THREADS), 1)
+__global__ void RadixSortScanBinsKernel(
+ OffsetT *d_spine, ///< [in,out] Privatized (per block) digit histograms (striped, i.e., 0s counts from each block, then 1s counts from each block, etc.)
+ int num_counts) ///< [in] Total number of bin-counts
+{
+ // Parameterize the AgentScan type for the current configuration
+ typedef AgentScan<
+ typename ChainedPolicyT::ActivePolicy::ScanPolicy,
+ OffsetT*,
+ OffsetT*,
+ cub::Sum,
+ OffsetT,
+ OffsetT>
+ AgentScanT;
+
+ // Shared memory storage
+ __shared__ typename AgentScanT::TempStorage temp_storage;
+
+ // Block scan instance
+ AgentScanT block_scan(temp_storage, d_spine, d_spine, cub::Sum(), OffsetT(0)) ;
+
+ // Process full input tiles
+ int block_offset = 0;
+ BlockScanRunningPrefixOp<OffsetT, Sum> prefix_op(0, Sum());
+ while (block_offset + AgentScanT::TILE_ITEMS <= num_counts)
+ {
+ block_scan.template ConsumeTile<false, false>(block_offset, prefix_op);
+ block_offset += AgentScanT::TILE_ITEMS;
+ }
+}
+
+
+/**
+ * Downsweep pass kernel entry point (multi-block). Scatters keys (and values) into corresponding bins for the current digit place.
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ bool ALT_DIGIT_BITS, ///< Whether or not to use the alternate (lower-bits) policy
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< Key type
+ typename ValueT, ///< Value type
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int((ALT_DIGIT_BITS) ?
+ ChainedPolicyT::ActivePolicy::AltDownsweepPolicy::BLOCK_THREADS :
+ ChainedPolicyT::ActivePolicy::DownsweepPolicy::BLOCK_THREADS))
+__global__ void DeviceRadixSortDownsweepKernel(
+ const KeyT *d_keys_in, ///< [in] Input keys buffer
+ KeyT *d_keys_out, ///< [in] Output keys buffer
+ const ValueT *d_values_in, ///< [in] Input values buffer
+ ValueT *d_values_out, ///< [in] Output values buffer
+ OffsetT *d_spine, ///< [in] Scan of privatized (per block) digit histograms (striped, i.e., 0s counts from each block, then 1s counts from each block, etc.)
+ OffsetT num_items, ///< [in] Total number of input data items
+ int current_bit, ///< [in] Bit position of current radix digit
+ int num_bits, ///< [in] Number of bits of current radix digit
+ GridEvenShare<OffsetT> even_share) ///< [in] Even-share descriptor for mapan equal number of tiles onto each thread block
+{
+ enum {
+ TILE_ITEMS = ChainedPolicyT::ActivePolicy::AltUpsweepPolicy::BLOCK_THREADS *
+ ChainedPolicyT::ActivePolicy::AltUpsweepPolicy::ITEMS_PER_THREAD
+ };
+
+ // Parameterize AgentRadixSortDownsweep type for the current configuration
+ typedef AgentRadixSortDownsweep<
+ typename If<(ALT_DIGIT_BITS),
+ typename ChainedPolicyT::ActivePolicy::AltDownsweepPolicy,
+ typename ChainedPolicyT::ActivePolicy::DownsweepPolicy>::Type,
+ IS_DESCENDING,
+ KeyT,
+ ValueT,
+ OffsetT>
+ AgentRadixSortDownsweepT;
+
+ // Shared memory storage
+ __shared__ typename AgentRadixSortDownsweepT::TempStorage temp_storage;
+
+ // Initialize even-share descriptor for this thread block
+ even_share.template BlockInit<TILE_ITEMS, GRID_MAPPING_RAKE>();
+
+ // Process input tiles
+ AgentRadixSortDownsweepT(temp_storage, num_items, d_spine, d_keys_in, d_keys_out, d_values_in, d_values_out, current_bit, num_bits).ProcessRegion(
+ even_share.block_offset,
+ even_share.block_end);
+}
+
+
+/**
+ * Single pass kernel entry point (single-block). Fully sorts a tile of input.
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< Key type
+ typename ValueT, ///< Value type
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int(ChainedPolicyT::ActivePolicy::SingleTilePolicy::BLOCK_THREADS), 1)
+__global__ void DeviceRadixSortSingleTileKernel(
+ const KeyT *d_keys_in, ///< [in] Input keys buffer
+ KeyT *d_keys_out, ///< [in] Output keys buffer
+ const ValueT *d_values_in, ///< [in] Input values buffer
+ ValueT *d_values_out, ///< [in] Output values buffer
+ OffsetT num_items, ///< [in] Total number of input data items
+ int current_bit, ///< [in] Bit position of current radix digit
+ int end_bit) ///< [in] The past-the-end (most-significant) bit index needed for key comparison
+{
+ // Constants
+ enum
+ {
+ BLOCK_THREADS = ChainedPolicyT::ActivePolicy::SingleTilePolicy::BLOCK_THREADS,
+ ITEMS_PER_THREAD = ChainedPolicyT::ActivePolicy::SingleTilePolicy::ITEMS_PER_THREAD,
+ KEYS_ONLY = Equals<ValueT, NullType>::VALUE,
+ };
+
+ // BlockRadixSort type
+ typedef BlockRadixSort<
+ KeyT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ ValueT,
+ ChainedPolicyT::ActivePolicy::SingleTilePolicy::RADIX_BITS,
+ (ChainedPolicyT::ActivePolicy::SingleTilePolicy::RANK_ALGORITHM == RADIX_RANK_MEMOIZE),
+ ChainedPolicyT::ActivePolicy::SingleTilePolicy::SCAN_ALGORITHM>
+ BlockRadixSortT;
+
+ // BlockLoad type (keys)
+ typedef BlockLoad<
+ KeyT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ ChainedPolicyT::ActivePolicy::SingleTilePolicy::LOAD_ALGORITHM> BlockLoadKeys;
+
+ // BlockLoad type (values)
+ typedef BlockLoad<
+ ValueT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ ChainedPolicyT::ActivePolicy::SingleTilePolicy::LOAD_ALGORITHM> BlockLoadValues;
+
+ // Unsigned word for key bits
+ typedef typename Traits<KeyT>::UnsignedBits UnsignedBitsT;
+
+ // Shared memory storage
+ __shared__ union TempStorage
+ {
+ typename BlockRadixSortT::TempStorage sort;
+ typename BlockLoadKeys::TempStorage load_keys;
+ typename BlockLoadValues::TempStorage load_values;
+
+ } temp_storage;
+
+ // Keys and values for the block
+ KeyT keys[ITEMS_PER_THREAD];
+ ValueT values[ITEMS_PER_THREAD];
+
+ // Get default (min/max) value for out-of-bounds keys
+ UnsignedBitsT default_key_bits = (IS_DESCENDING) ? Traits<KeyT>::LOWEST_KEY : Traits<KeyT>::MAX_KEY;
+ KeyT default_key = reinterpret_cast<KeyT&>(default_key_bits);
+
+ // Load keys
+ BlockLoadKeys(temp_storage.load_keys).Load(d_keys_in, keys, num_items, default_key);
+
+ CTA_SYNC();
+
+ // Load values
+ if (!KEYS_ONLY)
+ {
+ // Register pressure work-around: moving num_items through shfl prevents compiler
+ // from reusing guards/addressing from prior guarded loads
+ num_items = ShuffleIndex<CUB_PTX_WARP_THREADS>(num_items, 0, 0xffffffff);
+
+ BlockLoadValues(temp_storage.load_values).Load(d_values_in, values, num_items);
+
+ CTA_SYNC();
+ }
+
+ // Sort tile
+ BlockRadixSortT(temp_storage.sort).SortBlockedToStriped(
+ keys,
+ values,
+ current_bit,
+ end_bit,
+ Int2Type<IS_DESCENDING>(),
+ Int2Type<KEYS_ONLY>());
+
+ // Store keys and values
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ int item_offset = ITEM * BLOCK_THREADS + threadIdx.x;
+ if (item_offset < num_items)
+ {
+ d_keys_out[item_offset] = keys[ITEM];
+ if (!KEYS_ONLY)
+ d_values_out[item_offset] = values[ITEM];
+ }
+ }
+}
+
+
+/**
+ * Segmented radix sorting pass (one block per segment)
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ bool ALT_DIGIT_BITS, ///< Whether or not to use the alternate (lower-bits) policy
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< Key type
+ typename ValueT, ///< Value type
+ typename OffsetIteratorT, ///< Random-access input iterator type for reading segment offsets \iterator
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int((ALT_DIGIT_BITS) ?
+ ChainedPolicyT::ActivePolicy::AltSegmentedPolicy::BLOCK_THREADS :
+ ChainedPolicyT::ActivePolicy::SegmentedPolicy::BLOCK_THREADS))
+__global__ void DeviceSegmentedRadixSortKernel(
+ const KeyT *d_keys_in, ///< [in] Input keys buffer
+ KeyT *d_keys_out, ///< [in] Output keys buffer
+ const ValueT *d_values_in, ///< [in] Input values buffer
+ ValueT *d_values_out, ///< [in] Output values buffer
+ OffsetIteratorT d_begin_offsets, ///< [in] Pointer to the sequence of beginning offsets of length \p num_segments, such that <tt>d_begin_offsets[i]</tt> is the first element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>
+ OffsetIteratorT d_end_offsets, ///< [in] Pointer to the sequence of ending offsets of length \p num_segments, such that <tt>d_end_offsets[i]-1</tt> is the last element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>. If <tt>d_end_offsets[i]-1</tt> <= <tt>d_begin_offsets[i]</tt>, the <em>i</em><sup>th</sup> is considered empty.
+ int /*num_segments*/, ///< [in] The number of segments that comprise the sorting data
+ int current_bit, ///< [in] Bit position of current radix digit
+ int pass_bits) ///< [in] Number of bits of current radix digit
+{
+ //
+ // Constants
+ //
+
+ typedef typename If<(ALT_DIGIT_BITS),
+ typename ChainedPolicyT::ActivePolicy::AltSegmentedPolicy,
+ typename ChainedPolicyT::ActivePolicy::SegmentedPolicy>::Type SegmentedPolicyT;
+
+ enum
+ {
+ BLOCK_THREADS = SegmentedPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = SegmentedPolicyT::ITEMS_PER_THREAD,
+ RADIX_BITS = SegmentedPolicyT::RADIX_BITS,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ RADIX_DIGITS = 1 << RADIX_BITS,
+ KEYS_ONLY = Equals<ValueT, NullType>::VALUE,
+ };
+
+ // Upsweep type
+ typedef AgentRadixSortUpsweep<
+ AgentRadixSortUpsweepPolicy<BLOCK_THREADS, ITEMS_PER_THREAD, SegmentedPolicyT::LOAD_MODIFIER, RADIX_BITS>,
+ KeyT,
+ OffsetT>
+ BlockUpsweepT;
+
+ // Digit-scan type
+ typedef BlockScan<OffsetT, BLOCK_THREADS> DigitScanT;
+
+ // Downsweep type
+ typedef AgentRadixSortDownsweep<SegmentedPolicyT, IS_DESCENDING, KeyT, ValueT, OffsetT> BlockDownsweepT;
+
+ enum
+ {
+ /// Number of bin-starting offsets tracked per thread
+ BINS_TRACKED_PER_THREAD = BlockDownsweepT::BINS_TRACKED_PER_THREAD
+ };
+
+ //
+ // Process input tiles
+ //
+
+ // Shared memory storage
+ __shared__ union
+ {
+ typename BlockUpsweepT::TempStorage upsweep;
+ typename BlockDownsweepT::TempStorage downsweep;
+ struct
+ {
+ volatile OffsetT reverse_counts_in[RADIX_DIGITS];
+ volatile OffsetT reverse_counts_out[RADIX_DIGITS];
+ typename DigitScanT::TempStorage scan;
+ };
+
+ } temp_storage;
+
+ OffsetT segment_begin = d_begin_offsets[blockIdx.x];
+ OffsetT segment_end = d_end_offsets[blockIdx.x];
+ OffsetT num_items = segment_end - segment_begin;
+
+ // Check if empty segment
+ if (num_items <= 0)
+ return;
+
+ // Upsweep
+ BlockUpsweepT upsweep(temp_storage.upsweep, d_keys_in, current_bit, pass_bits);
+ upsweep.ProcessRegion(segment_begin, segment_end);
+
+ CTA_SYNC();
+
+ // The count of each digit value in this pass (valid in the first RADIX_DIGITS threads)
+ OffsetT bin_count[BINS_TRACKED_PER_THREAD];
+ upsweep.ExtractCounts(bin_count);
+
+ CTA_SYNC();
+
+ if (IS_DESCENDING)
+ {
+ // Reverse bin counts
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (threadIdx.x * BINS_TRACKED_PER_THREAD) + track;
+
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ temp_storage.reverse_counts_in[bin_idx] = bin_count[track];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (threadIdx.x * BINS_TRACKED_PER_THREAD) + track;
+
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ bin_count[track] = temp_storage.reverse_counts_in[RADIX_DIGITS - bin_idx - 1];
+ }
+ }
+
+ // Scan
+ OffsetT bin_offset[BINS_TRACKED_PER_THREAD]; // The global scatter base offset for each digit value in this pass (valid in the first RADIX_DIGITS threads)
+ DigitScanT(temp_storage.scan).ExclusiveSum(bin_count, bin_offset);
+
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ bin_offset[track] += segment_begin;
+ }
+
+ if (IS_DESCENDING)
+ {
+ // Reverse bin offsets
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (threadIdx.x * BINS_TRACKED_PER_THREAD) + track;
+
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ temp_storage.reverse_counts_out[threadIdx.x] = bin_offset[track];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (threadIdx.x * BINS_TRACKED_PER_THREAD) + track;
+
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ bin_offset[track] = temp_storage.reverse_counts_out[RADIX_DIGITS - bin_idx - 1];
+ }
+ }
+
+ CTA_SYNC();
+
+ // Downsweep
+ BlockDownsweepT downsweep(temp_storage.downsweep, bin_offset, num_items, d_keys_in, d_keys_out, d_values_in, d_values_out, current_bit, pass_bits);
+ downsweep.ProcessRegion(segment_begin, segment_end);
+}
+
+
+
+/******************************************************************************
+ * Policy
+ ******************************************************************************/
+
+/**
+ * Tuning policy for kernel specialization
+ */
+template <
+ typename KeyT, ///< Key type
+ typename ValueT, ///< Value type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DeviceRadixSortPolicy
+{
+ //------------------------------------------------------------------------------
+ // Constants
+ //------------------------------------------------------------------------------
+
+ enum
+ {
+ // Whether this is a keys-only (or key-value) sort
+ KEYS_ONLY = (Equals<ValueT, NullType>::VALUE),
+ };
+
+ // Dominant-sized key/value type
+ typedef typename If<(sizeof(ValueT) > 4) && (sizeof(KeyT) < sizeof(ValueT)), ValueT, KeyT>::Type DominantT;
+
+ //------------------------------------------------------------------------------
+ // Architecture-specific tuning policies
+ //------------------------------------------------------------------------------
+
+ /// SM20
+ struct Policy200 : ChainedPolicy<200, Policy200, Policy200>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = 5,
+ ALT_RADIX_BITS = PRIMARY_RADIX_BITS - 1,
+
+ // Relative size of KeyT type to a 4-byte word
+ SCALE_FACTOR_4B = (CUB_MAX(sizeof(KeyT), sizeof(ValueT)) + 3) / 4,
+ };
+
+ // Keys-only upsweep policies
+ typedef AgentRadixSortUpsweepPolicy <64, CUB_MAX(1, 18 / SCALE_FACTOR_4B), LOAD_DEFAULT, PRIMARY_RADIX_BITS> UpsweepPolicyKeys;
+ typedef AgentRadixSortUpsweepPolicy <64, CUB_MAX(1, 18 / SCALE_FACTOR_4B), LOAD_DEFAULT, ALT_RADIX_BITS> AltUpsweepPolicyKeys;
+
+ // Key-value pairs upsweep policies
+ typedef AgentRadixSortUpsweepPolicy <128, CUB_MAX(1, 13 / SCALE_FACTOR_4B), LOAD_DEFAULT, PRIMARY_RADIX_BITS> UpsweepPolicyPairs;
+ typedef AgentRadixSortUpsweepPolicy <128, CUB_MAX(1, 13 / SCALE_FACTOR_4B), LOAD_DEFAULT, ALT_RADIX_BITS> AltUpsweepPolicyPairs;
+
+ // Upsweep policies
+ typedef typename If<KEYS_ONLY, UpsweepPolicyKeys, UpsweepPolicyPairs>::Type UpsweepPolicy;
+ typedef typename If<KEYS_ONLY, AltUpsweepPolicyKeys, AltUpsweepPolicyPairs>::Type AltUpsweepPolicy;
+
+ // Scan policy
+ typedef AgentScanPolicy <512, 4, BLOCK_LOAD_VECTORIZE, LOAD_DEFAULT, BLOCK_STORE_VECTORIZE, BLOCK_SCAN_RAKING_MEMOIZE> ScanPolicy;
+
+ // Keys-only downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <64, CUB_MAX(1, 18 / SCALE_FACTOR_4B), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicyKeys;
+ typedef AgentRadixSortDownsweepPolicy <64, CUB_MAX(1, 18 / SCALE_FACTOR_4B), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, ALT_RADIX_BITS> AltDownsweepPolicyKeys;
+
+ // Key-value pairs downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <128, CUB_MAX(1, 13 / SCALE_FACTOR_4B), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicyPairs;
+ typedef AgentRadixSortDownsweepPolicy <128, CUB_MAX(1, 13 / SCALE_FACTOR_4B), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, ALT_RADIX_BITS> AltDownsweepPolicyPairs;
+
+ // Downsweep policies
+ typedef typename If<KEYS_ONLY, DownsweepPolicyKeys, DownsweepPolicyPairs>::Type DownsweepPolicy;
+ typedef typename If<KEYS_ONLY, AltDownsweepPolicyKeys, AltDownsweepPolicyPairs>::Type AltDownsweepPolicy;
+
+ // Single-tile policy
+ typedef DownsweepPolicy SingleTilePolicy;
+
+ // Segmented policies
+ typedef DownsweepPolicy SegmentedPolicy;
+ typedef AltDownsweepPolicy AltSegmentedPolicy;
+ };
+
+ /// SM30
+ struct Policy300 : ChainedPolicy<300, Policy300, Policy200>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = 5,
+ ALT_RADIX_BITS = PRIMARY_RADIX_BITS - 1,
+
+ // Relative size of KeyT type to a 4-byte word
+ SCALE_FACTOR_4B = (CUB_MAX(sizeof(KeyT), sizeof(ValueT)) + 3) / 4,
+ };
+
+ // Keys-only upsweep policies
+ typedef AgentRadixSortUpsweepPolicy <256, CUB_MAX(1, 7 / SCALE_FACTOR_4B), LOAD_DEFAULT, PRIMARY_RADIX_BITS> UpsweepPolicyKeys;
+ typedef AgentRadixSortUpsweepPolicy <256, CUB_MAX(1, 7 / SCALE_FACTOR_4B), LOAD_DEFAULT, ALT_RADIX_BITS> AltUpsweepPolicyKeys;
+
+ // Key-value pairs upsweep policies
+ typedef AgentRadixSortUpsweepPolicy <256, CUB_MAX(1, 5 / SCALE_FACTOR_4B), LOAD_DEFAULT, PRIMARY_RADIX_BITS> UpsweepPolicyPairs;
+ typedef AgentRadixSortUpsweepPolicy <256, CUB_MAX(1, 5 / SCALE_FACTOR_4B), LOAD_DEFAULT, ALT_RADIX_BITS> AltUpsweepPolicyPairs;
+
+ // Upsweep policies
+ typedef typename If<KEYS_ONLY, UpsweepPolicyKeys, UpsweepPolicyPairs>::Type UpsweepPolicy;
+ typedef typename If<KEYS_ONLY, AltUpsweepPolicyKeys, AltUpsweepPolicyPairs>::Type AltUpsweepPolicy;
+
+ // Scan policy
+ typedef AgentScanPolicy <1024, 4, BLOCK_LOAD_VECTORIZE, LOAD_DEFAULT, BLOCK_STORE_VECTORIZE, BLOCK_SCAN_WARP_SCANS> ScanPolicy;
+
+ // Keys-only downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <128, CUB_MAX(1, 14 / SCALE_FACTOR_4B), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicyKeys;
+ typedef AgentRadixSortDownsweepPolicy <128, CUB_MAX(1, 14 / SCALE_FACTOR_4B), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, ALT_RADIX_BITS> AltDownsweepPolicyKeys;
+
+ // Key-value pairs downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <128, CUB_MAX(1, 10 / SCALE_FACTOR_4B), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicyPairs;
+ typedef AgentRadixSortDownsweepPolicy <128, CUB_MAX(1, 10 / SCALE_FACTOR_4B), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, ALT_RADIX_BITS> AltDownsweepPolicyPairs;
+
+ // Downsweep policies
+ typedef typename If<KEYS_ONLY, DownsweepPolicyKeys, DownsweepPolicyPairs>::Type DownsweepPolicy;
+ typedef typename If<KEYS_ONLY, AltDownsweepPolicyKeys, AltDownsweepPolicyPairs>::Type AltDownsweepPolicy;
+
+ // Single-tile policy
+ typedef DownsweepPolicy SingleTilePolicy;
+
+ // Segmented policies
+ typedef DownsweepPolicy SegmentedPolicy;
+ typedef AltDownsweepPolicy AltSegmentedPolicy;
+ };
+
+
+ /// SM35
+ struct Policy350 : ChainedPolicy<350, Policy350, Policy300>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5, // 1.72B 32b keys/s, 1.17B 32b pairs/s, 1.55B 32b segmented keys/s (K40m)
+ };
+
+ // Scan policy
+ typedef AgentScanPolicy <1024, 4, BLOCK_LOAD_VECTORIZE, LOAD_DEFAULT, BLOCK_STORE_VECTORIZE, BLOCK_SCAN_WARP_SCANS> ScanPolicy;
+
+ // Keys-only downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(128, 9, DominantT), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_LDG, RADIX_RANK_MATCH, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicyKeys;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(64, 18, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS - 1> AltDownsweepPolicyKeys;
+
+ // Key-value pairs downsweep policies
+ typedef DownsweepPolicyKeys DownsweepPolicyPairs;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(128, 15, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS - 1> AltDownsweepPolicyPairs;
+
+ // Downsweep policies
+ typedef typename If<KEYS_ONLY, DownsweepPolicyKeys, DownsweepPolicyPairs>::Type DownsweepPolicy;
+ typedef typename If<KEYS_ONLY, AltDownsweepPolicyKeys, AltDownsweepPolicyPairs>::Type AltDownsweepPolicy;
+
+ // Upsweep policies
+ typedef DownsweepPolicy UpsweepPolicy;
+ typedef AltDownsweepPolicy AltUpsweepPolicy;
+
+ // Single-tile policy
+ typedef DownsweepPolicy SingleTilePolicy;
+
+ // Segmented policies
+ typedef DownsweepPolicy SegmentedPolicy;
+ typedef AltDownsweepPolicy AltSegmentedPolicy;
+
+
+ };
+
+
+ /// SM50
+ struct Policy500 : ChainedPolicy<500, Policy500, Policy350>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = (sizeof(KeyT) > 1) ? 7 : 5, // 3.5B 32b keys/s, 1.92B 32b pairs/s (TitanX)
+ SINGLE_TILE_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5,
+ SEGMENTED_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5, // 3.1B 32b segmented keys/s (TitanX)
+ };
+
+ // ScanPolicy
+ typedef AgentScanPolicy <512, 23, BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, BLOCK_STORE_WARP_TRANSPOSE, BLOCK_SCAN_RAKING_MEMOIZE> ScanPolicy;
+
+ // Downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(160, 39, DominantT), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_BASIC, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 16, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_RAKING_MEMOIZE, PRIMARY_RADIX_BITS - 1> AltDownsweepPolicy;
+
+ // Upsweep policies
+ typedef DownsweepPolicy UpsweepPolicy;
+ typedef AltDownsweepPolicy AltUpsweepPolicy;
+
+ // Single-tile policy
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 19, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SINGLE_TILE_RADIX_BITS> SingleTilePolicy;
+
+ // Segmented policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(192, 31, DominantT), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS> SegmentedPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 11, DominantT), BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS - 1> AltSegmentedPolicy;
+ };
+
+
+ /// SM60 (GP100)
+ struct Policy600 : ChainedPolicy<600, Policy600, Policy500>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = (sizeof(KeyT) > 1) ? 7 : 5, // 6.9B 32b keys/s (Quadro P100)
+ SINGLE_TILE_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5,
+ SEGMENTED_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5, // 5.9B 32b segmented keys/s (Quadro P100)
+ };
+
+ // ScanPolicy
+ typedef AgentScanPolicy <512, 23, BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, BLOCK_STORE_WARP_TRANSPOSE, BLOCK_SCAN_RAKING_MEMOIZE> ScanPolicy;
+
+ // Downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 25, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MATCH, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(192, 39, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS - 1> AltDownsweepPolicy;
+
+ // Upsweep policies
+ typedef DownsweepPolicy UpsweepPolicy;
+ typedef AltDownsweepPolicy AltUpsweepPolicy;
+
+ // Single-tile policy
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 19, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SINGLE_TILE_RADIX_BITS> SingleTilePolicy;
+
+ // Segmented policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(192, 39, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS> SegmentedPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(384, 11, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS - 1> AltSegmentedPolicy;
+
+ };
+
+
+ /// SM61 (GP104)
+ struct Policy610 : ChainedPolicy<610, Policy610, Policy600>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = (sizeof(KeyT) > 1) ? 7 : 5, // 3.4B 32b keys/s, 1.83B 32b pairs/s (1080)
+ SINGLE_TILE_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5,
+ SEGMENTED_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5, // 3.3B 32b segmented keys/s (1080)
+ };
+
+ // ScanPolicy
+ typedef AgentScanPolicy <512, 23, BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, BLOCK_STORE_WARP_TRANSPOSE, BLOCK_SCAN_RAKING_MEMOIZE> ScanPolicy;
+
+ // Downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(384, 31, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MATCH, BLOCK_SCAN_RAKING_MEMOIZE, PRIMARY_RADIX_BITS> DownsweepPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 35, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_RAKING_MEMOIZE, PRIMARY_RADIX_BITS - 1> AltDownsweepPolicy;
+
+ // Upsweep policies
+ typedef AgentRadixSortUpsweepPolicy <CUB_SCALED_GRANULARITIES(128, 16, DominantT), LOAD_LDG, PRIMARY_RADIX_BITS> UpsweepPolicy;
+ typedef AgentRadixSortUpsweepPolicy <CUB_SCALED_GRANULARITIES(128, 16, DominantT), LOAD_LDG, PRIMARY_RADIX_BITS - 1> AltUpsweepPolicy;
+
+ // Single-tile policy
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 19, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SINGLE_TILE_RADIX_BITS> SingleTilePolicy;
+
+ // Segmented policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(192, 39, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS> SegmentedPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(384, 11, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS - 1> AltSegmentedPolicy;
+ };
+
+
+ /// SM62 (Tegra, less RF)
+ struct Policy620 : ChainedPolicy<620, Policy620, Policy610>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = 5,
+ ALT_RADIX_BITS = PRIMARY_RADIX_BITS - 1,
+ };
+
+ // ScanPolicy
+ typedef AgentScanPolicy <512, 23, BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, BLOCK_STORE_WARP_TRANSPOSE, BLOCK_SCAN_RAKING_MEMOIZE> ScanPolicy;
+
+ // Downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 16, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_RAKING_MEMOIZE, PRIMARY_RADIX_BITS> DownsweepPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 16, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_RAKING_MEMOIZE, ALT_RADIX_BITS> AltDownsweepPolicy;
+
+ // Upsweep policies
+ typedef DownsweepPolicy UpsweepPolicy;
+ typedef AltDownsweepPolicy AltUpsweepPolicy;
+
+ // Single-tile policy
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 19, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> SingleTilePolicy;
+
+ // Segmented policies
+ typedef DownsweepPolicy SegmentedPolicy;
+ typedef AltDownsweepPolicy AltSegmentedPolicy;
+ };
+
+
+ /// SM70 (GV100)
+ struct Policy700 : ChainedPolicy<700, Policy700, Policy620>
+ {
+ enum {
+ PRIMARY_RADIX_BITS = (sizeof(KeyT) > 1) ? 7 : 5, // 7.62B 32b keys/s (GV100)
+ SINGLE_TILE_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5,
+ SEGMENTED_RADIX_BITS = (sizeof(KeyT) > 1) ? 6 : 5, // 8.7B 32b segmented keys/s (GV100)
+ };
+
+ // ScanPolicy
+ typedef AgentScanPolicy <512, 23, BLOCK_LOAD_WARP_TRANSPOSE, LOAD_DEFAULT, BLOCK_STORE_WARP_TRANSPOSE, BLOCK_SCAN_RAKING_MEMOIZE> ScanPolicy;
+
+ // Downsweep policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 25, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MATCH, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS> DownsweepPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 25, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, PRIMARY_RADIX_BITS - 1> AltDownsweepPolicy;
+
+ // Upsweep policies
+ typedef DownsweepPolicy UpsweepPolicy;
+ typedef AltDownsweepPolicy AltUpsweepPolicy;
+
+ // Single-tile policy
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(256, 19, DominantT), BLOCK_LOAD_DIRECT, LOAD_LDG, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SINGLE_TILE_RADIX_BITS> SingleTilePolicy;
+
+ // Segmented policies
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(192, 39, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS> SegmentedPolicy;
+ typedef AgentRadixSortDownsweepPolicy <CUB_SCALED_GRANULARITIES(384, 11, DominantT), BLOCK_LOAD_TRANSPOSE, LOAD_DEFAULT, RADIX_RANK_MEMOIZE, BLOCK_SCAN_WARP_SCANS, SEGMENTED_RADIX_BITS - 1> AltSegmentedPolicy;
+ };
+
+
+ /// MaxPolicy
+ typedef Policy700 MaxPolicy;
+
+
+};
+
+
+
+/******************************************************************************
+ * Single-problem dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for device-wide radix sort
+ */
+template <
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< Key type
+ typename ValueT, ///< Value type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DispatchRadixSort :
+ DeviceRadixSortPolicy<KeyT, ValueT, OffsetT>
+{
+ //------------------------------------------------------------------------------
+ // Constants
+ //------------------------------------------------------------------------------
+
+ enum
+ {
+ // Whether this is a keys-only (or key-value) sort
+ KEYS_ONLY = (Equals<ValueT, NullType>::VALUE),
+ };
+
+
+ //------------------------------------------------------------------------------
+ // Problem state
+ //------------------------------------------------------------------------------
+
+ void *d_temp_storage; ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes; ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ DoubleBuffer<KeyT> &d_keys; ///< [in,out] Double-buffer whose current buffer contains the unsorted input keys and, upon return, is updated to point to the sorted output keys
+ DoubleBuffer<ValueT> &d_values; ///< [in,out] Double-buffer whose current buffer contains the unsorted input values and, upon return, is updated to point to the sorted output values
+ OffsetT num_items; ///< [in] Number of items to sort
+ int begin_bit; ///< [in] The beginning (least-significant) bit index needed for key comparison
+ int end_bit; ///< [in] The past-the-end (most-significant) bit index needed for key comparison
+ cudaStream_t stream; ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous; ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int ptx_version; ///< [in] PTX version
+ bool is_overwrite_okay; ///< [in] Whether is okay to overwrite source buffers
+
+
+ //------------------------------------------------------------------------------
+ // Constructor
+ //------------------------------------------------------------------------------
+
+ /// Constructor
+ CUB_RUNTIME_FUNCTION __forceinline__
+ DispatchRadixSort(
+ void* d_temp_storage,
+ size_t &temp_storage_bytes,
+ DoubleBuffer<KeyT> &d_keys,
+ DoubleBuffer<ValueT> &d_values,
+ OffsetT num_items,
+ int begin_bit,
+ int end_bit,
+ bool is_overwrite_okay,
+ cudaStream_t stream,
+ bool debug_synchronous,
+ int ptx_version)
+ :
+ d_temp_storage(d_temp_storage),
+ temp_storage_bytes(temp_storage_bytes),
+ d_keys(d_keys),
+ d_values(d_values),
+ num_items(num_items),
+ begin_bit(begin_bit),
+ end_bit(end_bit),
+ stream(stream),
+ debug_synchronous(debug_synchronous),
+ ptx_version(ptx_version),
+ is_overwrite_okay(is_overwrite_okay)
+ {}
+
+
+ //------------------------------------------------------------------------------
+ // Small-problem (single tile) invocation
+ //------------------------------------------------------------------------------
+
+ /// Invoke a single block to sort in-core
+ template <
+ typename ActivePolicyT, ///< Umbrella policy active for the target device
+ typename SingleTileKernelT> ///< Function type of cub::DeviceRadixSortSingleTileKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokeSingleTile(
+ SingleTileKernelT single_tile_kernel) ///< [in] Kernel function pointer to parameterization of cub::DeviceRadixSortSingleTileKernel
+ {
+#ifndef CUB_RUNTIME_ENABLED
+ (void)single_tile_kernel;
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+#else
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ if (d_temp_storage == NULL)
+ {
+ temp_storage_bytes = 1;
+ break;
+ }
+
+ // Return if empty problem
+ if (num_items == 0)
+ break;
+
+ // Log single_tile_kernel configuration
+ if (debug_synchronous)
+ _CubLog("Invoking single_tile_kernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy, current bit %d, bit_grain %d\n",
+ 1, ActivePolicyT::SingleTilePolicy::BLOCK_THREADS, (long long) stream,
+ ActivePolicyT::SingleTilePolicy::ITEMS_PER_THREAD, 1, begin_bit, ActivePolicyT::SingleTilePolicy::RADIX_BITS);
+
+ // Invoke upsweep_kernel with same grid size as downsweep_kernel
+ single_tile_kernel<<<1, ActivePolicyT::SingleTilePolicy::BLOCK_THREADS, 0, stream>>>(
+ d_keys.Current(),
+ d_keys.Alternate(),
+ d_values.Current(),
+ d_values.Alternate(),
+ num_items,
+ begin_bit,
+ end_bit);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Update selector
+ d_keys.selector ^= 1;
+ d_values.selector ^= 1;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Normal problem size invocation
+ //------------------------------------------------------------------------------
+
+ /**
+ * Invoke a three-kernel sorting pass at the current bit.
+ */
+ template <typename PassConfigT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokePass(
+ const KeyT *d_keys_in,
+ KeyT *d_keys_out,
+ const ValueT *d_values_in,
+ ValueT *d_values_out,
+ OffsetT *d_spine,
+ int spine_length,
+ int &current_bit,
+ PassConfigT &pass_config)
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ int pass_bits = CUB_MIN(pass_config.radix_bits, (end_bit - current_bit));
+
+ // Log upsweep_kernel configuration
+ if (debug_synchronous)
+ _CubLog("Invoking upsweep_kernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy, current bit %d, bit_grain %d\n",
+ pass_config.even_share.grid_size, pass_config.upsweep_config.block_threads, (long long) stream,
+ pass_config.upsweep_config.items_per_thread, pass_config.upsweep_config.sm_occupancy, current_bit, pass_bits);
+
+ // Invoke upsweep_kernel with same grid size as downsweep_kernel
+ pass_config.upsweep_kernel<<<pass_config.even_share.grid_size, pass_config.upsweep_config.block_threads, 0, stream>>>(
+ d_keys_in,
+ d_spine,
+ num_items,
+ current_bit,
+ pass_bits,
+ pass_config.even_share);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Log scan_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking scan_kernel<<<%d, %d, 0, %lld>>>(), %d items per thread\n",
+ 1, pass_config.scan_config.block_threads, (long long) stream, pass_config.scan_config.items_per_thread);
+
+ // Invoke scan_kernel
+ pass_config.scan_kernel<<<1, pass_config.scan_config.block_threads, 0, stream>>>(
+ d_spine,
+ spine_length);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Log downsweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking downsweep_kernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ pass_config.even_share.grid_size, pass_config.downsweep_config.block_threads, (long long) stream,
+ pass_config.downsweep_config.items_per_thread, pass_config.downsweep_config.sm_occupancy);
+
+ // Invoke downsweep_kernel
+ pass_config.downsweep_kernel<<<pass_config.even_share.grid_size, pass_config.downsweep_config.block_threads, 0, stream>>>(
+ d_keys_in,
+ d_keys_out,
+ d_values_in,
+ d_values_out,
+ d_spine,
+ num_items,
+ current_bit,
+ pass_bits,
+ pass_config.even_share);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Update current bit
+ current_bit += pass_bits;
+ }
+ while (0);
+
+ return error;
+ }
+
+
+
+ /// Pass configuration structure
+ template <
+ typename UpsweepKernelT,
+ typename ScanKernelT,
+ typename DownsweepKernelT>
+ struct PassConfig
+ {
+ UpsweepKernelT upsweep_kernel;
+ KernelConfig upsweep_config;
+ ScanKernelT scan_kernel;
+ KernelConfig scan_config;
+ DownsweepKernelT downsweep_kernel;
+ KernelConfig downsweep_config;
+ int radix_bits;
+ int radix_digits;
+ int max_downsweep_grid_size;
+ GridEvenShare<OffsetT> even_share;
+
+ /// Initialize pass configuration
+ template <
+ typename UpsweepPolicyT,
+ typename ScanPolicyT,
+ typename DownsweepPolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InitPassConfig(
+ UpsweepKernelT upsweep_kernel,
+ ScanKernelT scan_kernel,
+ DownsweepKernelT downsweep_kernel,
+ int ptx_version,
+ int sm_count,
+ int num_items)
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ this->upsweep_kernel = upsweep_kernel;
+ this->scan_kernel = scan_kernel;
+ this->downsweep_kernel = downsweep_kernel;
+ radix_bits = DownsweepPolicyT::RADIX_BITS;
+ radix_digits = 1 << radix_bits;
+
+ if (CubDebug(error = upsweep_config.Init<UpsweepPolicyT>(upsweep_kernel))) break;
+ if (CubDebug(error = scan_config.Init<ScanPolicyT>(scan_kernel))) break;
+ if (CubDebug(error = downsweep_config.Init<DownsweepPolicyT>(downsweep_kernel))) break;
+
+ max_downsweep_grid_size = (downsweep_config.sm_occupancy * sm_count) * CUB_SUBSCRIPTION_FACTOR(ptx_version);
+
+ even_share.DispatchInit(
+ num_items,
+ max_downsweep_grid_size,
+ CUB_MAX(downsweep_config.tile_size, upsweep_config.tile_size));
+
+ }
+ while (0);
+ return error;
+ }
+
+ };
+
+
+ /// Invocation (run multiple digit passes)
+ template <
+ typename ActivePolicyT, ///< Umbrella policy active for the target device
+ typename UpsweepKernelT, ///< Function type of cub::DeviceRadixSortUpsweepKernel
+ typename ScanKernelT, ///< Function type of cub::SpineScanKernel
+ typename DownsweepKernelT> ///< Function type of cub::DeviceRadixSortDownsweepKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokePasses(
+ UpsweepKernelT upsweep_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceRadixSortUpsweepKernel
+ UpsweepKernelT alt_upsweep_kernel, ///< [in] Alternate kernel function pointer to parameterization of cub::DeviceRadixSortUpsweepKernel
+ ScanKernelT scan_kernel, ///< [in] Kernel function pointer to parameterization of cub::SpineScanKernel
+ DownsweepKernelT downsweep_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceRadixSortDownsweepKernel
+ DownsweepKernelT alt_downsweep_kernel) ///< [in] Alternate kernel function pointer to parameterization of cub::DeviceRadixSortDownsweepKernel
+ {
+#ifndef CUB_RUNTIME_ENABLED
+ (void)upsweep_kernel;
+ (void)alt_upsweep_kernel;
+ (void)scan_kernel;
+ (void)downsweep_kernel;
+ (void)alt_downsweep_kernel;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+#else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Init regular and alternate-digit kernel configurations
+ PassConfig<UpsweepKernelT, ScanKernelT, DownsweepKernelT> pass_config, alt_pass_config;
+ if ((error = pass_config.template InitPassConfig<
+ typename ActivePolicyT::UpsweepPolicy,
+ typename ActivePolicyT::ScanPolicy,
+ typename ActivePolicyT::DownsweepPolicy>(
+ upsweep_kernel, scan_kernel, downsweep_kernel, ptx_version, sm_count, num_items))) break;
+
+ if ((error = alt_pass_config.template InitPassConfig<
+ typename ActivePolicyT::AltUpsweepPolicy,
+ typename ActivePolicyT::ScanPolicy,
+ typename ActivePolicyT::AltDownsweepPolicy>(
+ alt_upsweep_kernel, scan_kernel, alt_downsweep_kernel, ptx_version, sm_count, num_items))) break;
+
+ // Get maximum spine length
+ int max_grid_size = CUB_MAX(pass_config.max_downsweep_grid_size, alt_pass_config.max_downsweep_grid_size);
+ int spine_length = (max_grid_size * pass_config.radix_digits) + pass_config.scan_config.tile_size;
+
+ // Temporary storage allocation requirements
+ void* allocations[3];
+ size_t allocation_sizes[3] =
+ {
+ spine_length * sizeof(OffsetT), // bytes needed for privatized block digit histograms
+ (is_overwrite_okay) ? 0 : num_items * sizeof(KeyT), // bytes needed for 3rd keys buffer
+ (is_overwrite_okay || (KEYS_ONLY)) ? 0 : num_items * sizeof(ValueT), // bytes needed for 3rd values buffer
+ };
+
+ // Alias the temporary allocations from the single storage blob (or compute the necessary size of the blob)
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+
+ // Return if the caller is simply requesting the size of the storage allocation
+ if (d_temp_storage == NULL)
+ return cudaSuccess;
+
+ // Pass planning. Run passes of the alternate digit-size configuration until we have an even multiple of our preferred digit size
+ int num_bits = end_bit - begin_bit;
+ int num_passes = (num_bits + pass_config.radix_bits - 1) / pass_config.radix_bits;
+ bool is_num_passes_odd = num_passes & 1;
+ int max_alt_passes = (num_passes * pass_config.radix_bits) - num_bits;
+ int alt_end_bit = CUB_MIN(end_bit, begin_bit + (max_alt_passes * alt_pass_config.radix_bits));
+
+ // Alias the temporary storage allocations
+ OffsetT *d_spine = static_cast<OffsetT*>(allocations[0]);
+
+ DoubleBuffer<KeyT> d_keys_remaining_passes(
+ (is_overwrite_okay || is_num_passes_odd) ? d_keys.Alternate() : static_cast<KeyT*>(allocations[1]),
+ (is_overwrite_okay) ? d_keys.Current() : (is_num_passes_odd) ? static_cast<KeyT*>(allocations[1]) : d_keys.Alternate());
+
+ DoubleBuffer<ValueT> d_values_remaining_passes(
+ (is_overwrite_okay || is_num_passes_odd) ? d_values.Alternate() : static_cast<ValueT*>(allocations[2]),
+ (is_overwrite_okay) ? d_values.Current() : (is_num_passes_odd) ? static_cast<ValueT*>(allocations[2]) : d_values.Alternate());
+
+ // Run first pass, consuming from the input's current buffers
+ int current_bit = begin_bit;
+ if (CubDebug(error = InvokePass(
+ d_keys.Current(), d_keys_remaining_passes.Current(),
+ d_values.Current(), d_values_remaining_passes.Current(),
+ d_spine, spine_length, current_bit,
+ (current_bit < alt_end_bit) ? alt_pass_config : pass_config))) break;
+
+ // Run remaining passes
+ while (current_bit < end_bit)
+ {
+ if (CubDebug(error = InvokePass(
+ d_keys_remaining_passes.d_buffers[d_keys_remaining_passes.selector], d_keys_remaining_passes.d_buffers[d_keys_remaining_passes.selector ^ 1],
+ d_values_remaining_passes.d_buffers[d_keys_remaining_passes.selector], d_values_remaining_passes.d_buffers[d_keys_remaining_passes.selector ^ 1],
+ d_spine, spine_length, current_bit,
+ (current_bit < alt_end_bit) ? alt_pass_config : pass_config))) break;;
+
+ // Invert selectors
+ d_keys_remaining_passes.selector ^= 1;
+ d_values_remaining_passes.selector ^= 1;
+ }
+
+ // Update selector
+ if (!is_overwrite_okay) {
+ num_passes = 1; // Sorted data always ends up in the other vector
+ }
+
+ d_keys.selector = (d_keys.selector + num_passes) & 1;
+ d_values.selector = (d_values.selector + num_passes) & 1;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Chained policy invocation
+ //------------------------------------------------------------------------------
+
+ /// Invocation
+ template <typename ActivePolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t Invoke()
+ {
+ typedef typename DispatchRadixSort::MaxPolicy MaxPolicyT;
+ typedef typename ActivePolicyT::SingleTilePolicy SingleTilePolicyT;
+
+ // Force kernel code-generation in all compiler passes
+ if (num_items <= (SingleTilePolicyT::BLOCK_THREADS * SingleTilePolicyT::ITEMS_PER_THREAD))
+ {
+ // Small, single tile size
+ return InvokeSingleTile<ActivePolicyT>(
+ DeviceRadixSortSingleTileKernel<MaxPolicyT, IS_DESCENDING, KeyT, ValueT, OffsetT>);
+ }
+ else
+ {
+ // Regular size
+ return InvokePasses<ActivePolicyT>(
+ DeviceRadixSortUpsweepKernel< MaxPolicyT, false, IS_DESCENDING, KeyT, OffsetT>,
+ DeviceRadixSortUpsweepKernel< MaxPolicyT, true, IS_DESCENDING, KeyT, OffsetT>,
+ RadixSortScanBinsKernel< MaxPolicyT, OffsetT>,
+ DeviceRadixSortDownsweepKernel< MaxPolicyT, false, IS_DESCENDING, KeyT, ValueT, OffsetT>,
+ DeviceRadixSortDownsweepKernel< MaxPolicyT, true, IS_DESCENDING, KeyT, ValueT, OffsetT>);
+ }
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Dispatch entrypoints
+ //------------------------------------------------------------------------------
+
+ /**
+ * Internal dispatch routine
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ DoubleBuffer<KeyT> &d_keys, ///< [in,out] Double-buffer whose current buffer contains the unsorted input keys and, upon return, is updated to point to the sorted output keys
+ DoubleBuffer<ValueT> &d_values, ///< [in,out] Double-buffer whose current buffer contains the unsorted input values and, upon return, is updated to point to the sorted output values
+ OffsetT num_items, ///< [in] Number of items to sort
+ int begin_bit, ///< [in] The beginning (least-significant) bit index needed for key comparison
+ int end_bit, ///< [in] The past-the-end (most-significant) bit index needed for key comparison
+ bool is_overwrite_okay, ///< [in] Whether is okay to overwrite source buffers
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ typedef typename DispatchRadixSort::MaxPolicy MaxPolicyT;
+
+ cudaError_t error;
+ do {
+ // Get PTX version
+ int ptx_version;
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+
+ // Create dispatch functor
+ DispatchRadixSort dispatch(
+ d_temp_storage, temp_storage_bytes,
+ d_keys, d_values,
+ num_items, begin_bit, end_bit, is_overwrite_okay,
+ stream, debug_synchronous, ptx_version);
+
+ // Dispatch to chained policy
+ if (CubDebug(error = MaxPolicyT::Invoke(ptx_version, dispatch))) break;
+
+ } while (0);
+
+ return error;
+ }
+};
+
+
+
+
+/******************************************************************************
+ * Segmented dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for segmented device-wide radix sort
+ */
+template <
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< Key type
+ typename ValueT, ///< Value type
+ typename OffsetIteratorT, ///< Random-access input iterator type for reading segment offsets \iterator
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DispatchSegmentedRadixSort :
+ DeviceRadixSortPolicy<KeyT, ValueT, OffsetT>
+{
+ //------------------------------------------------------------------------------
+ // Constants
+ //------------------------------------------------------------------------------
+
+ enum
+ {
+ // Whether this is a keys-only (or key-value) sort
+ KEYS_ONLY = (Equals<ValueT, NullType>::VALUE),
+ };
+
+
+ //------------------------------------------------------------------------------
+ // Parameter members
+ //------------------------------------------------------------------------------
+
+ void *d_temp_storage; ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes; ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ DoubleBuffer<KeyT> &d_keys; ///< [in,out] Double-buffer whose current buffer contains the unsorted input keys and, upon return, is updated to point to the sorted output keys
+ DoubleBuffer<ValueT> &d_values; ///< [in,out] Double-buffer whose current buffer contains the unsorted input values and, upon return, is updated to point to the sorted output values
+ OffsetT num_items; ///< [in] Number of items to sort
+ OffsetT num_segments; ///< [in] The number of segments that comprise the sorting data
+ OffsetIteratorT d_begin_offsets; ///< [in] Pointer to the sequence of beginning offsets of length \p num_segments, such that <tt>d_begin_offsets[i]</tt> is the first element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>
+ OffsetIteratorT d_end_offsets; ///< [in] Pointer to the sequence of ending offsets of length \p num_segments, such that <tt>d_end_offsets[i]-1</tt> is the last element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>. If <tt>d_end_offsets[i]-1</tt> <= <tt>d_begin_offsets[i]</tt>, the <em>i</em><sup>th</sup> is considered empty.
+ int begin_bit; ///< [in] The beginning (least-significant) bit index needed for key comparison
+ int end_bit; ///< [in] The past-the-end (most-significant) bit index needed for key comparison
+ cudaStream_t stream; ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous; ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int ptx_version; ///< [in] PTX version
+ bool is_overwrite_okay; ///< [in] Whether is okay to overwrite source buffers
+
+
+ //------------------------------------------------------------------------------
+ // Constructors
+ //------------------------------------------------------------------------------
+
+ /// Constructor
+ CUB_RUNTIME_FUNCTION __forceinline__
+ DispatchSegmentedRadixSort(
+ void* d_temp_storage,
+ size_t &temp_storage_bytes,
+ DoubleBuffer<KeyT> &d_keys,
+ DoubleBuffer<ValueT> &d_values,
+ OffsetT num_items,
+ OffsetT num_segments,
+ OffsetIteratorT d_begin_offsets,
+ OffsetIteratorT d_end_offsets,
+ int begin_bit,
+ int end_bit,
+ bool is_overwrite_okay,
+ cudaStream_t stream,
+ bool debug_synchronous,
+ int ptx_version)
+ :
+ d_temp_storage(d_temp_storage),
+ temp_storage_bytes(temp_storage_bytes),
+ d_keys(d_keys),
+ d_values(d_values),
+ num_items(num_items),
+ num_segments(num_segments),
+ d_begin_offsets(d_begin_offsets),
+ d_end_offsets(d_end_offsets),
+ begin_bit(begin_bit),
+ end_bit(end_bit),
+ is_overwrite_okay(is_overwrite_okay),
+ stream(stream),
+ debug_synchronous(debug_synchronous),
+ ptx_version(ptx_version)
+ {}
+
+
+ //------------------------------------------------------------------------------
+ // Multi-segment invocation
+ //------------------------------------------------------------------------------
+
+ /// Invoke a three-kernel sorting pass at the current bit.
+ template <typename PassConfigT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokePass(
+ const KeyT *d_keys_in,
+ KeyT *d_keys_out,
+ const ValueT *d_values_in,
+ ValueT *d_values_out,
+ int &current_bit,
+ PassConfigT &pass_config)
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ int pass_bits = CUB_MIN(pass_config.radix_bits, (end_bit - current_bit));
+
+ // Log kernel configuration
+ if (debug_synchronous)
+ _CubLog("Invoking segmented_kernels<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy, current bit %d, bit_grain %d\n",
+ num_segments, pass_config.segmented_config.block_threads, (long long) stream,
+ pass_config.segmented_config.items_per_thread, pass_config.segmented_config.sm_occupancy, current_bit, pass_bits);
+
+ pass_config.segmented_kernel<<<num_segments, pass_config.segmented_config.block_threads, 0, stream>>>(
+ d_keys_in, d_keys_out,
+ d_values_in, d_values_out,
+ d_begin_offsets, d_end_offsets, num_segments,
+ current_bit, pass_bits);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Update current bit
+ current_bit += pass_bits;
+ }
+ while (0);
+
+ return error;
+ }
+
+
+ /// PassConfig data structure
+ template <typename SegmentedKernelT>
+ struct PassConfig
+ {
+ SegmentedKernelT segmented_kernel;
+ KernelConfig segmented_config;
+ int radix_bits;
+ int radix_digits;
+
+ /// Initialize pass configuration
+ template <typename SegmentedPolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InitPassConfig(SegmentedKernelT segmented_kernel)
+ {
+ this->segmented_kernel = segmented_kernel;
+ this->radix_bits = SegmentedPolicyT::RADIX_BITS;
+ this->radix_digits = 1 << radix_bits;
+
+ return CubDebug(segmented_config.Init<SegmentedPolicyT>(segmented_kernel));
+ }
+ };
+
+
+ /// Invocation (run multiple digit passes)
+ template <
+ typename ActivePolicyT, ///< Umbrella policy active for the target device
+ typename SegmentedKernelT> ///< Function type of cub::DeviceSegmentedRadixSortKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokePasses(
+ SegmentedKernelT segmented_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceSegmentedRadixSortKernel
+ SegmentedKernelT alt_segmented_kernel) ///< [in] Alternate kernel function pointer to parameterization of cub::DeviceSegmentedRadixSortKernel
+ {
+#ifndef CUB_RUNTIME_ENABLED
+ (void)segmented_kernel;
+ (void)alt_segmented_kernel;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+#else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Init regular and alternate kernel configurations
+ PassConfig<SegmentedKernelT> pass_config, alt_pass_config;
+ if ((error = pass_config.template InitPassConfig<typename ActivePolicyT::SegmentedPolicy>(segmented_kernel))) break;
+ if ((error = alt_pass_config.template InitPassConfig<typename ActivePolicyT::AltSegmentedPolicy>(alt_segmented_kernel))) break;
+
+ // Temporary storage allocation requirements
+ void* allocations[2];
+ size_t allocation_sizes[2] =
+ {
+ (is_overwrite_okay) ? 0 : num_items * sizeof(KeyT), // bytes needed for 3rd keys buffer
+ (is_overwrite_okay || (KEYS_ONLY)) ? 0 : num_items * sizeof(ValueT), // bytes needed for 3rd values buffer
+ };
+
+ // Alias the temporary allocations from the single storage blob (or compute the necessary size of the blob)
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+
+ // Return if the caller is simply requesting the size of the storage allocation
+ if (d_temp_storage == NULL)
+ {
+ if (temp_storage_bytes == 0)
+ temp_storage_bytes = 1;
+ return cudaSuccess;
+ }
+
+ // Pass planning. Run passes of the alternate digit-size configuration until we have an even multiple of our preferred digit size
+ int radix_bits = ActivePolicyT::SegmentedPolicy::RADIX_BITS;
+ int alt_radix_bits = ActivePolicyT::AltSegmentedPolicy::RADIX_BITS;
+ int num_bits = end_bit - begin_bit;
+ int num_passes = (num_bits + radix_bits - 1) / radix_bits;
+ bool is_num_passes_odd = num_passes & 1;
+ int max_alt_passes = (num_passes * radix_bits) - num_bits;
+ int alt_end_bit = CUB_MIN(end_bit, begin_bit + (max_alt_passes * alt_radix_bits));
+
+ DoubleBuffer<KeyT> d_keys_remaining_passes(
+ (is_overwrite_okay || is_num_passes_odd) ? d_keys.Alternate() : static_cast<KeyT*>(allocations[0]),
+ (is_overwrite_okay) ? d_keys.Current() : (is_num_passes_odd) ? static_cast<KeyT*>(allocations[0]) : d_keys.Alternate());
+
+ DoubleBuffer<ValueT> d_values_remaining_passes(
+ (is_overwrite_okay || is_num_passes_odd) ? d_values.Alternate() : static_cast<ValueT*>(allocations[1]),
+ (is_overwrite_okay) ? d_values.Current() : (is_num_passes_odd) ? static_cast<ValueT*>(allocations[1]) : d_values.Alternate());
+
+ // Run first pass, consuming from the input's current buffers
+ int current_bit = begin_bit;
+
+ if (CubDebug(error = InvokePass(
+ d_keys.Current(), d_keys_remaining_passes.Current(),
+ d_values.Current(), d_values_remaining_passes.Current(),
+ current_bit,
+ (current_bit < alt_end_bit) ? alt_pass_config : pass_config))) break;
+
+ // Run remaining passes
+ while (current_bit < end_bit)
+ {
+ if (CubDebug(error = InvokePass(
+ d_keys_remaining_passes.d_buffers[d_keys_remaining_passes.selector], d_keys_remaining_passes.d_buffers[d_keys_remaining_passes.selector ^ 1],
+ d_values_remaining_passes.d_buffers[d_keys_remaining_passes.selector], d_values_remaining_passes.d_buffers[d_keys_remaining_passes.selector ^ 1],
+ current_bit,
+ (current_bit < alt_end_bit) ? alt_pass_config : pass_config))) break;
+
+ // Invert selectors and update current bit
+ d_keys_remaining_passes.selector ^= 1;
+ d_values_remaining_passes.selector ^= 1;
+ }
+
+ // Update selector
+ if (!is_overwrite_okay) {
+ num_passes = 1; // Sorted data always ends up in the other vector
+ }
+
+ d_keys.selector = (d_keys.selector + num_passes) & 1;
+ d_values.selector = (d_values.selector + num_passes) & 1;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Chained policy invocation
+ //------------------------------------------------------------------------------
+
+ /// Invocation
+ template <typename ActivePolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t Invoke()
+ {
+ typedef typename DispatchSegmentedRadixSort::MaxPolicy MaxPolicyT;
+
+ // Force kernel code-generation in all compiler passes
+ return InvokePasses<ActivePolicyT>(
+ DeviceSegmentedRadixSortKernel<MaxPolicyT, false, IS_DESCENDING, KeyT, ValueT, OffsetIteratorT, OffsetT>,
+ DeviceSegmentedRadixSortKernel<MaxPolicyT, true, IS_DESCENDING, KeyT, ValueT, OffsetIteratorT, OffsetT>);
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Dispatch entrypoints
+ //------------------------------------------------------------------------------
+
+
+ /// Internal dispatch routine
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ DoubleBuffer<KeyT> &d_keys, ///< [in,out] Double-buffer whose current buffer contains the unsorted input keys and, upon return, is updated to point to the sorted output keys
+ DoubleBuffer<ValueT> &d_values, ///< [in,out] Double-buffer whose current buffer contains the unsorted input values and, upon return, is updated to point to the sorted output values
+ int num_items, ///< [in] Number of items to sort
+ int num_segments, ///< [in] The number of segments that comprise the sorting data
+ OffsetIteratorT d_begin_offsets, ///< [in] Pointer to the sequence of beginning offsets of length \p num_segments, such that <tt>d_begin_offsets[i]</tt> is the first element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>
+ OffsetIteratorT d_end_offsets, ///< [in] Pointer to the sequence of ending offsets of length \p num_segments, such that <tt>d_end_offsets[i]-1</tt> is the last element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>. If <tt>d_end_offsets[i]-1</tt> <= <tt>d_begin_offsets[i]</tt>, the <em>i</em><sup>th</sup> is considered empty.
+ int begin_bit, ///< [in] The beginning (least-significant) bit index needed for key comparison
+ int end_bit, ///< [in] The past-the-end (most-significant) bit index needed for key comparison
+ bool is_overwrite_okay, ///< [in] Whether is okay to overwrite source buffers
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ typedef typename DispatchSegmentedRadixSort::MaxPolicy MaxPolicyT;
+
+ cudaError_t error;
+ do {
+ // Get PTX version
+ int ptx_version;
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+
+ // Create dispatch functor
+ DispatchSegmentedRadixSort dispatch(
+ d_temp_storage, temp_storage_bytes,
+ d_keys, d_values,
+ num_items, num_segments, d_begin_offsets, d_end_offsets,
+ begin_bit, end_bit, is_overwrite_okay,
+ stream, debug_synchronous, ptx_version);
+
+ // Dispatch to chained policy
+ if (CubDebug(error = MaxPolicyT::Invoke(ptx_version, dispatch))) break;
+
+ } while (0);
+
+ return error;
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce.cuh
new file mode 100644
index 0000000..e9d1b7a
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce.cuh
@@ -0,0 +1,882 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceReduce provides device-wide, parallel operations for computing a reduction across a sequence of data items residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "../../agent/agent_reduce.cuh"
+#include "../../iterator/arg_index_input_iterator.cuh"
+#include "../../thread/thread_operators.cuh"
+#include "../../grid/grid_even_share.cuh"
+#include "../../iterator/arg_index_input_iterator.cuh"
+#include "../../util_debug.cuh"
+#include "../../util_device.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/******************************************************************************
+ * Kernel entry points
+ *****************************************************************************/
+
+/**
+ * Reduce region kernel entry point (multi-block). Computes privatized reductions, one per thread block.
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OutputIteratorT, ///< Output iterator type for recording the reduced aggregate \iterator
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOpT> ///< Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+__launch_bounds__ (int(ChainedPolicyT::ActivePolicy::ReducePolicy::BLOCK_THREADS))
+__global__ void DeviceReduceKernel(
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output aggregate
+ OffsetT num_items, ///< [in] Total number of input data items
+ GridEvenShare<OffsetT> even_share, ///< [in] Even-share descriptor for mapping an equal number of tiles onto each thread block
+ ReductionOpT reduction_op) ///< [in] Binary reduction functor
+{
+ // The output value type
+ typedef typename If<(Equals<typename std::iterator_traits<OutputIteratorT>::value_type, void>::VALUE), // OutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<InputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<OutputIteratorT>::value_type>::Type OutputT; // ... else the output iterator's value type
+
+ // Thread block type for reducing input tiles
+ typedef AgentReduce<
+ typename ChainedPolicyT::ActivePolicy::ReducePolicy,
+ InputIteratorT,
+ OutputIteratorT,
+ OffsetT,
+ ReductionOpT>
+ AgentReduceT;
+
+ // Shared memory storage
+ __shared__ typename AgentReduceT::TempStorage temp_storage;
+
+ // Consume input tiles
+ OutputT block_aggregate = AgentReduceT(temp_storage, d_in, reduction_op).ConsumeTiles(even_share);
+
+ // Output result
+ if (threadIdx.x == 0)
+ d_out[blockIdx.x] = block_aggregate;
+}
+
+
+/**
+ * Reduce a single tile kernel entry point (single-block). Can be used to aggregate privatized thread block reductions from a previous multi-block reduction pass.
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OutputIteratorT, ///< Output iterator type for recording the reduced aggregate \iterator
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOpT, ///< Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ typename OuputT> ///< Data element type that is convertible to the \p value type of \p OutputIteratorT
+__launch_bounds__ (int(ChainedPolicyT::ActivePolicy::SingleTilePolicy::BLOCK_THREADS), 1)
+__global__ void DeviceReduceSingleTileKernel(
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output aggregate
+ OffsetT num_items, ///< [in] Total number of input data items
+ ReductionOpT reduction_op, ///< [in] Binary reduction functor
+ OuputT init) ///< [in] The initial value of the reduction
+{
+ // Thread block type for reducing input tiles
+ typedef AgentReduce<
+ typename ChainedPolicyT::ActivePolicy::SingleTilePolicy,
+ InputIteratorT,
+ OutputIteratorT,
+ OffsetT,
+ ReductionOpT>
+ AgentReduceT;
+
+ // Shared memory storage
+ __shared__ typename AgentReduceT::TempStorage temp_storage;
+
+ // Check if empty problem
+ if (num_items == 0)
+ {
+ if (threadIdx.x == 0)
+ *d_out = init;
+ return;
+ }
+
+ // Consume input tiles
+ OuputT block_aggregate = AgentReduceT(temp_storage, d_in, reduction_op).ConsumeRange(
+ OffsetT(0),
+ num_items);
+
+ // Output result
+ if (threadIdx.x == 0)
+ *d_out = reduction_op(init, block_aggregate);
+}
+
+
+/// Normalize input iterator to segment offset
+template <typename T, typename OffsetT, typename IteratorT>
+__device__ __forceinline__
+void NormalizeReductionOutput(
+ T &/*val*/,
+ OffsetT /*base_offset*/,
+ IteratorT /*itr*/)
+{}
+
+
+/// Normalize input iterator to segment offset (specialized for arg-index)
+template <typename KeyValuePairT, typename OffsetT, typename WrappedIteratorT, typename OutputValueT>
+__device__ __forceinline__
+void NormalizeReductionOutput(
+ KeyValuePairT &val,
+ OffsetT base_offset,
+ ArgIndexInputIterator<WrappedIteratorT, OffsetT, OutputValueT> /*itr*/)
+{
+ val.key -= base_offset;
+}
+
+
+/**
+ * Segmented reduction (one block per segment)
+ */
+template <
+ typename ChainedPolicyT, ///< Chained tuning policy
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OutputIteratorT, ///< Output iterator type for recording the reduced aggregate \iterator
+ typename OffsetIteratorT, ///< Random-access input iterator type for reading segment offsets \iterator
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOpT, ///< Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ typename OutputT> ///< Data element type that is convertible to the \p value type of \p OutputIteratorT
+__launch_bounds__ (int(ChainedPolicyT::ActivePolicy::ReducePolicy::BLOCK_THREADS))
+__global__ void DeviceSegmentedReduceKernel(
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output aggregate
+ OffsetIteratorT d_begin_offsets, ///< [in] Pointer to the sequence of beginning offsets of length \p num_segments, such that <tt>d_begin_offsets[i]</tt> is the first element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>
+ OffsetIteratorT d_end_offsets, ///< [in] Pointer to the sequence of ending offsets of length \p num_segments, such that <tt>d_end_offsets[i]-1</tt> is the last element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>. If <tt>d_end_offsets[i]-1</tt> <= <tt>d_begin_offsets[i]</tt>, the <em>i</em><sup>th</sup> is considered empty.
+ int /*num_segments*/, ///< [in] The number of segments that comprise the sorting data
+ ReductionOpT reduction_op, ///< [in] Binary reduction functor
+ OutputT init) ///< [in] The initial value of the reduction
+{
+ // Thread block type for reducing input tiles
+ typedef AgentReduce<
+ typename ChainedPolicyT::ActivePolicy::ReducePolicy,
+ InputIteratorT,
+ OutputIteratorT,
+ OffsetT,
+ ReductionOpT>
+ AgentReduceT;
+
+ // Shared memory storage
+ __shared__ typename AgentReduceT::TempStorage temp_storage;
+
+ OffsetT segment_begin = d_begin_offsets[blockIdx.x];
+ OffsetT segment_end = d_end_offsets[blockIdx.x];
+
+ // Check if empty problem
+ if (segment_begin == segment_end)
+ {
+ if (threadIdx.x == 0)
+ d_out[blockIdx.x] = init;
+ return;
+ }
+
+ // Consume input tiles
+ OutputT block_aggregate = AgentReduceT(temp_storage, d_in, reduction_op).ConsumeRange(
+ segment_begin,
+ segment_end);
+
+ // Normalize as needed
+ NormalizeReductionOutput(block_aggregate, segment_begin, d_in);
+
+ if (threadIdx.x == 0)
+ d_out[blockIdx.x] = reduction_op(init, block_aggregate);;
+}
+
+
+
+
+/******************************************************************************
+ * Policy
+ ******************************************************************************/
+
+template <
+ typename OuputT, ///< Data type
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOpT> ///< Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+struct DeviceReducePolicy
+{
+ //------------------------------------------------------------------------------
+ // Architecture-specific tuning policies
+ //------------------------------------------------------------------------------
+
+ /// SM13
+ struct Policy130 : ChainedPolicy<130, Policy130, Policy130>
+ {
+ // ReducePolicy
+ typedef AgentReducePolicy<
+ CUB_SCALED_GRANULARITIES(128, 8, OuputT), ///< Threads per block, items per thread
+ 2, ///< Number of items per vectorized load
+ BLOCK_REDUCE_RAKING, ///< Cooperative block-wide reduction algorithm to use
+ LOAD_DEFAULT> ///< Cache load modifier
+ ReducePolicy;
+
+ // SingleTilePolicy
+ typedef ReducePolicy SingleTilePolicy;
+
+ // SegmentedReducePolicy
+ typedef ReducePolicy SegmentedReducePolicy;
+ };
+
+
+ /// SM20
+ struct Policy200 : ChainedPolicy<200, Policy200, Policy130>
+ {
+ // ReducePolicy (GTX 580: 178.9 GB/s @ 48M 4B items, 158.1 GB/s @ 192M 1B items)
+ typedef AgentReducePolicy<
+ CUB_SCALED_GRANULARITIES(128, 8, OuputT), ///< Threads per block, items per thread
+ 4, ///< Number of items per vectorized load
+ BLOCK_REDUCE_RAKING, ///< Cooperative block-wide reduction algorithm to use
+ LOAD_DEFAULT> ///< Cache load modifier
+ ReducePolicy;
+
+ // SingleTilePolicy
+ typedef ReducePolicy SingleTilePolicy;
+
+ // SegmentedReducePolicy
+ typedef ReducePolicy SegmentedReducePolicy;
+ };
+
+
+ /// SM30
+ struct Policy300 : ChainedPolicy<300, Policy300, Policy200>
+ {
+ // ReducePolicy (GTX670: 154.0 @ 48M 4B items)
+ typedef AgentReducePolicy<
+ CUB_SCALED_GRANULARITIES(256, 20, OuputT), ///< Threads per block, items per thread
+ 2, ///< Number of items per vectorized load
+ BLOCK_REDUCE_WARP_REDUCTIONS, ///< Cooperative block-wide reduction algorithm to use
+ LOAD_DEFAULT> ///< Cache load modifier
+ ReducePolicy;
+
+ // SingleTilePolicy
+ typedef ReducePolicy SingleTilePolicy;
+
+ // SegmentedReducePolicy
+ typedef ReducePolicy SegmentedReducePolicy;
+ };
+
+
+ /// SM35
+ struct Policy350 : ChainedPolicy<350, Policy350, Policy300>
+ {
+ // ReducePolicy (GTX Titan: 255.1 GB/s @ 48M 4B items; 228.7 GB/s @ 192M 1B items)
+ typedef AgentReducePolicy<
+ CUB_SCALED_GRANULARITIES(256, 20, OuputT), ///< Threads per block, items per thread
+ 4, ///< Number of items per vectorized load
+ BLOCK_REDUCE_WARP_REDUCTIONS, ///< Cooperative block-wide reduction algorithm to use
+ LOAD_LDG> ///< Cache load modifier
+ ReducePolicy;
+
+ // SingleTilePolicy
+ typedef ReducePolicy SingleTilePolicy;
+
+ // SegmentedReducePolicy
+ typedef ReducePolicy SegmentedReducePolicy;
+ };
+
+ /// SM60
+ struct Policy600 : ChainedPolicy<600, Policy600, Policy350>
+ {
+ // ReducePolicy (P100: 591 GB/s @ 64M 4B items; 583 GB/s @ 256M 1B items)
+ typedef AgentReducePolicy<
+ CUB_SCALED_GRANULARITIES(256, 16, OuputT), ///< Threads per block, items per thread
+ 4, ///< Number of items per vectorized load
+ BLOCK_REDUCE_WARP_REDUCTIONS, ///< Cooperative block-wide reduction algorithm to use
+ LOAD_LDG> ///< Cache load modifier
+ ReducePolicy;
+
+ // SingleTilePolicy
+ typedef ReducePolicy SingleTilePolicy;
+
+ // SegmentedReducePolicy
+ typedef ReducePolicy SegmentedReducePolicy;
+ };
+
+
+ /// MaxPolicy
+ typedef Policy600 MaxPolicy;
+
+};
+
+
+
+/******************************************************************************
+ * Single-problem dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for device-wide reduction
+ */
+template <
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OutputIteratorT, ///< Output iterator type for recording the reduced aggregate \iterator
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOpT> ///< Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+struct DispatchReduce :
+ DeviceReducePolicy<
+ typename If<(Equals<typename std::iterator_traits<OutputIteratorT>::value_type, void>::VALUE), // OutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<InputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<OutputIteratorT>::value_type>::Type, // ... else the output iterator's value type
+ OffsetT,
+ ReductionOpT>
+{
+ //------------------------------------------------------------------------------
+ // Constants
+ //------------------------------------------------------------------------------
+
+ // Data type of output iterator
+ typedef typename If<(Equals<typename std::iterator_traits<OutputIteratorT>::value_type, void>::VALUE), // OutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<InputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<OutputIteratorT>::value_type>::Type OutputT; // ... else the output iterator's value type
+
+
+ //------------------------------------------------------------------------------
+ // Problem state
+ //------------------------------------------------------------------------------
+
+ void *d_temp_storage; ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes; ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in; ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out; ///< [out] Pointer to the output aggregate
+ OffsetT num_items; ///< [in] Total number of input items (i.e., length of \p d_in)
+ ReductionOpT reduction_op; ///< [in] Binary reduction functor
+ OutputT init; ///< [in] The initial value of the reduction
+ cudaStream_t stream; ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous; ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int ptx_version; ///< [in] PTX version
+
+ //------------------------------------------------------------------------------
+ // Constructor
+ //------------------------------------------------------------------------------
+
+ /// Constructor
+ CUB_RUNTIME_FUNCTION __forceinline__
+ DispatchReduce(
+ void* d_temp_storage,
+ size_t &temp_storage_bytes,
+ InputIteratorT d_in,
+ OutputIteratorT d_out,
+ OffsetT num_items,
+ ReductionOpT reduction_op,
+ OutputT init,
+ cudaStream_t stream,
+ bool debug_synchronous,
+ int ptx_version)
+ :
+ d_temp_storage(d_temp_storage),
+ temp_storage_bytes(temp_storage_bytes),
+ d_in(d_in),
+ d_out(d_out),
+ num_items(num_items),
+ reduction_op(reduction_op),
+ init(init),
+ stream(stream),
+ debug_synchronous(debug_synchronous),
+ ptx_version(ptx_version)
+ {}
+
+
+ //------------------------------------------------------------------------------
+ // Small-problem (single tile) invocation
+ //------------------------------------------------------------------------------
+
+ /// Invoke a single block block to reduce in-core
+ template <
+ typename ActivePolicyT, ///< Umbrella policy active for the target device
+ typename SingleTileKernelT> ///< Function type of cub::DeviceReduceSingleTileKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokeSingleTile(
+ SingleTileKernelT single_tile_kernel) ///< [in] Kernel function pointer to parameterization of cub::DeviceReduceSingleTileKernel
+ {
+#ifndef CUB_RUNTIME_ENABLED
+ (void)single_tile_kernel;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+#else
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ if (d_temp_storage == NULL)
+ {
+ temp_storage_bytes = 1;
+ break;
+ }
+
+ // Log single_reduce_sweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking DeviceReduceSingleTileKernel<<<1, %d, 0, %lld>>>(), %d items per thread\n",
+ ActivePolicyT::SingleTilePolicy::BLOCK_THREADS,
+ (long long) stream,
+ ActivePolicyT::SingleTilePolicy::ITEMS_PER_THREAD);
+
+ // Invoke single_reduce_sweep_kernel
+ single_tile_kernel<<<1, ActivePolicyT::SingleTilePolicy::BLOCK_THREADS, 0, stream>>>(
+ d_in,
+ d_out,
+ num_items,
+ reduction_op,
+ init);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Normal problem size invocation (two-pass)
+ //------------------------------------------------------------------------------
+
+ /// Invoke two-passes to reduce
+ template <
+ typename ActivePolicyT, ///< Umbrella policy active for the target device
+ typename ReduceKernelT, ///< Function type of cub::DeviceReduceKernel
+ typename SingleTileKernelT> ///< Function type of cub::DeviceReduceSingleTileKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokePasses(
+ ReduceKernelT reduce_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceReduceKernel
+ SingleTileKernelT single_tile_kernel) ///< [in] Kernel function pointer to parameterization of cub::DeviceReduceSingleTileKernel
+ {
+#ifndef CUB_RUNTIME_ENABLED
+ (void) reduce_kernel;
+ (void) single_tile_kernel;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+#else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Init regular kernel configuration
+ KernelConfig reduce_config;
+ if (CubDebug(error = reduce_config.Init<typename ActivePolicyT::ReducePolicy>(reduce_kernel))) break;
+ int reduce_device_occupancy = reduce_config.sm_occupancy * sm_count;
+
+ // Even-share work distribution
+ int max_blocks = reduce_device_occupancy * CUB_SUBSCRIPTION_FACTOR(ptx_version);
+ GridEvenShare<OffsetT> even_share;
+ even_share.DispatchInit(num_items, max_blocks, reduce_config.tile_size);
+
+ // Temporary storage allocation requirements
+ void* allocations[1];
+ size_t allocation_sizes[1] =
+ {
+ max_blocks * sizeof(OutputT) // bytes needed for privatized block reductions
+ };
+
+ // Alias the temporary allocations from the single storage blob (or compute the necessary size of the blob)
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ return cudaSuccess;
+ }
+
+ // Alias the allocation for the privatized per-block reductions
+ OutputT *d_block_reductions = (OutputT*) allocations[0];
+
+ // Get grid size for device_reduce_sweep_kernel
+ int reduce_grid_size = even_share.grid_size;
+
+ // Log device_reduce_sweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking DeviceReduceKernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ reduce_grid_size,
+ ActivePolicyT::ReducePolicy::BLOCK_THREADS,
+ (long long) stream,
+ ActivePolicyT::ReducePolicy::ITEMS_PER_THREAD,
+ reduce_config.sm_occupancy);
+
+ // Invoke DeviceReduceKernel
+ reduce_kernel<<<reduce_grid_size, ActivePolicyT::ReducePolicy::BLOCK_THREADS, 0, stream>>>(
+ d_in,
+ d_block_reductions,
+ num_items,
+ even_share,
+ reduction_op);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Log single_reduce_sweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking DeviceReduceSingleTileKernel<<<1, %d, 0, %lld>>>(), %d items per thread\n",
+ ActivePolicyT::SingleTilePolicy::BLOCK_THREADS,
+ (long long) stream,
+ ActivePolicyT::SingleTilePolicy::ITEMS_PER_THREAD);
+
+ // Invoke DeviceReduceSingleTileKernel
+ single_tile_kernel<<<1, ActivePolicyT::SingleTilePolicy::BLOCK_THREADS, 0, stream>>>(
+ d_block_reductions,
+ d_out,
+ reduce_grid_size,
+ reduction_op,
+ init);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Chained policy invocation
+ //------------------------------------------------------------------------------
+
+ /// Invocation
+ template <typename ActivePolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t Invoke()
+ {
+ typedef typename ActivePolicyT::SingleTilePolicy SingleTilePolicyT;
+ typedef typename DispatchReduce::MaxPolicy MaxPolicyT;
+
+ // Force kernel code-generation in all compiler passes
+ if (num_items <= (SingleTilePolicyT::BLOCK_THREADS * SingleTilePolicyT::ITEMS_PER_THREAD))
+ {
+ // Small, single tile size
+ return InvokeSingleTile<ActivePolicyT>(
+ DeviceReduceSingleTileKernel<MaxPolicyT, InputIteratorT, OutputIteratorT, OffsetT, ReductionOpT, OutputT>);
+ }
+ else
+ {
+ // Regular size
+ return InvokePasses<ActivePolicyT>(
+ DeviceReduceKernel<typename DispatchReduce::MaxPolicy, InputIteratorT, OutputT*, OffsetT, ReductionOpT>,
+ DeviceReduceSingleTileKernel<MaxPolicyT, OutputT*, OutputIteratorT, OffsetT, ReductionOpT, OutputT>);
+ }
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Dispatch entrypoints
+ //------------------------------------------------------------------------------
+
+ /**
+ * Internal dispatch routine for computing a device-wide reduction
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void *d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output aggregate
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ ReductionOpT reduction_op, ///< [in] Binary reduction functor
+ OutputT init, ///< [in] The initial value of the reduction
+ cudaStream_t stream, ///< [in] <b>[optional]</b> CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] <b>[optional]</b> Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ typedef typename DispatchReduce::MaxPolicy MaxPolicyT;
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+
+ // Create dispatch functor
+ DispatchReduce dispatch(
+ d_temp_storage, temp_storage_bytes,
+ d_in, d_out, num_items, reduction_op, init,
+ stream, debug_synchronous, ptx_version);
+
+ // Dispatch to chained policy
+ if (CubDebug(error = MaxPolicyT::Invoke(ptx_version, dispatch))) break;
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+
+
+/******************************************************************************
+ * Segmented dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for device-wide reduction
+ */
+template <
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OutputIteratorT, ///< Output iterator type for recording the reduced aggregate \iterator
+ typename OffsetIteratorT, ///< Random-access input iterator type for reading segment offsets \iterator
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOpT> ///< Binary reduction functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+struct DispatchSegmentedReduce :
+ DeviceReducePolicy<
+ typename std::iterator_traits<InputIteratorT>::value_type,
+ OffsetT,
+ ReductionOpT>
+{
+ //------------------------------------------------------------------------------
+ // Constants
+ //------------------------------------------------------------------------------
+
+ /// The output value type
+ typedef typename If<(Equals<typename std::iterator_traits<OutputIteratorT>::value_type, void>::VALUE), // OutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<InputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<OutputIteratorT>::value_type>::Type OutputT; // ... else the output iterator's value type
+
+
+ //------------------------------------------------------------------------------
+ // Problem state
+ //------------------------------------------------------------------------------
+
+ void *d_temp_storage; ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes; ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in; ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out; ///< [out] Pointer to the output aggregate
+ OffsetT num_segments; ///< [in] The number of segments that comprise the sorting data
+ OffsetIteratorT d_begin_offsets; ///< [in] Pointer to the sequence of beginning offsets of length \p num_segments, such that <tt>d_begin_offsets[i]</tt> is the first element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>
+ OffsetIteratorT d_end_offsets; ///< [in] Pointer to the sequence of ending offsets of length \p num_segments, such that <tt>d_end_offsets[i]-1</tt> is the last element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>. If <tt>d_end_offsets[i]-1</tt> <= <tt>d_begin_offsets[i]</tt>, the <em>i</em><sup>th</sup> is considered empty.
+ ReductionOpT reduction_op; ///< [in] Binary reduction functor
+ OutputT init; ///< [in] The initial value of the reduction
+ cudaStream_t stream; ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous; ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int ptx_version; ///< [in] PTX version
+
+ //------------------------------------------------------------------------------
+ // Constructor
+ //------------------------------------------------------------------------------
+
+ /// Constructor
+ CUB_RUNTIME_FUNCTION __forceinline__
+ DispatchSegmentedReduce(
+ void* d_temp_storage,
+ size_t &temp_storage_bytes,
+ InputIteratorT d_in,
+ OutputIteratorT d_out,
+ OffsetT num_segments,
+ OffsetIteratorT d_begin_offsets,
+ OffsetIteratorT d_end_offsets,
+ ReductionOpT reduction_op,
+ OutputT init,
+ cudaStream_t stream,
+ bool debug_synchronous,
+ int ptx_version)
+ :
+ d_temp_storage(d_temp_storage),
+ temp_storage_bytes(temp_storage_bytes),
+ d_in(d_in),
+ d_out(d_out),
+ num_segments(num_segments),
+ d_begin_offsets(d_begin_offsets),
+ d_end_offsets(d_end_offsets),
+ reduction_op(reduction_op),
+ init(init),
+ stream(stream),
+ debug_synchronous(debug_synchronous),
+ ptx_version(ptx_version)
+ {}
+
+
+
+ //------------------------------------------------------------------------------
+ // Chained policy invocation
+ //------------------------------------------------------------------------------
+
+ /// Invocation
+ template <
+ typename ActivePolicyT, ///< Umbrella policy active for the target device
+ typename DeviceSegmentedReduceKernelT> ///< Function type of cub::DeviceSegmentedReduceKernel
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t InvokePasses(
+ DeviceSegmentedReduceKernelT segmented_reduce_kernel) ///< [in] Kernel function pointer to parameterization of cub::DeviceSegmentedReduceKernel
+ {
+#ifndef CUB_RUNTIME_ENABLED
+ (void)segmented_reduce_kernel;
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+#else
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ if (d_temp_storage == NULL)
+ {
+ temp_storage_bytes = 1;
+ return cudaSuccess;
+ }
+
+ // Init kernel configuration
+ KernelConfig segmented_reduce_config;
+ if (CubDebug(error = segmented_reduce_config.Init<typename ActivePolicyT::SegmentedReducePolicy>(segmented_reduce_kernel))) break;
+
+ // Log device_reduce_sweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking SegmentedDeviceReduceKernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ num_segments,
+ ActivePolicyT::SegmentedReducePolicy::BLOCK_THREADS,
+ (long long) stream,
+ ActivePolicyT::SegmentedReducePolicy::ITEMS_PER_THREAD,
+ segmented_reduce_config.sm_occupancy);
+
+ // Invoke DeviceReduceKernel
+ segmented_reduce_kernel<<<num_segments, ActivePolicyT::SegmentedReducePolicy::BLOCK_THREADS, 0, stream>>>(
+ d_in,
+ d_out,
+ d_begin_offsets,
+ d_end_offsets,
+ num_segments,
+ reduction_op,
+ init);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+
+ }
+
+
+ /// Invocation
+ template <typename ActivePolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ cudaError_t Invoke()
+ {
+ typedef typename DispatchSegmentedReduce::MaxPolicy MaxPolicyT;
+
+ // Force kernel code-generation in all compiler passes
+ return InvokePasses<ActivePolicyT>(
+ DeviceSegmentedReduceKernel<MaxPolicyT, InputIteratorT, OutputIteratorT, OffsetIteratorT, OffsetT, ReductionOpT, OutputT>);
+ }
+
+
+ //------------------------------------------------------------------------------
+ // Dispatch entrypoints
+ //------------------------------------------------------------------------------
+
+ /**
+ * Internal dispatch routine for computing a device-wide reduction
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void *d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t &temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output aggregate
+ int num_segments, ///< [in] The number of segments that comprise the sorting data
+ OffsetIteratorT d_begin_offsets, ///< [in] Pointer to the sequence of beginning offsets of length \p num_segments, such that <tt>d_begin_offsets[i]</tt> is the first element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>
+ OffsetIteratorT d_end_offsets, ///< [in] Pointer to the sequence of ending offsets of length \p num_segments, such that <tt>d_end_offsets[i]-1</tt> is the last element of the <em>i</em><sup>th</sup> data segment in <tt>d_keys_*</tt> and <tt>d_values_*</tt>. If <tt>d_end_offsets[i]-1</tt> <= <tt>d_begin_offsets[i]</tt>, the <em>i</em><sup>th</sup> is considered empty.
+ ReductionOpT reduction_op, ///< [in] Binary reduction functor
+ OutputT init, ///< [in] The initial value of the reduction
+ cudaStream_t stream, ///< [in] <b>[optional]</b> CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] <b>[optional]</b> Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ typedef typename DispatchSegmentedReduce::MaxPolicy MaxPolicyT;
+
+ if (num_segments <= 0)
+ return cudaSuccess;
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+
+ // Create dispatch functor
+ DispatchSegmentedReduce dispatch(
+ d_temp_storage, temp_storage_bytes,
+ d_in, d_out,
+ num_segments, d_begin_offsets, d_end_offsets,
+ reduction_op, init,
+ stream, debug_synchronous, ptx_version);
+
+ // Dispatch to chained policy
+ if (CubDebug(error = MaxPolicyT::Invoke(ptx_version, dispatch))) break;
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce_by_key.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce_by_key.cuh
new file mode 100644
index 0000000..6f4837b
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_reduce_by_key.cuh
@@ -0,0 +1,554 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceReduceByKey provides device-wide, parallel operations for reducing segments of values residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "dispatch_scan.cuh"
+#include "../../agent/agent_reduce_by_key.cuh"
+#include "../../thread/thread_operators.cuh"
+#include "../../grid/grid_queue.cuh"
+#include "../../util_device.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/******************************************************************************
+ * Kernel entry points
+ *****************************************************************************/
+
+/**
+ * Multi-block reduce-by-key sweep kernel entry point
+ */
+template <
+ typename AgentReduceByKeyPolicyT, ///< Parameterized AgentReduceByKeyPolicyT tuning policy type
+ typename KeysInputIteratorT, ///< Random-access input iterator type for keys
+ typename UniqueOutputIteratorT, ///< Random-access output iterator type for keys
+ typename ValuesInputIteratorT, ///< Random-access input iterator type for values
+ typename AggregatesOutputIteratorT, ///< Random-access output iterator type for values
+ typename NumRunsOutputIteratorT, ///< Output iterator type for recording number of segments encountered
+ typename ScanTileStateT, ///< Tile status interface type
+ typename EqualityOpT, ///< KeyT equality operator type
+ typename ReductionOpT, ///< ValueT reduction operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int(AgentReduceByKeyPolicyT::BLOCK_THREADS))
+__global__ void DeviceReduceByKeyKernel(
+ KeysInputIteratorT d_keys_in, ///< Pointer to the input sequence of keys
+ UniqueOutputIteratorT d_unique_out, ///< Pointer to the output sequence of unique keys (one key per run)
+ ValuesInputIteratorT d_values_in, ///< Pointer to the input sequence of corresponding values
+ AggregatesOutputIteratorT d_aggregates_out, ///< Pointer to the output sequence of value aggregates (one aggregate per run)
+ NumRunsOutputIteratorT d_num_runs_out, ///< Pointer to total number of runs encountered (i.e., the length of d_unique_out)
+ ScanTileStateT tile_state, ///< Tile status interface
+ int start_tile, ///< The starting tile for the current grid
+ EqualityOpT equality_op, ///< KeyT equality operator
+ ReductionOpT reduction_op, ///< ValueT reduction operator
+ OffsetT num_items) ///< Total number of items to select from
+{
+ // Thread block type for reducing tiles of value segments
+ typedef AgentReduceByKey<
+ AgentReduceByKeyPolicyT,
+ KeysInputIteratorT,
+ UniqueOutputIteratorT,
+ ValuesInputIteratorT,
+ AggregatesOutputIteratorT,
+ NumRunsOutputIteratorT,
+ EqualityOpT,
+ ReductionOpT,
+ OffsetT>
+ AgentReduceByKeyT;
+
+ // Shared memory for AgentReduceByKey
+ __shared__ typename AgentReduceByKeyT::TempStorage temp_storage;
+
+ // Process tiles
+ AgentReduceByKeyT(temp_storage, d_keys_in, d_unique_out, d_values_in, d_aggregates_out, d_num_runs_out, equality_op, reduction_op).ConsumeRange(
+ num_items,
+ tile_state,
+ start_tile);
+}
+
+
+
+
+/******************************************************************************
+ * Dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for DeviceReduceByKey
+ */
+template <
+ typename KeysInputIteratorT, ///< Random-access input iterator type for keys
+ typename UniqueOutputIteratorT, ///< Random-access output iterator type for keys
+ typename ValuesInputIteratorT, ///< Random-access input iterator type for values
+ typename AggregatesOutputIteratorT, ///< Random-access output iterator type for values
+ typename NumRunsOutputIteratorT, ///< Output iterator type for recording number of segments encountered
+ typename EqualityOpT, ///< KeyT equality operator type
+ typename ReductionOpT, ///< ValueT reduction operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DispatchReduceByKey
+{
+ //-------------------------------------------------------------------------
+ // Types and constants
+ //-------------------------------------------------------------------------
+
+ // The input keys type
+ typedef typename std::iterator_traits<KeysInputIteratorT>::value_type KeyInputT;
+
+ // The output keys type
+ typedef typename If<(Equals<typename std::iterator_traits<UniqueOutputIteratorT>::value_type, void>::VALUE), // KeyOutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<KeysInputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<UniqueOutputIteratorT>::value_type>::Type KeyOutputT; // ... else the output iterator's value type
+
+ // The input values type
+ typedef typename std::iterator_traits<ValuesInputIteratorT>::value_type ValueInputT;
+
+ // The output values type
+ typedef typename If<(Equals<typename std::iterator_traits<AggregatesOutputIteratorT>::value_type, void>::VALUE), // ValueOutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<ValuesInputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<AggregatesOutputIteratorT>::value_type>::Type ValueOutputT; // ... else the output iterator's value type
+
+ enum
+ {
+ INIT_KERNEL_THREADS = 128,
+ MAX_INPUT_BYTES = CUB_MAX(sizeof(KeyOutputT), sizeof(ValueOutputT)),
+ COMBINED_INPUT_BYTES = sizeof(KeyOutputT) + sizeof(ValueOutputT),
+ };
+
+ // Tile status descriptor interface type
+ typedef ReduceByKeyScanTileState<ValueOutputT, OffsetT> ScanTileStateT;
+
+
+ //-------------------------------------------------------------------------
+ // Tuning policies
+ //-------------------------------------------------------------------------
+
+ /// SM35
+ struct Policy350
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 6,
+ ITEMS_PER_THREAD = (MAX_INPUT_BYTES <= 8) ? 6 : CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, ((NOMINAL_4B_ITEMS_PER_THREAD * 8) + COMBINED_INPUT_BYTES - 1) / COMBINED_INPUT_BYTES)),
+ };
+
+ typedef AgentReduceByKeyPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ BLOCK_SCAN_WARP_SCANS>
+ ReduceByKeyPolicyT;
+ };
+
+ /// SM30
+ struct Policy300
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 6,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, ((NOMINAL_4B_ITEMS_PER_THREAD * 8) + COMBINED_INPUT_BYTES - 1) / COMBINED_INPUT_BYTES)),
+ };
+
+ typedef AgentReduceByKeyPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ ReduceByKeyPolicyT;
+ };
+
+ /// SM20
+ struct Policy200
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 11,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, ((NOMINAL_4B_ITEMS_PER_THREAD * 8) + COMBINED_INPUT_BYTES - 1) / COMBINED_INPUT_BYTES)),
+ };
+
+ typedef AgentReduceByKeyPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ ReduceByKeyPolicyT;
+ };
+
+ /// SM13
+ struct Policy130
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 7,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, ((NOMINAL_4B_ITEMS_PER_THREAD * 8) + COMBINED_INPUT_BYTES - 1) / COMBINED_INPUT_BYTES)),
+ };
+
+ typedef AgentReduceByKeyPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ ReduceByKeyPolicyT;
+ };
+
+ /// SM11
+ struct Policy110
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 5,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 8) / COMBINED_INPUT_BYTES)),
+ };
+
+ typedef AgentReduceByKeyPolicy<
+ 64,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_RAKING>
+ ReduceByKeyPolicyT;
+ };
+
+
+ /******************************************************************************
+ * Tuning policies of current PTX compiler pass
+ ******************************************************************************/
+
+#if (CUB_PTX_ARCH >= 350)
+ typedef Policy350 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 300)
+ typedef Policy300 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 200)
+ typedef Policy200 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 130)
+ typedef Policy130 PtxPolicy;
+
+#else
+ typedef Policy110 PtxPolicy;
+
+#endif
+
+ // "Opaque" policies (whose parameterizations aren't reflected in the type signature)
+ struct PtxReduceByKeyPolicy : PtxPolicy::ReduceByKeyPolicyT {};
+
+
+ /******************************************************************************
+ * Utilities
+ ******************************************************************************/
+
+ /**
+ * Initialize kernel dispatch configurations with the policies corresponding to the PTX assembly we will use
+ */
+ template <typename KernelConfig>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static void InitConfigs(
+ int ptx_version,
+ KernelConfig &reduce_by_key_config)
+ {
+ #if (CUB_PTX_ARCH > 0)
+ (void)ptx_version;
+
+ // We're on the device, so initialize the kernel dispatch configurations with the current PTX policy
+ reduce_by_key_config.template Init<PtxReduceByKeyPolicy>();
+
+ #else
+
+ // We're on the host, so lookup and initialize the kernel dispatch configurations with the policies that match the device's PTX version
+ if (ptx_version >= 350)
+ {
+ reduce_by_key_config.template Init<typename Policy350::ReduceByKeyPolicyT>();
+ }
+ else if (ptx_version >= 300)
+ {
+ reduce_by_key_config.template Init<typename Policy300::ReduceByKeyPolicyT>();
+ }
+ else if (ptx_version >= 200)
+ {
+ reduce_by_key_config.template Init<typename Policy200::ReduceByKeyPolicyT>();
+ }
+ else if (ptx_version >= 130)
+ {
+ reduce_by_key_config.template Init<typename Policy130::ReduceByKeyPolicyT>();
+ }
+ else
+ {
+ reduce_by_key_config.template Init<typename Policy110::ReduceByKeyPolicyT>();
+ }
+
+ #endif
+ }
+
+
+ /**
+ * Kernel kernel dispatch configuration.
+ */
+ struct KernelConfig
+ {
+ int block_threads;
+ int items_per_thread;
+ int tile_items;
+
+ template <typename PolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ void Init()
+ {
+ block_threads = PolicyT::BLOCK_THREADS;
+ items_per_thread = PolicyT::ITEMS_PER_THREAD;
+ tile_items = block_threads * items_per_thread;
+ }
+ };
+
+
+ //---------------------------------------------------------------------
+ // Dispatch entrypoints
+ //---------------------------------------------------------------------
+
+ /**
+ * Internal dispatch routine for computing a device-wide reduce-by-key using the
+ * specified kernel functions.
+ */
+ template <
+ typename ScanInitKernelT, ///< Function type of cub::DeviceScanInitKernel
+ typename ReduceByKeyKernelT> ///< Function type of cub::DeviceReduceByKeyKernelT
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ KeysInputIteratorT d_keys_in, ///< [in] Pointer to the input sequence of keys
+ UniqueOutputIteratorT d_unique_out, ///< [out] Pointer to the output sequence of unique keys (one key per run)
+ ValuesInputIteratorT d_values_in, ///< [in] Pointer to the input sequence of corresponding values
+ AggregatesOutputIteratorT d_aggregates_out, ///< [out] Pointer to the output sequence of value aggregates (one aggregate per run)
+ NumRunsOutputIteratorT d_num_runs_out, ///< [out] Pointer to total number of runs encountered (i.e., the length of d_unique_out)
+ EqualityOpT equality_op, ///< [in] KeyT equality operator
+ ReductionOpT reduction_op, ///< [in] ValueT reduction operator
+ OffsetT num_items, ///< [in] Total number of items to select from
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int /*ptx_version*/, ///< [in] PTX version of dispatch kernels
+ ScanInitKernelT init_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceScanInitKernel
+ ReduceByKeyKernelT reduce_by_key_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceReduceByKeyKernel
+ KernelConfig reduce_by_key_config) ///< [in] Dispatch parameters that match the policy that \p reduce_by_key_kernel was compiled for
+ {
+
+#ifndef CUB_RUNTIME_ENABLED
+ (void)d_temp_storage;
+ (void)temp_storage_bytes;
+ (void)d_keys_in;
+ (void)d_unique_out;
+ (void)d_values_in;
+ (void)d_aggregates_out;
+ (void)d_num_runs_out;
+ (void)equality_op;
+ (void)reduction_op;
+ (void)num_items;
+ (void)stream;
+ (void)debug_synchronous;
+ (void)init_kernel;
+ (void)reduce_by_key_kernel;
+ (void)reduce_by_key_config;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported);
+
+#else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Number of input tiles
+ int tile_size = reduce_by_key_config.block_threads * reduce_by_key_config.items_per_thread;
+ int num_tiles = (num_items + tile_size - 1) / tile_size;
+
+ // Specify temporary storage allocation requirements
+ size_t allocation_sizes[1];
+ if (CubDebug(error = ScanTileStateT::AllocationSize(num_tiles, allocation_sizes[0]))) break; // bytes needed for tile status descriptors
+
+ // Compute allocation pointers into the single storage blob (or compute the necessary size of the blob)
+ void* allocations[1];
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ break;
+ }
+
+ // Construct the tile status interface
+ ScanTileStateT tile_state;
+ if (CubDebug(error = tile_state.Init(num_tiles, allocations[0], allocation_sizes[0]))) break;
+
+ // Log init_kernel configuration
+ int init_grid_size = CUB_MAX(1, (num_tiles + INIT_KERNEL_THREADS - 1) / INIT_KERNEL_THREADS);
+ if (debug_synchronous) _CubLog("Invoking init_kernel<<<%d, %d, 0, %lld>>>()\n", init_grid_size, INIT_KERNEL_THREADS, (long long) stream);
+
+ // Invoke init_kernel to initialize tile descriptors
+ init_kernel<<<init_grid_size, INIT_KERNEL_THREADS, 0, stream>>>(
+ tile_state,
+ num_tiles,
+ d_num_runs_out);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Return if empty problem
+ if (num_items == 0)
+ break;
+
+ // Get SM occupancy for reduce_by_key_kernel
+ int reduce_by_key_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ reduce_by_key_sm_occupancy, // out
+ reduce_by_key_kernel,
+ reduce_by_key_config.block_threads))) break;
+
+ // Get max x-dimension of grid
+ int max_dim_x;
+ if (CubDebug(error = cudaDeviceGetAttribute(&max_dim_x, cudaDevAttrMaxGridDimX, device_ordinal))) break;;
+
+ // Run grids in epochs (in case number of tiles exceeds max x-dimension
+ int scan_grid_size = CUB_MIN(num_tiles, max_dim_x);
+ for (int start_tile = 0; start_tile < num_tiles; start_tile += scan_grid_size)
+ {
+ // Log reduce_by_key_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking %d reduce_by_key_kernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ start_tile, scan_grid_size, reduce_by_key_config.block_threads, (long long) stream, reduce_by_key_config.items_per_thread, reduce_by_key_sm_occupancy);
+
+ // Invoke reduce_by_key_kernel
+ reduce_by_key_kernel<<<scan_grid_size, reduce_by_key_config.block_threads, 0, stream>>>(
+ d_keys_in,
+ d_unique_out,
+ d_values_in,
+ d_aggregates_out,
+ d_num_runs_out,
+ tile_state,
+ start_tile,
+ equality_op,
+ reduction_op,
+ num_items);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ /**
+ * Internal dispatch routine
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ KeysInputIteratorT d_keys_in, ///< [in] Pointer to the input sequence of keys
+ UniqueOutputIteratorT d_unique_out, ///< [out] Pointer to the output sequence of unique keys (one key per run)
+ ValuesInputIteratorT d_values_in, ///< [in] Pointer to the input sequence of corresponding values
+ AggregatesOutputIteratorT d_aggregates_out, ///< [out] Pointer to the output sequence of value aggregates (one aggregate per run)
+ NumRunsOutputIteratorT d_num_runs_out, ///< [out] Pointer to total number of runs encountered (i.e., the length of d_unique_out)
+ EqualityOpT equality_op, ///< [in] KeyT equality operator
+ ReductionOpT reduction_op, ///< [in] ValueT reduction operator
+ OffsetT num_items, ///< [in] Total number of items to select from
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel kernel dispatch configurations
+ KernelConfig reduce_by_key_config;
+ InitConfigs(ptx_version, reduce_by_key_config);
+
+ // Dispatch
+ if (CubDebug(error = Dispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_keys_in,
+ d_unique_out,
+ d_values_in,
+ d_aggregates_out,
+ d_num_runs_out,
+ equality_op,
+ reduction_op,
+ num_items,
+ stream,
+ debug_synchronous,
+ ptx_version,
+ DeviceCompactInitKernel<ScanTileStateT, NumRunsOutputIteratorT>,
+ DeviceReduceByKeyKernel<PtxReduceByKeyPolicy, KeysInputIteratorT, UniqueOutputIteratorT, ValuesInputIteratorT, AggregatesOutputIteratorT, NumRunsOutputIteratorT, ScanTileStateT, EqualityOpT, ReductionOpT, OffsetT>,
+ reduce_by_key_config))) break;
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_rle.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_rle.cuh
new file mode 100644
index 0000000..98c3681
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_rle.cuh
@@ -0,0 +1,538 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceRle provides device-wide, parallel operations for run-length-encoding sequences of data items residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "dispatch_scan.cuh"
+#include "../../agent/agent_rle.cuh"
+#include "../../thread/thread_operators.cuh"
+#include "../../grid/grid_queue.cuh"
+#include "../../util_device.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Kernel entry points
+ *****************************************************************************/
+
+/**
+ * Select kernel entry point (multi-block)
+ *
+ * Performs functor-based selection if SelectOp functor type != NullType
+ * Otherwise performs flag-based selection if FlagIterator's value type != NullType
+ * Otherwise performs discontinuity selection (keep unique)
+ */
+template <
+ typename AgentRlePolicyT, ///< Parameterized AgentRlePolicyT tuning policy type
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OffsetsOutputIteratorT, ///< Random-access output iterator type for writing run-offset values \iterator
+ typename LengthsOutputIteratorT, ///< Random-access output iterator type for writing run-length values \iterator
+ typename NumRunsOutputIteratorT, ///< Output iterator type for recording the number of runs encountered \iterator
+ typename ScanTileStateT, ///< Tile status interface type
+ typename EqualityOpT, ///< T equality operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int(AgentRlePolicyT::BLOCK_THREADS))
+__global__ void DeviceRleSweepKernel(
+ InputIteratorT d_in, ///< [in] Pointer to input sequence of data items
+ OffsetsOutputIteratorT d_offsets_out, ///< [out] Pointer to output sequence of run-offsets
+ LengthsOutputIteratorT d_lengths_out, ///< [out] Pointer to output sequence of run-lengths
+ NumRunsOutputIteratorT d_num_runs_out, ///< [out] Pointer to total number of runs (i.e., length of \p d_offsets_out)
+ ScanTileStateT tile_status, ///< [in] Tile status interface
+ EqualityOpT equality_op, ///< [in] Equality operator for input items
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ int num_tiles) ///< [in] Total number of tiles for the entire problem
+{
+ // Thread block type for selecting data from input tiles
+ typedef AgentRle<
+ AgentRlePolicyT,
+ InputIteratorT,
+ OffsetsOutputIteratorT,
+ LengthsOutputIteratorT,
+ EqualityOpT,
+ OffsetT> AgentRleT;
+
+ // Shared memory for AgentRle
+ __shared__ typename AgentRleT::TempStorage temp_storage;
+
+ // Process tiles
+ AgentRleT(temp_storage, d_in, d_offsets_out, d_lengths_out, equality_op, num_items).ConsumeRange(
+ num_tiles,
+ tile_status,
+ d_num_runs_out);
+}
+
+
+
+
+/******************************************************************************
+ * Dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for DeviceRle
+ */
+template <
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items \iterator
+ typename OffsetsOutputIteratorT, ///< Random-access output iterator type for writing run-offset values \iterator
+ typename LengthsOutputIteratorT, ///< Random-access output iterator type for writing run-length values \iterator
+ typename NumRunsOutputIteratorT, ///< Output iterator type for recording the number of runs encountered \iterator
+ typename EqualityOpT, ///< T equality operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DeviceRleDispatch
+{
+ /******************************************************************************
+ * Types and constants
+ ******************************************************************************/
+
+ // The input value type
+ typedef typename std::iterator_traits<InputIteratorT>::value_type T;
+
+ // The lengths output value type
+ typedef typename If<(Equals<typename std::iterator_traits<LengthsOutputIteratorT>::value_type, void>::VALUE), // LengthT = (if output iterator's value type is void) ?
+ OffsetT, // ... then the OffsetT type,
+ typename std::iterator_traits<LengthsOutputIteratorT>::value_type>::Type LengthT; // ... else the output iterator's value type
+
+ enum
+ {
+ INIT_KERNEL_THREADS = 128,
+ };
+
+ // Tile status descriptor interface type
+ typedef ReduceByKeyScanTileState<LengthT, OffsetT> ScanTileStateT;
+
+
+ /******************************************************************************
+ * Tuning policies
+ ******************************************************************************/
+
+ /// SM35
+ struct Policy350
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 15,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(T)))),
+ };
+
+ typedef AgentRlePolicy<
+ 96,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ true,
+ BLOCK_SCAN_WARP_SCANS>
+ RleSweepPolicy;
+ };
+
+ /// SM30
+ struct Policy300
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 5,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(T)))),
+ };
+
+ typedef AgentRlePolicy<
+ 256,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ true,
+ BLOCK_SCAN_RAKING_MEMOIZE>
+ RleSweepPolicy;
+ };
+
+ /// SM20
+ struct Policy200
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 15,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(T)))),
+ };
+
+ typedef AgentRlePolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ false,
+ BLOCK_SCAN_WARP_SCANS>
+ RleSweepPolicy;
+ };
+
+ /// SM13
+ struct Policy130
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 9,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(T)))),
+ };
+
+ typedef AgentRlePolicy<
+ 64,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ true,
+ BLOCK_SCAN_RAKING_MEMOIZE>
+ RleSweepPolicy;
+ };
+
+ /// SM10
+ struct Policy100
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 9,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(T)))),
+ };
+
+ typedef AgentRlePolicy<
+ 256,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ true,
+ BLOCK_SCAN_RAKING_MEMOIZE>
+ RleSweepPolicy;
+ };
+
+
+ /******************************************************************************
+ * Tuning policies of current PTX compiler pass
+ ******************************************************************************/
+
+#if (CUB_PTX_ARCH >= 350)
+ typedef Policy350 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 300)
+ typedef Policy300 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 200)
+ typedef Policy200 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 130)
+ typedef Policy130 PtxPolicy;
+
+#else
+ typedef Policy100 PtxPolicy;
+
+#endif
+
+ // "Opaque" policies (whose parameterizations aren't reflected in the type signature)
+ struct PtxRleSweepPolicy : PtxPolicy::RleSweepPolicy {};
+
+
+ /******************************************************************************
+ * Utilities
+ ******************************************************************************/
+
+ /**
+ * Initialize kernel dispatch configurations with the policies corresponding to the PTX assembly we will use
+ */
+ template <typename KernelConfig>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static void InitConfigs(
+ int ptx_version,
+ KernelConfig& device_rle_config)
+ {
+ #if (CUB_PTX_ARCH > 0)
+
+ // We're on the device, so initialize the kernel dispatch configurations with the current PTX policy
+ device_rle_config.template Init<PtxRleSweepPolicy>();
+
+ #else
+
+ // We're on the host, so lookup and initialize the kernel dispatch configurations with the policies that match the device's PTX version
+ if (ptx_version >= 350)
+ {
+ device_rle_config.template Init<typename Policy350::RleSweepPolicy>();
+ }
+ else if (ptx_version >= 300)
+ {
+ device_rle_config.template Init<typename Policy300::RleSweepPolicy>();
+ }
+ else if (ptx_version >= 200)
+ {
+ device_rle_config.template Init<typename Policy200::RleSweepPolicy>();
+ }
+ else if (ptx_version >= 130)
+ {
+ device_rle_config.template Init<typename Policy130::RleSweepPolicy>();
+ }
+ else
+ {
+ device_rle_config.template Init<typename Policy100::RleSweepPolicy>();
+ }
+
+ #endif
+ }
+
+
+ /**
+ * Kernel kernel dispatch configuration. Mirrors the constants within AgentRlePolicyT.
+ */
+ struct KernelConfig
+ {
+ int block_threads;
+ int items_per_thread;
+ BlockLoadAlgorithm load_policy;
+ bool store_warp_time_slicing;
+ BlockScanAlgorithm scan_algorithm;
+
+ template <typename AgentRlePolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ void Init()
+ {
+ block_threads = AgentRlePolicyT::BLOCK_THREADS;
+ items_per_thread = AgentRlePolicyT::ITEMS_PER_THREAD;
+ load_policy = AgentRlePolicyT::LOAD_ALGORITHM;
+ store_warp_time_slicing = AgentRlePolicyT::STORE_WARP_TIME_SLICING;
+ scan_algorithm = AgentRlePolicyT::SCAN_ALGORITHM;
+ }
+
+ CUB_RUNTIME_FUNCTION __forceinline__
+ void Print()
+ {
+ printf("%d, %d, %d, %d, %d",
+ block_threads,
+ items_per_thread,
+ load_policy,
+ store_warp_time_slicing,
+ scan_algorithm);
+ }
+ };
+
+
+ /******************************************************************************
+ * Dispatch entrypoints
+ ******************************************************************************/
+
+ /**
+ * Internal dispatch routine for computing a device-wide run-length-encode using the
+ * specified kernel functions.
+ */
+ template <
+ typename DeviceScanInitKernelPtr, ///< Function type of cub::DeviceScanInitKernel
+ typename DeviceRleSweepKernelPtr> ///< Function type of cub::DeviceRleSweepKernelPtr
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OffsetsOutputIteratorT d_offsets_out, ///< [out] Pointer to the output sequence of run-offsets
+ LengthsOutputIteratorT d_lengths_out, ///< [out] Pointer to the output sequence of run-lengths
+ NumRunsOutputIteratorT d_num_runs_out, ///< [out] Pointer to the total number of runs encountered (i.e., length of \p d_offsets_out)
+ EqualityOpT equality_op, ///< [in] Equality operator for input items
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int ptx_version, ///< [in] PTX version of dispatch kernels
+ DeviceScanInitKernelPtr device_scan_init_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceScanInitKernel
+ DeviceRleSweepKernelPtr device_rle_sweep_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceRleSweepKernel
+ KernelConfig device_rle_config) ///< [in] Dispatch parameters that match the policy that \p device_rle_sweep_kernel was compiled for
+ {
+
+#ifndef CUB_RUNTIME_ENABLED
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported);
+
+#else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Number of input tiles
+ int tile_size = device_rle_config.block_threads * device_rle_config.items_per_thread;
+ int num_tiles = (num_items + tile_size - 1) / tile_size;
+
+ // Specify temporary storage allocation requirements
+ size_t allocation_sizes[1];
+ if (CubDebug(error = ScanTileStateT::AllocationSize(num_tiles, allocation_sizes[0]))) break; // bytes needed for tile status descriptors
+
+ // Compute allocation pointers into the single storage blob (or compute the necessary size of the blob)
+ void* allocations[1];
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ break;
+ }
+
+ // Construct the tile status interface
+ ScanTileStateT tile_status;
+ if (CubDebug(error = tile_status.Init(num_tiles, allocations[0], allocation_sizes[0]))) break;
+
+ // Log device_scan_init_kernel configuration
+ int init_grid_size = CUB_MAX(1, (num_tiles + INIT_KERNEL_THREADS - 1) / INIT_KERNEL_THREADS);
+ if (debug_synchronous) _CubLog("Invoking device_scan_init_kernel<<<%d, %d, 0, %lld>>>()\n", init_grid_size, INIT_KERNEL_THREADS, (long long) stream);
+
+ // Invoke device_scan_init_kernel to initialize tile descriptors and queue descriptors
+ device_scan_init_kernel<<<init_grid_size, INIT_KERNEL_THREADS, 0, stream>>>(
+ tile_status,
+ num_tiles,
+ d_num_runs_out);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Return if empty problem
+ if (num_items == 0)
+ break;
+
+ // Get SM occupancy for device_rle_sweep_kernel
+ int device_rle_kernel_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ device_rle_kernel_sm_occupancy, // out
+ device_rle_sweep_kernel,
+ device_rle_config.block_threads))) break;
+
+ // Get max x-dimension of grid
+ int max_dim_x;
+ if (CubDebug(error = cudaDeviceGetAttribute(&max_dim_x, cudaDevAttrMaxGridDimX, device_ordinal))) break;;
+
+ // Get grid size for scanning tiles
+ dim3 scan_grid_size;
+ scan_grid_size.z = 1;
+ scan_grid_size.y = ((unsigned int) num_tiles + max_dim_x - 1) / max_dim_x;
+ scan_grid_size.x = CUB_MIN(num_tiles, max_dim_x);
+
+ // Log device_rle_sweep_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking device_rle_sweep_kernel<<<{%d,%d,%d}, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ scan_grid_size.x, scan_grid_size.y, scan_grid_size.z, device_rle_config.block_threads, (long long) stream, device_rle_config.items_per_thread, device_rle_kernel_sm_occupancy);
+
+ // Invoke device_rle_sweep_kernel
+ device_rle_sweep_kernel<<<scan_grid_size, device_rle_config.block_threads, 0, stream>>>(
+ d_in,
+ d_offsets_out,
+ d_lengths_out,
+ d_num_runs_out,
+ tile_status,
+ equality_op,
+ num_items,
+ num_tiles);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ /**
+ * Internal dispatch routine
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to input sequence of data items
+ OffsetsOutputIteratorT d_offsets_out, ///< [out] Pointer to output sequence of run-offsets
+ LengthsOutputIteratorT d_lengths_out, ///< [out] Pointer to output sequence of run-lengths
+ NumRunsOutputIteratorT d_num_runs_out, ///< [out] Pointer to total number of runs (i.e., length of \p d_offsets_out)
+ EqualityOpT equality_op, ///< [in] Equality operator for input items
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ cudaStream_t stream, ///< [in] <b>[optional]</b> CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] <b>[optional]</b> Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel kernel dispatch configurations
+ KernelConfig device_rle_config;
+ InitConfigs(ptx_version, device_rle_config);
+
+ // Dispatch
+ if (CubDebug(error = Dispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_in,
+ d_offsets_out,
+ d_lengths_out,
+ d_num_runs_out,
+ equality_op,
+ num_items,
+ stream,
+ debug_synchronous,
+ ptx_version,
+ DeviceCompactInitKernel<ScanTileStateT, NumRunsOutputIteratorT>,
+ DeviceRleSweepKernel<PtxRleSweepPolicy, InputIteratorT, OffsetsOutputIteratorT, LengthsOutputIteratorT, NumRunsOutputIteratorT, ScanTileStateT, EqualityOpT, OffsetT>,
+ device_rle_config))) break;
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_scan.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_scan.cuh
new file mode 100644
index 0000000..3ef720a
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_scan.cuh
@@ -0,0 +1,563 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceScan provides device-wide, parallel operations for computing a prefix scan across a sequence of data items residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "../../agent/agent_scan.cuh"
+#include "../../thread/thread_operators.cuh"
+#include "../../grid/grid_queue.cuh"
+#include "../../util_arch.cuh"
+#include "../../util_debug.cuh"
+#include "../../util_device.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Kernel entry points
+ *****************************************************************************/
+
+/**
+ * Initialization kernel for tile status initialization (multi-block)
+ */
+template <
+ typename ScanTileStateT> ///< Tile status interface type
+__global__ void DeviceScanInitKernel(
+ ScanTileStateT tile_state, ///< [in] Tile status interface
+ int num_tiles) ///< [in] Number of tiles
+{
+ // Initialize tile status
+ tile_state.InitializeStatus(num_tiles);
+}
+
+/**
+ * Initialization kernel for tile status initialization (multi-block)
+ */
+template <
+ typename ScanTileStateT, ///< Tile status interface type
+ typename NumSelectedIteratorT> ///< Output iterator type for recording the number of items selected
+__global__ void DeviceCompactInitKernel(
+ ScanTileStateT tile_state, ///< [in] Tile status interface
+ int num_tiles, ///< [in] Number of tiles
+ NumSelectedIteratorT d_num_selected_out) ///< [out] Pointer to the total number of items selected (i.e., length of \p d_selected_out)
+{
+ // Initialize tile status
+ tile_state.InitializeStatus(num_tiles);
+
+ // Initialize d_num_selected_out
+ if ((blockIdx.x == 0) && (threadIdx.x == 0))
+ *d_num_selected_out = 0;
+}
+
+
+/**
+ * Scan kernel entry point (multi-block)
+ */
+template <
+ typename ScanPolicyT, ///< Parameterized ScanPolicyT tuning policy type
+ typename InputIteratorT, ///< Random-access input iterator type for reading scan inputs \iterator
+ typename OutputIteratorT, ///< Random-access output iterator type for writing scan outputs \iterator
+ typename ScanTileStateT, ///< Tile status interface type
+ typename ScanOpT, ///< Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ typename InitValueT, ///< Initial value to seed the exclusive scan (cub::NullType for inclusive scans)
+ typename OffsetT> ///< Signed integer type for global offsets
+__launch_bounds__ (int(ScanPolicyT::BLOCK_THREADS))
+__global__ void DeviceScanKernel(
+ InputIteratorT d_in, ///< Input data
+ OutputIteratorT d_out, ///< Output data
+ ScanTileStateT tile_state, ///< Tile status interface
+ int start_tile, ///< The starting tile for the current grid
+ ScanOpT scan_op, ///< Binary scan functor
+ InitValueT init_value, ///< Initial value to seed the exclusive scan
+ OffsetT num_items) ///< Total number of scan items for the entire problem
+{
+ // Thread block type for scanning input tiles
+ typedef AgentScan<
+ ScanPolicyT,
+ InputIteratorT,
+ OutputIteratorT,
+ ScanOpT,
+ InitValueT,
+ OffsetT> AgentScanT;
+
+ // Shared memory for AgentScan
+ __shared__ typename AgentScanT::TempStorage temp_storage;
+
+ // Process tiles
+ AgentScanT(temp_storage, d_in, d_out, scan_op, init_value).ConsumeRange(
+ num_items,
+ tile_state,
+ start_tile);
+}
+
+
+
+
+/******************************************************************************
+ * Dispatch
+ ******************************************************************************/
+
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for DeviceScan
+ */
+template <
+ typename InputIteratorT, ///< Random-access input iterator type for reading scan inputs \iterator
+ typename OutputIteratorT, ///< Random-access output iterator type for writing scan outputs \iterator
+ typename ScanOpT, ///< Binary scan functor type having member <tt>T operator()(const T &a, const T &b)</tt>
+ typename InitValueT, ///< The init_value element type for ScanOpT (cub::NullType for inclusive scans)
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DispatchScan
+{
+ //---------------------------------------------------------------------
+ // Constants and Types
+ //---------------------------------------------------------------------
+
+ enum
+ {
+ INIT_KERNEL_THREADS = 128
+ };
+
+ // The output value type
+ typedef typename If<(Equals<typename std::iterator_traits<OutputIteratorT>::value_type, void>::VALUE), // OutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<InputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<OutputIteratorT>::value_type>::Type OutputT; // ... else the output iterator's value type
+
+ // Tile status descriptor interface type
+ typedef ScanTileState<OutputT> ScanTileStateT;
+
+
+ //---------------------------------------------------------------------
+ // Tuning policies
+ //---------------------------------------------------------------------
+
+ /// SM600
+ struct Policy600
+ {
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(128, 15, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_STORE_TRANSPOSE,
+ BLOCK_SCAN_WARP_SCANS>
+ ScanPolicyT;
+ };
+
+
+ /// SM520
+ struct Policy520
+ {
+ // Titan X: 32.47B items/s @ 48M 32-bit T
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(128, 12, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ BLOCK_STORE_WARP_TRANSPOSE,
+ BLOCK_SCAN_WARP_SCANS>
+ ScanPolicyT;
+ };
+
+
+ /// SM35
+ struct Policy350
+ {
+ // GTX Titan: 29.5B items/s (232.4 GB/s) @ 48M 32-bit T
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(128, 12, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ BLOCK_STORE_WARP_TRANSPOSE_TIMESLICED,
+ BLOCK_SCAN_RAKING>
+ ScanPolicyT;
+ };
+
+ /// SM30
+ struct Policy300
+ {
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(256, 9, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_STORE_WARP_TRANSPOSE,
+ BLOCK_SCAN_WARP_SCANS>
+ ScanPolicyT;
+ };
+
+ /// SM20
+ struct Policy200
+ {
+ // GTX 580: 20.3B items/s (162.3 GB/s) @ 48M 32-bit T
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(128, 12, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_STORE_WARP_TRANSPOSE,
+ BLOCK_SCAN_WARP_SCANS>
+ ScanPolicyT;
+ };
+
+ /// SM13
+ struct Policy130
+ {
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(96, 21, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_STORE_WARP_TRANSPOSE,
+ BLOCK_SCAN_RAKING_MEMOIZE>
+ ScanPolicyT;
+ };
+
+ /// SM10
+ struct Policy100
+ {
+ typedef AgentScanPolicy<
+ CUB_SCALED_GRANULARITIES(64, 9, OutputT), ///< Threads per block, items per thread
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_STORE_WARP_TRANSPOSE,
+ BLOCK_SCAN_WARP_SCANS>
+ ScanPolicyT;
+ };
+
+
+ //---------------------------------------------------------------------
+ // Tuning policies of current PTX compiler pass
+ //---------------------------------------------------------------------
+
+#if (CUB_PTX_ARCH >= 600)
+ typedef Policy600 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 520)
+ typedef Policy520 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 350)
+ typedef Policy350 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 300)
+ typedef Policy300 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 200)
+ typedef Policy200 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 130)
+ typedef Policy130 PtxPolicy;
+
+#else
+ typedef Policy100 PtxPolicy;
+
+#endif
+
+ // "Opaque" policies (whose parameterizations aren't reflected in the type signature)
+ struct PtxAgentScanPolicy : PtxPolicy::ScanPolicyT {};
+
+
+ //---------------------------------------------------------------------
+ // Utilities
+ //---------------------------------------------------------------------
+
+ /**
+ * Initialize kernel dispatch configurations with the policies corresponding to the PTX assembly we will use
+ */
+ template <typename KernelConfig>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static void InitConfigs(
+ int ptx_version,
+ KernelConfig &scan_kernel_config)
+ {
+ #if (CUB_PTX_ARCH > 0)
+ (void)ptx_version;
+
+ // We're on the device, so initialize the kernel dispatch configurations with the current PTX policy
+ scan_kernel_config.template Init<PtxAgentScanPolicy>();
+
+ #else
+
+ // We're on the host, so lookup and initialize the kernel dispatch configurations with the policies that match the device's PTX version
+ if (ptx_version >= 600)
+ {
+ scan_kernel_config.template Init<typename Policy600::ScanPolicyT>();
+ }
+ else if (ptx_version >= 520)
+ {
+ scan_kernel_config.template Init<typename Policy520::ScanPolicyT>();
+ }
+ else if (ptx_version >= 350)
+ {
+ scan_kernel_config.template Init<typename Policy350::ScanPolicyT>();
+ }
+ else if (ptx_version >= 300)
+ {
+ scan_kernel_config.template Init<typename Policy300::ScanPolicyT>();
+ }
+ else if (ptx_version >= 200)
+ {
+ scan_kernel_config.template Init<typename Policy200::ScanPolicyT>();
+ }
+ else if (ptx_version >= 130)
+ {
+ scan_kernel_config.template Init<typename Policy130::ScanPolicyT>();
+ }
+ else
+ {
+ scan_kernel_config.template Init<typename Policy100::ScanPolicyT>();
+ }
+
+ #endif
+ }
+
+
+ /**
+ * Kernel kernel dispatch configuration.
+ */
+ struct KernelConfig
+ {
+ int block_threads;
+ int items_per_thread;
+ int tile_items;
+
+ template <typename PolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ void Init()
+ {
+ block_threads = PolicyT::BLOCK_THREADS;
+ items_per_thread = PolicyT::ITEMS_PER_THREAD;
+ tile_items = block_threads * items_per_thread;
+ }
+ };
+
+
+ //---------------------------------------------------------------------
+ // Dispatch entrypoints
+ //---------------------------------------------------------------------
+
+ /**
+ * Internal dispatch routine for computing a device-wide prefix scan using the
+ * specified kernel functions.
+ */
+ template <
+ typename ScanInitKernelPtrT, ///< Function type of cub::DeviceScanInitKernel
+ typename ScanSweepKernelPtrT> ///< Function type of cub::DeviceScanKernelPtrT
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output sequence of data items
+ ScanOpT scan_op, ///< [in] Binary scan functor
+ InitValueT init_value, ///< [in] Initial value to seed the exclusive scan
+ OffsetT num_items, ///< [in] Total number of input items (i.e., the length of \p d_in)
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int /*ptx_version*/, ///< [in] PTX version of dispatch kernels
+ ScanInitKernelPtrT init_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceScanInitKernel
+ ScanSweepKernelPtrT scan_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceScanKernel
+ KernelConfig scan_kernel_config) ///< [in] Dispatch parameters that match the policy that \p scan_kernel was compiled for
+ {
+
+#ifndef CUB_RUNTIME_ENABLED
+ (void)d_temp_storage;
+ (void)temp_storage_bytes;
+ (void)d_in;
+ (void)d_out;
+ (void)scan_op;
+ (void)init_value;
+ (void)num_items;
+ (void)stream;
+ (void)debug_synchronous;
+ (void)init_kernel;
+ (void)scan_kernel;
+ (void)scan_kernel_config;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported);
+
+#else
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Number of input tiles
+ int tile_size = scan_kernel_config.block_threads * scan_kernel_config.items_per_thread;
+ int num_tiles = (num_items + tile_size - 1) / tile_size;
+
+ // Specify temporary storage allocation requirements
+ size_t allocation_sizes[1];
+ if (CubDebug(error = ScanTileStateT::AllocationSize(num_tiles, allocation_sizes[0]))) break; // bytes needed for tile status descriptors
+
+ // Compute allocation pointers into the single storage blob (or compute the necessary size of the blob)
+ void* allocations[1];
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ break;
+ }
+
+ // Return if empty problem
+ if (num_items == 0)
+ break;
+
+ // Construct the tile status interface
+ ScanTileStateT tile_state;
+ if (CubDebug(error = tile_state.Init(num_tiles, allocations[0], allocation_sizes[0]))) break;
+
+ // Log init_kernel configuration
+ int init_grid_size = (num_tiles + INIT_KERNEL_THREADS - 1) / INIT_KERNEL_THREADS;
+ if (debug_synchronous) _CubLog("Invoking init_kernel<<<%d, %d, 0, %lld>>>()\n", init_grid_size, INIT_KERNEL_THREADS, (long long) stream);
+
+ // Invoke init_kernel to initialize tile descriptors
+ init_kernel<<<init_grid_size, INIT_KERNEL_THREADS, 0, stream>>>(
+ tile_state,
+ num_tiles);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Get SM occupancy for scan_kernel
+ int scan_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ scan_sm_occupancy, // out
+ scan_kernel,
+ scan_kernel_config.block_threads))) break;
+
+ // Get max x-dimension of grid
+ int max_dim_x;
+ if (CubDebug(error = cudaDeviceGetAttribute(&max_dim_x, cudaDevAttrMaxGridDimX, device_ordinal))) break;;
+
+ // Run grids in epochs (in case number of tiles exceeds max x-dimension
+ int scan_grid_size = CUB_MIN(num_tiles, max_dim_x);
+ for (int start_tile = 0; start_tile < num_tiles; start_tile += scan_grid_size)
+ {
+ // Log scan_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking %d scan_kernel<<<%d, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ start_tile, scan_grid_size, scan_kernel_config.block_threads, (long long) stream, scan_kernel_config.items_per_thread, scan_sm_occupancy);
+
+ // Invoke scan_kernel
+ scan_kernel<<<scan_grid_size, scan_kernel_config.block_threads, 0, stream>>>(
+ d_in,
+ d_out,
+ tile_state,
+ start_tile,
+ scan_op,
+ init_value,
+ num_items);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ /**
+ * Internal dispatch routine
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ OutputIteratorT d_out, ///< [out] Pointer to the output sequence of data items
+ ScanOpT scan_op, ///< [in] Binary scan functor
+ InitValueT init_value, ///< [in] Initial value to seed the exclusive scan
+ OffsetT num_items, ///< [in] Total number of input items (i.e., the length of \p d_in)
+ cudaStream_t stream, ///< [in] <b>[optional]</b> CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] <b>[optional]</b> Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+
+ // Get kernel kernel dispatch configurations
+ KernelConfig scan_kernel_config;
+ InitConfigs(ptx_version, scan_kernel_config);
+
+ // Dispatch
+ if (CubDebug(error = Dispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_in,
+ d_out,
+ scan_op,
+ init_value,
+ num_items,
+ stream,
+ debug_synchronous,
+ ptx_version,
+ DeviceScanInitKernel<ScanTileStateT>,
+ DeviceScanKernel<PtxAgentScanPolicy, InputIteratorT, OutputIteratorT, ScanTileStateT, ScanOpT, InitValueT, OffsetT>,
+ scan_kernel_config))) break;
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_select_if.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_select_if.cuh
new file mode 100644
index 0000000..60b3313
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_select_if.cuh
@@ -0,0 +1,542 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceSelect provides device-wide, parallel operations for selecting items from sequences of data items residing within device-accessible memory.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "dispatch_scan.cuh"
+#include "../../agent/agent_select_if.cuh"
+#include "../../thread/thread_operators.cuh"
+#include "../../grid/grid_queue.cuh"
+#include "../../util_device.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/******************************************************************************
+ * Kernel entry points
+ *****************************************************************************/
+
+/**
+ * Select kernel entry point (multi-block)
+ *
+ * Performs functor-based selection if SelectOpT functor type != NullType
+ * Otherwise performs flag-based selection if FlagsInputIterator's value type != NullType
+ * Otherwise performs discontinuity selection (keep unique)
+ */
+template <
+ typename AgentSelectIfPolicyT, ///< Parameterized AgentSelectIfPolicyT tuning policy type
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items
+ typename FlagsInputIteratorT, ///< Random-access input iterator type for reading selection flags (NullType* if a selection functor or discontinuity flagging is to be used for selection)
+ typename SelectedOutputIteratorT, ///< Random-access output iterator type for writing selected items
+ typename NumSelectedIteratorT, ///< Output iterator type for recording the number of items selected
+ typename ScanTileStateT, ///< Tile status interface type
+ typename SelectOpT, ///< Selection operator type (NullType if selection flags or discontinuity flagging is to be used for selection)
+ typename EqualityOpT, ///< Equality operator type (NullType if selection functor or selection flags is to be used for selection)
+ typename OffsetT, ///< Signed integer type for global offsets
+ bool KEEP_REJECTS> ///< Whether or not we push rejected items to the back of the output
+__launch_bounds__ (int(AgentSelectIfPolicyT::BLOCK_THREADS))
+__global__ void DeviceSelectSweepKernel(
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ FlagsInputIteratorT d_flags, ///< [in] Pointer to the input sequence of selection flags (if applicable)
+ SelectedOutputIteratorT d_selected_out, ///< [out] Pointer to the output sequence of selected data items
+ NumSelectedIteratorT d_num_selected_out, ///< [out] Pointer to the total number of items selected (i.e., length of \p d_selected_out)
+ ScanTileStateT tile_status, ///< [in] Tile status interface
+ SelectOpT select_op, ///< [in] Selection operator
+ EqualityOpT equality_op, ///< [in] Equality operator
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ int num_tiles) ///< [in] Total number of tiles for the entire problem
+{
+ // Thread block type for selecting data from input tiles
+ typedef AgentSelectIf<
+ AgentSelectIfPolicyT,
+ InputIteratorT,
+ FlagsInputIteratorT,
+ SelectedOutputIteratorT,
+ SelectOpT,
+ EqualityOpT,
+ OffsetT,
+ KEEP_REJECTS> AgentSelectIfT;
+
+ // Shared memory for AgentSelectIf
+ __shared__ typename AgentSelectIfT::TempStorage temp_storage;
+
+ // Process tiles
+ AgentSelectIfT(temp_storage, d_in, d_flags, d_selected_out, select_op, equality_op, num_items).ConsumeRange(
+ num_tiles,
+ tile_status,
+ d_num_selected_out);
+}
+
+
+
+
+/******************************************************************************
+ * Dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for DeviceSelect
+ */
+template <
+ typename InputIteratorT, ///< Random-access input iterator type for reading input items
+ typename FlagsInputIteratorT, ///< Random-access input iterator type for reading selection flags (NullType* if a selection functor or discontinuity flagging is to be used for selection)
+ typename SelectedOutputIteratorT, ///< Random-access output iterator type for writing selected items
+ typename NumSelectedIteratorT, ///< Output iterator type for recording the number of items selected
+ typename SelectOpT, ///< Selection operator type (NullType if selection flags or discontinuity flagging is to be used for selection)
+ typename EqualityOpT, ///< Equality operator type (NullType if selection functor or selection flags is to be used for selection)
+ typename OffsetT, ///< Signed integer type for global offsets
+ bool KEEP_REJECTS> ///< Whether or not we push rejected items to the back of the output
+struct DispatchSelectIf
+{
+ /******************************************************************************
+ * Types and constants
+ ******************************************************************************/
+
+ // The output value type
+ typedef typename If<(Equals<typename std::iterator_traits<SelectedOutputIteratorT>::value_type, void>::VALUE), // OutputT = (if output iterator's value type is void) ?
+ typename std::iterator_traits<InputIteratorT>::value_type, // ... then the input iterator's value type,
+ typename std::iterator_traits<SelectedOutputIteratorT>::value_type>::Type OutputT; // ... else the output iterator's value type
+
+ // The flag value type
+ typedef typename std::iterator_traits<FlagsInputIteratorT>::value_type FlagT;
+
+ enum
+ {
+ INIT_KERNEL_THREADS = 128,
+ };
+
+ // Tile status descriptor interface type
+ typedef ScanTileState<OffsetT> ScanTileStateT;
+
+
+ /******************************************************************************
+ * Tuning policies
+ ******************************************************************************/
+
+ /// SM35
+ struct Policy350
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 10,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(OutputT)))),
+ };
+
+ typedef AgentSelectIfPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ BLOCK_SCAN_WARP_SCANS>
+ SelectIfPolicyT;
+ };
+
+ /// SM30
+ struct Policy300
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 7,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(3, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(OutputT)))),
+ };
+
+ typedef AgentSelectIfPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ SelectIfPolicyT;
+ };
+
+ /// SM20
+ struct Policy200
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = (KEEP_REJECTS) ? 7 : 15,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(OutputT)))),
+ };
+
+ typedef AgentSelectIfPolicy<
+ 128,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ SelectIfPolicyT;
+ };
+
+ /// SM13
+ struct Policy130
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 9,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(OutputT)))),
+ };
+
+ typedef AgentSelectIfPolicy<
+ 64,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_RAKING_MEMOIZE>
+ SelectIfPolicyT;
+ };
+
+ /// SM10
+ struct Policy100
+ {
+ enum {
+ NOMINAL_4B_ITEMS_PER_THREAD = 9,
+ ITEMS_PER_THREAD = CUB_MIN(NOMINAL_4B_ITEMS_PER_THREAD, CUB_MAX(1, (NOMINAL_4B_ITEMS_PER_THREAD * 4 / sizeof(OutputT)))),
+ };
+
+ typedef AgentSelectIfPolicy<
+ 64,
+ ITEMS_PER_THREAD,
+ BLOCK_LOAD_WARP_TRANSPOSE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_RAKING>
+ SelectIfPolicyT;
+ };
+
+
+ /******************************************************************************
+ * Tuning policies of current PTX compiler pass
+ ******************************************************************************/
+
+#if (CUB_PTX_ARCH >= 350)
+ typedef Policy350 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 300)
+ typedef Policy300 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 200)
+ typedef Policy200 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 130)
+ typedef Policy130 PtxPolicy;
+
+#else
+ typedef Policy100 PtxPolicy;
+
+#endif
+
+ // "Opaque" policies (whose parameterizations aren't reflected in the type signature)
+ struct PtxSelectIfPolicyT : PtxPolicy::SelectIfPolicyT {};
+
+
+ /******************************************************************************
+ * Utilities
+ ******************************************************************************/
+
+ /**
+ * Initialize kernel dispatch configurations with the policies corresponding to the PTX assembly we will use
+ */
+ template <typename KernelConfig>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static void InitConfigs(
+ int ptx_version,
+ KernelConfig &select_if_config)
+ {
+ #if (CUB_PTX_ARCH > 0)
+ (void)ptx_version;
+
+ // We're on the device, so initialize the kernel dispatch configurations with the current PTX policy
+ select_if_config.template Init<PtxSelectIfPolicyT>();
+
+ #else
+
+ // We're on the host, so lookup and initialize the kernel dispatch configurations with the policies that match the device's PTX version
+ if (ptx_version >= 350)
+ {
+ select_if_config.template Init<typename Policy350::SelectIfPolicyT>();
+ }
+ else if (ptx_version >= 300)
+ {
+ select_if_config.template Init<typename Policy300::SelectIfPolicyT>();
+ }
+ else if (ptx_version >= 200)
+ {
+ select_if_config.template Init<typename Policy200::SelectIfPolicyT>();
+ }
+ else if (ptx_version >= 130)
+ {
+ select_if_config.template Init<typename Policy130::SelectIfPolicyT>();
+ }
+ else
+ {
+ select_if_config.template Init<typename Policy100::SelectIfPolicyT>();
+ }
+
+ #endif
+ }
+
+
+ /**
+ * Kernel kernel dispatch configuration.
+ */
+ struct KernelConfig
+ {
+ int block_threads;
+ int items_per_thread;
+ int tile_items;
+
+ template <typename PolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ void Init()
+ {
+ block_threads = PolicyT::BLOCK_THREADS;
+ items_per_thread = PolicyT::ITEMS_PER_THREAD;
+ tile_items = block_threads * items_per_thread;
+ }
+ };
+
+
+ /******************************************************************************
+ * Dispatch entrypoints
+ ******************************************************************************/
+
+ /**
+ * Internal dispatch routine for computing a device-wide selection using the
+ * specified kernel functions.
+ */
+ template <
+ typename ScanInitKernelPtrT, ///< Function type of cub::DeviceScanInitKernel
+ typename SelectIfKernelPtrT> ///< Function type of cub::SelectIfKernelPtrT
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ FlagsInputIteratorT d_flags, ///< [in] Pointer to the input sequence of selection flags (if applicable)
+ SelectedOutputIteratorT d_selected_out, ///< [in] Pointer to the output sequence of selected data items
+ NumSelectedIteratorT d_num_selected_out, ///< [in] Pointer to the total number of items selected (i.e., length of \p d_selected_out)
+ SelectOpT select_op, ///< [in] Selection operator
+ EqualityOpT equality_op, ///< [in] Equality operator
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ int /*ptx_version*/, ///< [in] PTX version of dispatch kernels
+ ScanInitKernelPtrT scan_init_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceScanInitKernel
+ SelectIfKernelPtrT select_if_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceSelectSweepKernel
+ KernelConfig select_if_config) ///< [in] Dispatch parameters that match the policy that \p select_if_kernel was compiled for
+ {
+
+#ifndef CUB_RUNTIME_ENABLED
+ (void)d_temp_storage;
+ (void)temp_storage_bytes;
+ (void)d_in;
+ (void)d_flags;
+ (void)d_selected_out;
+ (void)d_num_selected_out;
+ (void)select_op;
+ (void)equality_op;
+ (void)num_items;
+ (void)stream;
+ (void)debug_synchronous;
+ (void)scan_init_kernel;
+ (void)select_if_kernel;
+ (void)select_if_config;
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported);
+
+#else
+
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Number of input tiles
+ int tile_size = select_if_config.block_threads * select_if_config.items_per_thread;
+ int num_tiles = (num_items + tile_size - 1) / tile_size;
+
+ // Specify temporary storage allocation requirements
+ size_t allocation_sizes[1];
+ if (CubDebug(error = ScanTileStateT::AllocationSize(num_tiles, allocation_sizes[0]))) break; // bytes needed for tile status descriptors
+
+ // Compute allocation pointers into the single storage blob (or compute the necessary size of the blob)
+ void* allocations[1];
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ break;
+ }
+
+ // Construct the tile status interface
+ ScanTileStateT tile_status;
+ if (CubDebug(error = tile_status.Init(num_tiles, allocations[0], allocation_sizes[0]))) break;
+
+ // Log scan_init_kernel configuration
+ int init_grid_size = CUB_MAX(1, (num_tiles + INIT_KERNEL_THREADS - 1) / INIT_KERNEL_THREADS);
+ if (debug_synchronous) _CubLog("Invoking scan_init_kernel<<<%d, %d, 0, %lld>>>()\n", init_grid_size, INIT_KERNEL_THREADS, (long long) stream);
+
+ // Invoke scan_init_kernel to initialize tile descriptors
+ scan_init_kernel<<<init_grid_size, INIT_KERNEL_THREADS, 0, stream>>>(
+ tile_status,
+ num_tiles,
+ d_num_selected_out);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Return if empty problem
+ if (num_items == 0)
+ break;
+
+ // Get SM occupancy for select_if_kernel
+ int range_select_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ range_select_sm_occupancy, // out
+ select_if_kernel,
+ select_if_config.block_threads))) break;
+
+ // Get max x-dimension of grid
+ int max_dim_x;
+ if (CubDebug(error = cudaDeviceGetAttribute(&max_dim_x, cudaDevAttrMaxGridDimX, device_ordinal))) break;;
+
+ // Get grid size for scanning tiles
+ dim3 scan_grid_size;
+ scan_grid_size.z = 1;
+ scan_grid_size.y = ((unsigned int) num_tiles + max_dim_x - 1) / max_dim_x;
+ scan_grid_size.x = CUB_MIN(num_tiles, max_dim_x);
+
+ // Log select_if_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking select_if_kernel<<<{%d,%d,%d}, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ scan_grid_size.x, scan_grid_size.y, scan_grid_size.z, select_if_config.block_threads, (long long) stream, select_if_config.items_per_thread, range_select_sm_occupancy);
+
+ // Invoke select_if_kernel
+ select_if_kernel<<<scan_grid_size, select_if_config.block_threads, 0, stream>>>(
+ d_in,
+ d_flags,
+ d_selected_out,
+ d_num_selected_out,
+ tile_status,
+ select_op,
+ equality_op,
+ num_items,
+ num_tiles);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ /**
+ * Internal dispatch routine
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ InputIteratorT d_in, ///< [in] Pointer to the input sequence of data items
+ FlagsInputIteratorT d_flags, ///< [in] Pointer to the input sequence of selection flags (if applicable)
+ SelectedOutputIteratorT d_selected_out, ///< [in] Pointer to the output sequence of selected data items
+ NumSelectedIteratorT d_num_selected_out, ///< [in] Pointer to the total number of items selected (i.e., length of \p d_selected_out)
+ SelectOpT select_op, ///< [in] Selection operator
+ EqualityOpT equality_op, ///< [in] Equality operator
+ OffsetT num_items, ///< [in] Total number of input items (i.e., length of \p d_in)
+ cudaStream_t stream, ///< [in] <b>[optional]</b> CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous) ///< [in] <b>[optional]</b> Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel kernel dispatch configurations
+ KernelConfig select_if_config;
+ InitConfigs(ptx_version, select_if_config);
+
+ // Dispatch
+ if (CubDebug(error = Dispatch(
+ d_temp_storage,
+ temp_storage_bytes,
+ d_in,
+ d_flags,
+ d_selected_out,
+ d_num_selected_out,
+ select_op,
+ equality_op,
+ num_items,
+ stream,
+ debug_synchronous,
+ ptx_version,
+ DeviceCompactInitKernel<ScanTileStateT, NumSelectedIteratorT>,
+ DeviceSelectSweepKernel<PtxSelectIfPolicyT, InputIteratorT, FlagsInputIteratorT, SelectedOutputIteratorT, NumSelectedIteratorT, ScanTileStateT, SelectOpT, EqualityOpT, OffsetT, KEEP_REJECTS>,
+ select_if_config))) break;
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_spmv_orig.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_spmv_orig.cuh
new file mode 100644
index 0000000..ab9c534
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/device/dispatch/dispatch_spmv_orig.cuh
@@ -0,0 +1,834 @@
+
+/******************************************************************************
+ * Copyright (c) 2011, Duane Merrill. All rights reserved.
+ * Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the NVIDIA CORPORATION nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+
+/**
+ * \file
+ * cub::DeviceSpmv provides device-wide parallel operations for performing sparse-matrix * vector multiplication (SpMV).
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <iterator>
+
+#include "../../agent/single_pass_scan_operators.cuh"
+#include "../../agent/agent_segment_fixup.cuh"
+#include "../../agent/agent_spmv_orig.cuh"
+#include "../../util_type.cuh"
+#include "../../util_debug.cuh"
+#include "../../util_device.cuh"
+#include "../../thread/thread_search.cuh"
+#include "../../grid/grid_queue.cuh"
+#include "../../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * SpMV kernel entry points
+ *****************************************************************************/
+
+/**
+ * Spmv search kernel. Identifies merge path starting coordinates for each tile.
+ */
+template <
+ typename AgentSpmvPolicyT, ///< Parameterized SpmvPolicy tuning policy type
+ typename ValueT, ///< Matrix and vector value type
+ typename OffsetT> ///< Signed integer type for sequence offsets
+__global__ void DeviceSpmv1ColKernel(
+ SpmvParams<ValueT, OffsetT> spmv_params) ///< [in] SpMV input parameter bundle
+{
+ typedef CacheModifiedInputIterator<
+ AgentSpmvPolicyT::VECTOR_VALUES_LOAD_MODIFIER,
+ ValueT,
+ OffsetT>
+ VectorValueIteratorT;
+
+ VectorValueIteratorT wrapped_vector_x(spmv_params.d_vector_x);
+
+ int row_idx = (blockIdx.x * blockDim.x) + threadIdx.x;
+ if (row_idx < spmv_params.num_rows)
+ {
+ OffsetT end_nonzero_idx = spmv_params.d_row_end_offsets[row_idx];
+ OffsetT nonzero_idx = spmv_params.d_row_end_offsets[row_idx - 1];
+
+ ValueT value = 0.0;
+ if (end_nonzero_idx != nonzero_idx)
+ {
+ value = spmv_params.d_values[nonzero_idx] * wrapped_vector_x[spmv_params.d_column_indices[nonzero_idx]];
+ }
+
+ spmv_params.d_vector_y[row_idx] = value;
+ }
+}
+
+
+/**
+ * Spmv search kernel. Identifies merge path starting coordinates for each tile.
+ */
+template <
+ typename SpmvPolicyT, ///< Parameterized SpmvPolicy tuning policy type
+ typename OffsetT, ///< Signed integer type for sequence offsets
+ typename CoordinateT, ///< Merge path coordinate type
+ typename SpmvParamsT> ///< SpmvParams type
+__global__ void DeviceSpmvSearchKernel(
+ int num_merge_tiles, ///< [in] Number of SpMV merge tiles (spmv grid size)
+ CoordinateT* d_tile_coordinates, ///< [out] Pointer to the temporary array of tile starting coordinates
+ SpmvParamsT spmv_params) ///< [in] SpMV input parameter bundle
+{
+ /// Constants
+ enum
+ {
+ BLOCK_THREADS = SpmvPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = SpmvPolicyT::ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ };
+
+ typedef CacheModifiedInputIterator<
+ SpmvPolicyT::ROW_OFFSETS_SEARCH_LOAD_MODIFIER,
+ OffsetT,
+ OffsetT>
+ RowOffsetsSearchIteratorT;
+
+ // Find the starting coordinate for all tiles (plus the end coordinate of the last one)
+ int tile_idx = (blockIdx.x * blockDim.x) + threadIdx.x;
+ if (tile_idx < num_merge_tiles + 1)
+ {
+ OffsetT diagonal = (tile_idx * TILE_ITEMS);
+ CoordinateT tile_coordinate;
+ CountingInputIterator<OffsetT> nonzero_indices(0);
+
+ // Search the merge path
+ MergePathSearch(
+ diagonal,
+ RowOffsetsSearchIteratorT(spmv_params.d_row_end_offsets),
+ nonzero_indices,
+ spmv_params.num_rows,
+ spmv_params.num_nonzeros,
+ tile_coordinate);
+
+ // Output starting offset
+ d_tile_coordinates[tile_idx] = tile_coordinate;
+ }
+}
+
+
+/**
+ * Spmv agent entry point
+ */
+template <
+ typename SpmvPolicyT, ///< Parameterized SpmvPolicy tuning policy type
+ typename ScanTileStateT, ///< Tile status interface type
+ typename ValueT, ///< Matrix and vector value type
+ typename OffsetT, ///< Signed integer type for sequence offsets
+ typename CoordinateT, ///< Merge path coordinate type
+ bool HAS_ALPHA, ///< Whether the input parameter Alpha is 1
+ bool HAS_BETA> ///< Whether the input parameter Beta is 0
+__launch_bounds__ (int(SpmvPolicyT::BLOCK_THREADS))
+__global__ void DeviceSpmvKernel(
+ SpmvParams<ValueT, OffsetT> spmv_params, ///< [in] SpMV input parameter bundle
+ CoordinateT* d_tile_coordinates, ///< [in] Pointer to the temporary array of tile starting coordinates
+ KeyValuePair<OffsetT,ValueT>* d_tile_carry_pairs, ///< [out] Pointer to the temporary array carry-out dot product row-ids, one per block
+ int num_tiles, ///< [in] Number of merge tiles
+ ScanTileStateT tile_state, ///< [in] Tile status interface for fixup reduce-by-key kernel
+ int num_segment_fixup_tiles) ///< [in] Number of reduce-by-key tiles (fixup grid size)
+{
+ // Spmv agent type specialization
+ typedef AgentSpmv<
+ SpmvPolicyT,
+ ValueT,
+ OffsetT,
+ HAS_ALPHA,
+ HAS_BETA>
+ AgentSpmvT;
+
+ // Shared memory for AgentSpmv
+ __shared__ typename AgentSpmvT::TempStorage temp_storage;
+
+ AgentSpmvT(temp_storage, spmv_params).ConsumeTile(
+ d_tile_coordinates,
+ d_tile_carry_pairs,
+ num_tiles);
+
+ // Initialize fixup tile status
+ tile_state.InitializeStatus(num_segment_fixup_tiles);
+
+}
+
+
+/**
+ * Multi-block reduce-by-key sweep kernel entry point
+ */
+template <
+ typename AgentSegmentFixupPolicyT, ///< Parameterized AgentSegmentFixupPolicy tuning policy type
+ typename PairsInputIteratorT, ///< Random-access input iterator type for keys
+ typename AggregatesOutputIteratorT, ///< Random-access output iterator type for values
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ScanTileStateT> ///< Tile status interface type
+__launch_bounds__ (int(AgentSegmentFixupPolicyT::BLOCK_THREADS))
+__global__ void DeviceSegmentFixupKernel(
+ PairsInputIteratorT d_pairs_in, ///< [in] Pointer to the array carry-out dot product row-ids, one per spmv block
+ AggregatesOutputIteratorT d_aggregates_out, ///< [in,out] Output value aggregates
+ OffsetT num_items, ///< [in] Total number of items to select from
+ int num_tiles, ///< [in] Total number of tiles for the entire problem
+ ScanTileStateT tile_state) ///< [in] Tile status interface
+{
+ // Thread block type for reducing tiles of value segments
+ typedef AgentSegmentFixup<
+ AgentSegmentFixupPolicyT,
+ PairsInputIteratorT,
+ AggregatesOutputIteratorT,
+ cub::Equality,
+ cub::Sum,
+ OffsetT>
+ AgentSegmentFixupT;
+
+ // Shared memory for AgentSegmentFixup
+ __shared__ typename AgentSegmentFixupT::TempStorage temp_storage;
+
+ // Process tiles
+ AgentSegmentFixupT(temp_storage, d_pairs_in, d_aggregates_out, cub::Equality(), cub::Sum()).ConsumeRange(
+ num_items,
+ num_tiles,
+ tile_state);
+}
+
+
+/******************************************************************************
+ * Dispatch
+ ******************************************************************************/
+
+/**
+ * Utility class for dispatching the appropriately-tuned kernels for DeviceSpmv
+ */
+template <
+ typename ValueT, ///< Matrix and vector value type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct DispatchSpmv
+{
+ //---------------------------------------------------------------------
+ // Constants and Types
+ //---------------------------------------------------------------------
+
+ enum
+ {
+ INIT_KERNEL_THREADS = 128
+ };
+
+ // SpmvParams bundle type
+ typedef SpmvParams<ValueT, OffsetT> SpmvParamsT;
+
+ // 2D merge path coordinate type
+ typedef typename CubVector<OffsetT, 2>::Type CoordinateT;
+
+ // Tile status descriptor interface type
+ typedef ReduceByKeyScanTileState<ValueT, OffsetT> ScanTileStateT;
+
+ // Tuple type for scanning (pairs accumulated segment-value with segment-index)
+ typedef KeyValuePair<OffsetT, ValueT> KeyValuePairT;
+
+
+ //---------------------------------------------------------------------
+ // Tuning policies
+ //---------------------------------------------------------------------
+
+ /// SM11
+ struct Policy110
+ {
+ typedef AgentSpmvPolicy<
+ 128,
+ 1,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ false,
+ BLOCK_SCAN_WARP_SCANS>
+ SpmvPolicyT;
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 4,
+ BLOCK_LOAD_VECTORIZE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ SegmentFixupPolicyT;
+ };
+
+ /// SM20
+ struct Policy200
+ {
+ typedef AgentSpmvPolicy<
+ 96,
+ 18,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ false,
+ BLOCK_SCAN_RAKING>
+ SpmvPolicyT;
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 4,
+ BLOCK_LOAD_VECTORIZE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ SegmentFixupPolicyT;
+
+ };
+
+
+
+ /// SM30
+ struct Policy300
+ {
+ typedef AgentSpmvPolicy<
+ 96,
+ 6,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ false,
+ BLOCK_SCAN_WARP_SCANS>
+ SpmvPolicyT;
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 4,
+ BLOCK_LOAD_VECTORIZE,
+ LOAD_DEFAULT,
+ BLOCK_SCAN_WARP_SCANS>
+ SegmentFixupPolicyT;
+
+ };
+
+
+ /// SM35
+ struct Policy350
+ {
+ typedef AgentSpmvPolicy<
+ (sizeof(ValueT) > 4) ? 96 : 128,
+ (sizeof(ValueT) > 4) ? 4 : 7,
+ LOAD_LDG,
+ LOAD_CA,
+ LOAD_LDG,
+ LOAD_LDG,
+ LOAD_LDG,
+ (sizeof(ValueT) > 4) ? true : false,
+ BLOCK_SCAN_WARP_SCANS>
+ SpmvPolicyT;
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 3,
+ BLOCK_LOAD_VECTORIZE,
+ LOAD_LDG,
+ BLOCK_SCAN_WARP_SCANS>
+ SegmentFixupPolicyT;
+ };
+
+
+ /// SM37
+ struct Policy370
+ {
+
+ typedef AgentSpmvPolicy<
+ (sizeof(ValueT) > 4) ? 128 : 128,
+ (sizeof(ValueT) > 4) ? 9 : 14,
+ LOAD_LDG,
+ LOAD_CA,
+ LOAD_LDG,
+ LOAD_LDG,
+ LOAD_LDG,
+ false,
+ BLOCK_SCAN_WARP_SCANS>
+ SpmvPolicyT;
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 3,
+ BLOCK_LOAD_VECTORIZE,
+ LOAD_LDG,
+ BLOCK_SCAN_WARP_SCANS>
+ SegmentFixupPolicyT;
+ };
+
+ /// SM50
+ struct Policy500
+ {
+ typedef AgentSpmvPolicy<
+ (sizeof(ValueT) > 4) ? 64 : 128,
+ (sizeof(ValueT) > 4) ? 6 : 7,
+ LOAD_LDG,
+ LOAD_DEFAULT,
+ (sizeof(ValueT) > 4) ? LOAD_LDG : LOAD_DEFAULT,
+ (sizeof(ValueT) > 4) ? LOAD_LDG : LOAD_DEFAULT,
+ LOAD_LDG,
+ (sizeof(ValueT) > 4) ? true : false,
+ (sizeof(ValueT) > 4) ? BLOCK_SCAN_WARP_SCANS : BLOCK_SCAN_RAKING_MEMOIZE>
+ SpmvPolicyT;
+
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 3,
+ BLOCK_LOAD_VECTORIZE,
+ LOAD_LDG,
+ BLOCK_SCAN_RAKING_MEMOIZE>
+ SegmentFixupPolicyT;
+ };
+
+
+ /// SM60
+ struct Policy600
+ {
+ typedef AgentSpmvPolicy<
+ (sizeof(ValueT) > 4) ? 64 : 128,
+ (sizeof(ValueT) > 4) ? 5 : 7,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ LOAD_DEFAULT,
+ false,
+ BLOCK_SCAN_WARP_SCANS>
+ SpmvPolicyT;
+
+
+ typedef AgentSegmentFixupPolicy<
+ 128,
+ 3,
+ BLOCK_LOAD_DIRECT,
+ LOAD_LDG,
+ BLOCK_SCAN_WARP_SCANS>
+ SegmentFixupPolicyT;
+ };
+
+
+
+ //---------------------------------------------------------------------
+ // Tuning policies of current PTX compiler pass
+ //---------------------------------------------------------------------
+
+#if (CUB_PTX_ARCH >= 600)
+ typedef Policy600 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 500)
+ typedef Policy500 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 370)
+ typedef Policy370 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 350)
+ typedef Policy350 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 300)
+ typedef Policy300 PtxPolicy;
+
+#elif (CUB_PTX_ARCH >= 200)
+ typedef Policy200 PtxPolicy;
+
+#else
+ typedef Policy110 PtxPolicy;
+
+#endif
+
+ // "Opaque" policies (whose parameterizations aren't reflected in the type signature)
+ struct PtxSpmvPolicyT : PtxPolicy::SpmvPolicyT {};
+ struct PtxSegmentFixupPolicy : PtxPolicy::SegmentFixupPolicyT {};
+
+
+ //---------------------------------------------------------------------
+ // Utilities
+ //---------------------------------------------------------------------
+
+ /**
+ * Initialize kernel dispatch configurations with the policies corresponding to the PTX assembly we will use
+ */
+ template <typename KernelConfig>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static void InitConfigs(
+ int ptx_version,
+ KernelConfig &spmv_config,
+ KernelConfig &segment_fixup_config)
+ {
+ #if (CUB_PTX_ARCH > 0)
+
+ // We're on the device, so initialize the kernel dispatch configurations with the current PTX policy
+ spmv_config.template Init<PtxSpmvPolicyT>();
+ segment_fixup_config.template Init<PtxSegmentFixupPolicy>();
+
+ #else
+
+ // We're on the host, so lookup and initialize the kernel dispatch configurations with the policies that match the device's PTX version
+ if (ptx_version >= 600)
+ {
+ spmv_config.template Init<typename Policy600::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy600::SegmentFixupPolicyT>();
+ }
+ else if (ptx_version >= 500)
+ {
+ spmv_config.template Init<typename Policy500::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy500::SegmentFixupPolicyT>();
+ }
+ else if (ptx_version >= 370)
+ {
+ spmv_config.template Init<typename Policy370::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy370::SegmentFixupPolicyT>();
+ }
+ else if (ptx_version >= 350)
+ {
+ spmv_config.template Init<typename Policy350::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy350::SegmentFixupPolicyT>();
+ }
+ else if (ptx_version >= 300)
+ {
+ spmv_config.template Init<typename Policy300::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy300::SegmentFixupPolicyT>();
+
+ }
+ else if (ptx_version >= 200)
+ {
+ spmv_config.template Init<typename Policy200::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy200::SegmentFixupPolicyT>();
+ }
+ else
+ {
+ spmv_config.template Init<typename Policy110::SpmvPolicyT>();
+ segment_fixup_config.template Init<typename Policy110::SegmentFixupPolicyT>();
+ }
+
+ #endif
+ }
+
+
+ /**
+ * Kernel kernel dispatch configuration.
+ */
+ struct KernelConfig
+ {
+ int block_threads;
+ int items_per_thread;
+ int tile_items;
+
+ template <typename PolicyT>
+ CUB_RUNTIME_FUNCTION __forceinline__
+ void Init()
+ {
+ block_threads = PolicyT::BLOCK_THREADS;
+ items_per_thread = PolicyT::ITEMS_PER_THREAD;
+ tile_items = block_threads * items_per_thread;
+ }
+ };
+
+
+ //---------------------------------------------------------------------
+ // Dispatch entrypoints
+ //---------------------------------------------------------------------
+
+ /**
+ * Internal dispatch routine for computing a device-wide reduction using the
+ * specified kernel functions.
+ *
+ * If the input is larger than a single tile, this method uses two-passes of
+ * kernel invocations.
+ */
+ template <
+ typename Spmv1ColKernelT, ///< Function type of cub::DeviceSpmv1ColKernel
+ typename SpmvSearchKernelT, ///< Function type of cub::AgentSpmvSearchKernel
+ typename SpmvKernelT, ///< Function type of cub::AgentSpmvKernel
+ typename SegmentFixupKernelT> ///< Function type of cub::DeviceSegmentFixupKernelT
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SpmvParamsT& spmv_params, ///< SpMV input parameter bundle
+ cudaStream_t stream, ///< [in] CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous, ///< [in] Whether or not to synchronize the stream after every kernel launch to check for errors. Also causes launch configurations to be printed to the console. Default is \p false.
+ Spmv1ColKernelT spmv_1col_kernel, ///< [in] Kernel function pointer to parameterization of DeviceSpmv1ColKernel
+ SpmvSearchKernelT spmv_search_kernel, ///< [in] Kernel function pointer to parameterization of AgentSpmvSearchKernel
+ SpmvKernelT spmv_kernel, ///< [in] Kernel function pointer to parameterization of AgentSpmvKernel
+ SegmentFixupKernelT segment_fixup_kernel, ///< [in] Kernel function pointer to parameterization of cub::DeviceSegmentFixupKernel
+ KernelConfig spmv_config, ///< [in] Dispatch parameters that match the policy that \p spmv_kernel was compiled for
+ KernelConfig segment_fixup_config) ///< [in] Dispatch parameters that match the policy that \p segment_fixup_kernel was compiled for
+ {
+#ifndef CUB_RUNTIME_ENABLED
+
+ // Kernel launch not supported from this device
+ return CubDebug(cudaErrorNotSupported );
+
+#else
+ cudaError error = cudaSuccess;
+ do
+ {
+ if (spmv_params.num_cols == 1)
+ {
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ temp_storage_bytes = 1;
+ break;
+ }
+
+ // Get search/init grid dims
+ int degen_col_kernel_block_size = INIT_KERNEL_THREADS;
+ int degen_col_kernel_grid_size = (spmv_params.num_rows + degen_col_kernel_block_size - 1) / degen_col_kernel_block_size;
+
+ if (debug_synchronous) _CubLog("Invoking spmv_1col_kernel<<<%d, %d, 0, %lld>>>()\n",
+ degen_col_kernel_grid_size, degen_col_kernel_block_size, (long long) stream);
+
+ // Invoke spmv_search_kernel
+ spmv_1col_kernel<<<degen_col_kernel_grid_size, degen_col_kernel_block_size, 0, stream>>>(
+ spmv_params);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ break;
+ }
+
+ // Get device ordinal
+ int device_ordinal;
+ if (CubDebug(error = cudaGetDevice(&device_ordinal))) break;
+
+ // Get SM count
+ int sm_count;
+ if (CubDebug(error = cudaDeviceGetAttribute (&sm_count, cudaDevAttrMultiProcessorCount, device_ordinal))) break;
+
+ // Get max x-dimension of grid
+ int max_dim_x;
+ if (CubDebug(error = cudaDeviceGetAttribute(&max_dim_x, cudaDevAttrMaxGridDimX, device_ordinal))) break;;
+
+ // Total number of spmv work items
+ int num_merge_items = spmv_params.num_rows + spmv_params.num_nonzeros;
+
+ // Tile sizes of kernels
+ int merge_tile_size = spmv_config.block_threads * spmv_config.items_per_thread;
+ int segment_fixup_tile_size = segment_fixup_config.block_threads * segment_fixup_config.items_per_thread;
+
+ // Number of tiles for kernels
+ unsigned int num_merge_tiles = (num_merge_items + merge_tile_size - 1) / merge_tile_size;
+ unsigned int num_segment_fixup_tiles = (num_merge_tiles + segment_fixup_tile_size - 1) / segment_fixup_tile_size;
+
+ // Get SM occupancy for kernels
+ int spmv_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ spmv_sm_occupancy,
+ spmv_kernel,
+ spmv_config.block_threads))) break;
+
+ int segment_fixup_sm_occupancy;
+ if (CubDebug(error = MaxSmOccupancy(
+ segment_fixup_sm_occupancy,
+ segment_fixup_kernel,
+ segment_fixup_config.block_threads))) break;
+
+ // Get grid dimensions
+ dim3 spmv_grid_size(
+ CUB_MIN(num_merge_tiles, max_dim_x),
+ (num_merge_tiles + max_dim_x - 1) / max_dim_x,
+ 1);
+
+ dim3 segment_fixup_grid_size(
+ CUB_MIN(num_segment_fixup_tiles, max_dim_x),
+ (num_segment_fixup_tiles + max_dim_x - 1) / max_dim_x,
+ 1);
+
+ // Get the temporary storage allocation requirements
+ size_t allocation_sizes[3];
+ if (CubDebug(error = ScanTileStateT::AllocationSize(num_segment_fixup_tiles, allocation_sizes[0]))) break; // bytes needed for reduce-by-key tile status descriptors
+ allocation_sizes[1] = num_merge_tiles * sizeof(KeyValuePairT); // bytes needed for block carry-out pairs
+ allocation_sizes[2] = (num_merge_tiles + 1) * sizeof(CoordinateT); // bytes needed for tile starting coordinates
+
+ // Alias the temporary allocations from the single storage blob (or compute the necessary size of the blob)
+ void* allocations[3];
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+ if (d_temp_storage == NULL)
+ {
+ // Return if the caller is simply requesting the size of the storage allocation
+ break;
+ }
+
+ // Construct the tile status interface
+ ScanTileStateT tile_state;
+ if (CubDebug(error = tile_state.Init(num_segment_fixup_tiles, allocations[0], allocation_sizes[0]))) break;
+
+ // Alias the other allocations
+ KeyValuePairT* d_tile_carry_pairs = (KeyValuePairT*) allocations[1]; // Agent carry-out pairs
+ CoordinateT* d_tile_coordinates = (CoordinateT*) allocations[2]; // Agent starting coordinates
+
+ // Get search/init grid dims
+ int search_block_size = INIT_KERNEL_THREADS;
+ int search_grid_size = (num_merge_tiles + 1 + search_block_size - 1) / search_block_size;
+
+#if (CUB_PTX_ARCH == 0)
+ // Init textures
+ if (CubDebug(error = spmv_params.t_vector_x.BindTexture(spmv_params.d_vector_x))) break;
+#endif
+
+ if (search_grid_size < sm_count)
+// if (num_merge_tiles < spmv_sm_occupancy * sm_count)
+ {
+ // Not enough spmv tiles to saturate the device: have spmv blocks search their own staring coords
+ d_tile_coordinates = NULL;
+ }
+ else
+ {
+ // Use separate search kernel if we have enough spmv tiles to saturate the device
+
+ // Log spmv_search_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking spmv_search_kernel<<<%d, %d, 0, %lld>>>()\n",
+ search_grid_size, search_block_size, (long long) stream);
+
+ // Invoke spmv_search_kernel
+ spmv_search_kernel<<<search_grid_size, search_block_size, 0, stream>>>(
+ num_merge_tiles,
+ d_tile_coordinates,
+ spmv_params);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+
+ // Log spmv_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking spmv_kernel<<<{%d,%d,%d}, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ spmv_grid_size.x, spmv_grid_size.y, spmv_grid_size.z, spmv_config.block_threads, (long long) stream, spmv_config.items_per_thread, spmv_sm_occupancy);
+
+ // Invoke spmv_kernel
+ spmv_kernel<<<spmv_grid_size, spmv_config.block_threads, 0, stream>>>(
+ spmv_params,
+ d_tile_coordinates,
+ d_tile_carry_pairs,
+ num_merge_tiles,
+ tile_state,
+ num_segment_fixup_tiles);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+
+ // Run reduce-by-key fixup if necessary
+ if (num_merge_tiles > 1)
+ {
+ // Log segment_fixup_kernel configuration
+ if (debug_synchronous) _CubLog("Invoking segment_fixup_kernel<<<{%d,%d,%d}, %d, 0, %lld>>>(), %d items per thread, %d SM occupancy\n",
+ segment_fixup_grid_size.x, segment_fixup_grid_size.y, segment_fixup_grid_size.z, segment_fixup_config.block_threads, (long long) stream, segment_fixup_config.items_per_thread, segment_fixup_sm_occupancy);
+
+ // Invoke segment_fixup_kernel
+ segment_fixup_kernel<<<segment_fixup_grid_size, segment_fixup_config.block_threads, 0, stream>>>(
+ d_tile_carry_pairs,
+ spmv_params.d_vector_y,
+ num_merge_tiles,
+ num_segment_fixup_tiles,
+ tile_state);
+
+ // Check for failure to launch
+ if (CubDebug(error = cudaPeekAtLastError())) break;
+
+ // Sync the stream if specified to flush runtime errors
+ if (debug_synchronous && (CubDebug(error = SyncStream(stream)))) break;
+ }
+
+#if (CUB_PTX_ARCH == 0)
+ // Free textures
+ if (CubDebug(error = spmv_params.t_vector_x.UnbindTexture())) break;
+#endif
+ }
+ while (0);
+
+ return error;
+
+#endif // CUB_RUNTIME_ENABLED
+ }
+
+
+ /**
+ * Internal dispatch routine for computing a device-wide reduction
+ */
+ CUB_RUNTIME_FUNCTION __forceinline__
+ static cudaError_t Dispatch(
+ void* d_temp_storage, ///< [in] %Device-accessible allocation of temporary storage. When NULL, the required allocation size is written to \p temp_storage_bytes and no work is done.
+ size_t& temp_storage_bytes, ///< [in,out] Reference to size in bytes of \p d_temp_storage allocation
+ SpmvParamsT& spmv_params, ///< SpMV input parameter bundle
+ cudaStream_t stream = 0, ///< [in] <b>[optional]</b> CUDA stream to launch kernels within. Default is stream<sub>0</sub>.
+ bool debug_synchronous = false) ///< [in] <b>[optional]</b> Whether or not to synchronize the stream after every kernel launch to check for errors. May cause significant slowdown. Default is \p false.
+ {
+ cudaError error = cudaSuccess;
+ do
+ {
+ // Get PTX version
+ int ptx_version;
+ #if (CUB_PTX_ARCH == 0)
+ if (CubDebug(error = PtxVersion(ptx_version))) break;
+ #else
+ ptx_version = CUB_PTX_ARCH;
+ #endif
+
+ // Get kernel kernel dispatch configurations
+ KernelConfig spmv_config, segment_fixup_config;
+ InitConfigs(ptx_version, spmv_config, segment_fixup_config);
+
+ if (CubDebug(error = Dispatch(
+ d_temp_storage, temp_storage_bytes, spmv_params, stream, debug_synchronous,
+ DeviceSpmv1ColKernel<PtxSpmvPolicyT, ValueT, OffsetT>,
+ DeviceSpmvSearchKernel<PtxSpmvPolicyT, OffsetT, CoordinateT, SpmvParamsT>,
+ DeviceSpmvKernel<PtxSpmvPolicyT, ScanTileStateT, ValueT, OffsetT, CoordinateT, false, false>,
+ DeviceSegmentFixupKernel<PtxSegmentFixupPolicy, KeyValuePairT*, ValueT*, OffsetT, ScanTileStateT>,
+ spmv_config, segment_fixup_config))) break;
+
+ }
+ while (0);
+
+ return error;
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
+