OpenCL将内存划分成主机内存 和设备内存。主机内存可在主机上使用,其并不在OpenCL的定义范围内。使用对应的OpenCL API可以进行主机和设备的数据传输,或者通过共享虚拟内存接口进行内存共享。而设备内存,指定是能在执行内核中使用的内存空间。
OpenCL将设备内存分成了四种,这四种内存分别代表了不同的内存区域。这些内存空间都与OpenCL内核有关。一个内核中,不同区域对应有不同的关键字,关键字用来指定变量使用哪种内存进行创建,或数据具体所存储的位置。内存区域在逻辑上是不相交的,并且不同区域的数据要被其他区域使用,是否需要进行数据转移是由内核开发者来控制。每个内存区域都有其各自的性能特性。由于性能特性的缘故,存储到不同区域的数据在读取时具有很大的性能差异。
下面简单的来描述一下每个内存区域:
-
全局内存 全局内存对于执行内核中的每个工作项都是可见的(类似于CPU上的内存)。当数据从主机端传输到设备端,数据就存储在全局内存中。有数据需要从设备端传回到主机端,那么对应的数据需要存储在全局内存中。其关键字为
global
或__global
,关键字加在指针类型描述符的前面,用来表示该指针指向的数据存储在全局内存中。 -
常量内存 常量内存并非为只读数据设计,但其能让所有工作项同时对该数据进行访问。这里存储的值通常不会变化(比如,某个数据变量存储着π的值)。OpenCL的内存模型中,常量内存为全局内存的子集,所以内存对象传输到全局内存的数据可以指定为"常量"。使用关键字
constant
或__constant
将相应的数据映射到常量内存。 -
局部内存 局部内存中的数据,只有在同一工作组内的工作项可以共享。通常情况下,局部内存会映射到片上的物理内存,例如:软件管理的暂存式存储器。比起全局内存,局部内存具有更短的访问延迟,以及更高的传输带宽。调用
clSetKernelArg()
设置局部内存时,只需要传递大小,而无需传递对应的指针,相应的局部内存会由运行时进行开辟。OpenCL内核中,使用local
或__local
关键字来描述指针,从而来定义局部内存(例如,local int *sharedData
)。不过,数据也可以通过关键字local
,静态申明成局部内存变量(例如,local int[64]
)。 -
私有内存私有内存只能由工作项自己进行访问。局部变量和非指针内核参数通常都在私有内存上开辟。实践中,私有变量通常都与寄存器对应。不过,当寄存器不够私有数组使用是,这些溢出的数据通常会存储到非片上内存(高延迟的内存空间)上。
参考资料
《OpenCL programming Guide》