将“for”循环转换为CUDA并行化代码

时间:2014-02-27 08:20:08

标签: multithreading loops parallel-processing cuda

我正在使用CUDA并行化的C转换最初编写的C代码。 还是一个新手,我将代码的大部分内容转换为CUDA,但我的一些内核没有正确地完成工作。

这是我的内核:

__global__ void kernel(long int *neighbour, double *f, double *r, double *b, double *fn, double *rn, double *bn, int nfluidsite){

int ns = blockDim.x * blockIdx.x + threadIdx.x;

    if(ns<nfluidsite)
 {
  double tempr = r[ns];
  double tempb = b[ns];
  rn[ns]=tempr;
  bn[ns]=tempb;
  for(int q=1;q<Q;++q)
  {  
  double confr=r[q*NSITE+ns];
  double confb=b[q*NSITE+ns];
  __syncthreads();
  int ns1=neighbour[q*NTOTAL+ns];
  __syncthreads();
  rn[q*NSITE+ns1]=confr;
  bn[q*NSITE+ns1]=confb;
  }
 }

if(ns<NSITE)
 {
  for(int q=0;q<Q;++q)
  {
      double rqns = rn[q*NSITE+ns];
      double bqns = bn[q*NSITE+ns];
  __syncthreads();
  r[q*NSITE+ns]=rqns;
  b[q*NSITE+ns]=bqns;
  f[q*NSITE+ns]=rqns+bqns;
  }
 }

}

所以,这段代码工作正常(尽管它根本没有优化),但我也希望在q上并行化内部for循环。所以,我这样做了:

    int ns = blockIdx.x;
    int q = threadIdx.x;

我按如下方式启动了我的内核:

blocksPerGrid = NSITE;
threadsPerBlock = Q;
kernel<<<blocksPerGrid,threadsPerBlock>>>(neighbourCu, fCu, rCu, bCu, fnCu, rnCu, bnCu, nfluidsite);

它根本不起作用,CUDA没有返回任何错误,但是数组上的操作有点随机......我在完全并行化的版本中添加了__syncthreads()命令,但它没有解决差异。

另外,我不是为什么,但如果我使用超过1024个线程,我的内核中的指令也随机运行...

好吧,我已经困惑了两个星期,如果有人看到我需要做什么,请给我一个提示!

1 个答案:

答案 0 :(得分:0)

我认为您不需要放置它们的__syncthreads();,您正在分配和读取线程本地(寄存器或本地内存)变量。

另一方面,您确实需要在以下代码开头的代码块之前调用__threadfence();

if(ns<NSITE) {
  ...
}

违规语句是:

  rn[q*NSITE+ns1]=confr;
  bn[q*NSITE+ns1]=confb;

之前和:

  double rqns = rn[q*NSITE+ns];
  double bqns = bn[q*NSITE+ns];

后。

由于一个线程写入某个全局内存而另一个线程从中读取,因此您需要至少将两者都置于中间:

__threadfence();
__syncthreads();

(更多信息here)。只有当rnbn被同一块中的线程修改时,这才能正常工作。如果发生甚至块外的线程都可以修改它们,那还不够:在继续之前需要保证所有块都已达到该点(注意:__syncthreads()仅保证同一块内的线程 < / em>已达到这一点 - 它是一个块本地屏障)。您有三种选择:

  1. 在这一点上将内核拆分为两个不同的内核 - 单独的内核调用是隐式同步的。我会从这开始,看看它是否有效。

  2. 如果NSITE只是一个线程块,就像看起来一样,你可以再次按照全局和here的例子:只有最后一个块才会这样做 - 其余的只会跳过。

  3. 实施全球障碍(这不是一件容易的事 - 但如果你在谷歌周围,你会找到很好的参考资料)。