在CUDA中重新排列数组

时间:2014-06-05 23:54:08

标签: cuda

我想在CUDA上实现以下问题:

我想读一个数组(比如“flag [20]”),并根据某个条件,将这个数组的索引写入另一个数组(比如说“pindex []”)

C中的简单代码实现可以是:

int N = 20;
int flag[N];
int pindex[N];

for(int i=0;i<N;i++)
    flag[i] = -1;

for(int i=0;i<N;i+=2)
    flag[i] = 0;

for(int i=0;i<N;i++)
    pindex[i] = 0;

//operation: count # of times flag != -1 and write those indices in a different array
int pcount1 = 0;
for(int i=0;i<N;i++)
{
    if(flag[i] != -1)
    {
        pindex[pcount1] = i;
        ++pcount1;
    }
}

我将如何在CUDA中实现这一点?

我可以使用atomicAdd()来计算满足条件的总次数。但是,如何在不同的数组中编写索引。例如,我尝试了以下内容:

__global__ void kernel_tryatomic(int N,int* pcount,int* flag, int* pindex)
{
  int tId=threadIdx.x;
  int n=(blockIdx.x*2+blockIdx.y)*BlockSize+tId;

  if(n > N-1) return;    

  if(flag[n] != -1)
  {
      atomicAdd(pcount,1);
      atomicExch(&pindex[*pcount],n); 
      //pindex[*pcount] = n;
  }
}

此代码正确计算“pcount”,但不更新“pindex”数组。

我需要帮助才能在GPU上执行此操作。

由于

1 个答案:

答案 0 :(得分:2)

由于你的条件(flag)在概念上是二进制的,你可以使用二进制前缀sum(彻底解释here)来确定带有肯定标志的线程应该写入的位置。

例如,如果N为20,则在以下__device__函数的帮助下:

__device__ int lanemask_lt(int lane) {
    return (1 << (lane)) − 1;
}

__device__ int warp_prefix_sums(int lane, int p) {
    const int mask = lanemask_lt( lane );
    int b = __ballot( p );
    return __popc( b & mask );
}

您的__global__函数可以简单地编写如下:

__global__ void kernel_scan(int N,int* pcount,int* flag, int* pindex)
{
    int tId=threadIdx.x;
    if(tId >= N)
        return;    
    int threadFlag = ( flag[tId] == -1 ) ? 0 : 1;
    int position_to_write = warp_prefix_sum( tId & (warpSize-1), threadFlag );
    if( threadFlag )
        pindex[ position_to_write ] = tId;  
}

如果N大于warp大小(32),则可以使用provided link中解释的块内二进制前缀和。