drout

Radix Sort Parallel Algorithm (n.elem > blockDim * blockDim)

Feb 6th, 2019
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.54 KB | None | 0 0
  1. #include "utils.h"
  2.  
  3. #define MAXTHREADS 1024
  4. typedef unsigned int uint;
  5. #define sizeuint sizeof( uint )
  6.  
  7.  
  8. __global__ void krn_new_scan_1(
  9.     const uint *d_inputVals,
  10.     uint *d_tmpScan0, uint *d_tmpScan1,
  11.     uint *d_tmpInterm0, uint *d_tmpInterm1,
  12.     int numElems, int nbit)
  13. {
  14.     int tgrd = threadIdx.x + blockDim.x * blockIdx.x;
  15.  
  16.     if( tgrd >= numElems )
  17.         return;
  18.  
  19.     int tblk = threadIdx.x;
  20.  
  21.     uint tmp0, tmp1;
  22.  
  23.     __shared__ uint shr_scan0[ MAXTHREADS ];
  24.     __shared__ uint shr_scan1[ MAXTHREADS ];
  25.  
  26.     int bit = (d_inputVals[ tgrd ] >> nbit) & 1;
  27.  
  28.     shr_scan0[ tblk ] = !bit;
  29.     shr_scan1[ tblk ] = bit;
  30.     __syncthreads();
  31.  
  32.     // inclusive scan
  33.     for( int i = 1; i <= MAXTHREADS / 2; i <<= 1 )
  34.     {
  35.         if( tblk >= i )
  36.         {
  37.             tmp0 = shr_scan0[ tblk - i ];
  38.             tmp1 = shr_scan1[ tblk - i ];
  39.         }
  40.         __syncthreads();
  41.  
  42.         if( tblk >= i )
  43.         {
  44.             shr_scan0[ tblk ] += tmp0;
  45.             shr_scan1[ tblk ] += tmp1;
  46.         }
  47.         __syncthreads();
  48.     }
  49.  
  50.     // change to exclusive prefix sum
  51.     d_tmpScan0[ tgrd ] = tblk ? shr_scan0[ tblk - 1 ] : 0;
  52.     d_tmpScan1[ tgrd ] = tblk ? shr_scan1[ tblk - 1 ] : 0;
  53.  
  54.     if( tblk == 0 ) // choosing one thread (0) to do this processing
  55.     {
  56.         int ult_elem;
  57.  
  58.         if( blockIdx.x == gridDim.x - 1 )
  59.             ult_elem = (numElems - 1) % blockDim.x;
  60.         else
  61.             ult_elem = blockDim.x - 1;
  62.  
  63.         // store the offset at each block; preparing to do their own prefix sum
  64.         d_tmpInterm0[ blockIdx.x ] = shr_scan0[ ult_elem ];
  65.         d_tmpInterm1[ blockIdx.x ] = shr_scan1[ ult_elem ];
  66.     }
  67. }
  68.  
  69.  
  70. __global__ void krn_new_scan_2_1(
  71.     uint *d_tmpInterm0, uint *d_tmpInterm1,
  72.     uint *d_tmpIntermAux0, uint *d_tmpIntermAux1,
  73.     int tmpIntermSize )
  74. {
  75.     int tgrd = threadIdx.x + blockDim.x * blockIdx.x;
  76.  
  77.     if( tgrd >= tmpIntermSize )
  78.         return;
  79.  
  80.     int tblk = threadIdx.x;
  81.  
  82.     uint tmp0, tmp1;
  83.  
  84.     __shared__ uint shr_interm0[ MAXTHREADS ];
  85.     __shared__ uint shr_interm1[ MAXTHREADS ];
  86.  
  87.     shr_interm0[ tblk ] = d_tmpInterm0[ tgrd ];
  88.     shr_interm1[ tblk ] = d_tmpInterm1[ tgrd ];
  89.     __syncthreads();
  90.  
  91.     // inclusive scan
  92.     for( int i = 1; i <= MAXTHREADS / 2; i <<= 1 )
  93.     {
  94.         if( tblk >= i )
  95.         {
  96.             tmp0 = shr_interm0[ tblk - i ];
  97.             tmp1 = shr_interm1[ tblk - i ];
  98.         }
  99.         __syncthreads();
  100.  
  101.         if( tblk >= i )
  102.         {
  103.             shr_interm0[ tblk ] += tmp0;
  104.             shr_interm1[ tblk ] += tmp1;
  105.         }
  106.         __syncthreads();
  107.     }
  108.  
  109.     // change to exclusive prefix sum
  110.     d_tmpInterm0[ tgrd ] = tblk ? shr_interm0[ tblk - 1 ] : 0;
  111.     d_tmpInterm1[ tgrd ] = tblk ? shr_interm1[ tblk - 1 ] : 0;
  112.  
  113.  
  114.     if (tblk == 0) // randomly choosing just one thread (0) to do the processing
  115.     {
  116.         int ult_elem;
  117.  
  118.         if( blockIdx.x == gridDim.x - 1 )
  119.             ult_elem = (tmpIntermSize - 1) % blockDim.x;
  120.         else
  121.             ult_elem = blockDim.x - 1;
  122.  
  123.         // store the offset at each block; preparing to do their own prefix sum
  124.         d_tmpIntermAux0[ blockIdx.x ] = shr_interm0[ ult_elem ];
  125.         d_tmpIntermAux1[ blockIdx.x ] = shr_interm1[ ult_elem ];
  126.     }
  127. }
  128.  
  129.  
  130. __global__ void krn_new_scan_2_2(
  131.     uint *d_tmpIntermAux0, uint *d_tmpIntermAux1)
  132. {
  133.     int tblk = threadIdx.x; // assuming grid dimension = 1 (only 1 block)
  134.  
  135.     if (tblk >= blockDim.x)
  136.         return;
  137.  
  138.     uint tmp0, tmp1;
  139.  
  140.     __shared__ uint shr_interm0[ MAXTHREADS ];
  141.     __shared__ uint shr_interm1[ MAXTHREADS ];
  142.  
  143.     shr_interm0[ tblk ] = d_tmpIntermAux0[ tblk ];
  144.     shr_interm1[ tblk ] = d_tmpIntermAux1[ tblk ];
  145.     __syncthreads();
  146.  
  147.     // inclusive scan
  148.     for( int i = 1; i <= MAXTHREADS / 2; i <<= 1 )
  149.     {
  150.         if( tblk >= i )
  151.         {
  152.             tmp0 = shr_interm0[ tblk - i ];
  153.             tmp1 = shr_interm1[ tblk - i ];
  154.         }
  155.         __syncthreads();
  156.  
  157.         if( tblk >= i )
  158.         {
  159.             shr_interm0[ tblk ] += tmp0;
  160.             shr_interm1[ tblk ] += tmp1;
  161.         }
  162.         __syncthreads();
  163.     }
  164.  
  165.     // change to exclusive prefix sum
  166.     d_tmpIntermAux0[ tblk ] = tblk ? shr_interm0[ tblk - 1 ] : 0;
  167.     d_tmpIntermAux1[ tblk ] = tblk ? shr_interm1[ tblk - 1 ] : 0;
  168.     d_tmpIntermAux1[ tblk ] += shr_interm0[ blockDim.x - 1 ]; // add offset (# of bits 0) to bits 1
  169. }
  170.  
  171.  
  172. __global__ void krn_new_scan_2_3(  
  173.     uint *d_tmpInterm0, uint *d_tmpInterm1,
  174.     uint *d_tmpIntermAux0, uint *d_tmpIntermAux1,
  175.     int tmpIntermSize )
  176. {
  177.     int tgrd = threadIdx.x + blockDim.x * blockIdx.x;
  178.  
  179.     if (tgrd >= tmpIntermSize)
  180.         return;
  181.  
  182.     d_tmpInterm0[ tgrd ] += d_tmpIntermAux0[ blockIdx.x ];
  183.     d_tmpInterm1[ tgrd ] += d_tmpIntermAux1[ blockIdx.x ];
  184. }
  185.  
  186.  
  187. __global__ void krn_new_scan_3(
  188.     uint *d_inputVals, uint *d_outputVals,
  189.     uint *d_tmpScan0, uint *d_tmpScan1,
  190.     uint *d_tmpInterm0, uint *d_tmpInterm1,
  191.     int numElems, int nbit)
  192. {
  193.  
  194.     int tgrd = threadIdx.x + blockDim.x * blockIdx.x;
  195.  
  196.     if( tgrd >= numElems )
  197.         return;
  198.  
  199.     int pos;
  200.  
  201.     int bit = (d_inputVals[ tgrd ] >> nbit) & 1;
  202.  
  203.     if( !bit )
  204.         pos = d_tmpScan0[ tgrd ] + d_tmpInterm0[ blockIdx.x ];
  205.     else
  206.         pos = d_tmpScan1[ tgrd ] + d_tmpInterm1[ blockIdx.x ];
  207.  
  208.     d_outputVals[ pos ] = d_inputVals[ tgrd ];
  209. }
  210.  
  211.  
  212.  
  213. //=================================================================
  214.  
  215. void computeHistogram( unsigned int*  d_vals, unsigned int numElems )
  216. {
  217.  
  218.     int blockDim = numBins; // 1024 (can't be > MAXTHREADS)
  219.     int gridDim = (numElems + blockDim - 1) / blockDim;
  220.     int subGridDim = (gridDim + blockDim - 1) / blockDim;
  221.  
  222.  
  223.     uint *d_vals_out;
  224.     uint *h_vals = new uint[ numElems ];
  225.         checkCudaErrors( cudaMalloc( &d_vals_out, numElems * sizeuint ) );
  226.  
  227.     int size_tmpScan = numElems;
  228.     uint *d_tmpScan0; uint *d_tmpScan1; uint *h_tmpScan0 = new uint[ size_tmpScan ]; uint *h_tmpScan1 = new uint[ size_tmpScan ];
  229.         checkCudaErrors( cudaMalloc( &d_tmpScan0, size_tmpScan * sizeuint ) ); checkCudaErrors( cudaMalloc( &d_tmpScan1, size_tmpScan * sizeuint ) );
  230.  
  231.     int size_tmpInterm = gridDim;
  232.     uint *d_tmpInterm0; uint *d_tmpInterm1; uint *h_tmpInterm0 = new uint[ size_tmpInterm ]; uint *h_tmpInterm1 = new uint[ size_tmpInterm ];
  233.         checkCudaErrors( cudaMalloc( &d_tmpInterm0, size_tmpInterm * sizeuint ) ); checkCudaErrors( cudaMalloc( &d_tmpInterm1, size_tmpInterm * sizeuint ) );
  234.  
  235.     int size_tmpIntermAux = subGridDim;
  236.     uint *d_tmpIntermAux0; uint *d_tmpIntermAux1; uint *h_tmpIntermAux0 = new uint[ size_tmpIntermAux ]; uint *h_tmpIntermAux1 = new uint[ size_tmpIntermAux ];
  237.         checkCudaErrors( cudaMalloc( &d_tmpIntermAux0, size_tmpIntermAux * sizeuint ) ); checkCudaErrors( cudaMalloc( &d_tmpIntermAux1, size_tmpIntermAux * sizeuint ) );
  238.  
  239.  
  240.     printf( "\n Starting. "
  241.          "numElems= %d  numBins= %d  gridDim= %d  blockDim= %d\n",
  242.          numElems,     numBins,     gridDim,     blockDim );
  243.  
  244.     const int bitsInUint = sizeuint * 8;
  245.  
  246.     uint *d_ptr_in = (uint*) d_vals;
  247.     uint *d_ptr_out = d_vals_out;
  248.  
  249.     for( int nbit = 0; nbit < bitsInUint; nbit++ )
  250.     {
  251.         krn_new_scan_1 << < gridDim, blockDim >> > (
  252.             d_ptr_in,
  253.             d_tmpScan0, d_tmpScan1,
  254.             d_tmpInterm0, d_tmpInterm1,
  255.             numElems, nbit);
  256.         cudaDeviceSynchronize(); checkCudaErrors( cudaGetLastError() );
  257.  
  258.         krn_new_scan_2_1 << < subGridDim, blockDim >> > (
  259.             d_tmpInterm0, d_tmpInterm1,
  260.             d_tmpIntermAux0, d_tmpIntermAux1,
  261.             gridDim );
  262.         cudaDeviceSynchronize(); checkCudaErrors( cudaGetLastError() );
  263.  
  264.         krn_new_scan_2_2 << < 1, subGridDim >> > (
  265.             d_tmpIntermAux0, d_tmpIntermAux1);
  266.         cudaDeviceSynchronize(); checkCudaErrors( cudaGetLastError() );
  267.  
  268.         krn_new_scan_2_3 << < subGridDim, blockDim >> > (
  269.             d_tmpInterm0, d_tmpInterm1,
  270.             d_tmpIntermAux0, d_tmpIntermAux1,
  271.             gridDim);
  272.         cudaDeviceSynchronize(); checkCudaErrors( cudaGetLastError() );
  273.  
  274.         krn_new_scan_3 << < gridDim, blockDim >> > (
  275.             d_ptr_in, d_ptr_out,
  276.             d_tmpScan0, d_tmpScan1,
  277.             d_tmpInterm0, d_tmpInterm1,
  278.             numElems, nbit);
  279.         cudaDeviceSynchronize(); checkCudaErrors( cudaGetLastError() );
  280.  
  281.         if (nbit < bitsInUint - 1)
  282.             std::swap( d_ptr_in, d_ptr_out );
  283.     }
  284.    
  285.     // Here: sorted list is in d_ptr_out;
  286. }
Advertisement
Add Comment
Please, Sign In to add comment