CUDA中计算素数的并行归约
我有一个计算素数的代码,我已经用OpenMP并行化了:CUDA中计算素数的并行归约,cuda,primes,reduction,Cuda,Primes,Reduction,我有一个计算素数的代码,我已经用OpenMP并行化了: #pragma omp parallel for private(i,j) reduction(+:pcount) schedule(dynamic) for (i = sqrt_limit+1; i < limit; i++) { check = 1; for (j = 2; j <= sqrt_limit; j++) {
#pragma omp parallel for private(i,j) reduction(+:pcount) schedule(dynamic)
for (i = sqrt_limit+1; i < limit; i++)
{
check = 1;
for (j = 2; j <= sqrt_limit; j++)
{
if ( !(j&1) && (i&(j-1)) == 0 )
{
check = 0;
break;
}
if ( j&1 && i%j == 0 )
{
check = 0;
break;
}
}
if (check)
pcount++;
}
虽然我声称对筛选素数一无所知,但在您的GPU版本中存在大量的正确性问题,无论您正在实现的算法是否正确,这些问题都会阻止它正常工作:
\uuu syncthreads()
调用必须是无条件的。如果分支分歧会使同一扭曲中的某些线程无法执行\uu syncthreads()
调用,则编写代码是不正确的。基本的PTX是bar.sync
,PTX指南中说:
屏障是在每一个扭曲的基础上执行的,就好像一个扭曲中的所有线程一样
“扭曲”处于活动状态。因此,如果扭曲中的任何线程执行一个条
指令,就好像扭曲中的所有线程都执行了
酒吧指导。经纱中的所有线都会暂停,直到障碍物
完成,并且屏障的到达计数将按
扭曲大小(不是扭曲中活动线程的数量)。在里面
有条件执行的代码,仅当
众所周知,所有线程对条件的评估都是相同的(
翘曲不发散)。因为屏障是在每一个扭曲上执行的
在此基础上,可选线程数必须是扭曲大小的倍数s\u标志设置为1。这肯定不是守则的目的吗
我认为您提出了错误的问题,并且以错误的顺序提问-首先是“我如何才能使此代码正确工作?”,然后是“我如何才能在CUDA中有效地完成此任务?”。第二个问题的答案可能与第一个问题的答案毫无关系。是的,我确实意识到情况就是这样,这个问题是在没有深思熟虑和匆忙的情况下提出的。
__global__ void sieve ( int *flags, int *o_flags, long int sqrootN, long int N)
{
long int gid = blockIdx.x*blockDim.x+threadIdx.x, tid = threadIdx.x, j;
__shared__ int s_flags[NTHREADS];
if (gid > sqrootN && gid < N)
s_flags[tid] = flags[gid];
else
return;
__syncthreads();
s_flags[tid] = 1;
for (j = 2; j <= sqrootN; j++)
{
if ( gid%j == 0 )
{
s_flags[tid] = 0;
break;
}
}
//reduce
for(unsigned int s=1; s < blockDim.x; s*=2)
{
if( tid % (2*s) == 0 )
{
s_flags[tid] += s_flags[tid + s];
}
__syncthreads();
}
//write results of this block to the global memory
if (tid == 0)
o_flags[blockIdx.x] = s_flags[0];
}
__global__ void sieve ( int *o_flags, long int sqrootN, long int N )
{
unsigned int gid = blockIdx.x*blockDim.x+threadIdx.x, tid = threadIdx.x;
volatile __shared__ int s_flags[NTHREADS];
s_flags[tid] = 1;
for (unsigned int j=2; j<=sqrootN; j++)
{
if ( gid % j == 0 )
s_flags[tid] = 0;
}
__syncthreads();
//reduce
reduce(s_flags, tid, o_flags);
}