在cuda线程之间共享大型常量数据

时间:2018-11-05 06:11:31

标签: c++ cuda opencl

我有一个被多次调用的内核。在每个调用中,线程将共享和处理大约240 KB的恒定数据。线程像映射函数一样独立工作。线程的停顿时间相当长。其背后的原因可能是内存读取的存储区冲突。我该如何处理?(我有GTX 1080 ti)

opencl的“ const global”可以处理吗? (因为cuda中的恒定内存限制为64 kb)

2 个答案:

答案 0 :(得分:7)

在CUDA中,我认为最好的建议是利用所谓的“只读”缓存。与__constant__内存/恒定缓存系统相比,这至少具有两个可能的好处:

  1. 它不限于__constant__存储器那样的64kB。
  2. 它不像恒定高速缓存那样期望或要求“统一访问”来提供完整的访问带宽/最佳性能。统一访问是指线程束中的所有线程都在访问相同的位置或相同的恒定内存值(按每个读取周期/指令)。

the CUDA programming guide中记录了只读缓存。可能最简单的使用方法是将decorate your pointers__restrict__传递到CUDA内核(假设您是not aliasing between pointers),并用{{装饰指向大常量数据的指针1}}。这将允许编译器生成适当的LDG指令以访问常量数据,并通过只读缓存机制将其提取。

此只读缓存机制仅在cc 3.5或更高版本的GPU上受支持,但涵盖了开普勒时代的某些GPU,以及麦克斯韦,帕斯卡(包括GTX 1080 ti),伏打和图灵世代的所有GPU。

如果您的GPU低于cc3.5,则可能获得类似好处的最佳建议(大于const ... __restrict__,不需要统一访问),则可以使用纹理内存。编程指南的其他地方也对此进行了记录,其中有各种CUDA示例代码演示了纹理内存的用法,并且在SO __const__标签上也涵盖了很多问题。

答案 1 :(得分:1)

不适合硬件常量缓冲区的常量内存通常会“溢出”到OpenCL上的global内存中。银行冲突通常是 local 内存的问题,所以可能不是。我假设CUDA的64kiB常量限制反映了nvidia的硬件,因此OpenCL不会在这里神奇地表现更好。

但是,如果没有可预测的模式读取全局内存,当然会很慢,特别是如果您没有足够的线程占用率和算法来掩盖内存延迟。

在不进一步了解您的问题空间的情况下,这也使我转向可以进行进一步优化的方向,假设您的全局内存读取是问题所在:

  • 减少所需的常量/全局数据量,例如通过使用更有效的类型,其他压缩机制,或动态计算某些值(可能将它们存储在local内存中,用于所有线程)一个小组分享)。
  • 将最常使用的数据聚集在一个小的constant缓冲区中,并显式地将更不常用的常量放置在global缓冲区中。这可以帮助运行时在硬件中更有效地进行布局。如果这样做没有帮助,请尝试将常用数据复制到local内存中,并使线程组较大且运行时间较长,以隐藏复制命中。
  • 检查是否可以提高线程占用率。通常可以,而且这几乎可以在任何情况下为您带来实质性的性能改进。 (除非您的代码已经非常受ALU / FPU约束)