用推力流压实;最佳实践和最快的方法?

时间:2015-06-07 08:05:30

标签: c++ cuda gpgpu thrust sparse-array

我感兴趣的是移植一些现有的代码来使用推力来看看我是否可以相对轻松地在GPU上加速它。

我想要完成的是一个流压缩操作,其中只保留非零元素。根据下面的示例代码,我主要使用它。我不确定如何处理的部分是在压实发生后处理d_res中的所有额外填充空间,从而处理h_res。

该示例仅使用0-99序列,所有偶数项都设置为零。这只是一个例子,真正的问题是一般的稀疏数组。

这里的答案对我有很大的帮助,尽管在读出数据时,只知道大小是不变的: How to quickly compact a sparse array with CUDA C?

我怀疑我可以通过计算d_src中0的数量来解决这个问题,然后只将d_res分配给那个大小,或者在压缩后进行计数,并且只复制那么多元素。这真的是正确的做法吗?

通过巧妙地使用迭代器或其他推力功能,我感觉会有一些简单的解决方法。

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>

//Predicate functor
struct is_not_zero
{
    __host__ __device__
        bool operator()(const int x)
    {
        return (x != 0);
    }
};

using namespace std;

int main(void)
{
    size_t N = 100;

    //Host Vector
    thrust::host_vector<int> h_src(N);

    //Fill with some zero and some nonzero data, as an example
    for (int i = 0; i < N; i++){
        if (i % 2 == 0){
            h_src[i] = 0;
        }
        else{
            h_src[i] = i;
        }
    }

    //Print out source data
    cout << "Source:" << endl;

    for (int i = 0; i < N; i++){
        cout << h_src[i] << " ";
    }
    cout << endl;

    //copies to device
    thrust::device_vector<int> d_src = h_src;

    //Result vector
    thrust::device_vector<int> d_res(d_src.size());

    //Copy non-zero elements from d_src to d_res
    thrust::copy_if(d_src.begin(), d_src.end(), d_res.begin(), is_not_zero());

    //Copy back to host
    thrust::host_vector<int> h_res(d_res.begin(), d_res.end());
    //thrust::host_vector<int> h_res = d_res; //Or just this?

    //Show results
    cout << "h_res size is " << h_res.size() << endl;
    cout << "Result after remove:" << endl;

    for (int i = 0; i < h_res.size(); i++){
        cout << h_res[i] << " ";
    }
    cout << endl;

    return 0;
}

另外,我是一个有推力的新手,所以如果上面的代码有任何明显的缺陷违反推荐使用推力的做法,请告诉我。

同样,速度总是令人感兴趣的。阅读一些各种推力教程,似乎在这里几乎没有什么变化,可以有很大的速度节省或浪费。所以,如果有一种聪明的方法可以加快速度,请告诉我。

1 个答案:

答案 0 :(得分:2)

你似乎忽略的是copy_if返回一个迭代器,它指向流压缩操作中复制数据的结尾。所以所需要的只是:

//copies to device
thrust::device_vector<int> d_src = h_src;

//Result vector
thrust::device_vector<int> d_res(d_src.size());

//Copy non-zero elements from d_src to d_res
auto result_end = thrust::copy_if(d_src.begin(), d_src.end(), d_res.begin(), is_not_zero());

//Copy back to host
thrust::host_vector<int> h_res(d_res.begin(), result_end);

执行此大小h_res仅保留非零并仅从流压缩的输出中复制非零。无需额外计算。