CUDA内核中全局内存加载事务的计算

CUDA内核中全局内存加载事务的计算,cuda,Cuda,我有一个关于CUDA内核中全局内存加载事务计算的问题,因为分析的值与我的期望值不匹配。以下面的简单矩阵乘法代码为例: __global__ void matmul_kernel(float *A, float* B, float *C, int n) { int i, j, k; float c; i = blockIdx.x; for(i=i; i < n; i += gridDim.x){ j = threadIdx.x;

我有一个关于CUDA内核中全局内存加载事务计算的问题,因为分析的值与我的期望值不匹配。以下面的简单矩阵乘法代码为例:

__global__ void matmul_kernel(float *A, float* B, float *C, int n)
{
    int i, j, k;
    float c;

    i = blockIdx.x;
    for(i=i; i < n; i += gridDim.x){
        j = threadIdx.x;
        c = 0.0;
        for(k = 0; k < n; k++)
            c += A[i*n + k]*B[k*n + j];
        C[i*n + j] = c;
    }
}
\uuuuu全局\uuuuu无效matmul\u内核(float*A、float*B、float*C、int-n)
{
int i,j,k;
浮点数c;
i=块IDx.x;
对于(i=i;i

dim3网格(1,1,1);
dim3区块(128,1,1);
n=128;
matmul_核(A,B,C,n);
我使用最简单的矩阵乘法作为例子。在上面的CUDA实现中,我将
I
循环迭代映射到块索引,并将
j
循环映射到每个线程块中的线程索引。螺纹块和网格都是一维的

请不要关注此实现的性能。我知道这是没有效率的,因为我只是把它用于实验目的

在这个实现中,因为我在每个块中分配了128个线程,所以
j
循环可以完全并行化。但是我只为
I
循环分配了1个块,所以它将循环
n次。下图显示了
k=0
时的执行状态。在此状态下,128个线程访问
A
的第一个元素和
B
的128个第一行元素。我在使用开普勒40体系结构的Quadro K6000上执行这个CUDA代码,并打开了一级缓存。由于合并了对
B
的128次访问,因此加载的数量为
128*4/128=4
(第一个128是128个元素,第二个128是以字节为单位的一级缓存线大小,4是浮动类型的字节)。对于对
A
的128次访问,由于它们访问同一个元素,1个缓存线负载应该足够了。因此,全局负载的数量为
4+1=5
。但这只是
k=0
时的荷载数量
k
将循环128次,
i
也将循环128次,因此总负载数为
5*128*128=81920
。但是,分析的全局荷载为
131072
。该值等于
(4+4)*128*128
。似乎
A
k=0
时的加载次数是4而不是1。有人能解释为什么分析的值与我的期望值不匹配吗


你只遗漏了一点。全局内存访问仅针对warp中的线程(请参阅)。在您的情况下,有4个扭曲。每一个都需要一个内存事务来处理A的元素

dim3 grid(1,1,1);
dim3 block(128,1,1);
n = 128;
matmul_kernel<<<grid, block>>>(A, B, C, n);