【问题标题】:OpenCL: Difference between __constant memory and const __global memoryOpenCL:__constant 内存和 const __global 内存之间的区别
【发布时间】:2022-04-08 22:03:09
【问题描述】:

我想了解当我创建具有只读属性的缓冲区并将其与内核中的__constant 地址空间限定符一起使用或与const __global 地址空间限定符一起使用时有什么区别。

我已经发现这些并不是我问题的真正答案,但它们包含一些有用的信息:

如果我理解得很好,GPU 内存中的分配发生在 clCreateBuffer 函数调用中。所以我不明白的是编译器如何决定缓冲区是在常量内存(有 64 KB 限制)还是在全局内存中。 (我知道在大多数情况下,常量内存是全局内存空间的一部分。)如果它取决于地址限定符,这意味着可以使用 const __global 忽略 64 KB 限制。

__constantconst __global 的性能有什么区别吗? __global 内存可能会被缓存,因此它们都是只读的并且(可能)被缓存。 (来源:3.3 内存模型/全局内存部分及图3.3;http://www.khronos.org/registry/cl/specs/opencl-1.x-latest.pdf#page=24

【问题讨论】:

  • 我猜这取决于 OpenCL 实现和/或硬件架构。

标签: opencl constants


【解决方案1】:

根据我的经验,两者在概念上没有区别,它们都暗示指向的数据是只读的。只有根据供应商使用的实现,差异才会很明显。

例如,在 nvidia GPU 上,标有 __constant 的内存被缓存(我相信对于所有当前设备,每个多处理器的缓存大小为 8KB)。需要注意的一点是,如果不同的工作项访问不同的地址,则对这个缓存的访问是序列化的,因此我发现它对于传递工作组内恒定的参数结构最有用。如果您查看 CUDA 编程指南中有关常量内存的部分,您将更好地了解其工作原理。我相信标记为 const __global 的内存不会被缓存,它只是告诉编译器如果您尝试更改指向的值则抛出错误。

我不确定 AMD 是否在他们的硬件上进行类似的缓存

希望有帮助

【讨论】:

  • 你确定缓存的大小是64KB吗?我认为整个 __constant 内存空间是 64KB。 (见 CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE)
  • 你确实是对的我错了。虽然总大小为 64KB,但每个多处理器缓存为 8KB。我已更新我的答案以更正此问题。
【解决方案2】:

对于用于 FPGA 上 OpenCL 的英特尔(以前称为 Altera)SDK,常量内存被加载到由所有工作组共享的片上常量缓存中。默认情况下,此缓存的大小为 16 KB,但如果您将 -const-cache-bytes=<N><N> 是常量缓存大小以字节为单位)标志添加到您的 aoc 命令,则可以更改此大小。他们的Best Practices Guide 第 138 页还提到了以下内容:

与具有额外硬件以容忍长内存的全局内存访问不同 延迟,常量缓存因缓存未命中而遭受很大的性能损失。如果 这 __constant 您的 OpenCL 内核代码中的参数无法放入缓存中,您 可能会获得更好的性能 __global const 取而代之的论据。

【讨论】:

  • 这似乎是我在某些情况下的经验:__global const 在某些情况下(如果缓冲区很大,大多数情况下)在英特尔芯片上给我带来了高达 2% 的性能提升,但这种差异是如此之大很小,可能是巧合/统计错误。
【解决方案3】:

对于 AMD 的 OpenCL 实现,请参见此处的说明: https://github.com/RadeonOpenCompute/ROCm/issues/203

基本上,constant 具有隐式restrict 的效果。 因此 constant int *p 大部分等价于 const global int * restrict p

【讨论】:

    【解决方案4】:

    constant 类似于D 中的immutable。这意味着在整个内核执行期间(所有工作项)该值不会改变。 另一方面,const 仅表示指向的内存不会通过 this const 指针更改,但仍然可以通过别名的非const 指针更改。

    constant 隐含const(如果没有人可以更改数据,那么您也不能)。

    constant 对编译器来说是一个巨大的优化机会。它可以发出代码来为每个工作项取消引用指针一次并将值保存在寄存器中(GPU 有很多寄存器!),甚至可以在子组中的不同工作项之间共享取消引用的值。

    至于编译器如何决定缓冲区在常量内存中,很简单:如果你在内核中写了constant,它就是常量地址空间。这意味着决定不早于clSetKernelArg 时间。

    【讨论】:

      猜你喜欢
      • 2013-07-27
      • 1970-01-01
      • 2011-03-29
      • 2012-02-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      相关资源
      最近更新 更多