我正在尝试学习OpenCL,但我很难决定使用哪些地址空间,因为我只找到组合资源来声明这些地址空间是什么,而不是为什么它们存在或何时使用它们。资源至少过于分散,所以有了这个问题,我希望收集所有这些信息:什么是地址空间,它们为什么存在,何时使用哪个地址空间以及有关内存的优缺点是什么?性能
据我所知(可能过于简化),GPU有两种物理类型的内存:全局内存,远离实际的处理器,所以很慢但很大,可供所有工作人员使用和本地内存,靠近实际处理器,速度快但很小,无法从其他工作人员访问。
直观地说,local
限定符确保将变量放在本地内存中,global
限定符确保将变量放在全局内存中,但我不确定这究竟是什么。这会留下private
和constant
限定符。那些人的目的是什么?
还有一些隐含的限定词。例如,我认为the specifications提到通用地址空间,它用于没有限定符的参数。这究竟是做什么的?然后还有局部函数变量。那些地址空间是什么?
这是一个使用我的直觉的例子,但不知道我在做什么:
示例:
假设我将类型long
和长度10000的数组传递给我将只用于读取的内核,然后我将其声明为global const
,因为它必须可供所有工作人员使用,并且不会更改。为什么我不使用constant
限定符?当通过CPU为这个数组设置缓冲区时,我实际上也可以将数组设为只读,这在我看来就像声明它const
一样。那么,我何时以及为什么要声明constant
或global const
?
执行内存密集型任务时,将数组复制到内核中的本地数组会更好吗?我的猜测是本地内存太小了,但如果数组的长度只有10呢?阵列什么时候太大/太小?更一般:何时值得将数据从全局内存复制到本地内存?
说我也想传递这个数组的长度,然后我会将const int length
添加到我的内核的参数中,但我不确定为什么我会省略global
限定符,除非因为我见过其他人这样做。毕竟,所有工作人员都必须能够访问length
。如果我是对的,那么length
会有一个通用的地址空间,但我再也不知道这意味着什么。
我希望有经验的人可以清楚这一点。这对我来说不仅不错,而且我希望其他爱好者也希望获得有关GPU内存管理的实用知识。
答案 0 :(得分:5)
常量:所有工作人员都可以看到一小部分缓存的全局内存。如果可以,请使用它,只读。
全局:慢,可见所有人,读或写。这是所有数据都将结束的地方,因此有些访问它总是必要的。
本地:您是否需要在本地群组中分享内容?使用本地!您所有本地工作人员是否都访问相同的全局内存?使用本地! 本地内存仅在本地工作人员中可见,并且大小有限,但速度非常快。
私有:仅对工作人员可见的内存,将其视为寄存器。默认情况下,所有未定义的值都是私有的。
假设我将一个long和long 10000类型的数组传递给我的内核 只会用来读取,然后我会声明它必须是全局const 适用于所有工人,不会改变。我为什么不用 常数限定符?
实际上,是的,您可以使用constant
限定词。将数据放在常量内存中(所有工作人员都可以快速访问一小部分只读内存)。 GPU使用它将制服传输到所有顶点着色器。
通过CPU设置此阵列的缓冲区时,我实际上也是 只是可以让数组只读,这在我看来是这样的 和声明它一样。所以,我何时以及为什么要宣布 某些常量或全局常量?
不是真的,当你创建一个缓冲区只读时你只是指定OpenCL你打算只读它,所以它可以在后面做优化,但你实际上可以从内核写入它。
global const
只是开发人员的安全保障,因此您不会意外地写入它,它会在编译时出错。
基本上,与普通C主机端计算相同。如果所有内存都是非常量的,程序也可以正常工作。
执行内存密集型任务时,将数组复制到内核中的本地数组会更好吗?我的猜测是本地内存太小了,但如果数组的长度只有10呢?阵列什么时候太大/太小?更一般:何时值得将数据从全局内存复制到本地内存?
只有所有工人都阅读它才有价值。如果每个worker读取全局内存的单个值,那么它就不值得。 在这里有用:
Worker0 -> Reads 0,1,2,3
Worker1 -> Reads 0,1,2,3
Worker2 -> Reads 0,1,2,3
Worker3 -> Reads 0,1,2,3
这里没用:
Worker0 -> Reads 0
Worker1 -> Reads 1
Worker2 -> Reads 2
Worker3 -> Reads 3
说我也想传递这个数组的长度,然后我会添加 const int length到我内核的参数,但我不确定为什么我 除了因为我见过其他人之外,我们会省略全局限定符 人们这样做。毕竟,所有工人都必须能够获得长度。如果 我是对的,那么长度会有一个通用的地址空间,但是, 我真的不知道这意味着什么。
如果你没有在内核参数中指定一个限定符,它通常默认为constant
,这是你想要的那些小元素,让所有工人都可以快速访问。
OpenCL编译器通常遵循的内核参数规则是:如果它只读取并适合常量,常量,否则全局。