我已经使用CUDA编写了一小段代码来乘以2个平方矩阵。但是,事实证明,大多数细胞都被错误地计算了。根据我使用的教程,一切应该正常。
__global__ void gpuMM(int *C, int *A, int *B, int N)
{
int row = blockIdx.x*blockDim.x + threadIdx.x;
int col = blockIdx.y*blockDim.y + threadIdx.y;
int sum = 0;
for (int n = 0; n < N; ++n)
sum += A[row*N+n]*B[n*N+col];
C[row*N+col] = sum;
}
#define ROW_SIZE 5
#define MATRIX_LENGTH ROW_SIZE*ROW_SIZE
#define BLOCK_SIZE 16
void MultiplyMatrixCUDA(int * pResult, int* pFactorA, int*pFactorB)
{
int size = MATRIX_LENGTH*sizeof(int);
int *dA,*dB,*dC;
cudaMalloc(&dA,size);
cudaMalloc(&dB,size);
cudaMalloc(&dC,size);
int K = 100;
dim3 threadBlock(BLOCK_SIZE,BLOCK_SIZE);
dim3 grid(K,K);
printf("A:\n");
DrawMatrix(pFactorA);
printf("\n");
printf("B:\n");
DrawMatrix(pFactorB);
printf("\n");
// Copy matrices from the host to device
cudaMemcpy(dA,pFactorA,size,cudaMemcpyHostToDevice);
cudaMemcpy(dB,pFactorB,size,cudaMemcpyHostToDevice);
//Execute the matrix multiplication kernel
gpuMM<<<grid,threadBlock>>>(dC,dA,dB,ROW_SIZE);
// Allocate memory to store the GPU answer on the host
int *C;
C = new int[MATRIX_LENGTH];
// Now copy the GPU result back to CPU
cudaMemcpy(C,dC,size,cudaMemcpyDeviceToHost);
cudaFree(dA);
cudaFree(dB);
cudaFree(dC);
printf("\nC from CUDA:\n");
DrawMatrix(C);
printf("\nC:\n");
DrawMatrix(MultiplyWithCPU(pResult,pFactorA, pFactorB)); // the code of multiplying function is irrevelant, I'm sure it works fine (double-checked)
}
结果表明,矩阵乘以标准CPU方法是正确的,但CUDA是错误的:
第一行始终是正确的,但是所有其他部分都是完全随机的。有时他们是消极的,有时不是。有时它们接近实际价值,有时则完全不同。
我怎么了 我看不出失败的地方。该算法看起来不错,似乎正确传递了变量,但是某些操作无效。
- - 编辑
所有变量(pResult和两个pFactor)都在代码的其他部分初始化(然后删除)。
由于每个块的线程数不等于输出矩阵中的元素数(您在16x16块上映射5x5矩阵),因此某些线程正在访问/写入无效的内存位置。
解决方案包括双重边界检查,以解决该问题。这将导致某些线程处于空闲状态。内核应如下所示:
__global__ void gpuMM(int *C, int *A, int *B, int N)
{
int row = blockIdx.x*blockDim.x + threadIdx.x;
int col = blockIdx.y*blockDim.y + threadIdx.y;
if( (row < N) && (col < N))
{
int sum = 0;
for (int n = 0; n < N; ++n){
sum += A[row*N+n]*B[n*N+col];
}
C[row*N+col] = sum;
}
}
另一个解决方案-实际上更有效,具体取决于您的设备-每块启动更少的线程(在这种情况下为25)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句