CUDA共享和全局内存之间有什么区别?

时间:2012-12-30 19:06:18

标签: memory cuda global shared-memory

我对如何在CUDA中使用共享和全局内存感到困惑,特别是对于以下内容:

  • 当我们使用cudaMalloc()时,我们会获得指向共享或全局的指针 存储器?
  • 全局内存是否驻留在主机或设备上?
  • 有没有 尺寸限制为任何一个?
  • 哪个访问速度更快?
  • 正在存储 共享内存中的变量与通过其传递地址相同 核心?即而不是

    __global__ void kernel() {
       __shared__ int i;
       foo(i);
    }
    

    为什么不等同呢

    __global__ void kernel(int *i_ptr) {
       foo(*i_ptr);
    }
    
    int main() {
       int *i_ptr;
       cudaMalloc(&i_ptr, sizeof(int));
       kernel<<<blocks,threads>>>(i_ptr);
    }
    

关于全局与共享内存中的特定速度问题,有很多问题,但没有一个问题包含在实践中何时使用这两个问题的概述。

非常感谢

3 个答案:

答案 0 :(得分:44)

  • 当我们使用cudaMalloc()

    为了将数据存储在可以传送回主机的gpu上,我们需要有一个存储的内存,直到它被释放,将全局内存看作具有生命的堆空间直到应用程序关闭或被释放,任何具有指向该内存区域的指针的线程和块都可以看到它。共享内存可以被视为具有生命的堆栈空间,直到内核块完成,可见性仅限于同一块内的线程。所以cudaMalloc用于在全局内存中分配空间。

  • 我们是否获得了共享或全局内存的指针?

    您将获得一个指向驻留在全局内存中的内存地址的指针。

  • 全局内存是否驻留在主机或设备上?

    全局内存驻留在设备上。但是,有一些方法可以使用映射内存将主机内存用作“全局”内存,请参阅:CUDA Zero Copy memory considerations但是,由于总线传输速度限制,速度可能会很慢。

  • 两者都有尺寸限制吗?

    全局内存的大小取决于卡到卡,从无到8GB。共享内存取决于计算能力。低于计算能力2.x的任何东西每个多处理器最多有16KB的共享内存(多处理器的数量因卡而异)。计算能力为2.x或更高的卡每个多处理器最多有48KB的共享内存。

    如果您使用的是映射内存,唯一的限制是主机在内存中的容量。

  • 哪个访问速度更快?

    就原始数字而言,共享内存要快得多(共享内存~1.7TB / s,而全局内存~150GB / s)。但是,为了做任何你需要用某些东西填充共享内存的东西,你通常会从全局内存中取出。如果内存访问全局内存是合并的(非随机),您将获得高达150-200GB / s的速度,具体取决于卡及其内存接口。

    共享内存的使用是指您需要在一个线程块内重用已经从全局内存中提取或评估的数据。因此,不要再次从全局内存中取出,而是将其放在共享内存中,以便查看和重用同一块中的其他线程。

  • 在共享内存中存储变量与通过内核传递地址相同吗?

    不,如果您传递任何地址,它始终是全局内存的地址。在主机中,您无法设置共享内存,除非您将其作为常量传递,内核将共享内存设置为该常量,或者将地址传递给全局内存,并在需要时由内核提取。

答案 1 :(得分:10)

全局内存的内容对网格的所有线程都是可见的。任何线程都可以读写全局内存的任何位置。

共享内存对于网格的每个块是独立的。块的任何线程都可以读取和写入该块的共享内存。一个块中的线程无法访问另一个块的共享内存。

  1. cudaMalloc始终分配全局内存。
  2. 全局内存驻留在设备上。
  3. 显然,每个内存都有大小限制。全局内存是您正在使用的GPU的DRAM总量。例如,我使用的是具有1536 MB DRAM的GTX460M,因此全局内存为1536 MB。共享内存由设备体系结构指定,并以每个块为基础进行测量。计算能力1.0至1.3的设备具有16 KB/Block,计算2.0至7.0具有48 KB/Block共享内存。
  4. 共享内存的访问速度比全局内存快。它就像一个块的线程之间共享的本地缓存。
  5. 否。只有全局内存地址可以传递给从主机启动的内核。在第一个示例中,变量是从共享内存中读取的,而在第二个示例中,它是从全局内存中读取的。
  6. <强>更新

    计算能力设备7.0(Volta Architecture)允许为每个块分配高达96 KB的共享内存,前提是满足以下条件。

    • 动态分配共享内存
    • 在启动内核之前,使用函数cudaFuncSetAttribute指定动态共享内存的最大大小,如下所示。

    __global__ void MyKernel(...)
    {
        extern __shared__ float shMem[];
    }
    
    int bytes = 98304; //96 KB
    cudaFuncSetAttribute(MyKernel, cudaFuncAttributeMaxDynamicSharedMemorySize, bytes);
    
    MyKernel<<<gridSize, blockSize, bytes>>>(...);
    

答案 2 :(得分:3)

CUDA共享内存是块内线程之间共享的内存,即网格中的块之间共享内存的内容未定义。它可以被认为是手动管理的L2缓存。

通常全局内存驻留在设备上,但最近版本的CUDA(如果设备支持它)可以将主机内存映射到设备地址空间,在这种情况下触发从主机到设备内存的原位DMA传输。

共享内存的大小限制,具体取决于设备。它在设备功能中报告,在枚举CUDA设备时检索。全局内存受GPU可用总内存的限制。例如,GTX680提供48kiB共享内存和2GiB设备内存。

共享内存的访问速度比全局内存快,但访问模式必须小心对齐(对于共享内存和全局内存)才能高效。如果无法正确对齐访问模式,请使用纹理(也可以使用全局内存,但可以通过不同的安全性和缓存访问,这可以更好地处理未对齐的访问)。

  

在共享内存中存储变量与通过内核传递地址相同吗?

不,绝对不是。您提出的代码将是您使用原位传输全局内存的情况。共享内存不能在内核之间传递,因为共享块的内容仅在线程的执行块中定义。