summaryrefslogtreecommitdiff
path: root/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent
diff options
context:
space:
mode:
authorMahmoud <[email protected]>2018-11-18 12:05:40 -0500
committerMahmoud <[email protected]>2018-11-18 12:05:40 -0500
commit773dcd0072e8d5e38377632f307d93ee856f5f73 (patch)
tree1d86d6c0b0c695eeef25490bb79ec53c9bd275cb /debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent
parent72c30bd7a251081eb7453ff4706ddcda30c744ac (diff)
parent8ec70c69eb89c1fa836c233be3e4c478602d9bb7 (diff)
Merge branch 'dev' of https://github.com/gpgpu-sim/gpgpu-sim_distribution into dev
Diffstat (limited to 'debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent')
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_histogram.cuh787
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_downsweep.cuh789
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_upsweep.cuh526
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce.cuh385
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce_by_key.cuh547
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_rle.cuh837
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_scan.cuh471
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_segment_fixup.cuh375
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_select_if.cuh703
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_spmv_orig.cuh670
-rw-r--r--debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/single_pass_scan_operators.cuh815
11 files changed, 6905 insertions, 0 deletions
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_histogram.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_histogram.cuh
new file mode 100644
index 0000000..37b1ec9
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_histogram.cuh
@@ -0,0 +1,787 @@
+/******************************************************************************
+ * 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::AgentHistogram implements a stateful abstraction of CUDA thread blocks for participating in device-wide histogram .
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "../util_type.cuh"
+#include "../block/block_load.cuh"
+#include "../grid/grid_queue.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy
+ ******************************************************************************/
+
+/**
+ *
+ */
+enum BlockHistogramMemoryPreference
+{
+ GMEM,
+ SMEM,
+ BLEND
+};
+
+
+/**
+ * Parameterizable tuning policy type for AgentHistogram
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _PIXELS_PER_THREAD, ///< Pixels per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading input elements
+ bool _RLE_COMPRESS, ///< Whether to perform localized RLE to compress samples before histogramming
+ BlockHistogramMemoryPreference _MEM_PREFERENCE, ///< Whether to prefer privatized shared-memory bins (versus privatized global-memory bins)
+ bool _WORK_STEALING> ///< Whether to dequeue tiles from a global work queue
+struct AgentHistogramPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ PIXELS_PER_THREAD = _PIXELS_PER_THREAD, ///< Pixels per thread (per tile of input)
+ IS_RLE_COMPRESS = _RLE_COMPRESS, ///< Whether to perform localized RLE to compress samples before histogramming
+ MEM_PREFERENCE = _MEM_PREFERENCE, ///< Whether to prefer privatized shared-memory bins (versus privatized global-memory bins)
+ IS_WORK_STEALING = _WORK_STEALING, ///< Whether to dequeue tiles from a global work queue
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+};
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentHistogram implements a stateful abstraction of CUDA thread blocks for participating in device-wide histogram .
+ */
+template <
+ typename AgentHistogramPolicyT, ///< Parameterized AgentHistogramPolicy tuning policy type
+ int PRIVATIZED_SMEM_BINS, ///< Number of privatized shared-memory histogram bins of any channel. Zero indicates privatized counters to be maintained in device-accessible memory.
+ int NUM_CHANNELS, ///< Number of channels interleaved in the input data. Supports up to four channels.
+ int NUM_ACTIVE_CHANNELS, ///< Number of channels actively being histogrammed
+ typename SampleIteratorT, ///< Random-access input iterator type for reading samples
+ 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
+ int PTX_ARCH = CUB_PTX_ARCH> ///< PTX compute capability
+struct AgentHistogram
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// The sample type of the input iterator
+ typedef typename std::iterator_traits<SampleIteratorT>::value_type SampleT;
+
+ /// The pixel type of SampleT
+ typedef typename CubVector<SampleT, NUM_CHANNELS>::Type PixelT;
+
+ /// The quad type of SampleT
+ typedef typename CubVector<SampleT, 4>::Type QuadT;
+
+ /// Constants
+ enum
+ {
+ BLOCK_THREADS = AgentHistogramPolicyT::BLOCK_THREADS,
+
+ PIXELS_PER_THREAD = AgentHistogramPolicyT::PIXELS_PER_THREAD,
+ SAMPLES_PER_THREAD = PIXELS_PER_THREAD * NUM_CHANNELS,
+ QUADS_PER_THREAD = SAMPLES_PER_THREAD / 4,
+
+ TILE_PIXELS = PIXELS_PER_THREAD * BLOCK_THREADS,
+ TILE_SAMPLES = SAMPLES_PER_THREAD * BLOCK_THREADS,
+
+ IS_RLE_COMPRESS = AgentHistogramPolicyT::IS_RLE_COMPRESS,
+
+ MEM_PREFERENCE = (PRIVATIZED_SMEM_BINS > 0) ?
+ AgentHistogramPolicyT::MEM_PREFERENCE :
+ GMEM,
+
+ IS_WORK_STEALING = AgentHistogramPolicyT::IS_WORK_STEALING,
+ };
+
+ /// Cache load modifier for reading input elements
+ static const CacheLoadModifier LOAD_MODIFIER = AgentHistogramPolicyT::LOAD_MODIFIER;
+
+
+ /// Input iterator wrapper type (for applying cache modifier)
+ typedef typename If<IsPointer<SampleIteratorT>::VALUE,
+ CacheModifiedInputIterator<LOAD_MODIFIER, SampleT, OffsetT>, // Wrap the native input pointer with CacheModifiedInputIterator
+ SampleIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedSampleIteratorT;
+
+ /// Pixel input iterator type (for applying cache modifier)
+ typedef CacheModifiedInputIterator<LOAD_MODIFIER, PixelT, OffsetT>
+ WrappedPixelIteratorT;
+
+ /// Qaud input iterator type (for applying cache modifier)
+ typedef CacheModifiedInputIterator<LOAD_MODIFIER, QuadT, OffsetT>
+ WrappedQuadIteratorT;
+
+ /// Parameterized BlockLoad type for samples
+ typedef BlockLoad<
+ SampleT,
+ BLOCK_THREADS,
+ SAMPLES_PER_THREAD,
+ AgentHistogramPolicyT::LOAD_ALGORITHM>
+ BlockLoadSampleT;
+
+ /// Parameterized BlockLoad type for pixels
+ typedef BlockLoad<
+ PixelT,
+ BLOCK_THREADS,
+ PIXELS_PER_THREAD,
+ AgentHistogramPolicyT::LOAD_ALGORITHM>
+ BlockLoadPixelT;
+
+ /// Parameterized BlockLoad type for quads
+ typedef BlockLoad<
+ QuadT,
+ BLOCK_THREADS,
+ QUADS_PER_THREAD,
+ AgentHistogramPolicyT::LOAD_ALGORITHM>
+ BlockLoadQuadT;
+
+ /// Shared memory type required by this thread block
+ struct _TempStorage
+ {
+ CounterT histograms[NUM_ACTIVE_CHANNELS][PRIVATIZED_SMEM_BINS + 1]; // Smem needed for block-privatized smem histogram (with 1 word of padding)
+
+ int tile_idx;
+
+ // Aliasable storage layout
+ union Aliasable
+ {
+ typename BlockLoadSampleT::TempStorage sample_load; // Smem needed for loading a tile of samples
+ typename BlockLoadPixelT::TempStorage pixel_load; // Smem needed for loading a tile of pixels
+ typename BlockLoadQuadT::TempStorage quad_load; // Smem needed for loading a tile of quads
+
+ } aliasable;
+ };
+
+
+ /// Temporary storage type (unionable)
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ /// Reference to temp_storage
+ _TempStorage &temp_storage;
+
+ /// Sample input iterator (with cache modifier applied, if possible)
+ WrappedSampleIteratorT d_wrapped_samples;
+
+ /// Native pointer for input samples (possibly NULL if unavailable)
+ SampleT* d_native_samples;
+
+ /// The number of output bins for each channel
+ int (&num_output_bins)[NUM_ACTIVE_CHANNELS];
+
+ /// The number of privatized bins for each channel
+ int (&num_privatized_bins)[NUM_ACTIVE_CHANNELS];
+
+ /// Reference to gmem privatized histograms for each channel
+ CounterT* d_privatized_histograms[NUM_ACTIVE_CHANNELS];
+
+ /// Reference to final output histograms (gmem)
+ CounterT* (&d_output_histograms)[NUM_ACTIVE_CHANNELS];
+
+ /// The transform operator for determining output bin-ids from privatized counter indices, one for each channel
+ OutputDecodeOpT (&output_decode_op)[NUM_ACTIVE_CHANNELS];
+
+ /// The transform operator for determining privatized counter indices from samples, one for each channel
+ PrivatizedDecodeOpT (&privatized_decode_op)[NUM_ACTIVE_CHANNELS];
+
+ /// Whether to prefer privatized smem counters vs privatized global counters
+ bool prefer_smem;
+
+
+ //---------------------------------------------------------------------
+ // Initialize privatized bin counters
+ //---------------------------------------------------------------------
+
+ // Initialize privatized bin counters
+ __device__ __forceinline__ void InitBinCounters(CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS])
+ {
+ // Initialize histogram bin counts to zeros
+ #pragma unroll
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ {
+ for (int privatized_bin = threadIdx.x; privatized_bin < num_privatized_bins[CHANNEL]; privatized_bin += BLOCK_THREADS)
+ {
+ privatized_histograms[CHANNEL][privatized_bin] = 0;
+ }
+ }
+
+ // Barrier to make sure all threads are done updating counters
+ CTA_SYNC();
+ }
+
+
+ // Initialize privatized bin counters. Specialized for privatized shared-memory counters
+ __device__ __forceinline__ void InitSmemBinCounters()
+ {
+ CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS];
+
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ privatized_histograms[CHANNEL] = temp_storage.histograms[CHANNEL];
+
+ InitBinCounters(privatized_histograms);
+ }
+
+
+ // Initialize privatized bin counters. Specialized for privatized global-memory counters
+ __device__ __forceinline__ void InitGmemBinCounters()
+ {
+ InitBinCounters(d_privatized_histograms);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Update final output histograms
+ //---------------------------------------------------------------------
+
+ // Update final output histograms from privatized histograms
+ __device__ __forceinline__ void StoreOutput(CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS])
+ {
+ // Barrier to make sure all threads are done updating counters
+ CTA_SYNC();
+
+ // Apply privatized bin counts to output bin counts
+ #pragma unroll
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ {
+ int channel_bins = num_privatized_bins[CHANNEL];
+ for (int privatized_bin = threadIdx.x;
+ privatized_bin < channel_bins;
+ privatized_bin += BLOCK_THREADS)
+ {
+ int output_bin = -1;
+ CounterT count = privatized_histograms[CHANNEL][privatized_bin];
+ bool is_valid = count > 0;
+
+ output_decode_op[CHANNEL].template BinSelect<LOAD_MODIFIER>((SampleT) privatized_bin, output_bin, is_valid);
+
+ if (output_bin >= 0)
+ {
+ atomicAdd(&d_output_histograms[CHANNEL][output_bin], count);
+ }
+
+ }
+ }
+ }
+
+
+ // Update final output histograms from privatized histograms. Specialized for privatized shared-memory counters
+ __device__ __forceinline__ void StoreSmemOutput()
+ {
+ CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS];
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ privatized_histograms[CHANNEL] = temp_storage.histograms[CHANNEL];
+
+ StoreOutput(privatized_histograms);
+ }
+
+
+ // Update final output histograms from privatized histograms. Specialized for privatized global-memory counters
+ __device__ __forceinline__ void StoreGmemOutput()
+ {
+ StoreOutput(d_privatized_histograms);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Tile accumulation
+ //---------------------------------------------------------------------
+
+ // Accumulate pixels. Specialized for RLE compression.
+ __device__ __forceinline__ void AccumulatePixels(
+ SampleT samples[PIXELS_PER_THREAD][NUM_CHANNELS],
+ bool is_valid[PIXELS_PER_THREAD],
+ CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS],
+ Int2Type<true> is_rle_compress)
+ {
+ #pragma unroll
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ {
+ // Bin pixels
+ int bins[PIXELS_PER_THREAD];
+
+ #pragma unroll
+ for (int PIXEL = 0; PIXEL < PIXELS_PER_THREAD; ++PIXEL)
+ {
+ bins[PIXEL] = -1;
+ privatized_decode_op[CHANNEL].template BinSelect<LOAD_MODIFIER>(samples[PIXEL][CHANNEL], bins[PIXEL], is_valid[PIXEL]);
+ }
+
+ CounterT accumulator = 1;
+
+ #pragma unroll
+ for (int PIXEL = 0; PIXEL < PIXELS_PER_THREAD - 1; ++PIXEL)
+ {
+ if (bins[PIXEL] != bins[PIXEL + 1])
+ {
+ if (bins[PIXEL] >= 0)
+ atomicAdd(privatized_histograms[CHANNEL] + bins[PIXEL], accumulator);
+
+ accumulator = 0;
+ }
+ accumulator++;
+ }
+
+ // Last pixel
+ if (bins[PIXELS_PER_THREAD - 1] >= 0)
+ atomicAdd(privatized_histograms[CHANNEL] + bins[PIXELS_PER_THREAD - 1], accumulator);
+ }
+ }
+
+
+ // Accumulate pixels. Specialized for individual accumulation of each pixel.
+ __device__ __forceinline__ void AccumulatePixels(
+ SampleT samples[PIXELS_PER_THREAD][NUM_CHANNELS],
+ bool is_valid[PIXELS_PER_THREAD],
+ CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS],
+ Int2Type<false> is_rle_compress)
+ {
+ #pragma unroll
+ for (int PIXEL = 0; PIXEL < PIXELS_PER_THREAD; ++PIXEL)
+ {
+ #pragma unroll
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ {
+ int bin = -1;
+ privatized_decode_op[CHANNEL].template BinSelect<LOAD_MODIFIER>(samples[PIXEL][CHANNEL], bin, is_valid[PIXEL]);
+ if (bin >= 0)
+ atomicAdd(privatized_histograms[CHANNEL] + bin, 1);
+ }
+ }
+ }
+
+
+ /**
+ * Accumulate pixel, specialized for smem privatized histogram
+ */
+ __device__ __forceinline__ void AccumulateSmemPixels(
+ SampleT samples[PIXELS_PER_THREAD][NUM_CHANNELS],
+ bool is_valid[PIXELS_PER_THREAD])
+ {
+ CounterT* privatized_histograms[NUM_ACTIVE_CHANNELS];
+
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ privatized_histograms[CHANNEL] = temp_storage.histograms[CHANNEL];
+
+ AccumulatePixels(samples, is_valid, privatized_histograms, Int2Type<IS_RLE_COMPRESS>());
+ }
+
+
+ /**
+ * Accumulate pixel, specialized for gmem privatized histogram
+ */
+ __device__ __forceinline__ void AccumulateGmemPixels(
+ SampleT samples[PIXELS_PER_THREAD][NUM_CHANNELS],
+ bool is_valid[PIXELS_PER_THREAD])
+ {
+ AccumulatePixels(samples, is_valid, d_privatized_histograms, Int2Type<IS_RLE_COMPRESS>());
+ }
+
+
+
+ //---------------------------------------------------------------------
+ // Tile loading
+ //---------------------------------------------------------------------
+
+ // Load full, aligned tile using pixel iterator (multi-channel)
+ template <int _NUM_ACTIVE_CHANNELS>
+ __device__ __forceinline__ void LoadFullAlignedTile(
+ OffsetT block_offset,
+ int valid_samples,
+ SampleT (&samples)[PIXELS_PER_THREAD][NUM_CHANNELS],
+ Int2Type<_NUM_ACTIVE_CHANNELS> num_active_channels)
+ {
+ typedef PixelT AliasedPixels[PIXELS_PER_THREAD];
+
+ WrappedPixelIteratorT d_wrapped_pixels((PixelT*) (d_native_samples + block_offset));
+
+ // Load using a wrapped pixel iterator
+ BlockLoadPixelT(temp_storage.aliasable.pixel_load).Load(
+ d_wrapped_pixels,
+ reinterpret_cast<AliasedPixels&>(samples));
+ }
+
+ // Load full, aligned tile using quad iterator (single-channel)
+ __device__ __forceinline__ void LoadFullAlignedTile(
+ OffsetT block_offset,
+ int valid_samples,
+ SampleT (&samples)[PIXELS_PER_THREAD][NUM_CHANNELS],
+ Int2Type<1> num_active_channels)
+ {
+ typedef QuadT AliasedQuads[QUADS_PER_THREAD];
+
+ WrappedQuadIteratorT d_wrapped_quads((QuadT*) (d_native_samples + block_offset));
+
+ // Load using a wrapped quad iterator
+ BlockLoadQuadT(temp_storage.aliasable.quad_load).Load(
+ d_wrapped_quads,
+ reinterpret_cast<AliasedQuads&>(samples));
+ }
+
+ // Load full, aligned tile
+ __device__ __forceinline__ void LoadTile(
+ OffsetT block_offset,
+ int valid_samples,
+ SampleT (&samples)[PIXELS_PER_THREAD][NUM_CHANNELS],
+ Int2Type<true> is_full_tile,
+ Int2Type<true> is_aligned)
+ {
+ LoadFullAlignedTile(block_offset, valid_samples, samples, Int2Type<NUM_ACTIVE_CHANNELS>());
+ }
+
+ // Load full, mis-aligned tile using sample iterator
+ __device__ __forceinline__ void LoadTile(
+ OffsetT block_offset,
+ int valid_samples,
+ SampleT (&samples)[PIXELS_PER_THREAD][NUM_CHANNELS],
+ Int2Type<true> is_full_tile,
+ Int2Type<false> is_aligned)
+ {
+ typedef SampleT AliasedSamples[SAMPLES_PER_THREAD];
+
+ // Load using sample iterator
+ BlockLoadSampleT(temp_storage.aliasable.sample_load).Load(
+ d_wrapped_samples + block_offset,
+ reinterpret_cast<AliasedSamples&>(samples));
+ }
+
+ // Load partially-full, aligned tile using the pixel iterator
+ __device__ __forceinline__ void LoadTile(
+ OffsetT block_offset,
+ int valid_samples,
+ SampleT (&samples)[PIXELS_PER_THREAD][NUM_CHANNELS],
+ Int2Type<false> is_full_tile,
+ Int2Type<true> is_aligned)
+ {
+ typedef PixelT AliasedPixels[PIXELS_PER_THREAD];
+
+ WrappedPixelIteratorT d_wrapped_pixels((PixelT*) (d_native_samples + block_offset));
+
+ int valid_pixels = valid_samples / NUM_CHANNELS;
+
+ // Load using a wrapped pixel iterator
+ BlockLoadPixelT(temp_storage.aliasable.pixel_load).Load(
+ d_wrapped_pixels,
+ reinterpret_cast<AliasedPixels&>(samples),
+ valid_pixels);
+ }
+
+ // Load partially-full, mis-aligned tile using sample iterator
+ __device__ __forceinline__ void LoadTile(
+ OffsetT block_offset,
+ int valid_samples,
+ SampleT (&samples)[PIXELS_PER_THREAD][NUM_CHANNELS],
+ Int2Type<false> is_full_tile,
+ Int2Type<false> is_aligned)
+ {
+ typedef SampleT AliasedSamples[SAMPLES_PER_THREAD];
+
+ BlockLoadSampleT(temp_storage.aliasable.sample_load).Load(
+ d_wrapped_samples + block_offset,
+ reinterpret_cast<AliasedSamples&>(samples),
+ valid_samples);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Tile processing
+ //---------------------------------------------------------------------
+
+ // Consume a tile of data samples
+ template <
+ bool IS_ALIGNED, // Whether the tile offset is aligned (quad-aligned for single-channel, pixel-aligned for multi-channel)
+ bool IS_FULL_TILE> // Whether the tile is full
+ __device__ __forceinline__ void ConsumeTile(OffsetT block_offset, int valid_samples)
+ {
+ SampleT samples[PIXELS_PER_THREAD][NUM_CHANNELS];
+ bool is_valid[PIXELS_PER_THREAD];
+
+ // Load tile
+ LoadTile(
+ block_offset,
+ valid_samples,
+ samples,
+ Int2Type<IS_FULL_TILE>(),
+ Int2Type<IS_ALIGNED>());
+
+ // Set valid flags
+ #pragma unroll
+ for (int PIXEL = 0; PIXEL < PIXELS_PER_THREAD; ++PIXEL)
+ is_valid[PIXEL] = IS_FULL_TILE || (((threadIdx.x * PIXELS_PER_THREAD + PIXEL) * NUM_CHANNELS) < valid_samples);
+
+ // Accumulate samples
+#if CUB_PTX_ARCH >= 120
+ if (prefer_smem)
+ AccumulateSmemPixels(samples, is_valid);
+ else
+ AccumulateGmemPixels(samples, is_valid);
+#else
+ AccumulateGmemPixels(samples, is_valid);
+#endif
+
+ }
+
+
+ // Consume row tiles. Specialized for work-stealing from queue
+ template <bool IS_ALIGNED>
+ __device__ __forceinline__ void ConsumeTiles(
+ 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,
+ Int2Type<true> is_work_stealing)
+ {
+
+ int num_tiles = num_rows * tiles_per_row;
+ int tile_idx = (blockIdx.y * gridDim.x) + blockIdx.x;
+ OffsetT num_even_share_tiles = gridDim.x * gridDim.y;
+
+ while (tile_idx < num_tiles)
+ {
+ int row = tile_idx / tiles_per_row;
+ int col = tile_idx - (row * tiles_per_row);
+ OffsetT row_offset = row * row_stride_samples;
+ OffsetT col_offset = (col * TILE_SAMPLES);
+ OffsetT tile_offset = row_offset + col_offset;
+
+ if (col == tiles_per_row - 1)
+ {
+ // Consume a partially-full tile at the end of the row
+ OffsetT num_remaining = (num_row_pixels * NUM_CHANNELS) - col_offset;
+ ConsumeTile<IS_ALIGNED, false>(tile_offset, num_remaining);
+ }
+ else
+ {
+ // Consume full tile
+ ConsumeTile<IS_ALIGNED, true>(tile_offset, TILE_SAMPLES);
+ }
+
+ CTA_SYNC();
+
+ // Get next tile
+ if (threadIdx.x == 0)
+ temp_storage.tile_idx = tile_queue.Drain(1) + num_even_share_tiles;
+
+ CTA_SYNC();
+
+ tile_idx = temp_storage.tile_idx;
+ }
+ }
+
+
+ // Consume row tiles. Specialized for even-share (striped across thread blocks)
+ template <bool IS_ALIGNED>
+ __device__ __forceinline__ void ConsumeTiles(
+ 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,
+ Int2Type<false> is_work_stealing)
+ {
+ for (int row = blockIdx.y; row < num_rows; row += gridDim.y)
+ {
+ OffsetT row_begin = row * row_stride_samples;
+ OffsetT row_end = row_begin + (num_row_pixels * NUM_CHANNELS);
+ OffsetT tile_offset = row_begin + (blockIdx.x * TILE_SAMPLES);
+
+ while (tile_offset < row_end)
+ {
+ OffsetT num_remaining = row_end - tile_offset;
+
+ if (num_remaining < TILE_SAMPLES)
+ {
+ // Consume partial tile
+ ConsumeTile<IS_ALIGNED, false>(tile_offset, num_remaining);
+ break;
+ }
+
+ // Consume full tile
+ ConsumeTile<IS_ALIGNED, true>(tile_offset, TILE_SAMPLES);
+ tile_offset += gridDim.x * TILE_SAMPLES;
+ }
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Parameter extraction
+ //---------------------------------------------------------------------
+
+ // Return a native pixel pointer (specialized for CacheModifiedInputIterator types)
+ template <
+ CacheLoadModifier _MODIFIER,
+ typename _ValueT,
+ typename _OffsetT>
+ __device__ __forceinline__ SampleT* NativePointer(CacheModifiedInputIterator<_MODIFIER, _ValueT, _OffsetT> itr)
+ {
+ return itr.ptr;
+ }
+
+ // Return a native pixel pointer (specialized for other types)
+ template <typename IteratorT>
+ __device__ __forceinline__ SampleT* NativePointer(IteratorT itr)
+ {
+ return NULL;
+ }
+
+
+
+ //---------------------------------------------------------------------
+ // Interface
+ //---------------------------------------------------------------------
+
+
+ /**
+ * Constructor
+ */
+ __device__ __forceinline__ AgentHistogram(
+ TempStorage &temp_storage, ///< Reference to temp_storage
+ SampleIteratorT d_samples, ///< Input data to reduce
+ int (&num_output_bins)[NUM_ACTIVE_CHANNELS], ///< The number bins per final output histogram
+ int (&num_privatized_bins)[NUM_ACTIVE_CHANNELS], ///< The number bins per privatized histogram
+ CounterT* (&d_output_histograms)[NUM_ACTIVE_CHANNELS], ///< Reference to final output histograms
+ CounterT* (&d_privatized_histograms)[NUM_ACTIVE_CHANNELS], ///< Reference to privatized histograms
+ OutputDecodeOpT (&output_decode_op)[NUM_ACTIVE_CHANNELS], ///< The transform operator for determining output bin-ids from privatized counter indices, one for each channel
+ PrivatizedDecodeOpT (&privatized_decode_op)[NUM_ACTIVE_CHANNELS]) ///< The transform operator for determining privatized counter indices from samples, one for each channel
+ :
+ temp_storage(temp_storage.Alias()),
+ d_wrapped_samples(d_samples),
+ num_output_bins(num_output_bins),
+ num_privatized_bins(num_privatized_bins),
+ d_output_histograms(d_output_histograms),
+ privatized_decode_op(privatized_decode_op),
+ output_decode_op(output_decode_op),
+ d_native_samples(NativePointer(d_wrapped_samples)),
+ prefer_smem((MEM_PREFERENCE == SMEM) ?
+ true : // prefer smem privatized histograms
+ (MEM_PREFERENCE == GMEM) ?
+ false : // prefer gmem privatized histograms
+ blockIdx.x & 1) // prefer blended privatized histograms
+ {
+ int blockId = (blockIdx.y * gridDim.x) + blockIdx.x;
+
+ // Initialize the locations of this block's privatized histograms
+ for (int CHANNEL = 0; CHANNEL < NUM_ACTIVE_CHANNELS; ++CHANNEL)
+ this->d_privatized_histograms[CHANNEL] = d_privatized_histograms[CHANNEL] + (blockId * num_privatized_bins[CHANNEL]);
+ }
+
+
+ /**
+ * Consume image
+ */
+ __device__ __forceinline__ void ConsumeTiles(
+ 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) ///< Queue descriptor for assigning tiles of work to thread blocks
+ {
+ // Check whether all row starting offsets are quad-aligned (in single-channel) or pixel-aligned (in multi-channel)
+ int quad_mask = AlignBytes<QuadT>::ALIGN_BYTES - 1;
+ int pixel_mask = AlignBytes<PixelT>::ALIGN_BYTES - 1;
+ size_t row_bytes = sizeof(SampleT) * row_stride_samples;
+
+ bool quad_aligned_rows = (NUM_CHANNELS == 1) && (SAMPLES_PER_THREAD % 4 == 0) && // Single channel
+ ((size_t(d_native_samples) & quad_mask) == 0) && // ptr is quad-aligned
+ ((num_rows == 1) || ((row_bytes & quad_mask) == 0)); // number of row-samples is a multiple of the alignment of the quad
+
+ bool pixel_aligned_rows = (NUM_CHANNELS > 1) && // Multi channel
+ ((size_t(d_native_samples) & pixel_mask) == 0) && // ptr is pixel-aligned
+ ((row_bytes & pixel_mask) == 0); // number of row-samples is a multiple of the alignment of the pixel
+
+ // Whether rows are aligned and can be vectorized
+ if ((d_native_samples != NULL) && (quad_aligned_rows || pixel_aligned_rows))
+ ConsumeTiles<true>(num_row_pixels, num_rows, row_stride_samples, tiles_per_row, tile_queue, Int2Type<IS_WORK_STEALING>());
+ else
+ ConsumeTiles<false>(num_row_pixels, num_rows, row_stride_samples, tiles_per_row, tile_queue, Int2Type<IS_WORK_STEALING>());
+ }
+
+
+ /**
+ * Initialize privatized bin counters. Specialized for privatized shared-memory counters
+ */
+ __device__ __forceinline__ void InitBinCounters()
+ {
+ if (prefer_smem)
+ InitSmemBinCounters();
+ else
+ InitGmemBinCounters();
+ }
+
+
+ /**
+ * Store privatized histogram to device-accessible memory. Specialized for privatized shared-memory counters
+ */
+ __device__ __forceinline__ void StoreOutput()
+ {
+ if (prefer_smem)
+ StoreSmemOutput();
+ else
+ StoreGmemOutput();
+ }
+
+
+};
+
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_downsweep.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_downsweep.cuh
new file mode 100644
index 0000000..faea881
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_downsweep.cuh
@@ -0,0 +1,789 @@
+/******************************************************************************
+ * 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
+ * AgentRadixSortDownsweep implements a stateful abstraction of CUDA thread blocks for participating in device-wide radix sort downsweep .
+ */
+
+
+#pragma once
+
+#include <stdint.h>
+
+#include "../thread/thread_load.cuh"
+#include "../block/block_load.cuh"
+#include "../block/block_store.cuh"
+#include "../block/block_radix_rank.cuh"
+#include "../block/block_exchange.cuh"
+#include "../util_type.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Radix ranking algorithm
+ */
+enum RadixRankAlgorithm
+{
+ RADIX_RANK_BASIC,
+ RADIX_RANK_MEMOIZE,
+ RADIX_RANK_MATCH
+};
+
+/**
+ * Parameterizable tuning policy type for AgentRadixSortDownsweep
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading keys (and values)
+ RadixRankAlgorithm _RANK_ALGORITHM, ///< The radix ranking algorithm to use
+ BlockScanAlgorithm _SCAN_ALGORITHM, ///< The block scan algorithm to use
+ int _RADIX_BITS> ///< The number of radix bits, i.e., log2(bins)
+struct AgentRadixSortDownsweepPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ RADIX_BITS = _RADIX_BITS, ///< The number of radix bits, i.e., log2(bins)
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading keys (and values)
+ static const RadixRankAlgorithm RANK_ALGORITHM = _RANK_ALGORITHM; ///< The radix ranking algorithm to use
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+};
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+
+
+
+
+/**
+ * \brief AgentRadixSortDownsweep implements a stateful abstraction of CUDA thread blocks for participating in device-wide radix sort downsweep .
+ */
+template <
+ typename AgentRadixSortDownsweepPolicy, ///< Parameterized AgentRadixSortDownsweepPolicy tuning policy type
+ bool IS_DESCENDING, ///< Whether or not the sorted-order is high-to-low
+ typename KeyT, ///< KeyT type
+ typename ValueT, ///< ValueT type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct AgentRadixSortDownsweep
+{
+ //---------------------------------------------------------------------
+ // Type definitions and constants
+ //---------------------------------------------------------------------
+
+ // Appropriate unsigned-bits representation of KeyT
+ typedef typename Traits<KeyT>::UnsignedBits UnsignedBits;
+
+ static const UnsignedBits LOWEST_KEY = Traits<KeyT>::LOWEST_KEY;
+ static const UnsignedBits MAX_KEY = Traits<KeyT>::MAX_KEY;
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = AgentRadixSortDownsweepPolicy::LOAD_ALGORITHM;
+ static const CacheLoadModifier LOAD_MODIFIER = AgentRadixSortDownsweepPolicy::LOAD_MODIFIER;
+ static const RadixRankAlgorithm RANK_ALGORITHM = AgentRadixSortDownsweepPolicy::RANK_ALGORITHM;
+ static const BlockScanAlgorithm SCAN_ALGORITHM = AgentRadixSortDownsweepPolicy::SCAN_ALGORITHM;
+
+ enum
+ {
+ BLOCK_THREADS = AgentRadixSortDownsweepPolicy::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentRadixSortDownsweepPolicy::ITEMS_PER_THREAD,
+ RADIX_BITS = AgentRadixSortDownsweepPolicy::RADIX_BITS,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+
+ RADIX_DIGITS = 1 << RADIX_BITS,
+ KEYS_ONLY = Equals<ValueT, NullType>::VALUE,
+ };
+
+ // Input iterator wrapper type (for applying cache modifier)s
+ typedef CacheModifiedInputIterator<LOAD_MODIFIER, UnsignedBits, OffsetT> KeysItr;
+ typedef CacheModifiedInputIterator<LOAD_MODIFIER, ValueT, OffsetT> ValuesItr;
+
+ // Radix ranking type to use
+ typedef typename If<(RANK_ALGORITHM == RADIX_RANK_BASIC),
+ BlockRadixRank<BLOCK_THREADS, RADIX_BITS, IS_DESCENDING, false, SCAN_ALGORITHM>,
+ typename If<(RANK_ALGORITHM == RADIX_RANK_MEMOIZE),
+ BlockRadixRank<BLOCK_THREADS, RADIX_BITS, IS_DESCENDING, true, SCAN_ALGORITHM>,
+ BlockRadixRankMatch<BLOCK_THREADS, RADIX_BITS, IS_DESCENDING, SCAN_ALGORITHM>
+ >::Type
+ >::Type BlockRadixRankT;
+
+ enum
+ {
+ /// Number of bin-starting offsets tracked per thread
+ BINS_TRACKED_PER_THREAD = BlockRadixRankT::BINS_TRACKED_PER_THREAD
+ };
+
+ // BlockLoad type (keys)
+ typedef BlockLoad<
+ UnsignedBits,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ LOAD_ALGORITHM> BlockLoadKeysT;
+
+ // BlockLoad type (values)
+ typedef BlockLoad<
+ ValueT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ LOAD_ALGORITHM> BlockLoadValuesT;
+
+ // Value exchange array type
+ typedef ValueT ValueExchangeT[TILE_ITEMS];
+
+ /**
+ * Shared memory storage layout
+ */
+ union __align__(16) _TempStorage
+ {
+ typename BlockLoadKeysT::TempStorage load_keys;
+ typename BlockLoadValuesT::TempStorage load_values;
+ typename BlockRadixRankT::TempStorage radix_rank;
+
+ struct
+ {
+ UnsignedBits exchange_keys[TILE_ITEMS];
+ OffsetT relative_bin_offsets[RADIX_DIGITS];
+ };
+
+ Uninitialized<ValueExchangeT> exchange_values;
+
+ OffsetT exclusive_digit_prefix[RADIX_DIGITS];
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Thread fields
+ //---------------------------------------------------------------------
+
+ // Shared storage for this CTA
+ _TempStorage &temp_storage;
+
+ // Input and output device pointers
+ KeysItr d_keys_in;
+ ValuesItr d_values_in;
+ UnsignedBits *d_keys_out;
+ ValueT *d_values_out;
+
+ // The global scatter base offset for each digit (valid in the first RADIX_DIGITS threads)
+ OffsetT bin_offset[BINS_TRACKED_PER_THREAD];
+
+ // The least-significant bit position of the current digit to extract
+ int current_bit;
+
+ // Number of bits in current digit
+ int num_bits;
+
+ // Whether to short-cirucit
+ int short_circuit;
+
+ //---------------------------------------------------------------------
+ // Utility methods
+ //---------------------------------------------------------------------
+
+
+ /**
+ * Scatter ranked keys through shared memory, then to device-accessible memory
+ */
+ template <bool FULL_TILE>
+ __device__ __forceinline__ void ScatterKeys(
+ UnsignedBits (&twiddled_keys)[ITEMS_PER_THREAD],
+ OffsetT (&relative_bin_offsets)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ OffsetT valid_items)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ temp_storage.exchange_keys[ranks[ITEM]] = twiddled_keys[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ UnsignedBits key = temp_storage.exchange_keys[threadIdx.x + (ITEM * BLOCK_THREADS)];
+ UnsignedBits digit = BFE(key, current_bit, num_bits);
+ relative_bin_offsets[ITEM] = temp_storage.relative_bin_offsets[digit];
+
+ // Un-twiddle
+ key = Traits<KeyT>::TwiddleOut(key);
+
+ if (FULL_TILE ||
+ (static_cast<OffsetT>(threadIdx.x + (ITEM * BLOCK_THREADS)) < valid_items))
+ {
+ d_keys_out[relative_bin_offsets[ITEM] + threadIdx.x + (ITEM * BLOCK_THREADS)] = key;
+ }
+ }
+ }
+
+
+ /**
+ * Scatter ranked values through shared memory, then to device-accessible memory
+ */
+ template <bool FULL_TILE>
+ __device__ __forceinline__ void ScatterValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ OffsetT (&relative_bin_offsets)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ OffsetT valid_items)
+ {
+ CTA_SYNC();
+
+ ValueExchangeT &exchange_values = temp_storage.exchange_values.Alias();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ exchange_values[ranks[ITEM]] = values[ITEM];
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ ValueT value = exchange_values[threadIdx.x + (ITEM * BLOCK_THREADS)];
+
+ if (FULL_TILE ||
+ (static_cast<OffsetT>(threadIdx.x + (ITEM * BLOCK_THREADS)) < valid_items))
+ {
+ d_values_out[relative_bin_offsets[ITEM] + threadIdx.x + (ITEM * BLOCK_THREADS)] = value;
+ }
+ }
+ }
+
+ /**
+ * Load a tile of keys (specialized for full tile, any ranking algorithm)
+ */
+ template <int _RANK_ALGORITHM>
+ __device__ __forceinline__ void LoadKeys(
+ UnsignedBits (&keys)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ UnsignedBits oob_item,
+ Int2Type<true> is_full_tile,
+ Int2Type<_RANK_ALGORITHM> rank_algorithm)
+ {
+ BlockLoadKeysT(temp_storage.load_keys).Load(
+ d_keys_in + block_offset, keys);
+
+ CTA_SYNC();
+ }
+
+
+ /**
+ * Load a tile of keys (specialized for partial tile, any ranking algorithm)
+ */
+ template <int _RANK_ALGORITHM>
+ __device__ __forceinline__ void LoadKeys(
+ UnsignedBits (&keys)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ UnsignedBits oob_item,
+ Int2Type<false> is_full_tile,
+ Int2Type<_RANK_ALGORITHM> rank_algorithm)
+ {
+ // Register pressure work-around: moving valid_items through shfl prevents compiler
+ // from reusing guards/addressing from prior guarded loads
+ valid_items = ShuffleIndex<CUB_PTX_WARP_THREADS>(valid_items, 0, 0xffffffff);
+
+ BlockLoadKeysT(temp_storage.load_keys).Load(
+ d_keys_in + block_offset, keys, valid_items, oob_item);
+
+ CTA_SYNC();
+ }
+
+
+ /**
+ * Load a tile of keys (specialized for full tile, match ranking algorithm)
+ */
+ __device__ __forceinline__ void LoadKeys(
+ UnsignedBits (&keys)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ UnsignedBits oob_item,
+ Int2Type<true> is_full_tile,
+ Int2Type<RADIX_RANK_MATCH> rank_algorithm)
+ {
+ LoadDirectWarpStriped(threadIdx.x, d_keys_in + block_offset, keys);
+ }
+
+
+ /**
+ * Load a tile of keys (specialized for partial tile, match ranking algorithm)
+ */
+ __device__ __forceinline__ void LoadKeys(
+ UnsignedBits (&keys)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ UnsignedBits oob_item,
+ Int2Type<false> is_full_tile,
+ Int2Type<RADIX_RANK_MATCH> rank_algorithm)
+ {
+ // Register pressure work-around: moving valid_items through shfl prevents compiler
+ // from reusing guards/addressing from prior guarded loads
+ valid_items = ShuffleIndex<CUB_PTX_WARP_THREADS>(valid_items, 0, 0xffffffff);
+
+ LoadDirectWarpStriped(threadIdx.x, d_keys_in + block_offset, keys, valid_items, oob_item);
+ }
+
+
+ /**
+ * Load a tile of values (specialized for full tile, any ranking algorithm)
+ */
+ template <int _RANK_ALGORITHM>
+ __device__ __forceinline__ void LoadValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ Int2Type<true> is_full_tile,
+ Int2Type<_RANK_ALGORITHM> rank_algorithm)
+ {
+ BlockLoadValuesT(temp_storage.load_values).Load(
+ d_values_in + block_offset, values);
+
+ CTA_SYNC();
+ }
+
+
+ /**
+ * Load a tile of values (specialized for partial tile, any ranking algorithm)
+ */
+ template <int _RANK_ALGORITHM>
+ __device__ __forceinline__ void LoadValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ Int2Type<false> is_full_tile,
+ Int2Type<_RANK_ALGORITHM> rank_algorithm)
+ {
+ // Register pressure work-around: moving valid_items through shfl prevents compiler
+ // from reusing guards/addressing from prior guarded loads
+ valid_items = ShuffleIndex<CUB_PTX_WARP_THREADS>(valid_items, 0, 0xffffffff);
+
+ BlockLoadValuesT(temp_storage.load_values).Load(
+ d_values_in + block_offset, values, valid_items);
+
+ CTA_SYNC();
+ }
+
+
+ /**
+ * Load a tile of items (specialized for full tile, match ranking algorithm)
+ */
+ __device__ __forceinline__ void LoadValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ Int2Type<true> is_full_tile,
+ Int2Type<RADIX_RANK_MATCH> rank_algorithm)
+ {
+ LoadDirectWarpStriped(threadIdx.x, d_values_in + block_offset, values);
+ }
+
+
+ /**
+ * Load a tile of items (specialized for partial tile, match ranking algorithm)
+ */
+ __device__ __forceinline__ void LoadValues(
+ ValueT (&values)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ Int2Type<false> is_full_tile,
+ Int2Type<RADIX_RANK_MATCH> rank_algorithm)
+ {
+ // Register pressure work-around: moving valid_items through shfl prevents compiler
+ // from reusing guards/addressing from prior guarded loads
+ valid_items = ShuffleIndex<CUB_PTX_WARP_THREADS>(valid_items, 0, 0xffffffff);
+
+ LoadDirectWarpStriped(threadIdx.x, d_values_in + block_offset, values, valid_items);
+ }
+
+
+ /**
+ * Truck along associated values
+ */
+ template <bool FULL_TILE>
+ __device__ __forceinline__ void GatherScatterValues(
+ OffsetT (&relative_bin_offsets)[ITEMS_PER_THREAD],
+ int (&ranks)[ITEMS_PER_THREAD],
+ OffsetT block_offset,
+ OffsetT valid_items,
+ Int2Type<false> /*is_keys_only*/)
+ {
+ ValueT values[ITEMS_PER_THREAD];
+
+ CTA_SYNC();
+
+ LoadValues(
+ values,
+ block_offset,
+ valid_items,
+ Int2Type<FULL_TILE>(),
+ Int2Type<RANK_ALGORITHM>());
+
+ ScatterValues<FULL_TILE>(
+ values,
+ relative_bin_offsets,
+ ranks,
+ valid_items);
+ }
+
+
+ /**
+ * Truck along associated values (specialized for key-only sorting)
+ */
+ template <bool FULL_TILE>
+ __device__ __forceinline__ void GatherScatterValues(
+ OffsetT (&/*relative_bin_offsets*/)[ITEMS_PER_THREAD],
+ int (&/*ranks*/)[ITEMS_PER_THREAD],
+ OffsetT /*block_offset*/,
+ OffsetT /*valid_items*/,
+ Int2Type<true> /*is_keys_only*/)
+ {}
+
+
+ /**
+ * Process tile
+ */
+ template <bool FULL_TILE>
+ __device__ __forceinline__ void ProcessTile(
+ OffsetT block_offset,
+ const OffsetT &valid_items = TILE_ITEMS)
+ {
+ UnsignedBits keys[ITEMS_PER_THREAD];
+ int ranks[ITEMS_PER_THREAD];
+ OffsetT relative_bin_offsets[ITEMS_PER_THREAD];
+
+ // Assign default (min/max) value to all keys
+ UnsignedBits default_key = (IS_DESCENDING) ? LOWEST_KEY : MAX_KEY;
+
+ // Load tile of keys
+ LoadKeys(
+ keys,
+ block_offset,
+ valid_items,
+ default_key,
+ Int2Type<FULL_TILE>(),
+ Int2Type<RANK_ALGORITHM>());
+
+ // Twiddle key bits if necessary
+ #pragma unroll
+ for (int KEY = 0; KEY < ITEMS_PER_THREAD; KEY++)
+ {
+ keys[KEY] = Traits<KeyT>::TwiddleIn(keys[KEY]);
+ }
+
+ // Rank the twiddled keys
+ int exclusive_digit_prefix[BINS_TRACKED_PER_THREAD];
+ BlockRadixRankT(temp_storage.radix_rank).RankKeys(
+ keys,
+ ranks,
+ current_bit,
+ num_bits,
+ exclusive_digit_prefix);
+
+ CTA_SYNC();
+
+ // Share exclusive digit prefix
+ #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))
+ {
+ // Store exclusive prefix
+ temp_storage.exclusive_digit_prefix[bin_idx] =
+ exclusive_digit_prefix[track];
+ }
+ }
+
+ CTA_SYNC();
+
+ // Get inclusive digit prefix
+ int inclusive_digit_prefix[BINS_TRACKED_PER_THREAD];
+
+ #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))
+ {
+ if (IS_DESCENDING)
+ {
+ // Get inclusive digit prefix from exclusive prefix (higher bins come first)
+ inclusive_digit_prefix[track] = (bin_idx == 0) ?
+ (BLOCK_THREADS * ITEMS_PER_THREAD) :
+ temp_storage.exclusive_digit_prefix[bin_idx - 1];
+ }
+ else
+ {
+ // Get inclusive digit prefix from exclusive prefix (lower bins come first)
+ inclusive_digit_prefix[track] = (bin_idx == RADIX_DIGITS - 1) ?
+ (BLOCK_THREADS * ITEMS_PER_THREAD) :
+ temp_storage.exclusive_digit_prefix[bin_idx + 1];
+ }
+ }
+ }
+
+ CTA_SYNC();
+
+ // Update global scatter base offsets for each digit
+ #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] -= exclusive_digit_prefix[track];
+ temp_storage.relative_bin_offsets[bin_idx] = bin_offset[track];
+ bin_offset[track] += inclusive_digit_prefix[track];
+ }
+ }
+
+ CTA_SYNC();
+
+ // Scatter keys
+ ScatterKeys<FULL_TILE>(keys, relative_bin_offsets, ranks, valid_items);
+
+ // Gather/scatter values
+ GatherScatterValues<FULL_TILE>(relative_bin_offsets , ranks, block_offset, valid_items, Int2Type<KEYS_ONLY>());
+ }
+
+ //---------------------------------------------------------------------
+ // Copy shortcut
+ //---------------------------------------------------------------------
+
+ /**
+ * Copy tiles within the range of input
+ */
+ template <
+ typename InputIteratorT,
+ typename T>
+ __device__ __forceinline__ void Copy(
+ InputIteratorT d_in,
+ T *d_out,
+ OffsetT block_offset,
+ OffsetT block_end)
+ {
+ // Simply copy the input
+ while (block_offset + TILE_ITEMS <= block_end)
+ {
+ T items[ITEMS_PER_THREAD];
+
+ LoadDirectStriped<BLOCK_THREADS>(threadIdx.x, d_in + block_offset, items);
+ CTA_SYNC();
+ StoreDirectStriped<BLOCK_THREADS>(threadIdx.x, d_out + block_offset, items);
+
+ block_offset += TILE_ITEMS;
+ }
+
+ // Clean up last partial tile with guarded-I/O
+ if (block_offset < block_end)
+ {
+ OffsetT valid_items = block_end - block_offset;
+
+ T items[ITEMS_PER_THREAD];
+
+ LoadDirectStriped<BLOCK_THREADS>(threadIdx.x, d_in + block_offset, items, valid_items);
+ CTA_SYNC();
+ StoreDirectStriped<BLOCK_THREADS>(threadIdx.x, d_out + block_offset, items, valid_items);
+ }
+ }
+
+
+ /**
+ * Copy tiles within the range of input (specialized for NullType)
+ */
+ template <typename InputIteratorT>
+ __device__ __forceinline__ void Copy(
+ InputIteratorT /*d_in*/,
+ NullType * /*d_out*/,
+ OffsetT /*block_offset*/,
+ OffsetT /*block_end*/)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Interface
+ //---------------------------------------------------------------------
+
+ /**
+ * Constructor
+ */
+ __device__ __forceinline__ AgentRadixSortDownsweep(
+ TempStorage &temp_storage,
+ OffsetT (&bin_offset)[BINS_TRACKED_PER_THREAD],
+ OffsetT num_items,
+ const KeyT *d_keys_in,
+ KeyT *d_keys_out,
+ const ValueT *d_values_in,
+ ValueT *d_values_out,
+ int current_bit,
+ int num_bits)
+ :
+ temp_storage(temp_storage.Alias()),
+ d_keys_in(reinterpret_cast<const UnsignedBits*>(d_keys_in)),
+ d_values_in(d_values_in),
+ d_keys_out(reinterpret_cast<UnsignedBits*>(d_keys_out)),
+ d_values_out(d_values_out),
+ current_bit(current_bit),
+ num_bits(num_bits),
+ short_circuit(1)
+ {
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ this->bin_offset[track] = bin_offset[track];
+
+ int bin_idx = (threadIdx.x * BINS_TRACKED_PER_THREAD) + track;
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ {
+ // Short circuit if the histogram has only bin counts of only zeros or problem-size
+ short_circuit = short_circuit && ((bin_offset[track] == 0) || (bin_offset[track] == num_items));
+ }
+ }
+
+ short_circuit = CTA_SYNC_AND(short_circuit);
+ }
+
+
+ /**
+ * Constructor
+ */
+ __device__ __forceinline__ AgentRadixSortDownsweep(
+ TempStorage &temp_storage,
+ OffsetT num_items,
+ OffsetT *d_spine,
+ const KeyT *d_keys_in,
+ KeyT *d_keys_out,
+ const ValueT *d_values_in,
+ ValueT *d_values_out,
+ int current_bit,
+ int num_bits)
+ :
+ temp_storage(temp_storage.Alias()),
+ d_keys_in(reinterpret_cast<const UnsignedBits*>(d_keys_in)),
+ d_values_in(d_values_in),
+ d_keys_out(reinterpret_cast<UnsignedBits*>(d_keys_out)),
+ d_values_out(d_values_out),
+ current_bit(current_bit),
+ num_bits(num_bits),
+ short_circuit(1)
+ {
+ #pragma unroll
+ for (int track = 0; track < BINS_TRACKED_PER_THREAD; ++track)
+ {
+ int bin_idx = (threadIdx.x * BINS_TRACKED_PER_THREAD) + track;
+
+ // Load digit bin offsets (each of the first RADIX_DIGITS threads will load an offset for that digit)
+ if ((BLOCK_THREADS == RADIX_DIGITS) || (bin_idx < RADIX_DIGITS))
+ {
+ if (IS_DESCENDING)
+ bin_idx = RADIX_DIGITS - bin_idx - 1;
+
+ // Short circuit if the first block's histogram has only bin counts of only zeros or problem-size
+ OffsetT first_block_bin_offset = d_spine[gridDim.x * bin_idx];
+ short_circuit = short_circuit && ((first_block_bin_offset == 0) || (first_block_bin_offset == num_items));
+
+ // Load my block's bin offset for my bin
+ bin_offset[track] = d_spine[(gridDim.x * bin_idx) + blockIdx.x];
+ }
+ }
+
+ short_circuit = CTA_SYNC_AND(short_circuit);
+ }
+
+
+ /**
+ * Distribute keys from a segment of input tiles.
+ */
+ __device__ __forceinline__ void ProcessRegion(
+ OffsetT block_offset,
+ OffsetT block_end)
+ {
+ if (short_circuit)
+ {
+ // Copy keys
+ Copy(d_keys_in, d_keys_out, block_offset, block_end);
+
+ // Copy values
+ Copy(d_values_in, d_values_out, block_offset, block_end);
+ }
+ else
+ {
+ // Process full tiles of tile_items
+ #pragma unroll 1
+ while (block_offset + TILE_ITEMS <= block_end)
+ {
+ ProcessTile<true>(block_offset);
+ block_offset += TILE_ITEMS;
+
+ CTA_SYNC();
+ }
+
+ // Clean up last partial tile with guarded-I/O
+ if (block_offset < block_end)
+ {
+ ProcessTile<false>(block_offset, block_end - block_offset);
+ }
+
+ }
+ }
+
+};
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_upsweep.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_upsweep.cuh
new file mode 100644
index 0000000..2081cef
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_radix_sort_upsweep.cuh
@@ -0,0 +1,526 @@
+/******************************************************************************
+ * 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
+ * AgentRadixSortUpsweep implements a stateful abstraction of CUDA thread blocks for participating in device-wide radix sort upsweep .
+ */
+
+#pragma once
+
+#include "../thread/thread_reduce.cuh"
+#include "../thread/thread_load.cuh"
+#include "../warp/warp_reduce.cuh"
+#include "../block/block_load.cuh"
+#include "../util_type.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentRadixSortUpsweep
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading keys
+ int _RADIX_BITS> ///< The number of radix bits, i.e., log2(bins)
+struct AgentRadixSortUpsweepPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ RADIX_BITS = _RADIX_BITS, ///< The number of radix bits, i.e., log2(bins)
+ };
+
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading keys
+};
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentRadixSortUpsweep implements a stateful abstraction of CUDA thread blocks for participating in device-wide radix sort upsweep .
+ */
+template <
+ typename AgentRadixSortUpsweepPolicy, ///< Parameterized AgentRadixSortUpsweepPolicy tuning policy type
+ typename KeyT, ///< KeyT type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct AgentRadixSortUpsweep
+{
+
+ //---------------------------------------------------------------------
+ // Type definitions and constants
+ //---------------------------------------------------------------------
+
+ typedef typename Traits<KeyT>::UnsignedBits UnsignedBits;
+
+ // Integer type for digit counters (to be packed into words of PackedCounters)
+ typedef unsigned char DigitCounter;
+
+ // Integer type for packing DigitCounters into columns of shared memory banks
+ typedef unsigned int PackedCounter;
+
+ static const CacheLoadModifier LOAD_MODIFIER = AgentRadixSortUpsweepPolicy::LOAD_MODIFIER;
+
+ enum
+ {
+ RADIX_BITS = AgentRadixSortUpsweepPolicy::RADIX_BITS,
+ BLOCK_THREADS = AgentRadixSortUpsweepPolicy::BLOCK_THREADS,
+ KEYS_PER_THREAD = AgentRadixSortUpsweepPolicy::ITEMS_PER_THREAD,
+
+ RADIX_DIGITS = 1 << RADIX_BITS,
+
+ LOG_WARP_THREADS = CUB_PTX_LOG_WARP_THREADS,
+ WARP_THREADS = 1 << LOG_WARP_THREADS,
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+
+ TILE_ITEMS = BLOCK_THREADS * KEYS_PER_THREAD,
+
+ BYTES_PER_COUNTER = sizeof(DigitCounter),
+ LOG_BYTES_PER_COUNTER = Log2<BYTES_PER_COUNTER>::VALUE,
+
+ PACKING_RATIO = sizeof(PackedCounter) / sizeof(DigitCounter),
+ LOG_PACKING_RATIO = Log2<PACKING_RATIO>::VALUE,
+
+ LOG_COUNTER_LANES = CUB_MAX(0, RADIX_BITS - LOG_PACKING_RATIO),
+ COUNTER_LANES = 1 << LOG_COUNTER_LANES,
+
+ // To prevent counter overflow, we must periodically unpack and aggregate the
+ // digit counters back into registers. Each counter lane is assigned to a
+ // warp for aggregation.
+
+ LANES_PER_WARP = CUB_MAX(1, (COUNTER_LANES + WARPS - 1) / WARPS),
+
+ // Unroll tiles in batches without risk of counter overflow
+ UNROLL_COUNT = CUB_MIN(64, 255 / KEYS_PER_THREAD),
+ UNROLLED_ELEMENTS = UNROLL_COUNT * TILE_ITEMS,
+ };
+
+
+ // Input iterator wrapper type (for applying cache modifier)s
+ typedef CacheModifiedInputIterator<LOAD_MODIFIER, UnsignedBits, OffsetT> KeysItr;
+
+ /**
+ * Shared memory storage layout
+ */
+ union __align__(16) _TempStorage
+ {
+ DigitCounter thread_counters[COUNTER_LANES][BLOCK_THREADS][PACKING_RATIO];
+ PackedCounter packed_thread_counters[COUNTER_LANES][BLOCK_THREADS];
+ OffsetT block_counters[WARP_THREADS][RADIX_DIGITS];
+ };
+
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Thread fields (aggregate state bundle)
+ //---------------------------------------------------------------------
+
+ // Shared storage for this CTA
+ _TempStorage &temp_storage;
+
+ // Thread-local counters for periodically aggregating composite-counter lanes
+ OffsetT local_counts[LANES_PER_WARP][PACKING_RATIO];
+
+ // Input and output device pointers
+ KeysItr d_keys_in;
+
+ // The least-significant bit position of the current digit to extract
+ int current_bit;
+
+ // Number of bits in current digit
+ int num_bits;
+
+
+
+ //---------------------------------------------------------------------
+ // Helper structure for templated iteration
+ //---------------------------------------------------------------------
+
+ // Iterate
+ template <int COUNT, int MAX>
+ struct Iterate
+ {
+ // BucketKeys
+ static __device__ __forceinline__ void BucketKeys(
+ AgentRadixSortUpsweep &cta,
+ UnsignedBits keys[KEYS_PER_THREAD])
+ {
+ cta.Bucket(keys[COUNT]);
+
+ // Next
+ Iterate<COUNT + 1, MAX>::BucketKeys(cta, keys);
+ }
+ };
+
+ // Terminate
+ template <int MAX>
+ struct Iterate<MAX, MAX>
+ {
+ // BucketKeys
+ static __device__ __forceinline__ void BucketKeys(AgentRadixSortUpsweep &/*cta*/, UnsignedBits /*keys*/[KEYS_PER_THREAD]) {}
+ };
+
+
+ //---------------------------------------------------------------------
+ // Utility methods
+ //---------------------------------------------------------------------
+
+ /**
+ * Decode a key and increment corresponding smem digit counter
+ */
+ __device__ __forceinline__ void Bucket(UnsignedBits key)
+ {
+ // Perform transform op
+ UnsignedBits converted_key = Traits<KeyT>::TwiddleIn(key);
+
+ // Extract current digit bits
+ UnsignedBits digit = BFE(converted_key, current_bit, num_bits);
+
+ // Get sub-counter offset
+ UnsignedBits sub_counter = digit & (PACKING_RATIO - 1);
+
+ // Get row offset
+ UnsignedBits row_offset = digit >> LOG_PACKING_RATIO;
+
+ // Increment counter
+ temp_storage.thread_counters[row_offset][threadIdx.x][sub_counter]++;
+ }
+
+
+ /**
+ * Reset composite counters
+ */
+ __device__ __forceinline__ void ResetDigitCounters()
+ {
+ #pragma unroll
+ for (int LANE = 0; LANE < COUNTER_LANES; LANE++)
+ {
+ temp_storage.packed_thread_counters[LANE][threadIdx.x] = 0;
+ }
+ }
+
+
+ /**
+ * Reset the unpacked counters in each thread
+ */
+ __device__ __forceinline__ void ResetUnpackedCounters()
+ {
+ #pragma unroll
+ for (int LANE = 0; LANE < LANES_PER_WARP; LANE++)
+ {
+ #pragma unroll
+ for (int UNPACKED_COUNTER = 0; UNPACKED_COUNTER < PACKING_RATIO; UNPACKED_COUNTER++)
+ {
+ local_counts[LANE][UNPACKED_COUNTER] = 0;
+ }
+ }
+ }
+
+
+ /**
+ * Extracts and aggregates the digit counters for each counter lane
+ * owned by this warp
+ */
+ __device__ __forceinline__ void UnpackDigitCounts()
+ {
+ unsigned int warp_id = threadIdx.x >> LOG_WARP_THREADS;
+ unsigned int warp_tid = LaneId();
+
+ #pragma unroll
+ for (int LANE = 0; LANE < LANES_PER_WARP; LANE++)
+ {
+ const int counter_lane = (LANE * WARPS) + warp_id;
+ if (counter_lane < COUNTER_LANES)
+ {
+ #pragma unroll
+ for (int PACKED_COUNTER = 0; PACKED_COUNTER < BLOCK_THREADS; PACKED_COUNTER += WARP_THREADS)
+ {
+ #pragma unroll
+ for (int UNPACKED_COUNTER = 0; UNPACKED_COUNTER < PACKING_RATIO; UNPACKED_COUNTER++)
+ {
+ OffsetT counter = temp_storage.thread_counters[counter_lane][warp_tid + PACKED_COUNTER][UNPACKED_COUNTER];
+ local_counts[LANE][UNPACKED_COUNTER] += counter;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Processes a single, full tile
+ */
+ __device__ __forceinline__ void ProcessFullTile(OffsetT block_offset)
+ {
+ // Tile of keys
+ UnsignedBits keys[KEYS_PER_THREAD];
+
+ LoadDirectStriped<BLOCK_THREADS>(threadIdx.x, d_keys_in + block_offset, keys);
+
+ // Prevent hoisting
+ CTA_SYNC();
+
+ // Bucket tile of keys
+ Iterate<0, KEYS_PER_THREAD>::BucketKeys(*this, keys);
+ }
+
+
+ /**
+ * Processes a single load (may have some threads masked off)
+ */
+ __device__ __forceinline__ void ProcessPartialTile(
+ OffsetT block_offset,
+ const OffsetT &block_end)
+ {
+ // Process partial tile if necessary using single loads
+ block_offset += threadIdx.x;
+ while (block_offset < block_end)
+ {
+ // Load and bucket key
+ UnsignedBits key = d_keys_in[block_offset];
+ Bucket(key);
+ block_offset += BLOCK_THREADS;
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Interface
+ //---------------------------------------------------------------------
+
+ /**
+ * Constructor
+ */
+ __device__ __forceinline__ AgentRadixSortUpsweep(
+ TempStorage &temp_storage,
+ const KeyT *d_keys_in,
+ int current_bit,
+ int num_bits)
+ :
+ temp_storage(temp_storage.Alias()),
+ d_keys_in(reinterpret_cast<const UnsignedBits*>(d_keys_in)),
+ current_bit(current_bit),
+ num_bits(num_bits)
+ {}
+
+
+ /**
+ * Compute radix digit histograms from a segment of input tiles.
+ */
+ __device__ __forceinline__ void ProcessRegion(
+ OffsetT block_offset,
+ const OffsetT &block_end)
+ {
+ // Reset digit counters in smem and unpacked counters in registers
+ ResetDigitCounters();
+ ResetUnpackedCounters();
+
+ // Unroll batches of full tiles
+ while (block_offset + UNROLLED_ELEMENTS <= block_end)
+ {
+ for (int i = 0; i < UNROLL_COUNT; ++i)
+ {
+ ProcessFullTile(block_offset);
+ block_offset += TILE_ITEMS;
+ }
+
+ CTA_SYNC();
+
+ // Aggregate back into local_count registers to prevent overflow
+ UnpackDigitCounts();
+
+ CTA_SYNC();
+
+ // Reset composite counters in lanes
+ ResetDigitCounters();
+ }
+
+ // Unroll single full tiles
+ while (block_offset + TILE_ITEMS <= block_end)
+ {
+ ProcessFullTile(block_offset);
+ block_offset += TILE_ITEMS;
+ }
+
+ // Process partial tile if necessary
+ ProcessPartialTile(
+ block_offset,
+ block_end);
+
+ CTA_SYNC();
+
+ // Aggregate back into local_count registers
+ UnpackDigitCounts();
+ }
+
+
+ /**
+ * Extract counts (saving them to the external array)
+ */
+ template <bool IS_DESCENDING>
+ __device__ __forceinline__ void ExtractCounts(
+ OffsetT *counters,
+ int bin_stride = 1,
+ int bin_offset = 0)
+ {
+ unsigned int warp_id = threadIdx.x >> LOG_WARP_THREADS;
+ unsigned int warp_tid = LaneId();
+
+ // Place unpacked digit counters in shared memory
+ #pragma unroll
+ for (int LANE = 0; LANE < LANES_PER_WARP; LANE++)
+ {
+ int counter_lane = (LANE * WARPS) + warp_id;
+ if (counter_lane < COUNTER_LANES)
+ {
+ int digit_row = counter_lane << LOG_PACKING_RATIO;
+
+ #pragma unroll
+ for (int UNPACKED_COUNTER = 0; UNPACKED_COUNTER < PACKING_RATIO; UNPACKED_COUNTER++)
+ {
+ int bin_idx = digit_row + UNPACKED_COUNTER;
+
+ temp_storage.block_counters[warp_tid][bin_idx] =
+ local_counts[LANE][UNPACKED_COUNTER];
+ }
+ }
+ }
+
+ CTA_SYNC();
+
+ // Rake-reduce bin_count reductions
+
+ // Whole blocks
+ #pragma unroll
+ for (int BIN_BASE = RADIX_DIGITS % BLOCK_THREADS;
+ (BIN_BASE + BLOCK_THREADS) <= RADIX_DIGITS;
+ BIN_BASE += BLOCK_THREADS)
+ {
+ int bin_idx = BIN_BASE + threadIdx.x;
+
+ OffsetT bin_count = 0;
+ #pragma unroll
+ for (int i = 0; i < WARP_THREADS; ++i)
+ bin_count += temp_storage.block_counters[i][bin_idx];
+
+ if (IS_DESCENDING)
+ bin_idx = RADIX_DIGITS - bin_idx - 1;
+
+ counters[(bin_stride * bin_idx) + bin_offset] = bin_count;
+ }
+
+ // Remainder
+ if ((RADIX_DIGITS % BLOCK_THREADS != 0) && (threadIdx.x < RADIX_DIGITS))
+ {
+ int bin_idx = threadIdx.x;
+
+ OffsetT bin_count = 0;
+ #pragma unroll
+ for (int i = 0; i < WARP_THREADS; ++i)
+ bin_count += temp_storage.block_counters[i][bin_idx];
+
+ if (IS_DESCENDING)
+ bin_idx = RADIX_DIGITS - bin_idx - 1;
+
+ counters[(bin_stride * bin_idx) + bin_offset] = bin_count;
+ }
+ }
+
+
+ /**
+ * Extract counts
+ */
+ template <int BINS_TRACKED_PER_THREAD>
+ __device__ __forceinline__ void ExtractCounts(
+ OffsetT (&bin_count)[BINS_TRACKED_PER_THREAD]) ///< [out] The exclusive prefix sum for the digits [(threadIdx.x * BINS_TRACKED_PER_THREAD) ... (threadIdx.x * BINS_TRACKED_PER_THREAD) + BINS_TRACKED_PER_THREAD - 1]
+ {
+ unsigned int warp_id = threadIdx.x >> LOG_WARP_THREADS;
+ unsigned int warp_tid = LaneId();
+
+ // Place unpacked digit counters in shared memory
+ #pragma unroll
+ for (int LANE = 0; LANE < LANES_PER_WARP; LANE++)
+ {
+ int counter_lane = (LANE * WARPS) + warp_id;
+ if (counter_lane < COUNTER_LANES)
+ {
+ int digit_row = counter_lane << LOG_PACKING_RATIO;
+
+ #pragma unroll
+ for (int UNPACKED_COUNTER = 0; UNPACKED_COUNTER < PACKING_RATIO; UNPACKED_COUNTER++)
+ {
+ int bin_idx = digit_row + UNPACKED_COUNTER;
+
+ temp_storage.block_counters[warp_tid][bin_idx] =
+ local_counts[LANE][UNPACKED_COUNTER];
+ }
+ }
+ }
+
+ CTA_SYNC();
+
+ // Rake-reduce bin_count reductions
+ #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] = 0;
+
+ #pragma unroll
+ for (int i = 0; i < WARP_THREADS; ++i)
+ bin_count[track] += temp_storage.block_counters[i][bin_idx];
+ }
+ }
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce.cuh
new file mode 100644
index 0000000..000a905
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce.cuh
@@ -0,0 +1,385 @@
+/******************************************************************************
+ * 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::AgentReduce implements a stateful abstraction of CUDA thread blocks for participating in device-wide reduction .
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "../block/block_load.cuh"
+#include "../block/block_reduce.cuh"
+#include "../grid/grid_mapping.cuh"
+#include "../grid/grid_even_share.cuh"
+#include "../util_type.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentReduce
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ int _VECTOR_LOAD_LENGTH, ///< Number of items per vectorized load
+ BlockReduceAlgorithm _BLOCK_ALGORITHM, ///< Cooperative block-wide reduction algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER> ///< Cache load modifier for reading input elements
+struct AgentReducePolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ VECTOR_LOAD_LENGTH = _VECTOR_LOAD_LENGTH, ///< Number of items per vectorized load
+ };
+
+ static const BlockReduceAlgorithm BLOCK_ALGORITHM = _BLOCK_ALGORITHM; ///< Cooperative block-wide reduction algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+};
+
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentReduce implements a stateful abstraction of CUDA thread blocks for participating in device-wide reduction .
+ *
+ * Each thread reduces only the values it loads. If \p FIRST_TILE, this
+ * partial reduction is stored into \p thread_aggregate. Otherwise it is
+ * accumulated into \p thread_aggregate.
+ */
+template <
+ typename AgentReducePolicy, ///< Parameterized AgentReducePolicy tuning policy type
+ typename InputIteratorT, ///< Random-access iterator type for input
+ typename OutputIteratorT, ///< Random-access iterator type for output
+ typename OffsetT, ///< Signed integer type for global offsets
+ typename ReductionOp> ///< Binary reduction operator type having member <tt>T operator()(const T &a, const T &b)</tt>
+struct AgentReduce
+{
+
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// The input value type
+ typedef typename std::iterator_traits<InputIteratorT>::value_type InputT;
+
+ /// 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
+
+ /// Vector type of InputT for data movement
+ typedef typename CubVector<InputT, AgentReducePolicy::VECTOR_LOAD_LENGTH>::Type VectorT;
+
+ /// Input iterator wrapper type (for applying cache modifier)
+ typedef typename If<IsPointer<InputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentReducePolicy::LOAD_MODIFIER, InputT, OffsetT>, // Wrap the native input pointer with CacheModifiedInputIterator
+ InputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedInputIteratorT;
+
+ /// Constants
+ enum
+ {
+ BLOCK_THREADS = AgentReducePolicy::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentReducePolicy::ITEMS_PER_THREAD,
+ VECTOR_LOAD_LENGTH = CUB_MIN(ITEMS_PER_THREAD, AgentReducePolicy::VECTOR_LOAD_LENGTH),
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+
+ // Can vectorize according to the policy if the input iterator is a native pointer to a primitive type
+ ATTEMPT_VECTORIZATION = (VECTOR_LOAD_LENGTH > 1) &&
+ (ITEMS_PER_THREAD % VECTOR_LOAD_LENGTH == 0) &&
+ (IsPointer<InputIteratorT>::VALUE) && Traits<InputT>::PRIMITIVE,
+
+ };
+
+ static const CacheLoadModifier LOAD_MODIFIER = AgentReducePolicy::LOAD_MODIFIER;
+ static const BlockReduceAlgorithm BLOCK_ALGORITHM = AgentReducePolicy::BLOCK_ALGORITHM;
+
+ /// Parameterized BlockReduce primitive
+ typedef BlockReduce<OutputT, BLOCK_THREADS, AgentReducePolicy::BLOCK_ALGORITHM> BlockReduceT;
+
+ /// Shared memory type required by this thread block
+ struct _TempStorage
+ {
+ typename BlockReduceT::TempStorage reduce;
+ };
+
+ /// Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ _TempStorage& temp_storage; ///< Reference to temp_storage
+ InputIteratorT d_in; ///< Input data to reduce
+ WrappedInputIteratorT d_wrapped_in; ///< Wrapped input data to reduce
+ ReductionOp reduction_op; ///< Binary reduction operator
+
+
+ //---------------------------------------------------------------------
+ // Utility
+ //---------------------------------------------------------------------
+
+
+ // Whether or not the input is aligned with the vector type (specialized for types we can vectorize)
+ template <typename Iterator>
+ static __device__ __forceinline__ bool IsAligned(
+ Iterator d_in,
+ Int2Type<true> /*can_vectorize*/)
+ {
+ return (size_t(d_in) & (sizeof(VectorT) - 1)) == 0;
+ }
+
+ // Whether or not the input is aligned with the vector type (specialized for types we cannot vectorize)
+ template <typename Iterator>
+ static __device__ __forceinline__ bool IsAligned(
+ Iterator /*d_in*/,
+ Int2Type<false> /*can_vectorize*/)
+ {
+ return false;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Constructor
+ //---------------------------------------------------------------------
+
+ /**
+ * Constructor
+ */
+ __device__ __forceinline__ AgentReduce(
+ TempStorage& temp_storage, ///< Reference to temp_storage
+ InputIteratorT d_in, ///< Input data to reduce
+ ReductionOp reduction_op) ///< Binary reduction operator
+ :
+ temp_storage(temp_storage.Alias()),
+ d_in(d_in),
+ d_wrapped_in(d_in),
+ reduction_op(reduction_op)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Tile consumption
+ //---------------------------------------------------------------------
+
+ /**
+ * Consume a full tile of input (non-vectorized)
+ */
+ template <int IS_FIRST_TILE>
+ __device__ __forceinline__ void ConsumeTile(
+ OutputT &thread_aggregate,
+ OffsetT block_offset, ///< The offset the tile to consume
+ int /*valid_items*/, ///< The number of valid items in the tile
+ Int2Type<true> /*is_full_tile*/, ///< Whether or not this is a full tile
+ Int2Type<false> /*can_vectorize*/) ///< Whether or not we can vectorize loads
+ {
+ OutputT items[ITEMS_PER_THREAD];
+
+ // Load items in striped fashion
+ LoadDirectStriped<BLOCK_THREADS>(threadIdx.x, d_wrapped_in + block_offset, items);
+
+ // Reduce items within each thread stripe
+ thread_aggregate = (IS_FIRST_TILE) ?
+ internal::ThreadReduce(items, reduction_op) :
+ internal::ThreadReduce(items, reduction_op, thread_aggregate);
+ }
+
+
+ /**
+ * Consume a full tile of input (vectorized)
+ */
+ template <int IS_FIRST_TILE>
+ __device__ __forceinline__ void ConsumeTile(
+ OutputT &thread_aggregate,
+ OffsetT block_offset, ///< The offset the tile to consume
+ int /*valid_items*/, ///< The number of valid items in the tile
+ Int2Type<true> /*is_full_tile*/, ///< Whether or not this is a full tile
+ Int2Type<true> /*can_vectorize*/) ///< Whether or not we can vectorize loads
+ {
+ // Alias items as an array of VectorT and load it in striped fashion
+ enum { WORDS = ITEMS_PER_THREAD / VECTOR_LOAD_LENGTH };
+
+ // Fabricate a vectorized input iterator
+ InputT *d_in_unqualified = const_cast<InputT*>(d_in) + block_offset + (threadIdx.x * VECTOR_LOAD_LENGTH);
+ CacheModifiedInputIterator<AgentReducePolicy::LOAD_MODIFIER, VectorT, OffsetT> d_vec_in(
+ reinterpret_cast<VectorT*>(d_in_unqualified));
+
+ // Load items as vector items
+ InputT input_items[ITEMS_PER_THREAD];
+ VectorT *vec_items = reinterpret_cast<VectorT*>(input_items);
+ #pragma unroll
+ for (int i = 0; i < WORDS; ++i)
+ vec_items[i] = d_vec_in[BLOCK_THREADS * i];
+
+ // Convert from input type to output type
+ OutputT items[ITEMS_PER_THREAD];
+ #pragma unroll
+ for (int i = 0; i < ITEMS_PER_THREAD; ++i)
+ items[i] = input_items[i];
+
+ // Reduce items within each thread stripe
+ thread_aggregate = (IS_FIRST_TILE) ?
+ internal::ThreadReduce(items, reduction_op) :
+ internal::ThreadReduce(items, reduction_op, thread_aggregate);
+ }
+
+
+ /**
+ * Consume a partial tile of input
+ */
+ template <int IS_FIRST_TILE, int CAN_VECTORIZE>
+ __device__ __forceinline__ void ConsumeTile(
+ OutputT &thread_aggregate,
+ OffsetT block_offset, ///< The offset the tile to consume
+ int valid_items, ///< The number of valid items in the tile
+ Int2Type<false> /*is_full_tile*/, ///< Whether or not this is a full tile
+ Int2Type<CAN_VECTORIZE> /*can_vectorize*/) ///< Whether or not we can vectorize loads
+ {
+ // Partial tile
+ int thread_offset = threadIdx.x;
+
+ // Read first item
+ if ((IS_FIRST_TILE) && (thread_offset < valid_items))
+ {
+ thread_aggregate = d_wrapped_in[block_offset + thread_offset];
+ thread_offset += BLOCK_THREADS;
+ }
+
+ // Continue reading items (block-striped)
+ while (thread_offset < valid_items)
+ {
+ OutputT item = d_wrapped_in[block_offset + thread_offset];
+ thread_aggregate = reduction_op(thread_aggregate, item);
+ thread_offset += BLOCK_THREADS;
+ }
+ }
+
+
+ //---------------------------------------------------------------
+ // Consume a contiguous segment of tiles
+ //---------------------------------------------------------------------
+
+ /**
+ * \brief Reduce a contiguous segment of input tiles
+ */
+ template <int CAN_VECTORIZE>
+ __device__ __forceinline__ OutputT ConsumeRange(
+ GridEvenShare<OffsetT> &even_share, ///< GridEvenShare descriptor
+ Int2Type<CAN_VECTORIZE> can_vectorize) ///< Whether or not we can vectorize loads
+ {
+ OutputT thread_aggregate;
+
+ if (even_share.block_offset + TILE_ITEMS > even_share.block_end)
+ {
+ // First tile isn't full (not all threads have valid items)
+ int valid_items = even_share.block_end - even_share.block_offset;
+ ConsumeTile<true>(thread_aggregate, even_share.block_offset, valid_items, Int2Type<false>(), can_vectorize);
+ return BlockReduceT(temp_storage.reduce).Reduce(thread_aggregate, reduction_op, valid_items);
+ }
+
+ // At least one full block
+ ConsumeTile<true>(thread_aggregate, even_share.block_offset, TILE_ITEMS, Int2Type<true>(), can_vectorize);
+ even_share.block_offset += even_share.block_stride;
+
+ // Consume subsequent full tiles of input
+ while (even_share.block_offset + TILE_ITEMS <= even_share.block_end)
+ {
+ ConsumeTile<false>(thread_aggregate, even_share.block_offset, TILE_ITEMS, Int2Type<true>(), can_vectorize);
+ even_share.block_offset += even_share.block_stride;
+ }
+
+ // Consume a partially-full tile
+ if (even_share.block_offset < even_share.block_end)
+ {
+ int valid_items = even_share.block_end - even_share.block_offset;
+ ConsumeTile<false>(thread_aggregate, even_share.block_offset, valid_items, Int2Type<false>(), can_vectorize);
+ }
+
+ // Compute block-wide reduction (all threads have valid items)
+ return BlockReduceT(temp_storage.reduce).Reduce(thread_aggregate, reduction_op);
+ }
+
+
+ /**
+ * \brief Reduce a contiguous segment of input tiles
+ */
+ __device__ __forceinline__ OutputT ConsumeRange(
+ OffsetT block_offset, ///< [in] Threadblock begin offset (inclusive)
+ OffsetT block_end) ///< [in] Threadblock end offset (exclusive)
+ {
+ GridEvenShare<OffsetT> even_share;
+ even_share.template BlockInit<TILE_ITEMS>(block_offset, block_end);
+
+ return (IsAligned(d_in + block_offset, Int2Type<ATTEMPT_VECTORIZATION>())) ?
+ ConsumeRange(even_share, Int2Type<true && ATTEMPT_VECTORIZATION>()) :
+ ConsumeRange(even_share, Int2Type<false && ATTEMPT_VECTORIZATION>());
+ }
+
+
+ /**
+ * Reduce a contiguous segment of input tiles
+ */
+ __device__ __forceinline__ OutputT ConsumeTiles(
+ GridEvenShare<OffsetT> &even_share) ///< [in] GridEvenShare descriptor
+ {
+ // Initialize GRID_MAPPING_STRIP_MINE even-share descriptor for this thread block
+ even_share.template BlockInit<TILE_ITEMS, GRID_MAPPING_STRIP_MINE>();
+
+ return (IsAligned(d_in, Int2Type<ATTEMPT_VECTORIZATION>())) ?
+ ConsumeRange(even_share, Int2Type<true && ATTEMPT_VECTORIZATION>()) :
+ ConsumeRange(even_share, Int2Type<false && ATTEMPT_VECTORIZATION>());
+
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce_by_key.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce_by_key.cuh
new file mode 100644
index 0000000..51964d3
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_reduce_by_key.cuh
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * 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::AgentReduceByKey implements a stateful abstraction of CUDA thread blocks for participating in device-wide reduce-value-by-key.
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "single_pass_scan_operators.cuh"
+#include "../block/block_load.cuh"
+#include "../block/block_store.cuh"
+#include "../block/block_scan.cuh"
+#include "../block/block_discontinuity.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../iterator/constant_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentReduceByKey
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading input elements
+ BlockScanAlgorithm _SCAN_ALGORITHM> ///< The BlockScan algorithm to use
+struct AgentReduceByKeyPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+};
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentReduceByKey implements a stateful abstraction of CUDA thread blocks for participating in device-wide reduce-value-by-key
+ */
+template <
+ typename AgentReduceByKeyPolicyT, ///< Parameterized AgentReduceByKeyPolicy 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 items selected
+ typename EqualityOpT, ///< KeyT equality operator type
+ typename ReductionOpT, ///< ValueT reduction operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct AgentReduceByKey
+{
+ //---------------------------------------------------------------------
+ // 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
+
+ // Tuple type for scanning (pairs accumulated segment-value with segment-index)
+ typedef KeyValuePair<OffsetT, ValueOutputT> OffsetValuePairT;
+
+ // Tuple type for pairing keys and values
+ typedef KeyValuePair<KeyOutputT, ValueOutputT> KeyValuePairT;
+
+ // Tile status descriptor interface type
+ typedef ReduceByKeyScanTileState<ValueOutputT, OffsetT> ScanTileStateT;
+
+ // Guarded inequality functor
+ template <typename _EqualityOpT>
+ struct GuardedInequalityWrapper
+ {
+ _EqualityOpT op; ///< Wrapped equality operator
+ int num_remaining; ///< Items remaining
+
+ /// Constructor
+ __host__ __device__ __forceinline__
+ GuardedInequalityWrapper(_EqualityOpT op, int num_remaining) : op(op), num_remaining(num_remaining) {}
+
+ /// Boolean inequality operator, returns <tt>(a != b)</tt>
+ template <typename T>
+ __host__ __device__ __forceinline__ bool operator()(const T &a, const T &b, int idx) const
+ {
+ if (idx < num_remaining)
+ return !op(a, b); // In bounds
+
+ // Return true if first out-of-bounds item, false otherwise
+ return (idx == num_remaining);
+ }
+ };
+
+
+ // Constants
+ enum
+ {
+ BLOCK_THREADS = AgentReduceByKeyPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentReduceByKeyPolicyT::ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ TWO_PHASE_SCATTER = (ITEMS_PER_THREAD > 1),
+
+ // Whether or not the scan operation has a zero-valued identity value (true if we're performing addition on a primitive type)
+ HAS_IDENTITY_ZERO = (Equals<ReductionOpT, cub::Sum>::VALUE) && (Traits<ValueOutputT>::PRIMITIVE),
+ };
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for keys
+ typedef typename If<IsPointer<KeysInputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentReduceByKeyPolicyT::LOAD_MODIFIER, KeyInputT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ KeysInputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedKeysInputIteratorT;
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for values
+ typedef typename If<IsPointer<ValuesInputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentReduceByKeyPolicyT::LOAD_MODIFIER, ValueInputT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ ValuesInputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedValuesInputIteratorT;
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for fixup values
+ typedef typename If<IsPointer<AggregatesOutputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentReduceByKeyPolicyT::LOAD_MODIFIER, ValueInputT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ AggregatesOutputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedFixupInputIteratorT;
+
+ // Reduce-value-by-segment scan operator
+ typedef ReduceBySegmentOp<ReductionOpT> ReduceBySegmentOpT;
+
+ // Parameterized BlockLoad type for keys
+ typedef BlockLoad<
+ KeyOutputT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ AgentReduceByKeyPolicyT::LOAD_ALGORITHM>
+ BlockLoadKeysT;
+
+ // Parameterized BlockLoad type for values
+ typedef BlockLoad<
+ ValueOutputT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ AgentReduceByKeyPolicyT::LOAD_ALGORITHM>
+ BlockLoadValuesT;
+
+ // Parameterized BlockDiscontinuity type for keys
+ typedef BlockDiscontinuity<
+ KeyOutputT,
+ BLOCK_THREADS>
+ BlockDiscontinuityKeys;
+
+ // Parameterized BlockScan type
+ typedef BlockScan<
+ OffsetValuePairT,
+ BLOCK_THREADS,
+ AgentReduceByKeyPolicyT::SCAN_ALGORITHM>
+ BlockScanT;
+
+ // Callback type for obtaining tile prefix during block scan
+ typedef TilePrefixCallbackOp<
+ OffsetValuePairT,
+ ReduceBySegmentOpT,
+ ScanTileStateT>
+ TilePrefixCallbackOpT;
+
+ // Key and value exchange types
+ typedef KeyOutputT KeyExchangeT[TILE_ITEMS + 1];
+ typedef ValueOutputT ValueExchangeT[TILE_ITEMS + 1];
+
+ // Shared memory type for this thread block
+ union _TempStorage
+ {
+ struct
+ {
+ typename BlockScanT::TempStorage scan; // Smem needed for tile scanning
+ typename TilePrefixCallbackOpT::TempStorage prefix; // Smem needed for cooperative prefix callback
+ typename BlockDiscontinuityKeys::TempStorage discontinuity; // Smem needed for discontinuity detection
+ };
+
+ // Smem needed for loading keys
+ typename BlockLoadKeysT::TempStorage load_keys;
+
+ // Smem needed for loading values
+ typename BlockLoadValuesT::TempStorage load_values;
+
+ // Smem needed for compacting key value pairs(allows non POD items in this union)
+ Uninitialized<KeyValuePairT[TILE_ITEMS + 1]> raw_exchange;
+ };
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ _TempStorage& temp_storage; ///< Reference to temp_storage
+ WrappedKeysInputIteratorT d_keys_in; ///< Input keys
+ UniqueOutputIteratorT d_unique_out; ///< Unique output keys
+ WrappedValuesInputIteratorT d_values_in; ///< Input values
+ AggregatesOutputIteratorT d_aggregates_out; ///< Output value aggregates
+ NumRunsOutputIteratorT d_num_runs_out; ///< Output pointer for total number of segments identified
+ EqualityOpT equality_op; ///< KeyT equality operator
+ ReductionOpT reduction_op; ///< Reduction operator
+ ReduceBySegmentOpT scan_op; ///< Reduce-by-segment scan operator
+
+
+ //---------------------------------------------------------------------
+ // Constructor
+ //---------------------------------------------------------------------
+
+ // Constructor
+ __device__ __forceinline__
+ AgentReduceByKey(
+ TempStorage& temp_storage, ///< Reference to temp_storage
+ KeysInputIteratorT d_keys_in, ///< Input keys
+ UniqueOutputIteratorT d_unique_out, ///< Unique output keys
+ ValuesInputIteratorT d_values_in, ///< Input values
+ AggregatesOutputIteratorT d_aggregates_out, ///< Output value aggregates
+ NumRunsOutputIteratorT d_num_runs_out, ///< Output pointer for total number of segments identified
+ EqualityOpT equality_op, ///< KeyT equality operator
+ ReductionOpT reduction_op) ///< ValueT reduction operator
+ :
+ temp_storage(temp_storage.Alias()),
+ d_keys_in(d_keys_in),
+ d_unique_out(d_unique_out),
+ d_values_in(d_values_in),
+ d_aggregates_out(d_aggregates_out),
+ d_num_runs_out(d_num_runs_out),
+ equality_op(equality_op),
+ reduction_op(reduction_op),
+ scan_op(reduction_op)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Scatter utility methods
+ //---------------------------------------------------------------------
+
+ /**
+ * Directly scatter flagged items to output offsets
+ */
+ __device__ __forceinline__ void ScatterDirect(
+ KeyValuePairT (&scatter_items)[ITEMS_PER_THREAD],
+ OffsetT (&segment_flags)[ITEMS_PER_THREAD],
+ OffsetT (&segment_indices)[ITEMS_PER_THREAD])
+ {
+ // Scatter flagged keys and values
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (segment_flags[ITEM])
+ {
+ d_unique_out[segment_indices[ITEM]] = scatter_items[ITEM].key;
+ d_aggregates_out[segment_indices[ITEM]] = scatter_items[ITEM].value;
+ }
+ }
+ }
+
+
+ /**
+ * 2-phase scatter flagged items to output offsets
+ *
+ * The exclusive scan causes each head flag to be paired with the previous
+ * value aggregate: the scatter offsets must be decremented for value aggregates
+ */
+ __device__ __forceinline__ void ScatterTwoPhase(
+ KeyValuePairT (&scatter_items)[ITEMS_PER_THREAD],
+ OffsetT (&segment_flags)[ITEMS_PER_THREAD],
+ OffsetT (&segment_indices)[ITEMS_PER_THREAD],
+ OffsetT num_tile_segments,
+ OffsetT num_tile_segments_prefix)
+ {
+ CTA_SYNC();
+
+ // Compact and scatter pairs
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (segment_flags[ITEM])
+ {
+ temp_storage.raw_exchange.Alias()[segment_indices[ITEM] - num_tile_segments_prefix] = scatter_items[ITEM];
+ }
+ }
+
+ CTA_SYNC();
+
+ for (int item = threadIdx.x; item < num_tile_segments; item += BLOCK_THREADS)
+ {
+ KeyValuePairT pair = temp_storage.raw_exchange.Alias()[item];
+ d_unique_out[num_tile_segments_prefix + item] = pair.key;
+ d_aggregates_out[num_tile_segments_prefix + item] = pair.value;
+ }
+ }
+
+
+ /**
+ * Scatter flagged items
+ */
+ __device__ __forceinline__ void Scatter(
+ KeyValuePairT (&scatter_items)[ITEMS_PER_THREAD],
+ OffsetT (&segment_flags)[ITEMS_PER_THREAD],
+ OffsetT (&segment_indices)[ITEMS_PER_THREAD],
+ OffsetT num_tile_segments,
+ OffsetT num_tile_segments_prefix)
+ {
+ // Do a one-phase scatter if (a) two-phase is disabled or (b) the average number of selected items per thread is less than one
+ if (TWO_PHASE_SCATTER && (num_tile_segments > BLOCK_THREADS))
+ {
+ ScatterTwoPhase(
+ scatter_items,
+ segment_flags,
+ segment_indices,
+ num_tile_segments,
+ num_tile_segments_prefix);
+ }
+ else
+ {
+ ScatterDirect(
+ scatter_items,
+ segment_flags,
+ segment_indices);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Cooperatively scan a device-wide sequence of tiles with other CTAs
+ //---------------------------------------------------------------------
+
+ /**
+ * Process a tile of input (dynamic chained scan)
+ */
+ template <bool IS_LAST_TILE> ///< Whether the current tile is the last tile
+ __device__ __forceinline__ void ConsumeTile(
+ OffsetT num_remaining, ///< Number of global input items remaining (including this tile)
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state) ///< Global tile state descriptor
+ {
+ KeyOutputT keys[ITEMS_PER_THREAD]; // Tile keys
+ KeyOutputT prev_keys[ITEMS_PER_THREAD]; // Tile keys shuffled up
+ ValueOutputT values[ITEMS_PER_THREAD]; // Tile values
+ OffsetT head_flags[ITEMS_PER_THREAD]; // Segment head flags
+ OffsetT segment_indices[ITEMS_PER_THREAD]; // Segment indices
+ OffsetValuePairT scan_items[ITEMS_PER_THREAD]; // Zipped values and segment flags|indices
+ KeyValuePairT scatter_items[ITEMS_PER_THREAD]; // Zipped key value pairs for scattering
+
+ // Load keys
+ if (IS_LAST_TILE)
+ BlockLoadKeysT(temp_storage.load_keys).Load(d_keys_in + tile_offset, keys, num_remaining);
+ else
+ BlockLoadKeysT(temp_storage.load_keys).Load(d_keys_in + tile_offset, keys);
+
+ // Load tile predecessor key in first thread
+ KeyOutputT tile_predecessor;
+ if (threadIdx.x == 0)
+ {
+ tile_predecessor = (tile_idx == 0) ?
+ keys[0] : // First tile gets repeat of first item (thus first item will not be flagged as a head)
+ d_keys_in[tile_offset - 1]; // Subsequent tiles get last key from previous tile
+ }
+
+ CTA_SYNC();
+
+ // Load values
+ if (IS_LAST_TILE)
+ BlockLoadValuesT(temp_storage.load_values).Load(d_values_in + tile_offset, values, num_remaining);
+ else
+ BlockLoadValuesT(temp_storage.load_values).Load(d_values_in + tile_offset, values);
+
+ CTA_SYNC();
+
+ // Initialize head-flags and shuffle up the previous keys
+ if (IS_LAST_TILE)
+ {
+ // Use custom flag operator to additionally flag the first out-of-bounds item
+ GuardedInequalityWrapper<EqualityOpT> flag_op(equality_op, num_remaining);
+ BlockDiscontinuityKeys(temp_storage.discontinuity).FlagHeads(
+ head_flags, keys, prev_keys, flag_op, tile_predecessor);
+ }
+ else
+ {
+ InequalityWrapper<EqualityOpT> flag_op(equality_op);
+ BlockDiscontinuityKeys(temp_storage.discontinuity).FlagHeads(
+ head_flags, keys, prev_keys, flag_op, tile_predecessor);
+ }
+
+ // Zip values and head flags
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ scan_items[ITEM].value = values[ITEM];
+ scan_items[ITEM].key = head_flags[ITEM];
+ }
+
+ // Perform exclusive tile scan
+ OffsetValuePairT block_aggregate; // Inclusive block-wide scan aggregate
+ OffsetT num_segments_prefix; // Number of segments prior to this tile
+ OffsetValuePairT total_aggregate; // The tile prefix folded with block_aggregate
+ if (tile_idx == 0)
+ {
+ // Scan first tile
+ BlockScanT(temp_storage.scan).ExclusiveScan(scan_items, scan_items, scan_op, block_aggregate);
+ num_segments_prefix = 0;
+ total_aggregate = block_aggregate;
+
+ // Update tile status if there are successor tiles
+ if ((!IS_LAST_TILE) && (threadIdx.x == 0))
+ tile_state.SetInclusive(0, block_aggregate);
+ }
+ else
+ {
+ // Scan non-first tile
+ TilePrefixCallbackOpT prefix_op(tile_state, temp_storage.prefix, scan_op, tile_idx);
+ BlockScanT(temp_storage.scan).ExclusiveScan(scan_items, scan_items, scan_op, prefix_op);
+
+ block_aggregate = prefix_op.GetBlockAggregate();
+ num_segments_prefix = prefix_op.GetExclusivePrefix().key;
+ total_aggregate = prefix_op.GetInclusivePrefix();
+ }
+
+ // Rezip scatter items and segment indices
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ scatter_items[ITEM].key = prev_keys[ITEM];
+ scatter_items[ITEM].value = scan_items[ITEM].value;
+ segment_indices[ITEM] = scan_items[ITEM].key;
+ }
+
+ // At this point, each flagged segment head has:
+ // - The key for the previous segment
+ // - The reduced value from the previous segment
+ // - The segment index for the reduced value
+
+ // Scatter flagged keys and values
+ OffsetT num_tile_segments = block_aggregate.key;
+ Scatter(scatter_items, head_flags, segment_indices, num_tile_segments, num_segments_prefix);
+
+ // Last thread in last tile will output final count (and last pair, if necessary)
+ if ((IS_LAST_TILE) && (threadIdx.x == BLOCK_THREADS - 1))
+ {
+ OffsetT num_segments = num_segments_prefix + num_tile_segments;
+
+ // If the last tile is a whole tile, output the final_value
+ if (num_remaining == TILE_ITEMS)
+ {
+ d_unique_out[num_segments] = keys[ITEMS_PER_THREAD - 1];
+ d_aggregates_out[num_segments] = total_aggregate.value;
+ num_segments++;
+ }
+
+ // Output the total number of items selected
+ *d_num_runs_out = num_segments;
+ }
+ }
+
+
+ /**
+ * Scan tiles of items as part of a dynamic chained scan
+ */
+ __device__ __forceinline__ void ConsumeRange(
+ int num_items, ///< Total number of input items
+ ScanTileStateT& tile_state, ///< Global tile state descriptor
+ int start_tile) ///< The starting tile for the current grid
+ {
+ // Blocks are launched in increasing order, so just assign one tile per block
+ int tile_idx = start_tile + blockIdx.x; // Current tile index
+ OffsetT tile_offset = OffsetT(TILE_ITEMS) * tile_idx; // Global offset for the current tile
+ OffsetT num_remaining = num_items - tile_offset; // Remaining items (including this tile)
+
+ if (num_remaining > TILE_ITEMS)
+ {
+ // Not last tile
+ ConsumeTile<false>(num_remaining, tile_idx, tile_offset, tile_state);
+ }
+ else if (num_remaining > 0)
+ {
+ // Last tile
+ ConsumeTile<true>(num_remaining, tile_idx, tile_offset, tile_state);
+ }
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_rle.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_rle.cuh
new file mode 100644
index 0000000..cb7a4a6
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_rle.cuh
@@ -0,0 +1,837 @@
+/******************************************************************************
+ * 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::AgentRle implements a stateful abstraction of CUDA thread blocks for participating in device-wide run-length-encode.
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "single_pass_scan_operators.cuh"
+#include "../block/block_load.cuh"
+#include "../block/block_store.cuh"
+#include "../block/block_scan.cuh"
+#include "../block/block_exchange.cuh"
+#include "../block/block_discontinuity.cuh"
+#include "../grid/grid_queue.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../iterator/constant_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentRle
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading input elements
+ bool _STORE_WARP_TIME_SLICING, ///< Whether or not only one warp's worth of shared memory should be allocated and time-sliced among block-warps during any store-related data transpositions (versus each warp having its own storage)
+ BlockScanAlgorithm _SCAN_ALGORITHM> ///< The BlockScan algorithm to use
+struct AgentRlePolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ STORE_WARP_TIME_SLICING = _STORE_WARP_TIME_SLICING, ///< Whether or not only one warp's worth of shared memory should be allocated and time-sliced among block-warps during any store-related data transpositions (versus each warp having its own storage)
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+};
+
+
+
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentRle implements a stateful abstraction of CUDA thread blocks for participating in device-wide run-length-encode
+ */
+template <
+ typename AgentRlePolicyT, ///< Parameterized AgentRlePolicyT tuning policy type
+ typename InputIteratorT, ///< Random-access input iterator type for data
+ typename OffsetsOutputIteratorT, ///< Random-access output iterator type for offset values
+ typename LengthsOutputIteratorT, ///< Random-access output iterator type for length values
+ typename EqualityOpT, ///< T equality operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct AgentRle
+{
+ //---------------------------------------------------------------------
+ // 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
+
+ /// Tuple type for scanning (pairs run-length and run-index)
+ typedef KeyValuePair<OffsetT, LengthT> LengthOffsetPair;
+
+ /// Tile status descriptor interface type
+ typedef ReduceByKeyScanTileState<LengthT, OffsetT> ScanTileStateT;
+
+ // Constants
+ enum
+ {
+ WARP_THREADS = CUB_WARP_THREADS(PTX_ARCH),
+ BLOCK_THREADS = AgentRlePolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentRlePolicyT::ITEMS_PER_THREAD,
+ WARP_ITEMS = WARP_THREADS * ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ WARPS = (BLOCK_THREADS + WARP_THREADS - 1) / WARP_THREADS,
+
+ /// Whether or not to sync after loading data
+ SYNC_AFTER_LOAD = (AgentRlePolicyT::LOAD_ALGORITHM != BLOCK_LOAD_DIRECT),
+
+ /// Whether or not only one warp's worth of shared memory should be allocated and time-sliced among block-warps during any store-related data transpositions (versus each warp having its own storage)
+ STORE_WARP_TIME_SLICING = AgentRlePolicyT::STORE_WARP_TIME_SLICING,
+ ACTIVE_EXCHANGE_WARPS = (STORE_WARP_TIME_SLICING) ? 1 : WARPS,
+ };
+
+
+ /**
+ * Special operator that signals all out-of-bounds items are not equal to everything else,
+ * forcing both (1) the last item to be tail-flagged and (2) all oob items to be marked
+ * trivial.
+ */
+ template <bool LAST_TILE>
+ struct OobInequalityOp
+ {
+ OffsetT num_remaining;
+ EqualityOpT equality_op;
+
+ __device__ __forceinline__ OobInequalityOp(
+ OffsetT num_remaining,
+ EqualityOpT equality_op)
+ :
+ num_remaining(num_remaining),
+ equality_op(equality_op)
+ {}
+
+ template <typename Index>
+ __host__ __device__ __forceinline__ bool operator()(T first, T second, Index idx)
+ {
+ if (!LAST_TILE || (idx < num_remaining))
+ return !equality_op(first, second);
+ else
+ return true;
+ }
+ };
+
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for data
+ typedef typename If<IsPointer<InputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentRlePolicyT::LOAD_MODIFIER, T, OffsetT>, // Wrap the native input pointer with CacheModifiedVLengthnputIterator
+ InputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedInputIteratorT;
+
+ // Parameterized BlockLoad type for data
+ typedef BlockLoad<
+ T,
+ AgentRlePolicyT::BLOCK_THREADS,
+ AgentRlePolicyT::ITEMS_PER_THREAD,
+ AgentRlePolicyT::LOAD_ALGORITHM>
+ BlockLoadT;
+
+ // Parameterized BlockDiscontinuity type for data
+ typedef BlockDiscontinuity<T, BLOCK_THREADS> BlockDiscontinuityT;
+
+ // Parameterized WarpScan type
+ typedef WarpScan<LengthOffsetPair> WarpScanPairs;
+
+ // Reduce-length-by-run scan operator
+ typedef ReduceBySegmentOp<cub::Sum> ReduceBySegmentOpT;
+
+ // Callback type for obtaining tile prefix during block scan
+ typedef TilePrefixCallbackOp<
+ LengthOffsetPair,
+ ReduceBySegmentOpT,
+ ScanTileStateT>
+ TilePrefixCallbackOpT;
+
+ // Warp exchange types
+ typedef WarpExchange<LengthOffsetPair, ITEMS_PER_THREAD> WarpExchangePairs;
+
+ typedef typename If<STORE_WARP_TIME_SLICING, typename WarpExchangePairs::TempStorage, NullType>::Type WarpExchangePairsStorage;
+
+ typedef WarpExchange<OffsetT, ITEMS_PER_THREAD> WarpExchangeOffsets;
+ typedef WarpExchange<LengthT, ITEMS_PER_THREAD> WarpExchangeLengths;
+
+ typedef LengthOffsetPair WarpAggregates[WARPS];
+
+ // Shared memory type for this thread block
+ struct _TempStorage
+ {
+ // Aliasable storage layout
+ union Aliasable
+ {
+ struct
+ {
+ typename BlockDiscontinuityT::TempStorage discontinuity; // Smem needed for discontinuity detection
+ typename WarpScanPairs::TempStorage warp_scan[WARPS]; // Smem needed for warp-synchronous scans
+ Uninitialized<LengthOffsetPair[WARPS]> warp_aggregates; // Smem needed for sharing warp-wide aggregates
+ typename TilePrefixCallbackOpT::TempStorage prefix; // Smem needed for cooperative prefix callback
+ };
+
+ // Smem needed for input loading
+ typename BlockLoadT::TempStorage load;
+
+ // Aliasable layout needed for two-phase scatter
+ union ScatterAliasable
+ {
+ unsigned long long align;
+ WarpExchangePairsStorage exchange_pairs[ACTIVE_EXCHANGE_WARPS];
+ typename WarpExchangeOffsets::TempStorage exchange_offsets[ACTIVE_EXCHANGE_WARPS];
+ typename WarpExchangeLengths::TempStorage exchange_lengths[ACTIVE_EXCHANGE_WARPS];
+
+ } scatter_aliasable;
+
+ } aliasable;
+
+ OffsetT tile_idx; // Shared tile index
+ LengthOffsetPair tile_inclusive; // Inclusive tile prefix
+ LengthOffsetPair tile_exclusive; // Exclusive tile prefix
+ };
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ _TempStorage& temp_storage; ///< Reference to temp_storage
+
+ WrappedInputIteratorT d_in; ///< Pointer to input sequence of data items
+ OffsetsOutputIteratorT d_offsets_out; ///< Input run offsets
+ LengthsOutputIteratorT d_lengths_out; ///< Output run lengths
+
+ EqualityOpT equality_op; ///< T equality operator
+ ReduceBySegmentOpT scan_op; ///< Reduce-length-by-flag scan operator
+ OffsetT num_items; ///< Total number of input items
+
+
+ //---------------------------------------------------------------------
+ // Constructor
+ //---------------------------------------------------------------------
+
+ // Constructor
+ __device__ __forceinline__
+ AgentRle(
+ TempStorage &temp_storage, ///< [in] Reference to temp_storage
+ 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
+ EqualityOpT equality_op, ///< [in] T equality operator
+ OffsetT num_items) ///< [in] Total number of input items
+ :
+ temp_storage(temp_storage.Alias()),
+ d_in(d_in),
+ d_offsets_out(d_offsets_out),
+ d_lengths_out(d_lengths_out),
+ equality_op(equality_op),
+ scan_op(cub::Sum()),
+ num_items(num_items)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Utility methods for initializing the selections
+ //---------------------------------------------------------------------
+
+ template <bool FIRST_TILE, bool LAST_TILE>
+ __device__ __forceinline__ void InitializeSelections(
+ OffsetT tile_offset,
+ OffsetT num_remaining,
+ T (&items)[ITEMS_PER_THREAD],
+ LengthOffsetPair (&lengths_and_num_runs)[ITEMS_PER_THREAD])
+ {
+ bool head_flags[ITEMS_PER_THREAD];
+ bool tail_flags[ITEMS_PER_THREAD];
+
+ OobInequalityOp<LAST_TILE> inequality_op(num_remaining, equality_op);
+
+ if (FIRST_TILE && LAST_TILE)
+ {
+ // First-and-last-tile always head-flags the first item and tail-flags the last item
+
+ BlockDiscontinuityT(temp_storage.aliasable.discontinuity).FlagHeadsAndTails(
+ head_flags, tail_flags, items, inequality_op);
+ }
+ else if (FIRST_TILE)
+ {
+ // First-tile always head-flags the first item
+
+ // Get the first item from the next tile
+ T tile_successor_item;
+ if (threadIdx.x == BLOCK_THREADS - 1)
+ tile_successor_item = d_in[tile_offset + TILE_ITEMS];
+
+ BlockDiscontinuityT(temp_storage.aliasable.discontinuity).FlagHeadsAndTails(
+ head_flags, tail_flags, tile_successor_item, items, inequality_op);
+ }
+ else if (LAST_TILE)
+ {
+ // Last-tile always flags the last item
+
+ // Get the last item from the previous tile
+ T tile_predecessor_item;
+ if (threadIdx.x == 0)
+ tile_predecessor_item = d_in[tile_offset - 1];
+
+ BlockDiscontinuityT(temp_storage.aliasable.discontinuity).FlagHeadsAndTails(
+ head_flags, tile_predecessor_item, tail_flags, items, inequality_op);
+ }
+ else
+ {
+ // Get the first item from the next tile
+ T tile_successor_item;
+ if (threadIdx.x == BLOCK_THREADS - 1)
+ tile_successor_item = d_in[tile_offset + TILE_ITEMS];
+
+ // Get the last item from the previous tile
+ T tile_predecessor_item;
+ if (threadIdx.x == 0)
+ tile_predecessor_item = d_in[tile_offset - 1];
+
+ BlockDiscontinuityT(temp_storage.aliasable.discontinuity).FlagHeadsAndTails(
+ head_flags, tile_predecessor_item, tail_flags, tile_successor_item, items, inequality_op);
+ }
+
+ // Zip counts and runs
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ lengths_and_num_runs[ITEM].key = head_flags[ITEM] && (!tail_flags[ITEM]);
+ lengths_and_num_runs[ITEM].value = ((!head_flags[ITEM]) || (!tail_flags[ITEM]));
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // Scan utility methods
+ //---------------------------------------------------------------------
+
+ /**
+ * Scan of allocations
+ */
+ __device__ __forceinline__ void WarpScanAllocations(
+ LengthOffsetPair &tile_aggregate,
+ LengthOffsetPair &warp_aggregate,
+ LengthOffsetPair &warp_exclusive_in_tile,
+ LengthOffsetPair &thread_exclusive_in_warp,
+ LengthOffsetPair (&lengths_and_num_runs)[ITEMS_PER_THREAD])
+ {
+ // Perform warpscans
+ unsigned int warp_id = ((WARPS == 1) ? 0 : threadIdx.x / WARP_THREADS);
+ int lane_id = LaneId();
+
+ LengthOffsetPair identity;
+ identity.key = 0;
+ identity.value = 0;
+
+ LengthOffsetPair thread_inclusive;
+ LengthOffsetPair thread_aggregate = internal::ThreadReduce(lengths_and_num_runs, scan_op);
+ WarpScanPairs(temp_storage.aliasable.warp_scan[warp_id]).Scan(
+ thread_aggregate,
+ thread_inclusive,
+ thread_exclusive_in_warp,
+ identity,
+ scan_op);
+
+ // Last lane in each warp shares its warp-aggregate
+ if (lane_id == WARP_THREADS - 1)
+ temp_storage.aliasable.warp_aggregates.Alias()[warp_id] = thread_inclusive;
+
+ CTA_SYNC();
+
+ // Accumulate total selected and the warp-wide prefix
+ warp_exclusive_in_tile = identity;
+ warp_aggregate = temp_storage.aliasable.warp_aggregates.Alias()[warp_id];
+ tile_aggregate = temp_storage.aliasable.warp_aggregates.Alias()[0];
+
+ #pragma unroll
+ for (int WARP = 1; WARP < WARPS; ++WARP)
+ {
+ if (warp_id == WARP)
+ warp_exclusive_in_tile = tile_aggregate;
+
+ tile_aggregate = scan_op(tile_aggregate, temp_storage.aliasable.warp_aggregates.Alias()[WARP]);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Utility methods for scattering selections
+ //---------------------------------------------------------------------
+
+ /**
+ * Two-phase scatter, specialized for warp time-slicing
+ */
+ template <bool FIRST_TILE>
+ __device__ __forceinline__ void ScatterTwoPhase(
+ OffsetT tile_num_runs_exclusive_in_global,
+ OffsetT warp_num_runs_aggregate,
+ OffsetT warp_num_runs_exclusive_in_tile,
+ OffsetT (&thread_num_runs_exclusive_in_warp)[ITEMS_PER_THREAD],
+ LengthOffsetPair (&lengths_and_offsets)[ITEMS_PER_THREAD],
+ Int2Type<true> is_warp_time_slice)
+ {
+ unsigned int warp_id = ((WARPS == 1) ? 0 : threadIdx.x / WARP_THREADS);
+ int lane_id = LaneId();
+
+ // Locally compact items within the warp (first warp)
+ if (warp_id == 0)
+ {
+ WarpExchangePairs(temp_storage.aliasable.scatter_aliasable.exchange_pairs[0]).ScatterToStriped(
+ lengths_and_offsets, thread_num_runs_exclusive_in_warp);
+ }
+
+ // Locally compact items within the warp (remaining warps)
+ #pragma unroll
+ for (int SLICE = 1; SLICE < WARPS; ++SLICE)
+ {
+ CTA_SYNC();
+
+ if (warp_id == SLICE)
+ {
+ WarpExchangePairs(temp_storage.aliasable.scatter_aliasable.exchange_pairs[0]).ScatterToStriped(
+ lengths_and_offsets, thread_num_runs_exclusive_in_warp);
+ }
+ }
+
+ // Global scatter
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if ((ITEM * WARP_THREADS) < warp_num_runs_aggregate - lane_id)
+ {
+ OffsetT item_offset =
+ tile_num_runs_exclusive_in_global +
+ warp_num_runs_exclusive_in_tile +
+ (ITEM * WARP_THREADS) + lane_id;
+
+ // Scatter offset
+ d_offsets_out[item_offset] = lengths_and_offsets[ITEM].key;
+
+ // Scatter length if not the first (global) length
+ if ((!FIRST_TILE) || (ITEM != 0) || (threadIdx.x > 0))
+ {
+ d_lengths_out[item_offset - 1] = lengths_and_offsets[ITEM].value;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Two-phase scatter
+ */
+ template <bool FIRST_TILE>
+ __device__ __forceinline__ void ScatterTwoPhase(
+ OffsetT tile_num_runs_exclusive_in_global,
+ OffsetT warp_num_runs_aggregate,
+ OffsetT warp_num_runs_exclusive_in_tile,
+ OffsetT (&thread_num_runs_exclusive_in_warp)[ITEMS_PER_THREAD],
+ LengthOffsetPair (&lengths_and_offsets)[ITEMS_PER_THREAD],
+ Int2Type<false> is_warp_time_slice)
+ {
+ unsigned int warp_id = ((WARPS == 1) ? 0 : threadIdx.x / WARP_THREADS);
+ int lane_id = LaneId();
+
+ // Unzip
+ OffsetT run_offsets[ITEMS_PER_THREAD];
+ LengthT run_lengths[ITEMS_PER_THREAD];
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ run_offsets[ITEM] = lengths_and_offsets[ITEM].key;
+ run_lengths[ITEM] = lengths_and_offsets[ITEM].value;
+ }
+
+ WarpExchangeOffsets(temp_storage.aliasable.scatter_aliasable.exchange_offsets[warp_id]).ScatterToStriped(
+ run_offsets, thread_num_runs_exclusive_in_warp);
+
+ WARP_SYNC(0xffffffff);
+
+ WarpExchangeLengths(temp_storage.aliasable.scatter_aliasable.exchange_lengths[warp_id]).ScatterToStriped(
+ run_lengths, thread_num_runs_exclusive_in_warp);
+
+ // Global scatter
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ if ((ITEM * WARP_THREADS) + lane_id < warp_num_runs_aggregate)
+ {
+ OffsetT item_offset =
+ tile_num_runs_exclusive_in_global +
+ warp_num_runs_exclusive_in_tile +
+ (ITEM * WARP_THREADS) + lane_id;
+
+ // Scatter offset
+ d_offsets_out[item_offset] = run_offsets[ITEM];
+
+ // Scatter length if not the first (global) length
+ if ((!FIRST_TILE) || (ITEM != 0) || (threadIdx.x > 0))
+ {
+ d_lengths_out[item_offset - 1] = run_lengths[ITEM];
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Direct scatter
+ */
+ template <bool FIRST_TILE>
+ __device__ __forceinline__ void ScatterDirect(
+ OffsetT tile_num_runs_exclusive_in_global,
+ OffsetT warp_num_runs_aggregate,
+ OffsetT warp_num_runs_exclusive_in_tile,
+ OffsetT (&thread_num_runs_exclusive_in_warp)[ITEMS_PER_THREAD],
+ LengthOffsetPair (&lengths_and_offsets)[ITEMS_PER_THREAD])
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (thread_num_runs_exclusive_in_warp[ITEM] < warp_num_runs_aggregate)
+ {
+ OffsetT item_offset =
+ tile_num_runs_exclusive_in_global +
+ warp_num_runs_exclusive_in_tile +
+ thread_num_runs_exclusive_in_warp[ITEM];
+
+ // Scatter offset
+ d_offsets_out[item_offset] = lengths_and_offsets[ITEM].key;
+
+ // Scatter length if not the first (global) length
+ if (item_offset >= 1)
+ {
+ d_lengths_out[item_offset - 1] = lengths_and_offsets[ITEM].value;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Scatter
+ */
+ template <bool FIRST_TILE>
+ __device__ __forceinline__ void Scatter(
+ OffsetT tile_num_runs_aggregate,
+ OffsetT tile_num_runs_exclusive_in_global,
+ OffsetT warp_num_runs_aggregate,
+ OffsetT warp_num_runs_exclusive_in_tile,
+ OffsetT (&thread_num_runs_exclusive_in_warp)[ITEMS_PER_THREAD],
+ LengthOffsetPair (&lengths_and_offsets)[ITEMS_PER_THREAD])
+ {
+ if ((ITEMS_PER_THREAD == 1) || (tile_num_runs_aggregate < BLOCK_THREADS))
+ {
+ // Direct scatter if the warp has any items
+ if (warp_num_runs_aggregate)
+ {
+ ScatterDirect<FIRST_TILE>(
+ tile_num_runs_exclusive_in_global,
+ warp_num_runs_aggregate,
+ warp_num_runs_exclusive_in_tile,
+ thread_num_runs_exclusive_in_warp,
+ lengths_and_offsets);
+ }
+ }
+ else
+ {
+ // Scatter two phase
+ ScatterTwoPhase<FIRST_TILE>(
+ tile_num_runs_exclusive_in_global,
+ warp_num_runs_aggregate,
+ warp_num_runs_exclusive_in_tile,
+ thread_num_runs_exclusive_in_warp,
+ lengths_and_offsets,
+ Int2Type<STORE_WARP_TIME_SLICING>());
+ }
+ }
+
+
+
+ //---------------------------------------------------------------------
+ // Cooperatively scan a device-wide sequence of tiles with other CTAs
+ //---------------------------------------------------------------------
+
+ /**
+ * Process a tile of input (dynamic chained scan)
+ */
+ template <
+ bool LAST_TILE>
+ __device__ __forceinline__ LengthOffsetPair ConsumeTile(
+ OffsetT num_items, ///< Total number of global input items
+ OffsetT num_remaining, ///< Number of global input items remaining (including this tile)
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT &tile_status) ///< Global list of tile status
+ {
+ if (tile_idx == 0)
+ {
+ // First tile
+
+ // Load items
+ T items[ITEMS_PER_THREAD];
+ if (LAST_TILE)
+ BlockLoadT(temp_storage.aliasable.load).Load(d_in + tile_offset, items, num_remaining, T());
+ else
+ BlockLoadT(temp_storage.aliasable.load).Load(d_in + tile_offset, items);
+
+ if (SYNC_AFTER_LOAD)
+ CTA_SYNC();
+
+ // Set flags
+ LengthOffsetPair lengths_and_num_runs[ITEMS_PER_THREAD];
+
+ InitializeSelections<true, LAST_TILE>(
+ tile_offset,
+ num_remaining,
+ items,
+ lengths_and_num_runs);
+
+ // Exclusive scan of lengths and runs
+ LengthOffsetPair tile_aggregate;
+ LengthOffsetPair warp_aggregate;
+ LengthOffsetPair warp_exclusive_in_tile;
+ LengthOffsetPair thread_exclusive_in_warp;
+
+ WarpScanAllocations(
+ tile_aggregate,
+ warp_aggregate,
+ warp_exclusive_in_tile,
+ thread_exclusive_in_warp,
+ lengths_and_num_runs);
+
+ // Update tile status if this is not the last tile
+ if (!LAST_TILE && (threadIdx.x == 0))
+ tile_status.SetInclusive(0, tile_aggregate);
+
+ // Update thread_exclusive_in_warp to fold in warp run-length
+ if (thread_exclusive_in_warp.key == 0)
+ thread_exclusive_in_warp.value += warp_exclusive_in_tile.value;
+
+ LengthOffsetPair lengths_and_offsets[ITEMS_PER_THREAD];
+ OffsetT thread_num_runs_exclusive_in_warp[ITEMS_PER_THREAD];
+ LengthOffsetPair lengths_and_num_runs2[ITEMS_PER_THREAD];
+
+ // Downsweep scan through lengths_and_num_runs
+ internal::ThreadScanExclusive(lengths_and_num_runs, lengths_and_num_runs2, scan_op, thread_exclusive_in_warp);
+
+ // Zip
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ lengths_and_offsets[ITEM].value = lengths_and_num_runs2[ITEM].value;
+ lengths_and_offsets[ITEM].key = tile_offset + (threadIdx.x * ITEMS_PER_THREAD) + ITEM;
+ thread_num_runs_exclusive_in_warp[ITEM] = (lengths_and_num_runs[ITEM].key) ?
+ lengths_and_num_runs2[ITEM].key : // keep
+ WARP_THREADS * ITEMS_PER_THREAD; // discard
+ }
+
+ OffsetT tile_num_runs_aggregate = tile_aggregate.key;
+ OffsetT tile_num_runs_exclusive_in_global = 0;
+ OffsetT warp_num_runs_aggregate = warp_aggregate.key;
+ OffsetT warp_num_runs_exclusive_in_tile = warp_exclusive_in_tile.key;
+
+ // Scatter
+ Scatter<true>(
+ tile_num_runs_aggregate,
+ tile_num_runs_exclusive_in_global,
+ warp_num_runs_aggregate,
+ warp_num_runs_exclusive_in_tile,
+ thread_num_runs_exclusive_in_warp,
+ lengths_and_offsets);
+
+ // Return running total (inclusive of this tile)
+ return tile_aggregate;
+ }
+ else
+ {
+ // Not first tile
+
+ // Load items
+ T items[ITEMS_PER_THREAD];
+ if (LAST_TILE)
+ BlockLoadT(temp_storage.aliasable.load).Load(d_in + tile_offset, items, num_remaining, T());
+ else
+ BlockLoadT(temp_storage.aliasable.load).Load(d_in + tile_offset, items);
+
+ if (SYNC_AFTER_LOAD)
+ CTA_SYNC();
+
+ // Set flags
+ LengthOffsetPair lengths_and_num_runs[ITEMS_PER_THREAD];
+
+ InitializeSelections<false, LAST_TILE>(
+ tile_offset,
+ num_remaining,
+ items,
+ lengths_and_num_runs);
+
+ // Exclusive scan of lengths and runs
+ LengthOffsetPair tile_aggregate;
+ LengthOffsetPair warp_aggregate;
+ LengthOffsetPair warp_exclusive_in_tile;
+ LengthOffsetPair thread_exclusive_in_warp;
+
+ WarpScanAllocations(
+ tile_aggregate,
+ warp_aggregate,
+ warp_exclusive_in_tile,
+ thread_exclusive_in_warp,
+ lengths_and_num_runs);
+
+ // First warp computes tile prefix in lane 0
+ TilePrefixCallbackOpT prefix_op(tile_status, temp_storage.aliasable.prefix, Sum(), tile_idx);
+ unsigned int warp_id = ((WARPS == 1) ? 0 : threadIdx.x / WARP_THREADS);
+ if (warp_id == 0)
+ {
+ prefix_op(tile_aggregate);
+ if (threadIdx.x == 0)
+ temp_storage.tile_exclusive = prefix_op.exclusive_prefix;
+ }
+
+ CTA_SYNC();
+
+ LengthOffsetPair tile_exclusive_in_global = temp_storage.tile_exclusive;
+
+ // Update thread_exclusive_in_warp to fold in warp and tile run-lengths
+ LengthOffsetPair thread_exclusive = scan_op(tile_exclusive_in_global, warp_exclusive_in_tile);
+ if (thread_exclusive_in_warp.key == 0)
+ thread_exclusive_in_warp.value += thread_exclusive.value;
+
+ // Downsweep scan through lengths_and_num_runs
+ LengthOffsetPair lengths_and_num_runs2[ITEMS_PER_THREAD];
+ LengthOffsetPair lengths_and_offsets[ITEMS_PER_THREAD];
+ OffsetT thread_num_runs_exclusive_in_warp[ITEMS_PER_THREAD];
+
+ internal::ThreadScanExclusive(lengths_and_num_runs, lengths_and_num_runs2, scan_op, thread_exclusive_in_warp);
+
+ // Zip
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ITEM++)
+ {
+ lengths_and_offsets[ITEM].value = lengths_and_num_runs2[ITEM].value;
+ lengths_and_offsets[ITEM].key = tile_offset + (threadIdx.x * ITEMS_PER_THREAD) + ITEM;
+ thread_num_runs_exclusive_in_warp[ITEM] = (lengths_and_num_runs[ITEM].key) ?
+ lengths_and_num_runs2[ITEM].key : // keep
+ WARP_THREADS * ITEMS_PER_THREAD; // discard
+ }
+
+ OffsetT tile_num_runs_aggregate = tile_aggregate.key;
+ OffsetT tile_num_runs_exclusive_in_global = tile_exclusive_in_global.key;
+ OffsetT warp_num_runs_aggregate = warp_aggregate.key;
+ OffsetT warp_num_runs_exclusive_in_tile = warp_exclusive_in_tile.key;
+
+ // Scatter
+ Scatter<false>(
+ tile_num_runs_aggregate,
+ tile_num_runs_exclusive_in_global,
+ warp_num_runs_aggregate,
+ warp_num_runs_exclusive_in_tile,
+ thread_num_runs_exclusive_in_warp,
+ lengths_and_offsets);
+
+ // Return running total (inclusive of this tile)
+ return prefix_op.inclusive_prefix;
+ }
+ }
+
+
+ /**
+ * Scan tiles of items as part of a dynamic chained scan
+ */
+ template <typename NumRunsIteratorT> ///< Output iterator type for recording number of items selected
+ __device__ __forceinline__ void ConsumeRange(
+ int num_tiles, ///< Total number of input tiles
+ ScanTileStateT& tile_status, ///< Global list of tile status
+ NumRunsIteratorT d_num_runs_out) ///< Output pointer for total number of runs identified
+ {
+ // Blocks are launched in increasing order, so just assign one tile per block
+ int tile_idx = (blockIdx.x * gridDim.y) + blockIdx.y; // Current tile index
+ OffsetT tile_offset = tile_idx * TILE_ITEMS; // Global offset for the current tile
+ OffsetT num_remaining = num_items - tile_offset; // Remaining items (including this tile)
+
+ if (tile_idx < num_tiles - 1)
+ {
+ // Not the last tile (full)
+ ConsumeTile<false>(num_items, num_remaining, tile_idx, tile_offset, tile_status);
+ }
+ else if (num_remaining > 0)
+ {
+ // The last tile (possibly partially-full)
+ LengthOffsetPair running_total = ConsumeTile<true>(num_items, num_remaining, tile_idx, tile_offset, tile_status);
+
+ if (threadIdx.x == 0)
+ {
+ // Output the total number of items selected
+ *d_num_runs_out = running_total.key;
+
+ // The inclusive prefix contains accumulated length reduction for the last run
+ if (running_total.key > 0)
+ d_lengths_out[running_total.key - 1] = running_total.value;
+ }
+ }
+ }
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_scan.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_scan.cuh
new file mode 100644
index 0000000..9368615
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_scan.cuh
@@ -0,0 +1,471 @@
+/******************************************************************************
+ * 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::AgentScan implements a stateful abstraction of CUDA thread blocks for participating in device-wide prefix scan .
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "single_pass_scan_operators.cuh"
+#include "../block/block_load.cuh"
+#include "../block/block_store.cuh"
+#include "../block/block_scan.cuh"
+#include "../grid/grid_queue.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentScan
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading input elements
+ BlockStoreAlgorithm _STORE_ALGORITHM, ///< The BlockStore algorithm to use
+ BlockScanAlgorithm _SCAN_ALGORITHM> ///< The BlockScan algorithm to use
+struct AgentScanPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+ static const BlockStoreAlgorithm STORE_ALGORITHM = _STORE_ALGORITHM; ///< The BlockStore algorithm to use
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+};
+
+
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentScan implements a stateful abstraction of CUDA thread blocks for participating in device-wide prefix scan .
+ */
+template <
+ typename AgentScanPolicyT, ///< Parameterized AgentScanPolicyT tuning policy type
+ typename InputIteratorT, ///< Random-access input iterator type
+ typename OutputIteratorT, ///< Random-access output iterator type
+ typename ScanOpT, ///< Scan functor type
+ typename InitValueT, ///< The init_value element for ScanOpT type (cub::NullType for inclusive scan)
+ typename OffsetT> ///< Signed integer type for global offsets
+struct AgentScan
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ // The input value type
+ typedef typename std::iterator_traits<InputIteratorT>::value_type InputT;
+
+ // 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;
+
+ // Input iterator wrapper type (for applying cache modifier)
+ typedef typename If<IsPointer<InputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentScanPolicyT::LOAD_MODIFIER, InputT, OffsetT>, // Wrap the native input pointer with CacheModifiedInputIterator
+ InputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedInputIteratorT;
+
+ // Constants
+ enum
+ {
+ IS_INCLUSIVE = Equals<InitValueT, NullType>::VALUE, // Inclusive scan if no init_value type is provided
+ BLOCK_THREADS = AgentScanPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentScanPolicyT::ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ };
+
+ // Parameterized BlockLoad type
+ typedef BlockLoad<
+ OutputT,
+ AgentScanPolicyT::BLOCK_THREADS,
+ AgentScanPolicyT::ITEMS_PER_THREAD,
+ AgentScanPolicyT::LOAD_ALGORITHM>
+ BlockLoadT;
+
+ // Parameterized BlockStore type
+ typedef BlockStore<
+ OutputT,
+ AgentScanPolicyT::BLOCK_THREADS,
+ AgentScanPolicyT::ITEMS_PER_THREAD,
+ AgentScanPolicyT::STORE_ALGORITHM>
+ BlockStoreT;
+
+ // Parameterized BlockScan type
+ typedef BlockScan<
+ OutputT,
+ AgentScanPolicyT::BLOCK_THREADS,
+ AgentScanPolicyT::SCAN_ALGORITHM>
+ BlockScanT;
+
+ // Callback type for obtaining tile prefix during block scan
+ typedef TilePrefixCallbackOp<
+ OutputT,
+ ScanOpT,
+ ScanTileStateT>
+ TilePrefixCallbackOpT;
+
+ // Stateful BlockScan prefix callback type for managing a running total while scanning consecutive tiles
+ typedef BlockScanRunningPrefixOp<
+ OutputT,
+ ScanOpT>
+ RunningPrefixCallbackOp;
+
+ // Shared memory type for this thread block
+ union _TempStorage
+ {
+ typename BlockLoadT::TempStorage load; // Smem needed for tile loading
+ typename BlockStoreT::TempStorage store; // Smem needed for tile storing
+
+ struct
+ {
+ typename TilePrefixCallbackOpT::TempStorage prefix; // Smem needed for cooperative prefix callback
+ typename BlockScanT::TempStorage scan; // Smem needed for tile scanning
+ };
+ };
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ _TempStorage& temp_storage; ///< Reference to temp_storage
+ WrappedInputIteratorT d_in; ///< Input data
+ OutputIteratorT d_out; ///< Output data
+ ScanOpT scan_op; ///< Binary scan operator
+ InitValueT init_value; ///< The init_value element for ScanOpT
+
+
+ //---------------------------------------------------------------------
+ // Block scan utility methods
+ //---------------------------------------------------------------------
+
+ /**
+ * Exclusive scan specialization (first tile)
+ */
+ __device__ __forceinline__
+ void ScanTile(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OutputT init_value,
+ ScanOpT scan_op,
+ OutputT &block_aggregate,
+ Int2Type<false> /*is_inclusive*/)
+ {
+ BlockScanT(temp_storage.scan).ExclusiveScan(items, items, init_value, scan_op, block_aggregate);
+ block_aggregate = scan_op(init_value, block_aggregate);
+ }
+
+
+ /**
+ * Inclusive scan specialization (first tile)
+ */
+ __device__ __forceinline__
+ void ScanTile(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ InitValueT /*init_value*/,
+ ScanOpT scan_op,
+ OutputT &block_aggregate,
+ Int2Type<true> /*is_inclusive*/)
+ {
+ BlockScanT(temp_storage.scan).InclusiveScan(items, items, scan_op, block_aggregate);
+ }
+
+
+ /**
+ * Exclusive scan specialization (subsequent tiles)
+ */
+ template <typename PrefixCallback>
+ __device__ __forceinline__
+ void ScanTile(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ ScanOpT scan_op,
+ PrefixCallback &prefix_op,
+ Int2Type<false> /*is_inclusive*/)
+ {
+ BlockScanT(temp_storage.scan).ExclusiveScan(items, items, scan_op, prefix_op);
+ }
+
+
+ /**
+ * Inclusive scan specialization (subsequent tiles)
+ */
+ template <typename PrefixCallback>
+ __device__ __forceinline__
+ void ScanTile(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ ScanOpT scan_op,
+ PrefixCallback &prefix_op,
+ Int2Type<true> /*is_inclusive*/)
+ {
+ BlockScanT(temp_storage.scan).InclusiveScan(items, items, scan_op, prefix_op);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Constructor
+ //---------------------------------------------------------------------
+
+ // Constructor
+ __device__ __forceinline__
+ AgentScan(
+ TempStorage& temp_storage, ///< Reference to temp_storage
+ InputIteratorT d_in, ///< Input data
+ OutputIteratorT d_out, ///< Output data
+ ScanOpT scan_op, ///< Binary scan operator
+ InitValueT init_value) ///< Initial value to seed the exclusive scan
+ :
+ temp_storage(temp_storage.Alias()),
+ d_in(d_in),
+ d_out(d_out),
+ scan_op(scan_op),
+ init_value(init_value)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Cooperatively scan a device-wide sequence of tiles with other CTAs
+ //---------------------------------------------------------------------
+
+ /**
+ * Process a tile of input (dynamic chained scan)
+ */
+ template <bool IS_LAST_TILE> ///< Whether the current tile is the last tile
+ __device__ __forceinline__ void ConsumeTile(
+ OffsetT num_remaining, ///< Number of global input items remaining (including this tile)
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state) ///< Global tile state descriptor
+ {
+ // Load items
+ OutputT items[ITEMS_PER_THREAD];
+
+ if (IS_LAST_TILE)
+ BlockLoadT(temp_storage.load).Load(d_in + tile_offset, items, num_remaining);
+ else
+ BlockLoadT(temp_storage.load).Load(d_in + tile_offset, items);
+
+ CTA_SYNC();
+
+ // Perform tile scan
+ if (tile_idx == 0)
+ {
+ // Scan first tile
+ OutputT block_aggregate;
+ ScanTile(items, init_value, scan_op, block_aggregate, Int2Type<IS_INCLUSIVE>());
+ if ((!IS_LAST_TILE) && (threadIdx.x == 0))
+ tile_state.SetInclusive(0, block_aggregate);
+ }
+ else
+ {
+ // Scan non-first tile
+ TilePrefixCallbackOpT prefix_op(tile_state, temp_storage.prefix, scan_op, tile_idx);
+ ScanTile(items, scan_op, prefix_op, Int2Type<IS_INCLUSIVE>());
+ }
+
+ CTA_SYNC();
+
+ // Store items
+ if (IS_LAST_TILE)
+ BlockStoreT(temp_storage.store).Store(d_out + tile_offset, items, num_remaining);
+ else
+ BlockStoreT(temp_storage.store).Store(d_out + tile_offset, items);
+ }
+
+
+ /**
+ * Scan tiles of items as part of a dynamic chained scan
+ */
+ __device__ __forceinline__ void ConsumeRange(
+ int num_items, ///< Total number of input items
+ ScanTileStateT& tile_state, ///< Global tile state descriptor
+ int start_tile) ///< The starting tile for the current grid
+ {
+ // Blocks are launched in increasing order, so just assign one tile per block
+ int tile_idx = start_tile + blockIdx.x; // Current tile index
+ OffsetT tile_offset = OffsetT(TILE_ITEMS) * tile_idx; // Global offset for the current tile
+ OffsetT num_remaining = num_items - tile_offset; // Remaining items (including this tile)
+
+ if (num_remaining > TILE_ITEMS)
+ {
+ // Not last tile
+ ConsumeTile<false>(num_remaining, tile_idx, tile_offset, tile_state);
+ }
+ else if (num_remaining > 0)
+ {
+ // Last tile
+ ConsumeTile<true>(num_remaining, tile_idx, tile_offset, tile_state);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Scan an sequence of consecutive tiles (independent of other thread blocks)
+ //---------------------------------------------------------------------
+
+ /**
+ * Process a tile of input
+ */
+ template <
+ bool IS_FIRST_TILE,
+ bool IS_LAST_TILE>
+ __device__ __forceinline__ void ConsumeTile(
+ OffsetT tile_offset, ///< Tile offset
+ RunningPrefixCallbackOp& prefix_op, ///< Running prefix operator
+ int valid_items = TILE_ITEMS) ///< Number of valid items in the tile
+ {
+ // Load items
+ OutputT items[ITEMS_PER_THREAD];
+
+ if (IS_LAST_TILE)
+ BlockLoadT(temp_storage.load).Load(d_in + tile_offset, items, valid_items);
+ else
+ BlockLoadT(temp_storage.load).Load(d_in + tile_offset, items);
+
+ CTA_SYNC();
+
+ // Block scan
+ if (IS_FIRST_TILE)
+ {
+ OutputT block_aggregate;
+ ScanTile(items, init_value, scan_op, block_aggregate, Int2Type<IS_INCLUSIVE>());
+ prefix_op.running_total = block_aggregate;
+ }
+ else
+ {
+ ScanTile(items, scan_op, prefix_op, Int2Type<IS_INCLUSIVE>());
+ }
+
+ CTA_SYNC();
+
+ // Store items
+ if (IS_LAST_TILE)
+ BlockStoreT(temp_storage.store).Store(d_out + tile_offset, items, valid_items);
+ else
+ BlockStoreT(temp_storage.store).Store(d_out + tile_offset, items);
+ }
+
+
+ /**
+ * Scan a consecutive share of input tiles
+ */
+ __device__ __forceinline__ void ConsumeRange(
+ OffsetT range_offset, ///< [in] Threadblock begin offset (inclusive)
+ OffsetT range_end) ///< [in] Threadblock end offset (exclusive)
+ {
+ BlockScanRunningPrefixOp<OutputT, ScanOpT> prefix_op(scan_op);
+
+ if (range_offset + TILE_ITEMS <= range_end)
+ {
+ // Consume first tile of input (full)
+ ConsumeTile<true, true>(range_offset, prefix_op);
+ range_offset += TILE_ITEMS;
+
+ // Consume subsequent full tiles of input
+ while (range_offset + TILE_ITEMS <= range_end)
+ {
+ ConsumeTile<false, true>(range_offset, prefix_op);
+ range_offset += TILE_ITEMS;
+ }
+
+ // Consume a partially-full tile
+ if (range_offset < range_end)
+ {
+ int valid_items = range_end - range_offset;
+ ConsumeTile<false, false>(range_offset, prefix_op, valid_items);
+ }
+ }
+ else
+ {
+ // Consume the first tile of input (partially-full)
+ int valid_items = range_end - range_offset;
+ ConsumeTile<true, false>(range_offset, prefix_op, valid_items);
+ }
+ }
+
+
+ /**
+ * Scan a consecutive share of input tiles, seeded with the specified prefix value
+ */
+ __device__ __forceinline__ void ConsumeRange(
+ OffsetT range_offset, ///< [in] Threadblock begin offset (inclusive)
+ OffsetT range_end, ///< [in] Threadblock end offset (exclusive)
+ OutputT prefix) ///< [in] The prefix to apply to the scan segment
+ {
+ BlockScanRunningPrefixOp<OutputT, ScanOpT> prefix_op(prefix, scan_op);
+
+ // Consume full tiles of input
+ while (range_offset + TILE_ITEMS <= range_end)
+ {
+ ConsumeTile<true, false>(range_offset, prefix_op);
+ range_offset += TILE_ITEMS;
+ }
+
+ // Consume a partially-full tile
+ if (range_offset < range_end)
+ {
+ int valid_items = range_end - range_offset;
+ ConsumeTile<false, false>(range_offset, prefix_op, valid_items);
+ }
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_segment_fixup.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_segment_fixup.cuh
new file mode 100644
index 0000000..e2de58e
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_segment_fixup.cuh
@@ -0,0 +1,375 @@
+/******************************************************************************
+ * 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::AgentSegmentFixup implements a stateful abstraction of CUDA thread blocks for participating in device-wide reduce-value-by-key.
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "single_pass_scan_operators.cuh"
+#include "../block/block_load.cuh"
+#include "../block/block_store.cuh"
+#include "../block/block_scan.cuh"
+#include "../block/block_discontinuity.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../iterator/constant_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentSegmentFixup
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading input elements
+ BlockScanAlgorithm _SCAN_ALGORITHM> ///< The BlockScan algorithm to use
+struct AgentSegmentFixupPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+};
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+/**
+ * \brief AgentSegmentFixup implements a stateful abstraction of CUDA thread blocks for participating in device-wide reduce-value-by-key
+ */
+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 EqualityOpT, ///< KeyT equality operator type
+ typename ReductionOpT, ///< ValueT reduction operator type
+ typename OffsetT> ///< Signed integer type for global offsets
+struct AgentSegmentFixup
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ // Data type of key-value input iterator
+ typedef typename std::iterator_traits<PairsInputIteratorT>::value_type KeyValuePairT;
+
+ // Value type
+ typedef typename KeyValuePairT::Value ValueT;
+
+ // Tile status descriptor interface type
+ typedef ReduceByKeyScanTileState<ValueT, OffsetT> ScanTileStateT;
+
+ // Constants
+ enum
+ {
+ BLOCK_THREADS = AgentSegmentFixupPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentSegmentFixupPolicyT::ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+
+ // Whether or not do fixup using RLE + global atomics
+ USE_ATOMIC_FIXUP = (CUB_PTX_ARCH >= 350) &&
+ (Equals<ValueT, float>::VALUE ||
+ Equals<ValueT, int>::VALUE ||
+ Equals<ValueT, unsigned int>::VALUE ||
+ Equals<ValueT, unsigned long long>::VALUE),
+
+ // Whether or not the scan operation has a zero-valued identity value (true if we're performing addition on a primitive type)
+ HAS_IDENTITY_ZERO = (Equals<ReductionOpT, cub::Sum>::VALUE) && (Traits<ValueT>::PRIMITIVE),
+ };
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for keys
+ typedef typename If<IsPointer<PairsInputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentSegmentFixupPolicyT::LOAD_MODIFIER, KeyValuePairT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ PairsInputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedPairsInputIteratorT;
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for fixup values
+ typedef typename If<IsPointer<AggregatesOutputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentSegmentFixupPolicyT::LOAD_MODIFIER, ValueT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ AggregatesOutputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedFixupInputIteratorT;
+
+ // Reduce-value-by-segment scan operator
+ typedef ReduceByKeyOp<cub::Sum> ReduceBySegmentOpT;
+
+ // Parameterized BlockLoad type for pairs
+ typedef BlockLoad<
+ KeyValuePairT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ AgentSegmentFixupPolicyT::LOAD_ALGORITHM>
+ BlockLoadPairs;
+
+ // Parameterized BlockScan type
+ typedef BlockScan<
+ KeyValuePairT,
+ BLOCK_THREADS,
+ AgentSegmentFixupPolicyT::SCAN_ALGORITHM>
+ BlockScanT;
+
+ // Callback type for obtaining tile prefix during block scan
+ typedef TilePrefixCallbackOp<
+ KeyValuePairT,
+ ReduceBySegmentOpT,
+ ScanTileStateT>
+ TilePrefixCallbackOpT;
+
+ // Shared memory type for this thread block
+ union _TempStorage
+ {
+ struct
+ {
+ typename BlockScanT::TempStorage scan; // Smem needed for tile scanning
+ typename TilePrefixCallbackOpT::TempStorage prefix; // Smem needed for cooperative prefix callback
+ };
+
+ // Smem needed for loading keys
+ typename BlockLoadPairs::TempStorage load_pairs;
+ };
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ _TempStorage& temp_storage; ///< Reference to temp_storage
+ WrappedPairsInputIteratorT d_pairs_in; ///< Input keys
+ AggregatesOutputIteratorT d_aggregates_out; ///< Output value aggregates
+ WrappedFixupInputIteratorT d_fixup_in; ///< Fixup input values
+ InequalityWrapper<EqualityOpT> inequality_op; ///< KeyT inequality operator
+ ReductionOpT reduction_op; ///< Reduction operator
+ ReduceBySegmentOpT scan_op; ///< Reduce-by-segment scan operator
+
+
+ //---------------------------------------------------------------------
+ // Constructor
+ //---------------------------------------------------------------------
+
+ // Constructor
+ __device__ __forceinline__
+ AgentSegmentFixup(
+ TempStorage& temp_storage, ///< Reference to temp_storage
+ PairsInputIteratorT d_pairs_in, ///< Input keys
+ AggregatesOutputIteratorT d_aggregates_out, ///< Output value aggregates
+ EqualityOpT equality_op, ///< KeyT equality operator
+ ReductionOpT reduction_op) ///< ValueT reduction operator
+ :
+ temp_storage(temp_storage.Alias()),
+ d_pairs_in(d_pairs_in),
+ d_aggregates_out(d_aggregates_out),
+ d_fixup_in(d_aggregates_out),
+ inequality_op(equality_op),
+ reduction_op(reduction_op),
+ scan_op(reduction_op)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Cooperatively scan a device-wide sequence of tiles with other CTAs
+ //---------------------------------------------------------------------
+
+
+ /**
+ * Process input tile. Specialized for atomic-fixup
+ */
+ template <bool IS_LAST_TILE>
+ __device__ __forceinline__ void ConsumeTile(
+ OffsetT num_remaining, ///< Number of global input items remaining (including this tile)
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state, ///< Global tile state descriptor
+ Int2Type<true> use_atomic_fixup) ///< Marker whether to use atomicAdd (instead of reduce-by-key)
+ {
+ KeyValuePairT pairs[ITEMS_PER_THREAD];
+
+ // Load pairs
+ KeyValuePairT oob_pair;
+ oob_pair.key = -1;
+
+ if (IS_LAST_TILE)
+ BlockLoadPairs(temp_storage.load_pairs).Load(d_pairs_in + tile_offset, pairs, num_remaining, oob_pair);
+ else
+ BlockLoadPairs(temp_storage.load_pairs).Load(d_pairs_in + tile_offset, pairs);
+
+ // RLE
+ #pragma unroll
+ for (int ITEM = 1; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ ValueT* d_scatter = d_aggregates_out + pairs[ITEM - 1].key;
+ if (pairs[ITEM].key != pairs[ITEM - 1].key)
+ atomicAdd(d_scatter, pairs[ITEM - 1].value);
+ else
+ pairs[ITEM].value = reduction_op(pairs[ITEM - 1].value, pairs[ITEM].value);
+ }
+
+ // Flush last item if valid
+ ValueT* d_scatter = d_aggregates_out + pairs[ITEMS_PER_THREAD - 1].key;
+ if ((!IS_LAST_TILE) || (pairs[ITEMS_PER_THREAD - 1].key >= 0))
+ atomicAdd(d_scatter, pairs[ITEMS_PER_THREAD - 1].value);
+ }
+
+
+ /**
+ * Process input tile. Specialized for reduce-by-key fixup
+ */
+ template <bool IS_LAST_TILE>
+ __device__ __forceinline__ void ConsumeTile(
+ OffsetT num_remaining, ///< Number of global input items remaining (including this tile)
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state, ///< Global tile state descriptor
+ Int2Type<false> use_atomic_fixup) ///< Marker whether to use atomicAdd (instead of reduce-by-key)
+ {
+ KeyValuePairT pairs[ITEMS_PER_THREAD];
+ KeyValuePairT scatter_pairs[ITEMS_PER_THREAD];
+
+ // Load pairs
+ KeyValuePairT oob_pair;
+ oob_pair.key = -1;
+
+ if (IS_LAST_TILE)
+ BlockLoadPairs(temp_storage.load_pairs).Load(d_pairs_in + tile_offset, pairs, num_remaining, oob_pair);
+ else
+ BlockLoadPairs(temp_storage.load_pairs).Load(d_pairs_in + tile_offset, pairs);
+
+ CTA_SYNC();
+
+ KeyValuePairT tile_aggregate;
+ if (tile_idx == 0)
+ {
+ // Exclusive scan of values and segment_flags
+ BlockScanT(temp_storage.scan).ExclusiveScan(pairs, scatter_pairs, scan_op, tile_aggregate);
+
+ // Update tile status if this is not the last tile
+ if (threadIdx.x == 0)
+ {
+ // Set first segment id to not trigger a flush (invalid from exclusive scan)
+ scatter_pairs[0].key = pairs[0].key;
+
+ if (!IS_LAST_TILE)
+ tile_state.SetInclusive(0, tile_aggregate);
+
+ }
+ }
+ else
+ {
+ // Exclusive scan of values and segment_flags
+ TilePrefixCallbackOpT prefix_op(tile_state, temp_storage.prefix, scan_op, tile_idx);
+ BlockScanT(temp_storage.scan).ExclusiveScan(pairs, scatter_pairs, scan_op, prefix_op);
+ tile_aggregate = prefix_op.GetBlockAggregate();
+ }
+
+ // Scatter updated values
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (scatter_pairs[ITEM].key != pairs[ITEM].key)
+ {
+ // Update the value at the key location
+ ValueT value = d_fixup_in[scatter_pairs[ITEM].key];
+ value = reduction_op(value, scatter_pairs[ITEM].value);
+
+ d_aggregates_out[scatter_pairs[ITEM].key] = value;
+ }
+ }
+
+ // Finalize the last item
+ if (IS_LAST_TILE)
+ {
+ // Last thread will output final count and last item, if necessary
+ if (threadIdx.x == BLOCK_THREADS - 1)
+ {
+ // If the last tile is a whole tile, the inclusive prefix contains accumulated value reduction for the last segment
+ if (num_remaining == TILE_ITEMS)
+ {
+ // Update the value at the key location
+ OffsetT last_key = pairs[ITEMS_PER_THREAD - 1].key;
+ d_aggregates_out[last_key] = reduction_op(tile_aggregate.value, d_fixup_in[last_key]);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Scan tiles of items as part of a dynamic chained scan
+ */
+ __device__ __forceinline__ void ConsumeRange(
+ int num_items, ///< Total number of input items
+ int num_tiles, ///< Total number of input tiles
+ ScanTileStateT& tile_state) ///< Global tile state descriptor
+ {
+ // Blocks are launched in increasing order, so just assign one tile per block
+ int tile_idx = (blockIdx.x * gridDim.y) + blockIdx.y; // Current tile index
+ OffsetT tile_offset = tile_idx * TILE_ITEMS; // Global offset for the current tile
+ OffsetT num_remaining = num_items - tile_offset; // Remaining items (including this tile)
+
+ if (num_remaining > TILE_ITEMS)
+ {
+ // Not the last tile (full)
+ ConsumeTile<false>(num_remaining, tile_idx, tile_offset, tile_state, Int2Type<USE_ATOMIC_FIXUP>());
+ }
+ else if (num_remaining > 0)
+ {
+ // The last tile (possibly partially-full)
+ ConsumeTile<true>(num_remaining, tile_idx, tile_offset, tile_state, Int2Type<USE_ATOMIC_FIXUP>());
+ }
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_select_if.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_select_if.cuh
new file mode 100644
index 0000000..52ca9fc
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_select_if.cuh
@@ -0,0 +1,703 @@
+/******************************************************************************
+ * 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::AgentSelectIf implements a stateful abstraction of CUDA thread blocks for participating in device-wide select.
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "single_pass_scan_operators.cuh"
+#include "../block/block_load.cuh"
+#include "../block/block_store.cuh"
+#include "../block/block_scan.cuh"
+#include "../block/block_exchange.cuh"
+#include "../block/block_discontinuity.cuh"
+#include "../grid/grid_queue.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy types
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentSelectIf
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ BlockLoadAlgorithm _LOAD_ALGORITHM, ///< The BlockLoad algorithm to use
+ CacheLoadModifier _LOAD_MODIFIER, ///< Cache load modifier for reading input elements
+ BlockScanAlgorithm _SCAN_ALGORITHM> ///< The BlockScan algorithm to use
+struct AgentSelectIfPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ };
+
+ static const BlockLoadAlgorithm LOAD_ALGORITHM = _LOAD_ALGORITHM; ///< The BlockLoad algorithm to use
+ static const CacheLoadModifier LOAD_MODIFIER = _LOAD_MODIFIER; ///< Cache load modifier for reading input elements
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+};
+
+
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+
+/**
+ * \brief AgentSelectIf implements a stateful abstraction of CUDA thread blocks for participating in device-wide selection
+ *
+ * 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 AgentSelectIfPolicy tuning policy type
+ typename InputIteratorT, ///< Random-access input iterator type for selection items
+ typename FlagsInputIteratorT, ///< Random-access input iterator type for selections (NullType* if a selection functor or discontinuity flagging is to be used for selection)
+ typename SelectedOutputIteratorT, ///< Random-access input iterator type for selection_flags items
+ typename SelectOpT, ///< Selection operator type (NullType if selections or discontinuity flagging is to be used for selection)
+ typename EqualityOpT, ///< Equality operator type (NullType if selection functor or selections 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 AgentSelectIf
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ // The input value type
+ typedef typename std::iterator_traits<InputIteratorT>::value_type InputT;
+
+ // 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;
+
+ // Tile status descriptor interface type
+ typedef ScanTileState<OffsetT> ScanTileStateT;
+
+ // Constants
+ enum
+ {
+ USE_SELECT_OP,
+ USE_SELECT_FLAGS,
+ USE_DISCONTINUITY,
+
+ BLOCK_THREADS = AgentSelectIfPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentSelectIfPolicyT::ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ TWO_PHASE_SCATTER = (ITEMS_PER_THREAD > 1),
+
+ SELECT_METHOD = (!Equals<SelectOpT, NullType>::VALUE) ?
+ USE_SELECT_OP :
+ (!Equals<FlagT, NullType>::VALUE) ?
+ USE_SELECT_FLAGS :
+ USE_DISCONTINUITY
+ };
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for items
+ typedef typename If<IsPointer<InputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentSelectIfPolicyT::LOAD_MODIFIER, InputT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ InputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedInputIteratorT;
+
+ // Cache-modified Input iterator wrapper type (for applying cache modifier) for values
+ typedef typename If<IsPointer<FlagsInputIteratorT>::VALUE,
+ CacheModifiedInputIterator<AgentSelectIfPolicyT::LOAD_MODIFIER, FlagT, OffsetT>, // Wrap the native input pointer with CacheModifiedValuesInputIterator
+ FlagsInputIteratorT>::Type // Directly use the supplied input iterator type
+ WrappedFlagsInputIteratorT;
+
+ // Parameterized BlockLoad type for input data
+ typedef BlockLoad<
+ OutputT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ AgentSelectIfPolicyT::LOAD_ALGORITHM>
+ BlockLoadT;
+
+ // Parameterized BlockLoad type for flags
+ typedef BlockLoad<
+ FlagT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD,
+ AgentSelectIfPolicyT::LOAD_ALGORITHM>
+ BlockLoadFlags;
+
+ // Parameterized BlockDiscontinuity type for items
+ typedef BlockDiscontinuity<
+ OutputT,
+ BLOCK_THREADS>
+ BlockDiscontinuityT;
+
+ // Parameterized BlockScan type
+ typedef BlockScan<
+ OffsetT,
+ BLOCK_THREADS,
+ AgentSelectIfPolicyT::SCAN_ALGORITHM>
+ BlockScanT;
+
+ // Callback type for obtaining tile prefix during block scan
+ typedef TilePrefixCallbackOp<
+ OffsetT,
+ cub::Sum,
+ ScanTileStateT>
+ TilePrefixCallbackOpT;
+
+ // Item exchange type
+ typedef OutputT ItemExchangeT[TILE_ITEMS];
+
+ // Shared memory type for this thread block
+ union _TempStorage
+ {
+ struct
+ {
+ typename BlockScanT::TempStorage scan; // Smem needed for tile scanning
+ typename TilePrefixCallbackOpT::TempStorage prefix; // Smem needed for cooperative prefix callback
+ typename BlockDiscontinuityT::TempStorage discontinuity; // Smem needed for discontinuity detection
+ };
+
+ // Smem needed for loading items
+ typename BlockLoadT::TempStorage load_items;
+
+ // Smem needed for loading values
+ typename BlockLoadFlags::TempStorage load_flags;
+
+ // Smem needed for compacting items (allows non POD items in this union)
+ Uninitialized<ItemExchangeT> raw_exchange;
+ };
+
+ // Alias wrapper allowing storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+ _TempStorage& temp_storage; ///< Reference to temp_storage
+ WrappedInputIteratorT d_in; ///< Input items
+ SelectedOutputIteratorT d_selected_out; ///< Unique output items
+ WrappedFlagsInputIteratorT d_flags_in; ///< Input selection flags (if applicable)
+ InequalityWrapper<EqualityOpT> inequality_op; ///< T inequality operator
+ SelectOpT select_op; ///< Selection operator
+ OffsetT num_items; ///< Total number of input items
+
+
+ //---------------------------------------------------------------------
+ // Constructor
+ //---------------------------------------------------------------------
+
+ // Constructor
+ __device__ __forceinline__
+ AgentSelectIf(
+ TempStorage &temp_storage, ///< Reference to temp_storage
+ InputIteratorT d_in, ///< Input data
+ FlagsInputIteratorT d_flags_in, ///< Input selection flags (if applicable)
+ SelectedOutputIteratorT d_selected_out, ///< Output data
+ SelectOpT select_op, ///< Selection operator
+ EqualityOpT equality_op, ///< Equality operator
+ OffsetT num_items) ///< Total number of input items
+ :
+ temp_storage(temp_storage.Alias()),
+ d_in(d_in),
+ d_flags_in(d_flags_in),
+ d_selected_out(d_selected_out),
+ select_op(select_op),
+ inequality_op(equality_op),
+ num_items(num_items)
+ {}
+
+
+ //---------------------------------------------------------------------
+ // Utility methods for initializing the selections
+ //---------------------------------------------------------------------
+
+ /**
+ * Initialize selections (specialized for selection operator)
+ */
+ template <bool IS_FIRST_TILE, bool IS_LAST_TILE>
+ __device__ __forceinline__ void InitializeSelections(
+ OffsetT /*tile_offset*/,
+ OffsetT num_tile_items,
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ Int2Type<USE_SELECT_OP> /*select_method*/)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ // Out-of-bounds items are selection_flags
+ selection_flags[ITEM] = 1;
+
+ if (!IS_LAST_TILE || (OffsetT(threadIdx.x * ITEMS_PER_THREAD) + ITEM < num_tile_items))
+ selection_flags[ITEM] = select_op(items[ITEM]);
+ }
+ }
+
+
+ /**
+ * Initialize selections (specialized for valid flags)
+ */
+ template <bool IS_FIRST_TILE, bool IS_LAST_TILE>
+ __device__ __forceinline__ void InitializeSelections(
+ OffsetT tile_offset,
+ OffsetT num_tile_items,
+ OutputT (&/*items*/)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ Int2Type<USE_SELECT_FLAGS> /*select_method*/)
+ {
+ CTA_SYNC();
+
+ FlagT flags[ITEMS_PER_THREAD];
+
+ if (IS_LAST_TILE)
+ {
+ // Out-of-bounds items are selection_flags
+ BlockLoadFlags(temp_storage.load_flags).Load(d_flags_in + tile_offset, flags, num_tile_items, 1);
+ }
+ else
+ {
+ BlockLoadFlags(temp_storage.load_flags).Load(d_flags_in + tile_offset, flags);
+ }
+
+ // Convert flag type to selection_flags type
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ selection_flags[ITEM] = flags[ITEM];
+ }
+ }
+
+
+ /**
+ * Initialize selections (specialized for discontinuity detection)
+ */
+ template <bool IS_FIRST_TILE, bool IS_LAST_TILE>
+ __device__ __forceinline__ void InitializeSelections(
+ OffsetT tile_offset,
+ OffsetT num_tile_items,
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ Int2Type<USE_DISCONTINUITY> /*select_method*/)
+ {
+ if (IS_FIRST_TILE)
+ {
+ CTA_SYNC();
+
+ // Set head selection_flags. First tile sets the first flag for the first item
+ BlockDiscontinuityT(temp_storage.discontinuity).FlagHeads(selection_flags, items, inequality_op);
+ }
+ else
+ {
+ OutputT tile_predecessor;
+ if (threadIdx.x == 0)
+ tile_predecessor = d_in[tile_offset - 1];
+
+ CTA_SYNC();
+
+ BlockDiscontinuityT(temp_storage.discontinuity).FlagHeads(selection_flags, items, inequality_op, tile_predecessor);
+ }
+
+ // Set selection flags for out-of-bounds items
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ // Set selection_flags for out-of-bounds items
+ if ((IS_LAST_TILE) && (OffsetT(threadIdx.x * ITEMS_PER_THREAD) + ITEM >= num_tile_items))
+ selection_flags[ITEM] = 1;
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Scatter utility methods
+ //---------------------------------------------------------------------
+
+ /**
+ * Scatter flagged items to output offsets (specialized for direct scattering)
+ */
+ template <bool IS_LAST_TILE, bool IS_FIRST_TILE>
+ __device__ __forceinline__ void ScatterDirect(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ OffsetT (&selection_indices)[ITEMS_PER_THREAD],
+ OffsetT num_selections)
+ {
+ // Scatter flagged items
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (selection_flags[ITEM])
+ {
+ if ((!IS_LAST_TILE) || selection_indices[ITEM] < num_selections)
+ {
+ d_selected_out[selection_indices[ITEM]] = items[ITEM];
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Scatter flagged items to output offsets (specialized for two-phase scattering)
+ */
+ template <bool IS_LAST_TILE, bool IS_FIRST_TILE>
+ __device__ __forceinline__ void ScatterTwoPhase(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ OffsetT (&selection_indices)[ITEMS_PER_THREAD],
+ int /*num_tile_items*/, ///< Number of valid items in this tile
+ int num_tile_selections, ///< Number of selections in this tile
+ OffsetT num_selections_prefix, ///< Total number of selections prior to this tile
+ OffsetT /*num_rejected_prefix*/, ///< Total number of rejections prior to this tile
+ Int2Type<false> /*is_keep_rejects*/) ///< Marker type indicating whether to keep rejected items in the second partition
+ {
+ CTA_SYNC();
+
+ // Compact and scatter items
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ int local_scatter_offset = selection_indices[ITEM] - num_selections_prefix;
+ if (selection_flags[ITEM])
+ {
+ temp_storage.raw_exchange.Alias()[local_scatter_offset] = items[ITEM];
+ }
+ }
+
+ CTA_SYNC();
+
+ for (int item = threadIdx.x; item < num_tile_selections; item += BLOCK_THREADS)
+ {
+ d_selected_out[num_selections_prefix + item] = temp_storage.raw_exchange.Alias()[item];
+ }
+ }
+
+
+ /**
+ * Scatter flagged items to output offsets (specialized for two-phase scattering)
+ */
+ template <bool IS_LAST_TILE, bool IS_FIRST_TILE>
+ __device__ __forceinline__ void ScatterTwoPhase(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ OffsetT (&selection_indices)[ITEMS_PER_THREAD],
+ int num_tile_items, ///< Number of valid items in this tile
+ int num_tile_selections, ///< Number of selections in this tile
+ OffsetT num_selections_prefix, ///< Total number of selections prior to this tile
+ OffsetT num_rejected_prefix, ///< Total number of rejections prior to this tile
+ Int2Type<true> /*is_keep_rejects*/) ///< Marker type indicating whether to keep rejected items in the second partition
+ {
+ CTA_SYNC();
+
+ int tile_num_rejections = num_tile_items - num_tile_selections;
+
+ // Scatter items to shared memory (rejections first)
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ int item_idx = (threadIdx.x * ITEMS_PER_THREAD) + ITEM;
+ int local_selection_idx = selection_indices[ITEM] - num_selections_prefix;
+ int local_rejection_idx = item_idx - local_selection_idx;
+ int local_scatter_offset = (selection_flags[ITEM]) ?
+ tile_num_rejections + local_selection_idx :
+ local_rejection_idx;
+
+ temp_storage.raw_exchange.Alias()[local_scatter_offset] = items[ITEM];
+ }
+
+ CTA_SYNC();
+
+ // Gather items from shared memory and scatter to global
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ int item_idx = (ITEM * BLOCK_THREADS) + threadIdx.x;
+ int rejection_idx = item_idx;
+ int selection_idx = item_idx - tile_num_rejections;
+ OffsetT scatter_offset = (item_idx < tile_num_rejections) ?
+ num_items - num_rejected_prefix - rejection_idx - 1 :
+ num_selections_prefix + selection_idx;
+
+ OutputT item = temp_storage.raw_exchange.Alias()[item_idx];
+
+ if (!IS_LAST_TILE || (item_idx < num_tile_items))
+ {
+ d_selected_out[scatter_offset] = item;
+ }
+ }
+ }
+
+
+ /**
+ * Scatter flagged items
+ */
+ template <bool IS_LAST_TILE, bool IS_FIRST_TILE>
+ __device__ __forceinline__ void Scatter(
+ OutputT (&items)[ITEMS_PER_THREAD],
+ OffsetT (&selection_flags)[ITEMS_PER_THREAD],
+ OffsetT (&selection_indices)[ITEMS_PER_THREAD],
+ int num_tile_items, ///< Number of valid items in this tile
+ int num_tile_selections, ///< Number of selections in this tile
+ OffsetT num_selections_prefix, ///< Total number of selections prior to this tile
+ OffsetT num_rejected_prefix, ///< Total number of rejections prior to this tile
+ OffsetT num_selections) ///< Total number of selections including this tile
+ {
+ // Do a two-phase scatter if (a) keeping both partitions or (b) two-phase is enabled and the average number of selection_flags items per thread is greater than one
+ if (KEEP_REJECTS || (TWO_PHASE_SCATTER && (num_tile_selections > BLOCK_THREADS)))
+ {
+ ScatterTwoPhase<IS_LAST_TILE, IS_FIRST_TILE>(
+ items,
+ selection_flags,
+ selection_indices,
+ num_tile_items,
+ num_tile_selections,
+ num_selections_prefix,
+ num_rejected_prefix,
+ Int2Type<KEEP_REJECTS>());
+ }
+ else
+ {
+ ScatterDirect<IS_LAST_TILE, IS_FIRST_TILE>(
+ items,
+ selection_flags,
+ selection_indices,
+ num_selections);
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // Cooperatively scan a device-wide sequence of tiles with other CTAs
+ //---------------------------------------------------------------------
+
+
+ /**
+ * Process first tile of input (dynamic chained scan). Returns the running count of selections (including this tile)
+ */
+ template <bool IS_LAST_TILE>
+ __device__ __forceinline__ OffsetT ConsumeFirstTile(
+ int num_tile_items, ///< Number of input items comprising this tile
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state) ///< Global tile state descriptor
+ {
+ OutputT items[ITEMS_PER_THREAD];
+ OffsetT selection_flags[ITEMS_PER_THREAD];
+ OffsetT selection_indices[ITEMS_PER_THREAD];
+
+ // Load items
+ if (IS_LAST_TILE)
+ BlockLoadT(temp_storage.load_items).Load(d_in + tile_offset, items, num_tile_items);
+ else
+ BlockLoadT(temp_storage.load_items).Load(d_in + tile_offset, items);
+
+ // Initialize selection_flags
+ InitializeSelections<true, IS_LAST_TILE>(
+ tile_offset,
+ num_tile_items,
+ items,
+ selection_flags,
+ Int2Type<SELECT_METHOD>());
+
+ CTA_SYNC();
+
+ // Exclusive scan of selection_flags
+ OffsetT num_tile_selections;
+ BlockScanT(temp_storage.scan).ExclusiveSum(selection_flags, selection_indices, num_tile_selections);
+
+ if (threadIdx.x == 0)
+ {
+ // Update tile status if this is not the last tile
+ if (!IS_LAST_TILE)
+ tile_state.SetInclusive(0, num_tile_selections);
+ }
+
+ // Discount any out-of-bounds selections
+ if (IS_LAST_TILE)
+ num_tile_selections -= (TILE_ITEMS - num_tile_items);
+
+ // Scatter flagged items
+ Scatter<IS_LAST_TILE, true>(
+ items,
+ selection_flags,
+ selection_indices,
+ num_tile_items,
+ num_tile_selections,
+ 0,
+ 0,
+ num_tile_selections);
+
+ return num_tile_selections;
+ }
+
+
+ /**
+ * Process subsequent tile of input (dynamic chained scan). Returns the running count of selections (including this tile)
+ */
+ template <bool IS_LAST_TILE>
+ __device__ __forceinline__ OffsetT ConsumeSubsequentTile(
+ int num_tile_items, ///< Number of input items comprising this tile
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state) ///< Global tile state descriptor
+ {
+ OutputT items[ITEMS_PER_THREAD];
+ OffsetT selection_flags[ITEMS_PER_THREAD];
+ OffsetT selection_indices[ITEMS_PER_THREAD];
+
+ // Load items
+ if (IS_LAST_TILE)
+ BlockLoadT(temp_storage.load_items).Load(d_in + tile_offset, items, num_tile_items);
+ else
+ BlockLoadT(temp_storage.load_items).Load(d_in + tile_offset, items);
+
+ // Initialize selection_flags
+ InitializeSelections<false, IS_LAST_TILE>(
+ tile_offset,
+ num_tile_items,
+ items,
+ selection_flags,
+ Int2Type<SELECT_METHOD>());
+
+ CTA_SYNC();
+
+ // Exclusive scan of values and selection_flags
+ TilePrefixCallbackOpT prefix_op(tile_state, temp_storage.prefix, cub::Sum(), tile_idx);
+ BlockScanT(temp_storage.scan).ExclusiveSum(selection_flags, selection_indices, prefix_op);
+
+ OffsetT num_tile_selections = prefix_op.GetBlockAggregate();
+ OffsetT num_selections = prefix_op.GetInclusivePrefix();
+ OffsetT num_selections_prefix = prefix_op.GetExclusivePrefix();
+ OffsetT num_rejected_prefix = (tile_idx * TILE_ITEMS) - num_selections_prefix;
+
+ // Discount any out-of-bounds selections
+ if (IS_LAST_TILE)
+ {
+ int num_discount = TILE_ITEMS - num_tile_items;
+ num_selections -= num_discount;
+ num_tile_selections -= num_discount;
+ }
+
+ // Scatter flagged items
+ Scatter<IS_LAST_TILE, false>(
+ items,
+ selection_flags,
+ selection_indices,
+ num_tile_items,
+ num_tile_selections,
+ num_selections_prefix,
+ num_rejected_prefix,
+ num_selections);
+
+ return num_selections;
+ }
+
+
+ /**
+ * Process a tile of input
+ */
+ template <bool IS_LAST_TILE>
+ __device__ __forceinline__ OffsetT ConsumeTile(
+ int num_tile_items, ///< Number of input items comprising this tile
+ int tile_idx, ///< Tile index
+ OffsetT tile_offset, ///< Tile offset
+ ScanTileStateT& tile_state) ///< Global tile state descriptor
+ {
+ OffsetT num_selections;
+ if (tile_idx == 0)
+ {
+ num_selections = ConsumeFirstTile<IS_LAST_TILE>(num_tile_items, tile_offset, tile_state);
+ }
+ else
+ {
+ num_selections = ConsumeSubsequentTile<IS_LAST_TILE>(num_tile_items, tile_idx, tile_offset, tile_state);
+ }
+
+ return num_selections;
+ }
+
+
+ /**
+ * Scan tiles of items as part of a dynamic chained scan
+ */
+ template <typename NumSelectedIteratorT> ///< Output iterator type for recording number of items selection_flags
+ __device__ __forceinline__ void ConsumeRange(
+ int num_tiles, ///< Total number of input tiles
+ ScanTileStateT& tile_state, ///< Global tile state descriptor
+ NumSelectedIteratorT d_num_selected_out) ///< Output total number selection_flags
+ {
+ // Blocks are launched in increasing order, so just assign one tile per block
+ int tile_idx = (blockIdx.x * gridDim.y) + blockIdx.y; // Current tile index
+ OffsetT tile_offset = tile_idx * TILE_ITEMS; // Global offset for the current tile
+
+ if (tile_idx < num_tiles - 1)
+ {
+ // Not the last tile (full)
+ ConsumeTile<false>(TILE_ITEMS, tile_idx, tile_offset, tile_state);
+ }
+ else
+ {
+ // The last tile (possibly partially-full)
+ OffsetT num_remaining = num_items - tile_offset;
+ OffsetT num_selections = ConsumeTile<true>(num_remaining, tile_idx, tile_offset, tile_state);
+
+ if (threadIdx.x == 0)
+ {
+ // Output the total number of items selection_flags
+ *d_num_selected_out = num_selections;
+ }
+ }
+ }
+
+};
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_spmv_orig.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_spmv_orig.cuh
new file mode 100644
index 0000000..54e2a13
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/agent_spmv_orig.cuh
@@ -0,0 +1,670 @@
+/******************************************************************************
+ * 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::AgentSpmv implements a stateful abstraction of CUDA thread blocks for participating in device-wide SpMV.
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "../util_type.cuh"
+#include "../block/block_reduce.cuh"
+#include "../block/block_scan.cuh"
+#include "../block/block_exchange.cuh"
+#include "../thread/thread_search.cuh"
+#include "../thread/thread_operators.cuh"
+#include "../iterator/cache_modified_input_iterator.cuh"
+#include "../iterator/counting_input_iterator.cuh"
+#include "../iterator/tex_ref_input_iterator.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Tuning policy
+ ******************************************************************************/
+
+/**
+ * Parameterizable tuning policy type for AgentSpmv
+ */
+template <
+ int _BLOCK_THREADS, ///< Threads per thread block
+ int _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ CacheLoadModifier _ROW_OFFSETS_SEARCH_LOAD_MODIFIER, ///< Cache load modifier for reading CSR row-offsets during search
+ CacheLoadModifier _ROW_OFFSETS_LOAD_MODIFIER, ///< Cache load modifier for reading CSR row-offsets
+ CacheLoadModifier _COLUMN_INDICES_LOAD_MODIFIER, ///< Cache load modifier for reading CSR column-indices
+ CacheLoadModifier _VALUES_LOAD_MODIFIER, ///< Cache load modifier for reading CSR values
+ CacheLoadModifier _VECTOR_VALUES_LOAD_MODIFIER, ///< Cache load modifier for reading vector values
+ bool _DIRECT_LOAD_NONZEROS, ///< Whether to load nonzeros directly from global during sequential merging (vs. pre-staged through shared memory)
+ BlockScanAlgorithm _SCAN_ALGORITHM> ///< The BlockScan algorithm to use
+struct AgentSpmvPolicy
+{
+ enum
+ {
+ BLOCK_THREADS = _BLOCK_THREADS, ///< Threads per thread block
+ ITEMS_PER_THREAD = _ITEMS_PER_THREAD, ///< Items per thread (per tile of input)
+ DIRECT_LOAD_NONZEROS = _DIRECT_LOAD_NONZEROS, ///< Whether to load nonzeros directly from global during sequential merging (pre-staged through shared memory)
+ };
+
+ static const CacheLoadModifier ROW_OFFSETS_SEARCH_LOAD_MODIFIER = _ROW_OFFSETS_SEARCH_LOAD_MODIFIER; ///< Cache load modifier for reading CSR row-offsets
+ static const CacheLoadModifier ROW_OFFSETS_LOAD_MODIFIER = _ROW_OFFSETS_LOAD_MODIFIER; ///< Cache load modifier for reading CSR row-offsets
+ static const CacheLoadModifier COLUMN_INDICES_LOAD_MODIFIER = _COLUMN_INDICES_LOAD_MODIFIER; ///< Cache load modifier for reading CSR column-indices
+ static const CacheLoadModifier VALUES_LOAD_MODIFIER = _VALUES_LOAD_MODIFIER; ///< Cache load modifier for reading CSR values
+ static const CacheLoadModifier VECTOR_VALUES_LOAD_MODIFIER = _VECTOR_VALUES_LOAD_MODIFIER; ///< Cache load modifier for reading vector values
+ static const BlockScanAlgorithm SCAN_ALGORITHM = _SCAN_ALGORITHM; ///< The BlockScan algorithm to use
+
+};
+
+
+/******************************************************************************
+ * Thread block abstractions
+ ******************************************************************************/
+
+template <
+ typename ValueT, ///< Matrix and vector value type
+ typename OffsetT> ///< Signed integer type for sequence offsets
+struct SpmvParams
+{
+ ValueT* d_values; ///< Pointer to the array of \p num_nonzeros values of the corresponding nonzero elements of matrix <b>A</b>.
+ OffsetT* d_row_end_offsets; ///< Pointer to the array of \p m offsets demarcating the end of every row in \p d_column_indices and \p d_values
+ OffsetT* d_column_indices; ///< Pointer to the array of \p num_nonzeros column-indices of the corresponding nonzero elements of matrix <b>A</b>. (Indices are zero-valued.)
+ ValueT* d_vector_x; ///< Pointer to the array of \p num_cols values corresponding to the dense input vector <em>x</em>
+ ValueT* d_vector_y; ///< Pointer to the array of \p num_rows values corresponding to the dense output vector <em>y</em>
+ int num_rows; ///< Number of rows of matrix <b>A</b>.
+ int num_cols; ///< Number of columns of matrix <b>A</b>.
+ int num_nonzeros; ///< Number of nonzero elements of matrix <b>A</b>.
+ ValueT alpha; ///< Alpha multiplicand
+ ValueT beta; ///< Beta addend-multiplicand
+
+ TexRefInputIterator<ValueT, 66778899, OffsetT> t_vector_x;
+};
+
+
+/**
+ * \brief AgentSpmv implements a stateful abstraction of CUDA thread blocks for participating in device-wide SpMV.
+ */
+template <
+ typename AgentSpmvPolicyT, ///< Parameterized AgentSpmvPolicy tuning policy type
+ typename ValueT, ///< Matrix and vector value type
+ typename OffsetT, ///< Signed integer type for sequence offsets
+ bool HAS_ALPHA, ///< Whether the input parameter \p alpha is 1
+ bool HAS_BETA, ///< Whether the input parameter \p beta is 0
+ int PTX_ARCH = CUB_PTX_ARCH> ///< PTX compute capability
+struct AgentSpmv
+{
+ //---------------------------------------------------------------------
+ // Types and constants
+ //---------------------------------------------------------------------
+
+ /// Constants
+ enum
+ {
+ BLOCK_THREADS = AgentSpmvPolicyT::BLOCK_THREADS,
+ ITEMS_PER_THREAD = AgentSpmvPolicyT::ITEMS_PER_THREAD,
+ TILE_ITEMS = BLOCK_THREADS * ITEMS_PER_THREAD,
+ };
+
+ /// 2D merge path coordinate type
+ typedef typename CubVector<OffsetT, 2>::Type CoordinateT;
+
+ /// Input iterator wrapper types (for applying cache modifiers)
+
+ typedef CacheModifiedInputIterator<
+ AgentSpmvPolicyT::ROW_OFFSETS_SEARCH_LOAD_MODIFIER,
+ OffsetT,
+ OffsetT>
+ RowOffsetsSearchIteratorT;
+
+ typedef CacheModifiedInputIterator<
+ AgentSpmvPolicyT::ROW_OFFSETS_LOAD_MODIFIER,
+ OffsetT,
+ OffsetT>
+ RowOffsetsIteratorT;
+
+ typedef CacheModifiedInputIterator<
+ AgentSpmvPolicyT::COLUMN_INDICES_LOAD_MODIFIER,
+ OffsetT,
+ OffsetT>
+ ColumnIndicesIteratorT;
+
+ typedef CacheModifiedInputIterator<
+ AgentSpmvPolicyT::VALUES_LOAD_MODIFIER,
+ ValueT,
+ OffsetT>
+ ValueIteratorT;
+
+ typedef CacheModifiedInputIterator<
+ AgentSpmvPolicyT::VECTOR_VALUES_LOAD_MODIFIER,
+ ValueT,
+ OffsetT>
+ VectorValueIteratorT;
+
+ // Tuple type for scanning (pairs accumulated segment-value with segment-index)
+ typedef KeyValuePair<OffsetT, ValueT> KeyValuePairT;
+
+ // Reduce-value-by-segment scan operator
+ typedef ReduceByKeyOp<cub::Sum> ReduceBySegmentOpT;
+
+ // BlockReduce specialization
+ typedef BlockReduce<
+ ValueT,
+ BLOCK_THREADS,
+ BLOCK_REDUCE_WARP_REDUCTIONS>
+ BlockReduceT;
+
+ // BlockScan specialization
+ typedef BlockScan<
+ KeyValuePairT,
+ BLOCK_THREADS,
+ AgentSpmvPolicyT::SCAN_ALGORITHM>
+ BlockScanT;
+
+ // BlockScan specialization
+ typedef BlockScan<
+ ValueT,
+ BLOCK_THREADS,
+ AgentSpmvPolicyT::SCAN_ALGORITHM>
+ BlockPrefixSumT;
+
+ // BlockExchange specialization
+ typedef BlockExchange<
+ ValueT,
+ BLOCK_THREADS,
+ ITEMS_PER_THREAD>
+ BlockExchangeT;
+
+ /// Merge item type (either a non-zero value or a row-end offset)
+ union MergeItem
+ {
+ // Value type to pair with index type OffsetT (NullType if loading values directly during merge)
+ typedef typename If<AgentSpmvPolicyT::DIRECT_LOAD_NONZEROS, NullType, ValueT>::Type MergeValueT;
+
+ OffsetT row_end_offset;
+ MergeValueT nonzero;
+ };
+
+ /// Shared memory type required by this thread block
+ struct _TempStorage
+ {
+ CoordinateT tile_coords[2];
+
+ union Aliasable
+ {
+ // Smem needed for tile of merge items
+ MergeItem merge_items[ITEMS_PER_THREAD + TILE_ITEMS + 1];
+
+ // Smem needed for block exchange
+ typename BlockExchangeT::TempStorage exchange;
+
+ // Smem needed for block-wide reduction
+ typename BlockReduceT::TempStorage reduce;
+
+ // Smem needed for tile scanning
+ typename BlockScanT::TempStorage scan;
+
+ // Smem needed for tile prefix sum
+ typename BlockPrefixSumT::TempStorage prefix_sum;
+
+ } aliasable;
+ };
+
+ /// Temporary storage type (unionable)
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+
+ //---------------------------------------------------------------------
+ // Per-thread fields
+ //---------------------------------------------------------------------
+
+
+ _TempStorage& temp_storage; /// Reference to temp_storage
+
+ SpmvParams<ValueT, OffsetT>& spmv_params;
+
+ ValueIteratorT wd_values; ///< Wrapped pointer to the array of \p num_nonzeros values of the corresponding nonzero elements of matrix <b>A</b>.
+ RowOffsetsIteratorT wd_row_end_offsets; ///< Wrapped Pointer to the array of \p m offsets demarcating the end of every row in \p d_column_indices and \p d_values
+ ColumnIndicesIteratorT wd_column_indices; ///< Wrapped Pointer to the array of \p num_nonzeros column-indices of the corresponding nonzero elements of matrix <b>A</b>. (Indices are zero-valued.)
+ VectorValueIteratorT wd_vector_x; ///< Wrapped Pointer to the array of \p num_cols values corresponding to the dense input vector <em>x</em>
+ VectorValueIteratorT wd_vector_y; ///< Wrapped Pointer to the array of \p num_cols values corresponding to the dense input vector <em>x</em>
+
+
+ //---------------------------------------------------------------------
+ // Interface
+ //---------------------------------------------------------------------
+
+ /**
+ * Constructor
+ */
+ __device__ __forceinline__ AgentSpmv(
+ TempStorage& temp_storage, ///< Reference to temp_storage
+ SpmvParams<ValueT, OffsetT>& spmv_params) ///< SpMV input parameter bundle
+ :
+ temp_storage(temp_storage.Alias()),
+ spmv_params(spmv_params),
+ wd_values(spmv_params.d_values),
+ wd_row_end_offsets(spmv_params.d_row_end_offsets),
+ wd_column_indices(spmv_params.d_column_indices),
+ wd_vector_x(spmv_params.d_vector_x),
+ wd_vector_y(spmv_params.d_vector_y)
+ {}
+
+
+
+
+ /**
+ * Consume a merge tile, specialized for direct-load of nonzeros
+ */
+ __device__ __forceinline__ KeyValuePairT ConsumeTile(
+ int tile_idx,
+ CoordinateT tile_start_coord,
+ CoordinateT tile_end_coord,
+ Int2Type<true> is_direct_load) ///< Marker type indicating whether to load nonzeros directly during path-discovery or beforehand in batch
+ {
+ int tile_num_rows = tile_end_coord.x - tile_start_coord.x;
+ int tile_num_nonzeros = tile_end_coord.y - tile_start_coord.y;
+ OffsetT* s_tile_row_end_offsets = &temp_storage.aliasable.merge_items[0].row_end_offset;
+
+ // Gather the row end-offsets for the merge tile into shared memory
+ for (int item = threadIdx.x; item <= tile_num_rows; item += BLOCK_THREADS)
+ {
+ s_tile_row_end_offsets[item] = wd_row_end_offsets[tile_start_coord.x + item];
+ }
+
+ CTA_SYNC();
+
+ // Search for the thread's starting coordinate within the merge tile
+ CountingInputIterator<OffsetT> tile_nonzero_indices(tile_start_coord.y);
+ CoordinateT thread_start_coord;
+
+ MergePathSearch(
+ OffsetT(threadIdx.x * ITEMS_PER_THREAD), // Diagonal
+ s_tile_row_end_offsets, // List A
+ tile_nonzero_indices, // List B
+ tile_num_rows,
+ tile_num_nonzeros,
+ thread_start_coord);
+
+ CTA_SYNC(); // Perf-sync
+
+ // Compute the thread's merge path segment
+ CoordinateT thread_current_coord = thread_start_coord;
+ KeyValuePairT scan_segment[ITEMS_PER_THREAD];
+
+ ValueT running_total = 0.0;
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ OffsetT nonzero_idx = CUB_MIN(tile_nonzero_indices[thread_current_coord.y], spmv_params.num_nonzeros - 1);
+ OffsetT column_idx = wd_column_indices[nonzero_idx];
+ ValueT value = wd_values[nonzero_idx];
+
+ ValueT vector_value = spmv_params.t_vector_x[column_idx];
+#if (CUB_PTX_ARCH >= 350)
+ vector_value = wd_vector_x[column_idx];
+#endif
+ ValueT nonzero = value * vector_value;
+
+ OffsetT row_end_offset = s_tile_row_end_offsets[thread_current_coord.x];
+
+ if (tile_nonzero_indices[thread_current_coord.y] < row_end_offset)
+ {
+ // Move down (accumulate)
+ running_total += nonzero;
+ scan_segment[ITEM].value = running_total;
+ scan_segment[ITEM].key = tile_num_rows;
+ ++thread_current_coord.y;
+ }
+ else
+ {
+ // Move right (reset)
+ scan_segment[ITEM].value = running_total;
+ scan_segment[ITEM].key = thread_current_coord.x;
+ running_total = 0.0;
+ ++thread_current_coord.x;
+ }
+ }
+
+ CTA_SYNC();
+
+ // Block-wide reduce-value-by-segment
+ KeyValuePairT tile_carry;
+ ReduceBySegmentOpT scan_op;
+ KeyValuePairT scan_item;
+
+ scan_item.value = running_total;
+ scan_item.key = thread_current_coord.x;
+
+ BlockScanT(temp_storage.aliasable.scan).ExclusiveScan(scan_item, scan_item, scan_op, tile_carry);
+
+ if (tile_num_rows > 0)
+ {
+ if (threadIdx.x == 0)
+ scan_item.key = -1;
+
+ // Direct scatter
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (scan_segment[ITEM].key < tile_num_rows)
+ {
+ if (scan_item.key == scan_segment[ITEM].key)
+ scan_segment[ITEM].value = scan_item.value + scan_segment[ITEM].value;
+
+ if (HAS_ALPHA)
+ {
+ scan_segment[ITEM].value *= spmv_params.alpha;
+ }
+
+ if (HAS_BETA)
+ {
+ // Update the output vector element
+ ValueT addend = spmv_params.beta * wd_vector_y[tile_start_coord.x + scan_segment[ITEM].key];
+ scan_segment[ITEM].value += addend;
+ }
+
+ // Set the output vector element
+ spmv_params.d_vector_y[tile_start_coord.x + scan_segment[ITEM].key] = scan_segment[ITEM].value;
+ }
+ }
+ }
+
+ // Return the tile's running carry-out
+ return tile_carry;
+ }
+
+
+
+ /**
+ * Consume a merge tile, specialized for indirect load of nonzeros
+ */
+ __device__ __forceinline__ KeyValuePairT ConsumeTile(
+ int tile_idx,
+ CoordinateT tile_start_coord,
+ CoordinateT tile_end_coord,
+ Int2Type<false> is_direct_load) ///< Marker type indicating whether to load nonzeros directly during path-discovery or beforehand in batch
+ {
+ int tile_num_rows = tile_end_coord.x - tile_start_coord.x;
+ int tile_num_nonzeros = tile_end_coord.y - tile_start_coord.y;
+
+#if (CUB_PTX_ARCH >= 520)
+
+ OffsetT* s_tile_row_end_offsets = &temp_storage.aliasable.merge_items[0].row_end_offset;
+ ValueT* s_tile_nonzeros = &temp_storage.aliasable.merge_items[tile_num_rows + ITEMS_PER_THREAD].nonzero;
+
+ // Gather the nonzeros for the merge tile into shared memory
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ int nonzero_idx = threadIdx.x + (ITEM * BLOCK_THREADS);
+
+ ValueIteratorT a = wd_values + tile_start_coord.y + nonzero_idx;
+ ColumnIndicesIteratorT ci = wd_column_indices + tile_start_coord.y + nonzero_idx;
+ ValueT* s = s_tile_nonzeros + nonzero_idx;
+
+ if (nonzero_idx < tile_num_nonzeros)
+ {
+
+ OffsetT column_idx = *ci;
+ ValueT value = *a;
+
+ ValueT vector_value = spmv_params.t_vector_x[column_idx];
+ vector_value = wd_vector_x[column_idx];
+
+ ValueT nonzero = value * vector_value;
+
+ *s = nonzero;
+ }
+ }
+
+
+#else
+
+ OffsetT* s_tile_row_end_offsets = &temp_storage.aliasable.merge_items[0].row_end_offset;
+ ValueT* s_tile_nonzeros = &temp_storage.aliasable.merge_items[tile_num_rows + ITEMS_PER_THREAD].nonzero;
+
+ // Gather the nonzeros for the merge tile into shared memory
+ if (tile_num_nonzeros > 0)
+ {
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ int nonzero_idx = threadIdx.x + (ITEM * BLOCK_THREADS);
+ nonzero_idx = CUB_MIN(nonzero_idx, tile_num_nonzeros - 1);
+
+ OffsetT column_idx = wd_column_indices[tile_start_coord.y + nonzero_idx];
+ ValueT value = wd_values[tile_start_coord.y + nonzero_idx];
+
+ ValueT vector_value = spmv_params.t_vector_x[column_idx];
+#if (CUB_PTX_ARCH >= 350)
+ vector_value = wd_vector_x[column_idx];
+#endif
+ ValueT nonzero = value * vector_value;
+
+ s_tile_nonzeros[nonzero_idx] = nonzero;
+ }
+ }
+
+#endif
+
+ // Gather the row end-offsets for the merge tile into shared memory
+ #pragma unroll 1
+ for (int item = threadIdx.x; item <= tile_num_rows; item += BLOCK_THREADS)
+ {
+ s_tile_row_end_offsets[item] = wd_row_end_offsets[tile_start_coord.x + item];
+ }
+
+ CTA_SYNC();
+
+ // Search for the thread's starting coordinate within the merge tile
+ CountingInputIterator<OffsetT> tile_nonzero_indices(tile_start_coord.y);
+ CoordinateT thread_start_coord;
+
+ MergePathSearch(
+ OffsetT(threadIdx.x * ITEMS_PER_THREAD), // Diagonal
+ s_tile_row_end_offsets, // List A
+ tile_nonzero_indices, // List B
+ tile_num_rows,
+ tile_num_nonzeros,
+ thread_start_coord);
+
+ CTA_SYNC(); // Perf-sync
+
+ // Compute the thread's merge path segment
+ CoordinateT thread_current_coord = thread_start_coord;
+ KeyValuePairT scan_segment[ITEMS_PER_THREAD];
+ ValueT running_total = 0.0;
+
+ OffsetT row_end_offset = s_tile_row_end_offsets[thread_current_coord.x];
+ ValueT nonzero = s_tile_nonzeros[thread_current_coord.y];
+
+ #pragma unroll
+ for (int ITEM = 0; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (tile_nonzero_indices[thread_current_coord.y] < row_end_offset)
+ {
+ // Move down (accumulate)
+ scan_segment[ITEM].value = nonzero;
+ running_total += nonzero;
+ ++thread_current_coord.y;
+ nonzero = s_tile_nonzeros[thread_current_coord.y];
+ }
+ else
+ {
+ // Move right (reset)
+ scan_segment[ITEM].value = 0.0;
+ running_total = 0.0;
+ ++thread_current_coord.x;
+ row_end_offset = s_tile_row_end_offsets[thread_current_coord.x];
+ }
+
+ scan_segment[ITEM].key = thread_current_coord.x;
+ }
+
+ CTA_SYNC();
+
+ // Block-wide reduce-value-by-segment
+ KeyValuePairT tile_carry;
+ ReduceBySegmentOpT scan_op;
+ KeyValuePairT scan_item;
+
+ scan_item.value = running_total;
+ scan_item.key = thread_current_coord.x;
+
+ BlockScanT(temp_storage.aliasable.scan).ExclusiveScan(scan_item, scan_item, scan_op, tile_carry);
+
+ if (threadIdx.x == 0)
+ {
+ scan_item.key = thread_start_coord.x;
+ scan_item.value = 0.0;
+ }
+
+ if (tile_num_rows > 0)
+ {
+
+ CTA_SYNC();
+
+ // Scan downsweep and scatter
+ ValueT* s_partials = &temp_storage.aliasable.merge_items[0].nonzero;
+
+ if (scan_item.key != scan_segment[0].key)
+ {
+ s_partials[scan_item.key] = scan_item.value;
+ }
+ else
+ {
+ scan_segment[0].value += scan_item.value;
+ }
+
+ #pragma unroll
+ for (int ITEM = 1; ITEM < ITEMS_PER_THREAD; ++ITEM)
+ {
+ if (scan_segment[ITEM - 1].key != scan_segment[ITEM].key)
+ {
+ s_partials[scan_segment[ITEM - 1].key] = scan_segment[ITEM - 1].value;
+ }
+ else
+ {
+ scan_segment[ITEM].value += scan_segment[ITEM - 1].value;
+ }
+ }
+
+ CTA_SYNC();
+
+ #pragma unroll 1
+ for (int item = threadIdx.x; item < tile_num_rows; item += BLOCK_THREADS)
+ {
+ spmv_params.d_vector_y[tile_start_coord.x + item] = s_partials[item];
+ }
+ }
+
+ // Return the tile's running carry-out
+ return tile_carry;
+ }
+
+
+ /**
+ * Consume input tile
+ */
+ __device__ __forceinline__ void ConsumeTile(
+ CoordinateT* d_tile_coordinates, ///< [in] Pointer to the temporary array of tile starting coordinates
+ KeyValuePairT* d_tile_carry_pairs, ///< [out] Pointer to the temporary array carry-out dot product row-ids, one per block
+ int num_merge_tiles) ///< [in] Number of merge tiles
+ {
+ int tile_idx = (blockIdx.x * gridDim.y) + blockIdx.y; // Current tile index
+
+ if (tile_idx >= num_merge_tiles)
+ return;
+
+ // Read our starting coordinates
+ if (threadIdx.x < 2)
+ {
+ if (d_tile_coordinates == NULL)
+ {
+ // Search our starting coordinates
+ OffsetT diagonal = (tile_idx + threadIdx.x) * TILE_ITEMS;
+ CoordinateT tile_coord;
+ 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_coord);
+
+ temp_storage.tile_coords[threadIdx.x] = tile_coord;
+ }
+ else
+ {
+ temp_storage.tile_coords[threadIdx.x] = d_tile_coordinates[tile_idx + threadIdx.x];
+ }
+ }
+
+ CTA_SYNC();
+
+ CoordinateT tile_start_coord = temp_storage.tile_coords[0];
+ CoordinateT tile_end_coord = temp_storage.tile_coords[1];
+
+ // Consume multi-segment tile
+ KeyValuePairT tile_carry = ConsumeTile(
+ tile_idx,
+ tile_start_coord,
+ tile_end_coord,
+ Int2Type<AgentSpmvPolicyT::DIRECT_LOAD_NONZEROS>());
+
+ // Output the tile's carry-out
+ if (threadIdx.x == 0)
+ {
+ if (HAS_ALPHA)
+ tile_carry.value *= spmv_params.alpha;
+
+ tile_carry.key += tile_start_coord.x;
+ d_tile_carry_pairs[tile_idx] = tile_carry;
+ }
+ }
+
+
+};
+
+
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+
diff --git a/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/single_pass_scan_operators.cuh b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/single_pass_scan_operators.cuh
new file mode 100644
index 0000000..53409bd
--- /dev/null
+++ b/debug_tools/WatchYourStep/ptxjitplus/inc/cub/agent/single_pass_scan_operators.cuh
@@ -0,0 +1,815 @@
+/******************************************************************************
+ * 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
+ * Callback operator types for supplying BlockScan prefixes
+ */
+
+#pragma once
+
+#include <iterator>
+
+#include "../thread/thread_load.cuh"
+#include "../thread/thread_store.cuh"
+#include "../warp/warp_reduce.cuh"
+#include "../util_arch.cuh"
+#include "../util_device.cuh"
+#include "../util_namespace.cuh"
+
+/// Optional outer namespace(s)
+CUB_NS_PREFIX
+
+/// CUB namespace
+namespace cub {
+
+
+/******************************************************************************
+ * Prefix functor type for maintaining a running prefix while scanning a
+ * region independent of other thread blocks
+ ******************************************************************************/
+
+/**
+ * Stateful callback operator type for supplying BlockScan prefixes.
+ * Maintains a running prefix that can be applied to consecutive
+ * BlockScan operations.
+ */
+template <
+ typename T, ///< BlockScan value type
+ typename ScanOpT> ///< Wrapped scan operator type
+struct BlockScanRunningPrefixOp
+{
+ ScanOpT op; ///< Wrapped scan operator
+ T running_total; ///< Running block-wide prefix
+
+ /// Constructor
+ __device__ __forceinline__ BlockScanRunningPrefixOp(ScanOpT op)
+ :
+ op(op)
+ {}
+
+ /// Constructor
+ __device__ __forceinline__ BlockScanRunningPrefixOp(
+ T starting_prefix,
+ ScanOpT op)
+ :
+ op(op),
+ running_total(starting_prefix)
+ {}
+
+ /**
+ * Prefix callback operator. Returns the block-wide running_total in thread-0.
+ */
+ __device__ __forceinline__ T operator()(
+ const T &block_aggregate) ///< The aggregate sum of the BlockScan inputs
+ {
+ T retval = running_total;
+ running_total = op(running_total, block_aggregate);
+ return retval;
+ }
+};
+
+
+/******************************************************************************
+ * Generic tile status interface types for block-cooperative scans
+ ******************************************************************************/
+
+/**
+ * Enumerations of tile status
+ */
+enum ScanTileStatus
+{
+ SCAN_TILE_OOB, // Out-of-bounds (e.g., padding)
+ SCAN_TILE_INVALID = 99, // Not yet processed
+ SCAN_TILE_PARTIAL, // Tile aggregate is available
+ SCAN_TILE_INCLUSIVE, // Inclusive tile prefix is available
+};
+
+
+/**
+ * Tile status interface.
+ */
+template <
+ typename T,
+ bool SINGLE_WORD = Traits<T>::PRIMITIVE>
+struct ScanTileState;
+
+
+/**
+ * Tile status interface specialized for scan status and value types
+ * that can be combined into one machine word that can be
+ * read/written coherently in a single access.
+ */
+template <typename T>
+struct ScanTileState<T, true>
+{
+ // Status word type
+ typedef typename If<(sizeof(T) == 8),
+ long long,
+ typename If<(sizeof(T) == 4),
+ int,
+ typename If<(sizeof(T) == 2),
+ short,
+ char>::Type>::Type>::Type StatusWord;
+
+
+ // Unit word type
+ typedef typename If<(sizeof(T) == 8),
+ longlong2,
+ typename If<(sizeof(T) == 4),
+ int2,
+ typename If<(sizeof(T) == 2),
+ int,
+ uchar2>::Type>::Type>::Type TxnWord;
+
+
+ // Device word type
+ struct TileDescriptor
+ {
+ StatusWord status;
+ T value;
+ };
+
+
+ // Constants
+ enum
+ {
+ TILE_STATUS_PADDING = CUB_PTX_WARP_THREADS,
+ };
+
+
+ // Device storage
+ TxnWord *d_tile_descriptors;
+
+ /// Constructor
+ __host__ __device__ __forceinline__
+ ScanTileState()
+ :
+ d_tile_descriptors(NULL)
+ {}
+
+
+ /// Initializer
+ __host__ __device__ __forceinline__
+ cudaError_t Init(
+ int /*num_tiles*/, ///< [in] Number of tiles
+ 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] Size in bytes of \t d_temp_storage allocation
+ {
+ d_tile_descriptors = reinterpret_cast<TxnWord*>(d_temp_storage);
+ return cudaSuccess;
+ }
+
+
+ /**
+ * Compute device memory needed for tile status
+ */
+ __host__ __device__ __forceinline__
+ static cudaError_t AllocationSize(
+ int num_tiles, ///< [in] Number of tiles
+ size_t &temp_storage_bytes) ///< [out] Size in bytes of \t d_temp_storage allocation
+ {
+ temp_storage_bytes = (num_tiles + TILE_STATUS_PADDING) * sizeof(TileDescriptor); // bytes needed for tile status descriptors
+ return cudaSuccess;
+ }
+
+
+ /**
+ * Initialize (from device)
+ */
+ __device__ __forceinline__ void InitializeStatus(int num_tiles)
+ {
+ int tile_idx = (blockIdx.x * blockDim.x) + threadIdx.x;
+
+ TxnWord val = TxnWord();
+ TileDescriptor *descriptor = reinterpret_cast<TileDescriptor*>(&val);
+
+ if (tile_idx < num_tiles)
+ {
+ // Not-yet-set
+ descriptor->status = StatusWord(SCAN_TILE_INVALID);
+ d_tile_descriptors[TILE_STATUS_PADDING + tile_idx] = val;
+ }
+
+ if ((blockIdx.x == 0) && (threadIdx.x < TILE_STATUS_PADDING))
+ {
+ // Padding
+ descriptor->status = StatusWord(SCAN_TILE_OOB);
+ d_tile_descriptors[threadIdx.x] = val;
+ }
+ }
+
+
+ /**
+ * Update the specified tile's inclusive value and corresponding status
+ */
+ __device__ __forceinline__ void SetInclusive(int tile_idx, T tile_inclusive)
+ {
+ TileDescriptor tile_descriptor;
+ tile_descriptor.status = SCAN_TILE_INCLUSIVE;
+ tile_descriptor.value = tile_inclusive;
+
+ TxnWord alias;
+ *reinterpret_cast<TileDescriptor*>(&alias) = tile_descriptor;
+ ThreadStore<STORE_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx, alias);
+ }
+
+
+ /**
+ * Update the specified tile's partial value and corresponding status
+ */
+ __device__ __forceinline__ void SetPartial(int tile_idx, T tile_partial)
+ {
+ TileDescriptor tile_descriptor;
+ tile_descriptor.status = SCAN_TILE_PARTIAL;
+ tile_descriptor.value = tile_partial;
+
+ TxnWord alias;
+ *reinterpret_cast<TileDescriptor*>(&alias) = tile_descriptor;
+ ThreadStore<STORE_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx, alias);
+ }
+
+ /**
+ * Wait for the corresponding tile to become non-invalid
+ */
+ __device__ __forceinline__ void WaitForValid(
+ int tile_idx,
+ StatusWord &status,
+ T &value)
+ {
+ TileDescriptor tile_descriptor;
+ do
+ {
+ __threadfence_block(); // prevent hoisting loads from loop
+ TxnWord alias = ThreadLoad<LOAD_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx);
+ tile_descriptor = reinterpret_cast<TileDescriptor&>(alias);
+
+ } while (WARP_ANY((tile_descriptor.status == SCAN_TILE_INVALID), 0xffffffff));
+
+ status = tile_descriptor.status;
+ value = tile_descriptor.value;
+ }
+
+};
+
+
+
+/**
+ * Tile status interface specialized for scan status and value types that
+ * cannot be combined into one machine word.
+ */
+template <typename T>
+struct ScanTileState<T, false>
+{
+ // Status word type
+ typedef char StatusWord;
+
+ // Constants
+ enum
+ {
+ TILE_STATUS_PADDING = CUB_PTX_WARP_THREADS,
+ };
+
+ // Device storage
+ StatusWord *d_tile_status;
+ T *d_tile_partial;
+ T *d_tile_inclusive;
+
+ /// Constructor
+ __host__ __device__ __forceinline__
+ ScanTileState()
+ :
+ d_tile_status(NULL),
+ d_tile_partial(NULL),
+ d_tile_inclusive(NULL)
+ {}
+
+
+ /// Initializer
+ __host__ __device__ __forceinline__
+ cudaError_t Init(
+ int num_tiles, ///< [in] Number of tiles
+ 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] Size in bytes of \t d_temp_storage allocation
+ {
+ cudaError_t error = cudaSuccess;
+ do
+ {
+ void* allocations[3];
+ size_t allocation_sizes[3];
+
+ allocation_sizes[0] = (num_tiles + TILE_STATUS_PADDING) * sizeof(StatusWord); // bytes needed for tile status descriptors
+ allocation_sizes[1] = (num_tiles + TILE_STATUS_PADDING) * sizeof(Uninitialized<T>); // bytes needed for partials
+ allocation_sizes[2] = (num_tiles + TILE_STATUS_PADDING) * sizeof(Uninitialized<T>); // bytes needed for inclusives
+
+ // Compute allocation pointers into the single storage blob
+ if (CubDebug(error = AliasTemporaries(d_temp_storage, temp_storage_bytes, allocations, allocation_sizes))) break;
+
+ // Alias the offsets
+ d_tile_status = reinterpret_cast<StatusWord*>(allocations[0]);
+ d_tile_partial = reinterpret_cast<T*>(allocations[1]);
+ d_tile_inclusive = reinterpret_cast<T*>(allocations[2]);
+ }
+ while (0);
+
+ return error;
+ }
+
+
+ /**
+ * Compute device memory needed for tile status
+ */
+ __host__ __device__ __forceinline__
+ static cudaError_t AllocationSize(
+ int num_tiles, ///< [in] Number of tiles
+ size_t &temp_storage_bytes) ///< [out] Size in bytes of \t d_temp_storage allocation
+ {
+ // Specify storage allocation requirements
+ size_t allocation_sizes[3];
+ allocation_sizes[0] = (num_tiles + TILE_STATUS_PADDING) * sizeof(StatusWord); // bytes needed for tile status descriptors
+ allocation_sizes[1] = (num_tiles + TILE_STATUS_PADDING) * sizeof(Uninitialized<T>); // bytes needed for partials
+ allocation_sizes[2] = (num_tiles + TILE_STATUS_PADDING) * sizeof(Uninitialized<T>); // bytes needed for inclusives
+
+ // Set the necessary size of the blob
+ void* allocations[3];
+ return CubDebug(AliasTemporaries(NULL, temp_storage_bytes, allocations, allocation_sizes));
+ }
+
+
+ /**
+ * Initialize (from device)
+ */
+ __device__ __forceinline__ void InitializeStatus(int num_tiles)
+ {
+ int tile_idx = (blockIdx.x * blockDim.x) + threadIdx.x;
+ if (tile_idx < num_tiles)
+ {
+ // Not-yet-set
+ d_tile_status[TILE_STATUS_PADDING + tile_idx] = StatusWord(SCAN_TILE_INVALID);
+ }
+
+ if ((blockIdx.x == 0) && (threadIdx.x < TILE_STATUS_PADDING))
+ {
+ // Padding
+ d_tile_status[threadIdx.x] = StatusWord(SCAN_TILE_OOB);
+ }
+ }
+
+
+ /**
+ * Update the specified tile's inclusive value and corresponding status
+ */
+ __device__ __forceinline__ void SetInclusive(int tile_idx, T tile_inclusive)
+ {
+ // Update tile inclusive value
+ ThreadStore<STORE_CG>(d_tile_inclusive + TILE_STATUS_PADDING + tile_idx, tile_inclusive);
+
+ // Fence
+ __threadfence();
+
+ // Update tile status
+ ThreadStore<STORE_CG>(d_tile_status + TILE_STATUS_PADDING + tile_idx, StatusWord(SCAN_TILE_INCLUSIVE));
+ }
+
+
+ /**
+ * Update the specified tile's partial value and corresponding status
+ */
+ __device__ __forceinline__ void SetPartial(int tile_idx, T tile_partial)
+ {
+ // Update tile partial value
+ ThreadStore<STORE_CG>(d_tile_partial + TILE_STATUS_PADDING + tile_idx, tile_partial);
+
+ // Fence
+ __threadfence();
+
+ // Update tile status
+ ThreadStore<STORE_CG>(d_tile_status + TILE_STATUS_PADDING + tile_idx, StatusWord(SCAN_TILE_PARTIAL));
+ }
+
+ /**
+ * Wait for the corresponding tile to become non-invalid
+ */
+ __device__ __forceinline__ void WaitForValid(
+ int tile_idx,
+ StatusWord &status,
+ T &value)
+ {
+ do {
+ status = ThreadLoad<LOAD_CG>(d_tile_status + TILE_STATUS_PADDING + tile_idx);
+
+ __threadfence(); // prevent hoisting loads from loop or loads below above this one
+
+ } while (status == SCAN_TILE_INVALID);
+
+ if (status == StatusWord(SCAN_TILE_PARTIAL))
+ value = ThreadLoad<LOAD_CG>(d_tile_partial + TILE_STATUS_PADDING + tile_idx);
+ else
+ value = ThreadLoad<LOAD_CG>(d_tile_inclusive + TILE_STATUS_PADDING + tile_idx);
+ }
+};
+
+
+/******************************************************************************
+ * ReduceByKey tile status interface types for block-cooperative scans
+ ******************************************************************************/
+
+/**
+ * Tile status interface for reduction by key.
+ *
+ */
+template <
+ typename ValueT,
+ typename KeyT,
+ bool SINGLE_WORD = (Traits<ValueT>::PRIMITIVE) && (sizeof(ValueT) + sizeof(KeyT) < 16)>
+struct ReduceByKeyScanTileState;
+
+
+/**
+ * Tile status interface for reduction by key, specialized for scan status and value types that
+ * cannot be combined into one machine word.
+ */
+template <
+ typename ValueT,
+ typename KeyT>
+struct ReduceByKeyScanTileState<ValueT, KeyT, false> :
+ ScanTileState<KeyValuePair<KeyT, ValueT> >
+{
+ typedef ScanTileState<KeyValuePair<KeyT, ValueT> > SuperClass;
+
+ /// Constructor
+ __host__ __device__ __forceinline__
+ ReduceByKeyScanTileState() : SuperClass() {}
+};
+
+
+/**
+ * Tile status interface for reduction by key, specialized for scan status and value types that
+ * can be combined into one machine word that can be read/written coherently in a single access.
+ */
+template <
+ typename ValueT,
+ typename KeyT>
+struct ReduceByKeyScanTileState<ValueT, KeyT, true>
+{
+ typedef KeyValuePair<KeyT, ValueT>KeyValuePairT;
+
+ // Constants
+ enum
+ {
+ PAIR_SIZE = sizeof(ValueT) + sizeof(KeyT),
+ TXN_WORD_SIZE = 1 << Log2<PAIR_SIZE + 1>::VALUE,
+ STATUS_WORD_SIZE = TXN_WORD_SIZE - PAIR_SIZE,
+
+ TILE_STATUS_PADDING = CUB_PTX_WARP_THREADS,
+ };
+
+ // Status word type
+ typedef typename If<(STATUS_WORD_SIZE == 8),
+ long long,
+ typename If<(STATUS_WORD_SIZE == 4),
+ int,
+ typename If<(STATUS_WORD_SIZE == 2),
+ short,
+ char>::Type>::Type>::Type StatusWord;
+
+ // Status word type
+ typedef typename If<(TXN_WORD_SIZE == 16),
+ longlong2,
+ typename If<(TXN_WORD_SIZE == 8),
+ long long,
+ int>::Type>::Type TxnWord;
+
+ // Device word type (for when sizeof(ValueT) == sizeof(KeyT))
+ struct TileDescriptorBigStatus
+ {
+ KeyT key;
+ ValueT value;
+ StatusWord status;
+ };
+
+ // Device word type (for when sizeof(ValueT) != sizeof(KeyT))
+ struct TileDescriptorLittleStatus
+ {
+ ValueT value;
+ StatusWord status;
+ KeyT key;
+ };
+
+ // Device word type
+ typedef typename If<
+ (sizeof(ValueT) == sizeof(KeyT)),
+ TileDescriptorBigStatus,
+ TileDescriptorLittleStatus>::Type
+ TileDescriptor;
+
+
+ // Device storage
+ TxnWord *d_tile_descriptors;
+
+
+ /// Constructor
+ __host__ __device__ __forceinline__
+ ReduceByKeyScanTileState()
+ :
+ d_tile_descriptors(NULL)
+ {}
+
+
+ /// Initializer
+ __host__ __device__ __forceinline__
+ cudaError_t Init(
+ int /*num_tiles*/, ///< [in] Number of tiles
+ 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] Size in bytes of \t d_temp_storage allocation
+ {
+ d_tile_descriptors = reinterpret_cast<TxnWord*>(d_temp_storage);
+ return cudaSuccess;
+ }
+
+
+ /**
+ * Compute device memory needed for tile status
+ */
+ __host__ __device__ __forceinline__
+ static cudaError_t AllocationSize(
+ int num_tiles, ///< [in] Number of tiles
+ size_t &temp_storage_bytes) ///< [out] Size in bytes of \t d_temp_storage allocation
+ {
+ temp_storage_bytes = (num_tiles + TILE_STATUS_PADDING) * sizeof(TileDescriptor); // bytes needed for tile status descriptors
+ return cudaSuccess;
+ }
+
+
+ /**
+ * Initialize (from device)
+ */
+ __device__ __forceinline__ void InitializeStatus(int num_tiles)
+ {
+ int tile_idx = (blockIdx.x * blockDim.x) + threadIdx.x;
+ TxnWord val = TxnWord();
+ TileDescriptor *descriptor = reinterpret_cast<TileDescriptor*>(&val);
+
+ if (tile_idx < num_tiles)
+ {
+ // Not-yet-set
+ descriptor->status = StatusWord(SCAN_TILE_INVALID);
+ d_tile_descriptors[TILE_STATUS_PADDING + tile_idx] = val;
+ }
+
+ if ((blockIdx.x == 0) && (threadIdx.x < TILE_STATUS_PADDING))
+ {
+ // Padding
+ descriptor->status = StatusWord(SCAN_TILE_OOB);
+ d_tile_descriptors[threadIdx.x] = val;
+ }
+ }
+
+
+ /**
+ * Update the specified tile's inclusive value and corresponding status
+ */
+ __device__ __forceinline__ void SetInclusive(int tile_idx, KeyValuePairT tile_inclusive)
+ {
+ TileDescriptor tile_descriptor;
+ tile_descriptor.status = SCAN_TILE_INCLUSIVE;
+ tile_descriptor.value = tile_inclusive.value;
+ tile_descriptor.key = tile_inclusive.key;
+
+ TxnWord alias;
+ *reinterpret_cast<TileDescriptor*>(&alias) = tile_descriptor;
+ ThreadStore<STORE_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx, alias);
+ }
+
+
+ /**
+ * Update the specified tile's partial value and corresponding status
+ */
+ __device__ __forceinline__ void SetPartial(int tile_idx, KeyValuePairT tile_partial)
+ {
+ TileDescriptor tile_descriptor;
+ tile_descriptor.status = SCAN_TILE_PARTIAL;
+ tile_descriptor.value = tile_partial.value;
+ tile_descriptor.key = tile_partial.key;
+
+ TxnWord alias;
+ *reinterpret_cast<TileDescriptor*>(&alias) = tile_descriptor;
+ ThreadStore<STORE_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx, alias);
+ }
+
+ /**
+ * Wait for the corresponding tile to become non-invalid
+ */
+ __device__ __forceinline__ void WaitForValid(
+ int tile_idx,
+ StatusWord &status,
+ KeyValuePairT &value)
+ {
+// TxnWord alias = ThreadLoad<LOAD_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx);
+// TileDescriptor tile_descriptor = reinterpret_cast<TileDescriptor&>(alias);
+//
+// while (tile_descriptor.status == SCAN_TILE_INVALID)
+// {
+// __threadfence_block(); // prevent hoisting loads from loop
+//
+// alias = ThreadLoad<LOAD_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx);
+// tile_descriptor = reinterpret_cast<TileDescriptor&>(alias);
+// }
+//
+// status = tile_descriptor.status;
+// value.value = tile_descriptor.value;
+// value.key = tile_descriptor.key;
+
+ TileDescriptor tile_descriptor;
+ do
+ {
+ __threadfence_block(); // prevent hoisting loads from loop
+ TxnWord alias = ThreadLoad<LOAD_CG>(d_tile_descriptors + TILE_STATUS_PADDING + tile_idx);
+ tile_descriptor = reinterpret_cast<TileDescriptor&>(alias);
+
+ } while (WARP_ANY((tile_descriptor.status == SCAN_TILE_INVALID), 0xffffffff));
+
+ status = tile_descriptor.status;
+ value.value = tile_descriptor.value;
+ value.key = tile_descriptor.key;
+ }
+
+};
+
+
+/******************************************************************************
+ * Prefix call-back operator for coupling local block scan within a
+ * block-cooperative scan
+ ******************************************************************************/
+
+/**
+ * Stateful block-scan prefix functor. Provides the the running prefix for
+ * the current tile by using the call-back warp to wait on on
+ * aggregates/prefixes from predecessor tiles to become available.
+ */
+template <
+ typename T,
+ typename ScanOpT,
+ typename ScanTileStateT,
+ int PTX_ARCH = CUB_PTX_ARCH>
+struct TilePrefixCallbackOp
+{
+ // Parameterized warp reduce
+ typedef WarpReduce<T, CUB_PTX_WARP_THREADS, PTX_ARCH> WarpReduceT;
+
+ // Temporary storage type
+ struct _TempStorage
+ {
+ typename WarpReduceT::TempStorage warp_reduce;
+ T exclusive_prefix;
+ T inclusive_prefix;
+ T block_aggregate;
+ };
+
+ // Alias wrapper allowing temporary storage to be unioned
+ struct TempStorage : Uninitialized<_TempStorage> {};
+
+ // Type of status word
+ typedef typename ScanTileStateT::StatusWord StatusWord;
+
+ // Fields
+ _TempStorage& temp_storage; ///< Reference to a warp-reduction instance
+ ScanTileStateT& tile_status; ///< Interface to tile status
+ ScanOpT scan_op; ///< Binary scan operator
+ int tile_idx; ///< The current tile index
+ T exclusive_prefix; ///< Exclusive prefix for the tile
+ T inclusive_prefix; ///< Inclusive prefix for the tile
+
+ // Constructor
+ __device__ __forceinline__
+ TilePrefixCallbackOp(
+ ScanTileStateT &tile_status,
+ TempStorage &temp_storage,
+ ScanOpT scan_op,
+ int tile_idx)
+ :
+ temp_storage(temp_storage.Alias()),
+ tile_status(tile_status),
+ scan_op(scan_op),
+ tile_idx(tile_idx) {}
+
+
+ // Block until all predecessors within the warp-wide window have non-invalid status
+ __device__ __forceinline__
+ void ProcessWindow(
+ int predecessor_idx, ///< Preceding tile index to inspect
+ StatusWord &predecessor_status, ///< [out] Preceding tile status
+ T &window_aggregate) ///< [out] Relevant partial reduction from this window of preceding tiles
+ {
+ T value;
+ tile_status.WaitForValid(predecessor_idx, predecessor_status, value);
+
+ // Perform a segmented reduction to get the prefix for the current window.
+ // Use the swizzled scan operator because we are now scanning *down* towards thread0.
+
+ int tail_flag = (predecessor_status == StatusWord(SCAN_TILE_INCLUSIVE));
+ window_aggregate = WarpReduceT(temp_storage.warp_reduce).TailSegmentedReduce(
+ value,
+ tail_flag,
+ SwizzleScanOp<ScanOpT>(scan_op));
+ }
+
+
+ // BlockScan prefix callback functor (called by the first warp)
+ __device__ __forceinline__
+ T operator()(T block_aggregate)
+ {
+
+ // Update our status with our tile-aggregate
+ if (threadIdx.x == 0)
+ {
+ temp_storage.block_aggregate = block_aggregate;
+ tile_status.SetPartial(tile_idx, block_aggregate);
+ }
+
+ int predecessor_idx = tile_idx - threadIdx.x - 1;
+ StatusWord predecessor_status;
+ T window_aggregate;
+
+ // Wait for the warp-wide window of predecessor tiles to become valid
+ ProcessWindow(predecessor_idx, predecessor_status, window_aggregate);
+
+ // The exclusive tile prefix starts out as the current window aggregate
+ exclusive_prefix = window_aggregate;
+
+ // Keep sliding the window back until we come across a tile whose inclusive prefix is known
+ while (WARP_ALL((predecessor_status != StatusWord(SCAN_TILE_INCLUSIVE)), 0xffffffff))
+ {
+ predecessor_idx -= CUB_PTX_WARP_THREADS;
+
+ // Update exclusive tile prefix with the window prefix
+ ProcessWindow(predecessor_idx, predecessor_status, window_aggregate);
+ exclusive_prefix = scan_op(window_aggregate, exclusive_prefix);
+ }
+
+ // Compute the inclusive tile prefix and update the status for this tile
+ if (threadIdx.x == 0)
+ {
+ inclusive_prefix = scan_op(exclusive_prefix, block_aggregate);
+ tile_status.SetInclusive(tile_idx, inclusive_prefix);
+
+ temp_storage.exclusive_prefix = exclusive_prefix;
+ temp_storage.inclusive_prefix = inclusive_prefix;
+ }
+
+ // Return exclusive_prefix
+ return exclusive_prefix;
+ }
+
+ // Get the exclusive prefix stored in temporary storage
+ __device__ __forceinline__
+ T GetExclusivePrefix()
+ {
+ return temp_storage.exclusive_prefix;
+ }
+
+ // Get the inclusive prefix stored in temporary storage
+ __device__ __forceinline__
+ T GetInclusivePrefix()
+ {
+ return temp_storage.inclusive_prefix;
+ }
+
+ // Get the block aggregate stored in temporary storage
+ __device__ __forceinline__
+ T GetBlockAggregate()
+ {
+ return temp_storage.block_aggregate;
+ }
+
+};
+
+
+} // CUB namespace
+CUB_NS_POSTFIX // Optional outer namespace(s)
+