Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm CUDA流压缩算法_Algorithm_Parallel Processing_Cuda_Stream Compaction - Fatal编程技术网

Algorithm CUDA流压缩算法

Algorithm CUDA流压缩算法,algorithm,parallel-processing,cuda,stream-compaction,Algorithm,Parallel Processing,Cuda,Stream Compaction,我正在尝试用CUDA构造一个并行算法,它接受一个整数数组,并删除所有0,无论是否保持顺序 例如: 全局内存:{0,0,0,0,14,0,0,0,17,0,0,0,0,13} 主机内存结果:{17,13,14,0,0,…} 最简单的方法是使用主机删除O(n)时间中的0。但是考虑到我有大约1000个元素,在发送之前,将所有元素都放在GPU上并进行压缩可能会更快 首选的方法是创建一个设备上堆栈,这样每个线程都可以弹出并推(以任何顺序)到堆栈上或从堆栈上推出。然而,我认为CUDA没有实现这一点 一种等效

我正在尝试用CUDA构造一个并行算法,它接受一个整数数组,并删除所有
0
,无论是否保持顺序

例如:

全局内存:{0,0,0,0,14,0,0,0,17,0,0,0,0,13}

主机内存结果:{17,13,14,0,0,…}

最简单的方法是使用主机删除
O(n)
时间中的
0
。但是考虑到我有大约1000个元素,在发送之前,将所有元素都放在GPU上并进行压缩可能会更快

首选的方法是创建一个设备上堆栈,这样每个线程都可以弹出并推(以任何顺序)到堆栈上或从堆栈上推出。然而,我认为CUDA没有实现这一点

一种等效(但要慢得多)方法是继续尝试写入,直到所有线程都完成写入:

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;
    }
}
kernalremovespace(int*array,int*outArray,int-arraySize){
if(数组[threadId.x]==0)
返回;
for(int i=0;i
这种方法的唯一好处是,我们将在
O(f(x))
时间中执行,其中
f(x)
是数组中存在的非零值的平均数(
f(x)~=ln(n)
对于我的实现,因此
O(ln(n))
时间,但具有较高的
O
常数)

最后,像quicksort或mergesort这样的排序算法也可以解决这个问题,而且实际上是在
O(ln(n))
相对时间内运行的。我认为可能有一种算法比这更快,因为我们不需要浪费时间排序(交换)零零元素对和非零非零元素对(不需要保持顺序)

所以我不确定哪种方法最快,我仍然 我想有更好的方法来处理这件事。有什么建议吗


您需要的是一个名为streamcompaction1的经典并行算法

如果推力是一个选项,您可以简单地使用。这是一个稳定的算法,它保留了所有元素的相对顺序

草图:

#include <thrust/copy.h>

template<typename T>
struct is_non_zero {
    __host__ __device__
    auto operator()(T x) const -> bool {
        return x != 0;
    }
};

// ... your input and output vectors here

thrust::copy_if(input.begin(), input.end(), output.begin(), is_non_zero<int>());
#包括
模板
结构为非零{
__主机设备__
自动运算符()(T x)常量->布尔{
返回x!=0;
}
};
// ... 在这里输入和输出向量
推力::复制如果(input.begin()、input.end()、output.begin()、是非零();
如果推力不是一个选项,您可以自己实现流压缩(关于这个主题有很多文献)。这是一个有趣且相当简单的练习,同时也是更复杂的并行原语的基本构建块


(1)严格来说,它不是传统意义上的流压缩,因为流压缩传统上是一种稳定的算法,但您的要求不包括稳定性。这种宽松的要求可能会导致更高效的实现?

流压缩是一个众所周知的问题,为此编写了很多代码(Struch,Chagg引用了两个在CUDA上实现流压缩的库)

如果您有一个相对较新的支持CUDA的设备,该设备支持“投票”(计算能力>=3.0)的固有功能,那么值得尝试一个小型CUDA程序,该程序执行流压缩比推力快得多

这里查找代码和最小文档。

Is以单个内核的方式使用抽签函数来执行压缩


编辑:
我写了一篇文章解释这种方法的内部工作原理。如果您感兴趣,可以找到它。

有了这个答案,我只想提供更多关于戴维德·斯帕塔罗方法的细节

正如您所提到的,流压缩包括根据谓词删除集合中不需要的元素。例如,考虑整数数组和谓词
p(x)=x>5
,数组
A={6,3,2,11,4,5,3,7,5,77,94,0}
被压缩为
B={6,11,7,77,94}

流压缩方法的一般思想是将不同的计算线程分配给要压缩的数组的不同元素。每个这样的线程都必须决定将其对应的元素写入输出数组,这取决于它是否满足相关谓词。因此,流压缩的主要问题是让每个线程知道必须在输出数组中写入相应元素的位置

[1,2]中的方法是上述推力的
copy\u的替代方法,包括三个步骤:

  • 第1步。设
    P
    为已启动线程的数量,
    N
    ,其中
    N>P
    ,为要压缩的向量的大小。将输入向量划分为大小
    S
    等于块大小的子向量。利用
    \uuuu syncthreads\u count(pred)
    块内在特性,计算满足谓词pred的块中的线程数。作为第一步的结果,数组
    d_BlockCounts
    的每个元素(其大小
    N/P
    )包含在相应块中满足谓词pred的元素数

  • 第二步。对阵列d_块计数执行独占扫描操作。作为第二步的结果,每个线程都知道前面块中有多少个元素写入一个元素。因此,它知道写入其相应元素的位置,但与自身块相关的偏移量除外

  • 第三步。每个线程使用warp内在函数计算上述偏移量,并最终写入输出数组。应该注意,步骤3的执行与t相关
    [1] M.Biller, O. Olsson, U. Assarsson, “Efficient stream compaction on wide SIMD many-core architectures,” 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, “InK-Compact: in-kernel stream compaction and its application to multi-kernel data visualization on General-Purpose GPUs,” Computer Graphics Forum, vol. 32, n. 6, pp. 178-188, 2013.