我是CUDA编程的新手,我遇到了以下问题。
如果我使用以下代码执行矩阵乘法,由于CUDA使用笛卡尔索引进行线程索引,而C / C ++使用矩阵的行主索引,是否会影响计算的准确性?
__global__ void gpuMM(float *A, float *B, float *C, int N)
{
// Matrix multiplication for NxN matrices C=A*B
// Each thread computes a single element of C
int col = blockIdx.y*blockDim.y + threadIdx.y;
int row = blockIdx.x*blockDim.x + threadIdx.x;
float sum = 0.f;
for (int n = 0; n < N; ++n)
sum += A[row*N+n]*B[n*N+col];
C[row*N+col] = sum;
}
答案 0 :(得分:4)
CUDA并不意味着任何内存存储结构。你可以说CUDA C是矩阵存储的行专业,但这是由于C而不是CUDA。 (CUDA Fortran将是列专业。)线程索引维度是任意的。它们并不意味着内存中的数据存储顺序。
当您编写代码时,会出现对内存中数据存储顺序的影响。从正确性的角度来看,如果我们根据x线程维度或y线程维度分配行索引并不重要。您可以使用任一方法(基于x的行,或基于y的行)为此矩阵乘法示例编写正确的代码。
然而,从合并的角度来看,我们通常希望相邻的执行线程读取或写入内存中的相邻单元。相邻线程(用于执行)通常首先分组为x。因此,这是优选的(对于您的内核代码):
int row = blockIdx.y*blockDim.y + threadIdx.y;
int col = blockIdx.x*blockDim.x + threadIdx.x;
因为它允许读取B[]
和写C[]
来合并。
这很容易向自己证明。尝试两种方式,并测量内核的执行时间。结果是正确的(与使用基于主机的矩阵乘法产生的结果相匹配)无论哪种方式,但是一个公式的运行速度明显快于另一个公式。
这很容易尝试,因为你的内核代码意味着方形矩阵。