C++ 矩阵相乘在CUDA上给出错误的结果
我已经用CUDA写了一小段代码来乘2个方阵。Hovewer,事实证明大部分细胞都计算错了。根据我使用的教程,一切都会很顺利C++ 矩阵相乘在CUDA上给出错误的结果,c++,cuda,C++,Cuda,我已经用CUDA写了一小段代码来乘2个方阵。Hovewer,事实证明大部分细胞都计算错了。根据我使用的教程,一切都会很顺利 __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
__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)
}
\uuuu全局\uuuuu无效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;
整数和=0;
对于(int n=0;n
结果表明,用标准CPU方法乘以矩阵是正确的,但CUDA方法是错误的:
第一行总是正确的,但所有其他部分都是完全随机的。有时是消极的,有时不是。有时它们接近真实值,有时它们完全不同
我犯了什么错?我不知道失败在哪里。算法看起来很好,变量似乎传递正确,但有些东西不起作用
---编辑
所有变量(PRESLT和两个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;
}
}
\uuuu全局\uuuuu无效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;
如果((行
另一个解决方案——更有效,取决于你的设备——是每个块启动更少的线程(本例中为25个) 由于每个块的线程数不等于输出矩阵中的元素数(您正在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;
}
}
\uuuu全局\uuuuu无效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;
如果((行
另一个解决方案——更有效,取决于你的设备——是每个块启动更少的线程(本例中为25个)
preslt
在哪里初始化?@PaulMcKenzie在我调用main()
中的multipleMatrixCuda
之前,它们已初始化。我已编辑了我的问题。您正在处理5x5矩阵,但块大小为16x16。这意味着,除了一个线程试图处理非常真实的(行,列)=(1,0)之外,还有一个线程试图处理不存在的(行,列)=(0,5)-但是这两个项目重叠(0*N+5=1*N+0=5)。因此,有多个工作项写入C的同一个元素,其中一些正在访问内存的无效部分,从而产生无意义的结果。在gpuMM中,您应该测试该行在哪里预设得到初始化?@PaulMcKenzie在我调用MultipleMatrix xCuda
之前,它们被初始化,在mymain()
中。我已编辑了我的问题。您正在处理5x5矩阵,但块大小为16x16。这意味着,除了一个线程试图处理非常真实的(行,列)=(1,0)之外,还有一个线程试图处理不存在的(行,列)=(0,5)-但是这两个项目重叠(0*N+5=1*N+0=5)。因此,有多个工作项写入C的同一个元素,其中一些正在访问内存的无效部分,从而产生无意义的结果。在gpuMM中,您应该测试该行