CUDA中_syncthreads()的替代方案
我正在使用CUDA对C代码进行并行化。我发现我们可以按照以下模式进行计算: 因此,在第一步中,我们只能计算标记为“1”的一个元素,只有在第一个元素的计算完成后,我们才能开始计算标记为“2”的下两个对角元素,因为我们具有数据依赖性。其他元素等等 我们解决这个问题的方法是为每一行分配一个线程,其中每一行在每个步骤结束时执行CUDA中_syncthreads()的替代方案,cuda,gpu,Cuda,Gpu,我正在使用CUDA对C代码进行并行化。我发现我们可以按照以下模式进行计算: 因此,在第一步中,我们只能计算标记为“1”的一个元素,只有在第一个元素的计算完成后,我们才能开始计算标记为“2”的下两个对角元素,因为我们具有数据依赖性。其他元素等等 我们解决这个问题的方法是为每一行分配一个线程,其中每一行在每个步骤结束时执行\uu syncthreads(),以实现上述同步 但是,\uu syncthreads()需要很多时间。这个问题有没有其他解决办法 编辑1: 计算每个元素X的依赖模式如下:
\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次同步
但这种解决方案有其自身的缺点:
(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次同步
但这种解决方案有其自身的缺点:
(warpsInBlock*2)x17x17
的数组,在这里,每个warp将评估两个较小的块,共享内存使用量将大约减少两倍,但同步数将增加两倍