我编写了这个程序,并且在使用内核调用行中的dim3变量来理解如何使用多个块时遇到了一些麻烦。当我进行1000 * 1000矩阵乘法时,此代码工作正常,但对于较低尺寸(如100 * 100,200 * 200)没有得到正确答案。
#include <stdio.h>
#include <cuda.h>
#define width 1000
__global__ void kernel(int *a,int *b,int *c)
{
int tx = threadIdx.x + blockIdx.x*blockDim.x;
int ty = threadIdx.y + blockIdx.y*blockDim.y;
int sum=0,k;
for(k=0;k<(width);++k)
{
sum += a[ty*width +k]*b[k*width + tx];
}
c[ty*width + tx] = sum;
}
int main()
{
int a[width*width],c[width*width],b[width*width];
int *dev_a,*dev_b,*dev_c;
int i,count=0;
int size = (width*width)*sizeof(int);
for(i=0;i<(width*width);i++)
{
a[i] = 1;
b[i] = 1;
}
cudaMalloc((void **)&dev_a,size);
cudaMalloc((void **)&dev_b,size);
cudaMalloc((void **)&dev_c,size);
cudaMemcpy(dev_a,&a,size,cudaMemcpyHostToDevice);
cudaMemcpy(dev_b,&b,size,cudaMemcpyHostToDevice);
dim3 dimBlock(20,20);
dim3 blockID(50,50);
kernel<<<blockID,dimBlock>>>(dev_a,dev_b,dev_c);
cudaMemcpy(&c,dev_c,size,cudaMemcpyDeviceToHost);
for(i=0;i<(width*width);i++)
{
count++;
if(count == (width+1))
{
count = 1;
printf("\n");
}
printf("%d ",c[i]);
}
printf("\n");
return 0;
}
答案 0 :(得分:1)
此代码适用于非常具体的维度,但不适用于其他维度。
当width
完全等于块尺寸(线程数 - 您显示的代码中的20)和网格尺寸(块数 - 50 in)的乘积时,它将适用于方阵乘法你已经展示的代码。)
因此当width
为20 * 50(1000)时,它将如图所示工作。但是,如果我将width
更改为其他值(例如800)并且不进行其他更改,则代码将无效。但是,在800的情况下,我可以通过将网格尺寸从50更改为40,然后width
= 800 = 20 * 40来使代码工作。
但是如果我需要乘以width
799的两个矩阵怎么办?我无法想出一个与width
完全匹配的网格和块维度的产品。
这是CUDA编程中一个相当标准的问题 - 我无法提出方便的块和网格尺寸来完全匹配我的工作(即数据)大小,如果我发起太多(线程/块)事情看起来不像工作。
要解决这个问题,我们必须做两件事:
为了解决上面的第1项,我们将网格尺寸计算修改为:
dim3 dimBlock(16,16);
dim3 blockID((width+dimBlock.x-1)/dimBlock.x,(width+dimBlock.y-1)/dimBlock.y);
为了解决上面的第2项,我们修改了我们的内核代码,以调整线程是否与有效数据相对应的线程行为:
__global__ void kernel(int *a,int *b,int *c, int mwidth)
{
int tx = threadIdx.x + blockIdx.x*blockDim.x;
int ty = threadIdx.y + blockIdx.y*blockDim.y;
if ((tx<mwidth)&&(ty<mwidth)){
int sum=0,k;
for(k=0;k<(mwidth);++k)
{
sum += a[ty*mwidth +k]*b[k*mwidth + tx];
}
c[ty*mwidth + tx] = sum;}
}
由于我们使用新参数修改了内核,因此我们必须在调用时传递该参数:
kernel<<<blockID,dimBlock>>>(dev_a,dev_b,dev_c, width);
这应该是逻辑扩展您显示的代码以处理“任意”维度所需的内容。我建议您在遇到CUDA代码时遇到问题时添加proper cuda error checking。