CUDA和线程阻塞开销

时间:2017-05-14 10:04:41

标签: cuda gpgpu

我实现了一个计算矩阵乘法的简单内核。这是代码:

__global__ void MatMultKernel(Mat A, Mat B, Mat C){

int i;
double val=0.0;
int ix=blockDim.x*blockIdx.x+threadIdx.x;  
int iy=blockDim.y*blockIdx.y+threadIdx.y;
if(ix<A.nrows && iy<B.nrows){
    for(i=0;i<A.nrows;i++)
        val+=A.value[iy*A.nrows+i]*B.value[i*B.nrows+ix];
    C.value[iy*C.nrows+ix]=val;
 }
}

我通过改变线程和阻塞配置来测量这个内核的运行时间。

如果在列块中分配线程,我发现执行时间总是更糟(例如dim3(1,256,1))是什么原因?

1 个答案:

答案 0 :(得分:3)

首先,我要指出您的代码仅适用于方形矩阵,通常您应该在代码的所有三个位置使用A.ncols而不是A.nrows

性能差异是由于内存访问造成的。您有三个以行主格式存储的矩阵,代码执行以下操作:每个线程访问iy AixBi并计算他们的点积。请注意,warp中的所有线程总是同时执行相同的指令,因此在代码中的串行循环(256, 1, 1)对于warp中的所有线程始终是相同的。在您的代码中,块形状很重要,因为:

  • 如果块大小为iy,则块中的每个线程都具有相同的ix,但B不同。让我们看一下B的访问模式:同一个warp中的所有线程始终访问B.value[i*B.nrows+ix]的同一行,因为在iix相同且(1, 256, 1)不同,因此加载可以是coalesced
  • 如果块大小为A,则情境会被转置,因此您可能希望合并iy的加载。但事实并非如此,因为A.ncols确定了行,并且两个相邻线程访问的值被C偏移。

B的访问模式与SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table 的访问模式相同,但重要性要低得多。对于2D块,情况介于两个1D案例之间。

如果您想进一步优化代码,可以使用共享内存,如CUDA Programming Guide所示。