Nvidia visual profiler中一级本地存储/一级全局读取的含义 \uuuuu全局\uuuuuu无效内核(int*gpuArr){ INTA; a=gpuArr[threadIdx.x+1]; } int main(字符**argv,int argc){ int*gpuArr; Cudamaloc((void**)和gpuArr,628*sizeof(int)); kern(gpuArr); cudaDeviceSynchronize(); }

Nvidia visual profiler中一级本地存储/一级全局读取的含义 \uuuuu全局\uuuuuu无效内核(int*gpuArr){ INTA; a=gpuArr[threadIdx.x+1]; } int main(字符**argv,int argc){ int*gpuArr; Cudamaloc((void**)和gpuArr,628*sizeof(int)); kern(gpuArr); cudaDeviceSynchronize(); },cuda,Cuda,在Nvidia visual profiler中评测上述代码时,我得到了以下内存带宽分析 据我所知,发生的情况是: 全局内存负载-L2缺失 将5*32B从全局复制到L2(我认为L2的缓存行大小总是32B) 将2*128B从二级缓存线复制到一级缓存线(包括来自二级缓存线的附加数据,因为一级缓存线是128B?) 对每个线程执行a=L1\u位置[threadIdx.x]的等效操作 那么,每个线程中的局部变量“a”存储在哪里?根据调试器,它不在寄存器中(通常在变量选项卡中显示为@register in

在Nvidia visual profiler中评测上述代码时,我得到了以下内存带宽分析

据我所知,发生的情况是:

全局内存负载-L2缺失

将5*32B从全局复制到L2(我认为L2的缓存行大小总是32B)

将2*128B从二级缓存线复制到一级缓存线(包括来自二级缓存线的附加数据,因为一级缓存线是128B?)

对每个线程执行a=L1\u位置[threadIdx.x]的等效操作

那么,每个线程中的局部变量“a”存储在哪里?根据调试器,它不在寄存器中(通常在变量选项卡中显示为@register int,但改为显示为@local int)。“本地商店1”这句话到底是什么意思?我们已经做了2*128B L2到L1拷贝(“全局加载”),那么“本地存储”是什么意思呢。为什么只有1家“本地店”而只有2家“全球店”


另外,我使用的是cc 3.0,因此首先根据规范,L1中的全局内存缓存是不可能的,正如已经指出的:

  • 您正在运行使用调试开关(
    -G
    )编译的代码。这不会给您提供最佳性能,也不能代表(无论是性能方面还是行为方面)没有它编译的代码,因此分析此类代码是一项有问题的活动

  • 由于
    -G
    禁用了编译器优化,因此这些代码的行为可能与您期望的不一样

  • 那么,每个线程中的局部变量“a”存储在哪里

    它存储在本地逻辑空间中。这正是探查器(和调试器)告诉您的。“本地”逻辑空间可以存在于寄存器或物理(板载DRAM)内存中。它不在寄存器中的原因是,您已经使用
    -G
    开关禁用了优化,并且在寄存器中放置逻辑数据是一种优化。您无法通过取消
    -G
    开关直接确认这一点,因为如果您这样做,编译器将完全优化您编写的代码,因为它对任何全局状态都没有影响

    “本地商店1”这句话到底是什么意思

    如上所述,变量
    a
    位于本地逻辑空间中,因此从全局读取和写入本地发生在这里:

    __global__ void kern (int* gpuArr) {
        int a;
    
        a = gpuArr[threadIdx.x+1];
    }
    
    int main(char** argv, int argc) {
        int* gpuArr;
        cudaMalloc((void**)&gpuArr,628*sizeof(int));
    
        kern<<<1,32>>>(gpuArr);
    
        cudaDeviceSynchronize();
    }
    
    a
    被“写入”时,将导致本地存储

    为什么只有1家“本地店”而只有2家“全球店”

    存储在DRAM内存中的属于本地逻辑空间的变量将以这样的方式存储在内存中,即当进行DRAM内存事务时,warp中线程的连续访问将生成相邻(即“合并”)访问,以读取或写入此类值。这意味着,如果每个线程都有一个局部变量
    a
    ,那么首先存储线程0的
    a
    ,然后存储线程1的
    a
    ,然后存储线程2的
    a
    ,以此类推。因此,如果每个线程都读取(或写入)
    a
    ,那么结果访问将合并。由于您有32个线程组成的1个扭曲,每个线程写入
    a
    int
    值,这将导致单个128字节的本地存储事务

    在全局内存情况下(即读取),您已使读取跨过缓存线/段边界,并将1添加到数组索引中:

    a = gpuArr[threadIdx.x+1];
    
    因此,它需要两个全局事务来收集warp请求的数据。如果要确认这一点,请删除数组索引上的+1,全局事务应该从2降至1


    作为一个警告,对非常少量的活动进行分析可能并不总能得到预期的结果(尽管在这种情况下它似乎是有效的)。这样做的原因是,为SMs的某个子集捕获一些探查器度量,然后乘以SMs的数量以反映完整的GPU活动。如果对于非常小的数据集的结果没有意义,那么对于更大的数据集,您可能会得到更合理的结果,这些数据集更适合在SMs中使用一致的活动“填充”GPU。

    首先,正如已经指出的:

  • 您正在运行使用调试开关(
    -G
    )编译的代码。这不会给您提供最佳性能,也不能代表(无论是性能方面还是行为方面)没有它编译的代码,因此分析此类代码是一项有问题的活动

  • 由于
    -G
    禁用了编译器优化,因此这些代码的行为可能与您期望的不一样

  • 那么,每个线程中的局部变量“a”存储在哪里

    它存储在本地逻辑空间中。这正是探查器(和调试器)告诉您的。“本地”逻辑空间可以存在于寄存器或物理(板载DRAM)内存中。它不在寄存器中的原因是,您已经使用
    -G
    开关禁用了优化,并且在寄存器中放置逻辑数据是一种优化。您无法通过取消
    -G
    开关直接确认这一点,因为如果您这样做,编译器将完全优化您编写的代码,因为它对任何全局状态都没有影响

    “本地商店1”这句话到底是什么意思

    如上所述,变量
    a
    位于本地逻辑空间中,因此从全局读取和写入本地发生在这里:

    __global__ void kern (int* gpuArr) {
        int a;
    
        a = gpuArr[threadIdx.x+1];
    }
    
    int main(char** argv, int argc) {
        int* gpuArr;
        cudaMalloc((void**)&gpuArr,628*sizeof(int));
    
        kern<<<1,32>>>(gpuArr);
    
        cudaDeviceSynchronize();
    }
    
    a
    被“写入”时,将导致本地存储

    为什么只有1家“本地店”而只有2家“全球店”

    存储在DRAM内存中属于