CUDA中__syncthreads()的替代方法

时间:2015-09-29 15:02:41

标签: cuda gpu-programming

我正在使用CUDA并行化C代码。我想到的是我们可以用以下模式进行计算: computational pattern

因此,我们只能计算一个标有“' 1'在第一步中,只有在完成第一个元素的计算之后,我们才能开始计算标记为' 2'的下两个对角线元素,因为我们有数据依赖性。等等其他元素......

我们为解决这个问题而采取的方法是为每一行分配一个线程,每一行都在每一步的末尾执行__syncthreads(),以实现上述同步。

但是,__syncthreads()需要花费很多时间。是否有任何替代解决方案。

编辑1: 计算每个元素X的依赖模式如下:

5 point stencil

此处,元素X需要红色和绿色元素的值。 它仅依赖于红色元素(在前一次迭代中计算)。

提前致谢。

2 个答案:

答案 0 :(得分:2)

您可以利用warp中的所有线程同时执行而不需要显式同步的事实。为此,让我们使每个warp评估一个独立的大块结果,并仅在大块处理之间使用同步。让我们加载大方块的边界数据,并在独立的warp中处理它们。 在这里我尝试绘制新模式,每个方块围绕单个warp的数据,颜色开关表示需要同步,L表示warp需要加载该元素,E表示warp将负责元素评估。当然,块必须和经线一样大,而不是像图像那么小。

代码可能如下所示:

volatile shared sharedChunks[warpsInBlock][33][33];
int warpId = threadIdx.x / 32;
int inWarpId = threadIdx.x % 32;
while(not done){
  sharedChunks[warpId][0][inWarpId + 1] =
    data[mapToCorrectHorisontalLoadId(threadIdx, iteration)];
  sharedChunks[warpId][inWarpId + 1][0] =
    data[mapToCorrectVerticalLoadId(threadIdx, iteration)];
  // Filling upper left triangle of array
  for(int i = 0; i < 32; ++i){
    if(inWarpId <= i){
      sharedChunks[warpId][i - inWarpId + 1][inWarpId + 1] =
        sharedChunks[warpId][i - inWarpId][inWarpId + 1] +
        sharedChunks[warpId][i - inWarpId + 1][inWarpId];
    }
  }
  // Filling lower right triangle of array
  for(int i = 1; i < 32; ++i){
    if(inWarpId >= i)
      sharedChunks[warpId][i + inWarpId + 1][31 - inWarpId + 1] =
        sharedChunks[warpId][i + inWarpId][31 - inWarpId + 1] +
        sharedChunks[warpId][i + inWarpId + 1][31 - inWarpId];
  }
  for(int i = 0; i < 32; ++i){
    data[backwardMapping(threadIdx, iteration, i)] =
      sharedChunks[warpId][i + 1][inWarpId + 1];
  }
  __syncthreads();
}

这里要完全评估32个对角线上的元素,您只需要进行两次同步而不是32次。

但是这个解决方案有其自身的缺点:

  1. 您必须弄清楚从全局内存数据索引到intrawarp索引的映射。如果装载或商店没有足够的合并,你可能无法获得任何加速。
  2. 正如您所看到的,在块评估期间,一些线程在很多时间内都无所事事。大约有一半的时间不会被使用。
  3. 高度依赖可用于块的共享内存。共享内存使用量可以降低更多同步的成本。例如,您可以使用大小为(warpsInBlock*2)x17x17的数组,此处每个warp将评估两个较小的块,共享内存使用量将大约低两倍,但同步数量将高出两倍。
  4. 也许别的什么我忘了。

    你可能会尝试这样做,但真正的加速将高度依赖于许多因素。

答案 1 :(得分:0)

首先,很抱歉要复活一个超旧线程。

您可以对项目进行重新排序(通过巧妙的寻址,而不是在内存中)以获得如下访问模式:

Uncaught TypeError: Failed to set an indexed property on 'HTMLSelectElement': The provided value is not of type 'HTMLOptionElement'.
at ob (jquery.dataTables.min.js:50)
at nb (jquery.dataTables.min.js:32)
at ha (jquery.dataTables.min.js:48)
at e (jquery.dataTables.min.js:93)
at b (jquery.dataTables.min.js:73)
at Jb (jquery.dataTables.min.js:74)
at HTMLTableElement.<anonymous> (jquery.dataTables.min.js:93)
at Function.each (jquery-3.3.1.min.js:2)
at w.fn.init.each (jquery-3.3.1.min.js:2)
at w.fn.init.n [as dataTable] (jquery.dataTables.min.js:83)

...等等。仅在每一行之后都需要1 2 2 3 3 3 4 4 4 4 ,这样会更快。