OpenCL 何时使用全局、私有、本地、常量地址空间

OpenCL When to use global, private, local, constant address spaces

我正在尝试学习 OpenCL,但我很难决定使用哪个地址 space,因为我只找到 assembled 资源声明这些地址 spaces 是,但不是它们存在的原因或何时使用它们。至少资源太分散了,所以带着这个问题我希望assemble所有这些信息:所有地址space是什么,它们为什么存在,什么时候使用哪个地址 space 以及内存和性能方面的优缺点。

据我了解(这可能过于简化),GPU 有两种物理内存类型:全局内存,与实际的处理器相去甚远,速度很慢但相当大所有工作人员都可以使用,本地内存,接近实际处理器,速度快但体积小,其他工作人员无法访问。

直觉上,local 限定符确保将变量放置在本地内存中,而 global 限定符确保将变量放置在全局内存中,但我不确定这是否准确发生什么了。这留下了 privateconstant 限定符。这些的目的是什么?

还有一些隐含的限定词。例如,the specifications 提到 通用地址 space,我认为它用于没有限定符的参数。这到底是做什么的?然后还有局部函数变量。这些地址 space 是什么?

这是一个使用我的直觉的例子,但不知道我实际上在做什么:

示例: 假设我将类型为 long 且长度为 10000 的数组传递给一个我将仅用于读取的内核,然后我将声明它 global const 因为它必须对所有工作人员可用并且它不会改变。为什么我不使用 constant 限定符?当通过 CPU 为这个数组设置缓冲区时,我实际上也可以将数组设为只读,在我看来这与声明它 const 一样。再说一遍,我什么时候以及为什么要声明某些东西 constantglobal const?

在执行内存密集型任务时,将数组复制到内核内部的本地数组会更好吗?我的猜测是本地内​​存太小,但如果数组的长度只有 10 怎么办?数组什么时候会太big/small?更一般化:什么时候值得将数据从全局内存复制到本地内存?

假设我还想传递这个数组的长度,那么我会在内核的参数中添加 const int length,但我不确定为什么我会省略 global 限定符,除了因为我见过其他人这样做。毕竟,所有工作人员都必须可以访问 length。如果我是对的,那么 length 会有一个通用地址 space,但同样,我真的不知道那是什么意思。

希望有经验的大神指点一下。这不仅对我有好处,而且我希望对其他想要获得有关 GPU 内存管理的实用知识的爱好者也有帮助。

常量:一小部分缓存的全局内存对所有工作人员可见。如果可以就用它,只读。

全局:慢,所有人可见,读或写。这是您所有数据的结束位置,因此始终需要对其进行一些访问。

本地:您需要在本地群组中分享内容吗?使用本地!您所有的本地工作人员都访问相同的全局内存吗?使用本地! 本地内存仅在本地工作人员内部可见,并且大小有限,但速度非常快。

Private: 只对工作人员可见的内存,将其视为寄存器。默认情况下,所有未定义的值都是私有的。


Say I pass an array of type long and length 10000 to a kernel which I will only use to read, then I would declare it global const as it must be available to all workers and it will not change. Why wouldn't I use the constant qualifier?

实际上,是的,您可以而且应该使用 constant 限定符。它将您的数据放在常量内存中(所有工作人员都可以快速访问的一小部分只读内存)。 GPU 使用它来将制服传输到所有顶点着色器。

When setting the buffer for this array via the CPU, I actually also just could have made the array read-only, which in my eyes says the same as declaring it const. So again, when and why would I declare something constant or global const?

不是真的,当您创建一个只读缓冲区时,您只是向 OpenCL 指定您计划以只读方式使用它,因此它可以在后面进行优化,但您实际上可以从内核写入它。 global const只是给开发者的一个保障,别不小心写进去了,编译的时候会报错。 基本上,与普通 C 主机端计算相同。如果所有内存都是非常量,程序也能正常工作。

When performing memory-intensive tasks, would it be better to copy the array to a local array inside the kernel? My guess is that local memory would be too small, but what if the array only had a length of 10? When would the array be too big/small? More general: when is it worth copying data from global to local memory?

只有所有工人都读过才有价值。如果每个 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

Say I also want to pass the length of this array, then I would add const int length to the arguments of my kernel, but I'm unsure why I would omit the global qualifier except because I have seen other people do it. After all, length must be accessible for all workers. If I'm right, then length would have a generic address space, but again, I don't really know what that means.

当您没有在内核参数中指定限定符时,它通常默认为 constant,这是您希望这些小元素能够被所有工作人员快速访问的。

OpenCL 编译器通常遵循的内核参数规则是:如果它仅读取并适合常量,则为常量,否则为全局。