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

Share large constant data among cuda threads

本文关键字:常量 数据 共享 cuda 线程 之间      更新时间:2023-10-16

我有一个内核,它被调用了多次。在每次调用中,线程将共享和处理大约240千字节的恒定数据。线程像映射函数一样独立工作。线程的停滞时间相当长。这背后的原因可能是记忆读取的银行冲突。我该如何处理?(我有GTX 1080 ti(

opencl的"constglobal"能处理这个问题吗?(因为cuda中的恒定内存限制为64kb(

在CUDA中,我认为最好的建议是使用所谓的"只读"缓存。与__constant__内存/常量缓存系统相比,这至少有两个可能的好处:

  1. 它不限于64kB,就像__constant__内存一样
  2. 它不期望或要求像恒定缓存那样的"统一访问",以提供完全访问带宽/最佳性能。统一访问是指扭曲中的所有线程都在访问相同的位置或相同的恒定内存值(每个读取周期/指令(

CUDA编程指南中介绍了只读缓存。使用它最简单的方法可能是用__restrict__装饰传递给CUDA内核的指针(假设指针之间没有混叠(,并用const ... __restrict__装饰引用大常量数据的指针。这将允许编译器生成适当的LDG指令来访问常量数据,并通过只读缓存机制将其拉入。

这种只读缓存机制仅在cc 3.5或更高版本的GPU上受支持,但它涵盖了开普勒一代的一些GPU以及Maxwell、Pascal(包括您的GTX 1080 ti(、Volta和图灵一代的所有GPU。

如果你的GPU小于cc3.5,那么对于类似的好处(大于__const__,不需要统一访问(,最好的建议可能是使用纹理内存。这也在编程指南的其他地方进行了记录,有各种CUDA示例代码演示了纹理内存的使用,还有很多关于SOcuda标签的问题。

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

然而,在没有可预测模式的情况下读取全局内存当然会很慢,尤其是在没有足够的线程占用率和算术来掩盖内存延迟的情况下。

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

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