CUDA stream compaction algorithm
我正在尝试使用CUDA构造并行算法,该算法采用整数数组并删除所有
示例:
全局内存:{0,0,0,0,14,0,0,17,17,0,0,0,0,13}
主机内存结果:{17,13,14,0,0,...}
最简单的方法是使用主机在
首选方法是创建设备上的堆栈,这样每个线程都可以弹出(按任何顺序)插入或退出堆栈。但是,我认为CUDA没有实现此功能。
等效的方法(但要慢得多)是继续尝试写入,直到所有线程完成写入为止:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | kernalRemoveSpacing(int * array, int * outArray, int arraySize) { if (array[threadId.x] == 0) return; for (int i = 0; i < arraySize; i++) { array = arr[threadId.x]; __threadfence(); // If we were the lucky thread we won! // kill the thread and continue re-reincarnated in a different thread if (array[i] == arr[threadId.x]) return; } } |
此方法的唯一好处是我们将在
最后,诸如quicksort或mergesort之类的排序算法也可以解决该问题,并且实际上在相对时间
So I'm not quite sure which method would be the fastest, and I still
think there's a better way of handling this. Any suggestions?
您要的是一种经典的并行算法,称为流压缩1。
如果选择"推力",则可以简单地使用
草图:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <thrust/copy.h> template<typename T> struct is_non_zero { __host__ __device__ auto operator()(T x) const -> bool { return T != 0; } }; // ... your input and output vectors here thrust::copy_if(input.begin(), input.end(), output.begin(), is_non_zero<int>()); |
如果没有选择"推力",则可以自己实现流压缩(有关该主题的文献很多)。这是一个有趣且相当简单的练习,同时也是更复杂的并行基元的基本构建块。
(1)严格来说,它不是传统意义上的流压缩,因为流压缩在传统上是一种稳定的算法,但您的要求不包括稳定性。放宽要求可能会导致更有效的实施?
有了这个答案,我只是想为Davide Spataro的方法提供更多细节。
如前所述,流压缩包括根据谓词除去集合中不需要的元素。例如,考虑整数数组和谓词
流压缩方法的一般思想是将不同的计算线程分配给要压缩的数组的不同元素。每个此类线程都必须根据是否满足相关谓词来决定将其对应的元素写入输出数组。因此,流压缩的主要问题是让每个线程知道必须在输出数组中写入相应元素的位置。
[1,2]中的方法是上述Thrust
步骤1。假设
第2步。独占扫描操作在数组d_BlockCounts上执行。作为第二步的结果,每个线程都知道前面的块中有多少个元素写入一个元素。因此,它知道在哪里写入其相应元素的位置,但知道与其自身块相关的偏移量。
第3步。每个线程使用扭曲内在函数计算所提到的偏移量,并最终写入输出数组。应当注意,步骤#3的执行与翘曲调度有关。因此,输出数组中的元素顺序不一定反映输入数组中的元素顺序。
在以上三个步骤中,第二个步骤由CUDA Thrusta的
对于
1)专为支持扭曲固有元素的卡片量身定制;
2)该方法不能保证输出顺序。
请注意,我们还针对inkc.sourceforge.net上提供的代码测试了该方法。尽管后面的代码安排在单个内核调用中(它不使用任何CUDA Thrust原语),但与三内核版本相比,它的性能并不更好。
完整的代码在这里可用,并且与原始Davide Spataro的例程相比略有优化。
1 2 | [1] M.Biller, O. Olsson, U. Assarsson, a€?Efficient stream compaction on wide SIMD many-core architectures,a€? Proc. of the Conf. on High Performance Graphics, New Orleans, LA, Aug. 01 - 03, 2009, pp. 159-166. [2] D.M. Hughes, I.S. Lim, M.W. Jones, A. Knoll, B. Spencer, a€?InK-Compact: in-kernel stream compaction and its application to multi-kernel data visualization on General-Purpose GPUs,a€? Computer Graphics Forum, vol. 32, n. 6, pp. 178-188, 2013. |
流压缩是一个众所周知的问题,编写了很多代码(Thrust,Chagg引用了两个在CUDA上实现流压缩的库)。
如果您有一个相对较新的支持CUDA的设备,该设备支持__ballot的固有功能(计算cdapability> = 3.0),则值得尝试一个小的CUDA过程,该过程执行流压缩的速度比Thrust快得多。
在这里找到代码和最小文档。
https://github.com/knotman90/cuStreamComp
以单内核方式使用投票功能来执行压缩。