我想在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上执行此操作。
由于
答案 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中解释的块内二进制前缀和。