Algorithm CUDA:还原还是原子操作?

Algorithm CUDA:还原还是原子操作?,algorithm,matrix,cuda,reduction,gpu-atomics,Algorithm,Matrix,Cuda,Reduction,Gpu Atomics,我正在编写一个CUDA内核,其中包括计算给定矩阵上的最大值,并评估可能性。我能找到的最好办法是: 强制每个线程在共享内存中存储一个值,然后使用缩减算法确定最大值(赞成:最小分歧反对:2.0设备上的共享内存限制为48Kb) 我无法使用原子操作,因为既有读取操作也有写入操作,因此synchthreads无法同步线程 您还有其他想法吗?NVIDIA有一个CUDA演示,可以减少:。随附的白皮书解释了设计背后的一些动机 这是减少CUDA的常用方法 在每个街区内 1) 在共享内存中为每个线程保留一个运行中的

我正在编写一个CUDA内核,其中包括计算给定矩阵上的最大值,并评估可能性。我能找到的最好办法是:

强制每个线程在共享内存中存储一个值,然后使用缩减算法确定最大值(赞成:最小分歧反对:2.0设备上的共享内存限制为48Kb)

我无法使用原子操作,因为既有读取操作也有写入操作,因此synchthreads无法同步线程


您还有其他想法吗?

NVIDIA有一个CUDA演示,可以减少:。随附的白皮书解释了设计背后的一些动机

这是减少CUDA的常用方法

在每个街区内

1) 在共享内存中为每个线程保留一个运行中的缩减值。因此,每个线程将从全局内存中读取n(我个人倾向于16到32)个值,并更新这些值的缩减值

2) 在块内执行缩减算法,以获得每个块的最终缩减值

这样,您就不需要比(线程数)*sizeof(datatye)字节更多的共享内存

由于每个块都有一个缩减值,因此需要执行第二次缩减过程以获得最终值

例如,如果每个块启动256个线程,并且每个线程读取16个值,那么每个块将能够减少(256*16=4096)个元素

因此,给定100万个元素,您将需要在第一个过程中启动大约250个块,在第二个过程中只启动一个块

如果此配置的元素数大于(4096)^2,则可能需要第三次通过


您必须注意合并全局内存读取。您不能合并全局内存写入,但这是您需要承受的性能损失

您可能还希望使用CUDA 4.0的一部分或可用的CUDA推力的缩减例程

该库由一对nVidia工程师编写,与大量手工优化的代码相比具有优势。我相信网格/块大小也会自动调整

通过包装原始设备指针,您可以轻松地与自己的内核进行接口


这完全是从快速集成的角度出发的。有关理论,请参见tkerwin的答案。

也可以使用
原子添加
函数,但其效率远低于上述方法

我发现使用CUDA学习并行归约的基础知识非常有用。它有点陈旧,因此必须有额外的技巧来进一步提高性能。

如果你有K20或Titan,我建议动态并行:午餐一个单线程内核,午餐#items工作者内核线程来生成数据,然后午餐#items/第一轮缩减因子线程来进行第一轮缩减,继续吃午饭直到结果出来。

实际上,你所描述的问题并不是关于矩阵的。输入数据的二维视图并不重要(假设矩阵数据在内存中连续排列)。它只是对一系列值的简化,所有的矩阵元素在内存中出现的顺序都是一样的

假设矩阵表示在内存中是连续的,您只需要执行一个简单的缩减。而目前可用的最好的实现——据我所知——是nVIDIA的Duane Merill的优秀实现。是关于其设备范围最大计算功能的文档


但是请注意,除非矩阵很小,否则对于大多数计算来说,它只是线程读取数据并更新自己的线程特定最大值。只有当一个线程通过一个大的矩阵样本(或者更确切地说,一个大的跨步样本)完成读取后,它才会在任何地方写入其局部最大值——通常是写入共享内存以进行块级缩减。至于原子学,你可能会在每一次令人讨厌的大量矩阵元素读取时打一次电话——如果不是更多的话,也可能是上万次。

共享内存限制是一个什么缺点?现在我推荐英伟达(Duane Merill)而不是他们的主旨。谢谢libcub的提示。@masterxilo:如果你不是太注重矩阵,您可能还想看看my,它的发布级别可能较低,但在我看来,它的使用更加灵活。不过,这还不完全是发布等级代码。我的意思是,它已经过很多测试,而且缺少外部文档。