Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CUDA中_syncthreads()的替代方案_Cuda_Gpu - Fatal编程技术网

CUDA中_syncthreads()的替代方案

CUDA中_syncthreads()的替代方案,cuda,gpu,Cuda,Gpu,我正在使用CUDA对C代码进行并行化。我发现我们可以按照以下模式进行计算: 因此,在第一步中,我们只能计算标记为“1”的一个元素,只有在第一个元素的计算完成后,我们才能开始计算标记为“2”的下两个对角元素,因为我们具有数据依赖性。其他元素等等 我们解决这个问题的方法是为每一行分配一个线程,其中每一行在每个步骤结束时执行\uu syncthreads(),以实现上述同步 但是,\uu syncthreads()需要很多时间。这个问题有没有其他解决办法 编辑1: 计算每个元素X的依赖模式如下:

我正在使用CUDA对C代码进行并行化。我发现我们可以按照以下模式进行计算:

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

我们解决这个问题的方法是为每一行分配一个线程,其中每一行在每个步骤结束时执行
\uu syncthreads()
,以实现上述同步

但是,
\uu syncthreads()
需要很多时间。这个问题有没有其他解决办法

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

这里,元素
X
需要红色和绿色元素的值。 它仅依赖于颜色为红色的元素(在上一次迭代中计算)


提前感谢。

您可以利用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();
}
volatile共享sharedChunks[warpsInBlock][33][33];
int warpId=threadIdx.x/32;
int inWarpId=threadIdx.x%32;
虽然(未完成){
sharedChunks[warpId][0][inWarpId+1]=
数据[MapToCorrectHorisontalloid(线程IDX,迭代)];
sharedChunks[warpId][inWarpId+1][0]=
数据[mapToCorrectVerticalLoadId(threadIdx,迭代)];
//填充数组的左上三角形
对于(int i=0;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];
}
对于(int i=0;i<32;++i){
数据[反向映射(线程IDX,迭代,i)]=
sharedChunks[warpId][i+1][inWarpId+1];
}
__同步线程();
}
在这里,要完全评估32条对角线上的元素,您只需要进行两次同步,而不是32次同步

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

  • 您必须找出从全局内存数据索引到intrawarp索引的映射。如果装载或存储的速度不够集中,您可能无法获得任何加速
  • 正如您所看到的,在块计算期间,一些线程在很长时间内什么也不做。大约一半的时间不会被使用
  • 高度依赖于块可用的共享内存。共享内存的使用可以降低更多同步的成本。例如,您可以使用大小为
    (warpsInBlock*2)x17x17
    的数组,在这里,每个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();
    }
    
    volatile共享sharedChunks[warpsInBlock][33][33];
    int warpId=threadIdx.x/32;
    int inWarpId=threadIdx.x%32;
    虽然(未完成){
    sharedChunks[warpId][0][inWarpId+1]=
    数据[MapToCorrectHorisontalloid(线程IDX,迭代)];
    sharedChunks[warpId][inWarpId+1][0]=
    数据[mapToCorrectVerticalLoadId(threadIdx,迭代)];
    //填充数组的左上三角形
    对于(int i=0;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];
    }
    对于(int i=0;i<32;++i){
    数据[反向映射(线程IDX,迭代,i)]=
    sharedChunks[warpId][i+1][inWarpId+1];
    }
    __同步线程();
    }
    
    在这里,要完全评估32条对角线上的元素,您只需要进行两次同步,而不是32次同步

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

  • 您必须找出从全局内存数据索引到intrawarp索引的映射。如果装载或存储的速度不够集中,您可能无法获得任何加速
  • 正如您所看到的,在块计算期间,一些线程在很长时间内什么也不做。大约一半的时间不会被使用
  • 高度依赖于块可用的共享内存。共享内存的使用可以降低更多同步的成本。例如,您可以使用大小为
    (warpsInBlock*2)x17x17
    的数组,在这里,每个warp将评估两个较小的块,共享内存使用量将大约减少两倍,但同步数将增加两倍
  • 也许是