我正在写一个CUDA内核,它涉及计算给定矩阵的最大值,我正在评估可能性。我能找到的最好方法是:
强制每个线程在共享内存中存储一个值,然后使用减少算法来确定最大值(pro:最小分歧:在2.0设备上共享内存限制为48Kb)
我无法使用原子操作,因为同时存在读取和写入操作,因此无法通过同步线程同步线程。
还有其他想法进入你的脑海吗?
答案 0 :(得分:6)
您可能还想使用CUDA Thrust附带的缩减例程,它是CUDA 4.0的一部分或可用here。
该库由一对nVidia工程师编写,与手工优化的代码相比具有优势。我相信还有一些网格/块大小的自动调整。
您可以通过包装原始设备指针轻松地与您自己的内核连接。
严格来说,这是从快速整合的角度出发的。对于理论,请参阅tkerwin的答案。
答案 1 :(得分:4)
这是执行CUDA减少的常用方法
在每个区块内,
1)在每个线程的共享内存中保持运行减少的值。因此,每个线程将读取n(我个人支持16到32之间),来自全局内存的值并更新这些值的减少值
2)在块内执行缩减算法,以获得每个块的最终减少值。
这样,您不需要比(线程数)* sizeof(datatye)字节更多的共享内存。
由于每个块都是减少的值,因此您需要执行第二次减少传递以获得最终值。
例如,如果每个块启动256个线程,并且每个线程读取16个值,则每个块可以减少(256 * 16 = 4096)个元素。
所以给定100万个元素,你需要在第一遍中启动大约250个块,在第二个通道中只需要一个块。
当元素数量> 1时,您可能需要第三次传递。 (4096)^ 2用于此配置。
您必须注意全局内存读取是否合并。您无法合并全局内存写入,但这是您需要采取的性能影响之一。
答案 2 :(得分:3)
NVIDIA有一个减少的CUDA演示:here。这里有一份白皮书,它解释了设计背后的一些动机。
答案 3 :(得分:2)
我发现this document对于学习使用CUDA进行并行缩减的基础知识非常有用。它有点陈旧,所以必须有额外的技巧来进一步提升性能。
答案 4 :(得分:1)
实际上,你描述的问题并不是关于矩阵。输入数据的二维视图不重要(假设矩阵数据在存储器中连续布局)。它只是对一系列值的缩减,是所有矩阵元素,无论它们出现在内存中的顺序如何。
假设矩阵表示在内存中是连续的,您只想执行简单的缩减。现在最好的实施 - 据我所知 - 是nVIDIA的Duane Merill的优秀libcub。 Here是有关其设备范围最大计算功能的文档。
但请注意,除非矩阵很小,否则对于大多数计算而言,它只是线程读取数据并更新自己的线程特定最大值。只有当一个线程通过矩阵的一个大样本(或者更确切地说,一个大的strided swath)完成读取时,它才会在任何地方写入其局部最大值 - 通常是在共享内存中进行块级减少。对于原子,你可能会在每次大量的矩阵元素读取时进行一次atomicMax()
调用 - 如果不是更多的话,就会成为数万个。
答案 5 :(得分:0)
也可以使用atomicAdd
函数,但效率远低于上述方法。 http://supercomputingblog.com/cuda/cuda-tutorial-4-atomic-operations/
答案 6 :(得分:0)
如果您有K20或Titan,我建议使用动态并行:午餐单个线程内核,其中#items工作线程内核线程产生数据,然后午餐#stems / first-round-reduction-factor线程进行第一轮减少,并保持午餐,直到结果出来。