3

我很难理解对 CUDA 常量内存的限制。

  1. 为什么我们不能__constant__在运行时分配内存?为什么我需要在近乎全局范围的固定大小变量中进行编译?

  2. 常量内存何时实际加载或卸载?我知道这cudaMemcpytoSymbol 是用来加载特定数组的,但是每个内核是否使用自己的常量内存分配?相关,绑定和解绑是否有成本,类似于绑定纹理的旧成本(也就是,使用纹理为每个内核调用增加了成本)?

  3. 常量内存驻留在芯片的什么位置?

CUDA 架构

我主要对与 Pascal 和 Volta 相关的答案感兴趣。

4

1 回答 1

5

以相反的顺序回答这六个问题可能是最容易的:

常量内存驻留在芯片的什么位置?

它没有。常量内存存储在片外静态保留的物理内存中,并通过每个 SM 缓存访问。当编译器可以识别出一个变量存储在逻辑常量内存空间中时,它将发出特定的 PTX 指令,允许通过常量缓存访问该静态内存。另请注意,在所有当前支持的体系结构上都有特定的保留常量内存库用于存储内核参数。

绑定和解除绑定的成本是否类似于绑定纹理的旧成本(又名,使用纹理会为每个内核调用增加成本)?

不,但也没有“绑定”或“解除绑定”,因为保留是静态执行的。唯一的运行时成本是主机到设备的内存传输以及作为上下文建立的一部分将符号加载到上下文中的成本。

我知道这cudaMemcpytoSymbol是用来加载特定数组的,但是每个内核是否使用自己的常量内存分配?

不,整个 GPU 只有一个“分配”(尽管如上所述,内核参数有特定的常量内存库,所以在某种意义上你可以说常量内存有一个内核组件)。

常量内存何时实际加载或卸载?

这取决于您所说的“加载”和“卸载”。加载实际上是一个两阶段的过程——首先检索符号并将其加载到上下文中(如果您使用运行时 API,这是自动完成的),其次是任何用户运行时操作以通过 cudaMemcpytoSymbol.

为什么我需要在近乎全局范围的固定大小变量中进行编译?

如前所述,常量内存基本上是 PTX 内存层次结构中的一个逻辑地址空间,它反映在 GPU DRAM 映射的有限大小保留区域中,并且需要编译器发出特定指令以通过专用的片上缓存或统一访问缓存。鉴于其静态、编译器分析驱动的性质,它在语言中的实现也将主要是静态的。

为什么我们不能__constant__在运行时分配内存?

主要是因为 NVIDIA 选择不公开它。但是考虑到上面列出的所有限制,我不认为这是一个非常糟糕的选择。其中一些很可能是历史性的,因为从一开始,恒定内存就一直是 CUDA 设计的一部分。几乎所有 CUDA 设计中的原始特性和功能都映射到硬件特性,这些特性是为了硬件的第一个目的而存在的,即 GPU 旨在支持的图形 API。因此,您所问的一些问题很可能与 OpenGL 或 Direct 3D 的历史特性或限制有关,但我对两者都不够熟悉,无法肯定地说。

于 2017-08-11T07:04:58.077 回答