CUDA:对矢量进行排序&lt; vector <int>&gt;在GPU上</int>

时间:2013-04-08 16:14:05

标签: c++ sorting vector cuda thrust

我已经为STL的sort函数实现了自己的比较器,这有助于对 CPU 上的std::vector< std::vector<int> >进行排序。 用户将std::vector< std::vector<int> >和字符串变量作为输入提供,例如021。通过使用此字符串,首先在第一列上完成排序,然后在第三列上完成排序,然后在第二列上完成排序。例如:

  1 2 3
  3 2 1
  1 1 1
  1 1 2

假设字符串为10

输出

  1 1 1
  1 1 2
  1 2 3
  3 2 1

我的CPU实现使用了一个名为Sorting的类,该类使用以下两个文件实现:

Sorting.h

class Sorting{

   private:

   public:

Sorting();
~Sorting();
std::vector<std::vector<int>> applySort(std::vector<std::vector<int>>
    data,const std::string& attr);

 };

Sorting.cpp

 Sorting::Sorting(){}

 Sorting::~Sorting(){}


 std::vector<std::vector<int>> Sorting::applySort(
      std::vector<std::vector<int>> data, const std::string& attr){

         std::sort(data.begin(), data.begin()+data.size(), Comparator(attr));

         return data;
  }

Comparator.h

   class Comparator{

   private:
     std::string attr;

   public:
     Comparator(const std::string& attr) { this->attr = attr; }

     bool operator()(const std::vector<int>& first, const std::vector<int>&
          second){

    size_t i;
    for(i=0;i<attr.size();i++){
        if(first[attr.at(i) - '0'] < second[attr.at(i) - '0']) return true;
        else if(first[attr.at(i) - '0'] > second[attr.at(i)-'0'])          
             return  false;
    }
    return false;
  }

  };

我的实施已经过测试,并且运行正常。我有兴趣做一个类似的CUDA实现,利用GPU的功能,以便更快地生成输出。

最初我认为因为我的目标有点令人困惑,也许改变已知的GPU排序实现会完成我的工作。但是我开始搜索许多类似于此处描述的实现:http://blogs.nvidia.com/2012/09/how-tesla-k20-speeds-up-quicksort-a-familiar-comp-sci-code/并且它让我意识到它将很难实现。

我不确定这是否是最好的行动方案。我开始搜索库并找到Thrust。但是,虽然Thrust允许你定义自己的比较器,但在question我昨天问到的时候我才知道创建host_vector < host_vector<int> >是不可能的。

我猜我将矢量向量转换为单个向量对我没有多大帮助,因为我不知道如何实现我的比较器类。

我想听听你对这个问题的看法:

  1. 我该如何解决这个问题?
  2. 是否可以使用Thrust
  3. 来实现它
  4. 在GPU中执行此操作会在整体代码上提供更好的性能吗?请注意,矢量矢量可能很大,数百万行但只有几(5-10)列。
  5. 设计我自己的排序或更改已有的排序功能会更好吗?虽然这听起来不错,但在实践中我觉得这需要我付出很多努力。使用简单的比较器和库中的排序函数对我来说是最好的,但是Thrust的限制不允许我这样做。
  6. 提前谢谢

2 个答案:

答案 0 :(得分:1)

我看到你正在尝试实现一种词典排序技术(但是我已经用单个1D巨型向量做了),我已经在那里并且我已经实现了对向量进行排序的功能但实际上它落后于落后的方式词典排序,反正我不知道我是否可以在这里发布代码,所以如果你需要任何帮助我会很乐意帮助

PS:看一下lexicographical_sort.cu在推力示例代码中的实现(我已经调整了它但是那个也落后了) 下面列出了你可能需要的比较器函数,以便从1D向量中的两个区别位置(其中包含所有数据)进行检查(顺便说一句,这种技术比CPU慢)但是谁知道你可能想出你的想法改进它或使用它比我更好

struct arbitrary_functor
{
    template <typename Tuple>   __host__ __device__
        void operator()(Tuple t)
        {
            if(thrust::get<0>(t)>thrust::get<1>(t))
                thrust::get<2>(t) = 1;
            else
                thrust::get<2>(t) = 0;
        }
};

int checkLexo_1vec(const thrust::device_vector<char> & A, int bv1, int bv2, int N){
    int i;

    thrust::device_vector<char> temp(N);
    thrust::device_vector<char> sum(N);

    thrust::for_each(thrust::make_zip_iterator(
                        thrust::make_tuple(A.begin()+bv2, A.begin()+bv1,temp.begin())),
                    thrust::make_zip_iterator(
                        thrust::make_tuple(A.end()+(bv2+N),A.end()+(bv1+N), temp.end())),
                    arbitrary_functor());


    thrust::inclusive_scan(temp.begin(),temp.end(),sum.begin());

    int a = thrust::lower_bound(sum.begin(),sum.end(),1) - sum.begin();

    thrust::for_each(thrust::make_zip_iterator(
                        thrust::make_tuple(A.begin()+bv1, A.begin()+bv2, temp.begin())),
                    thrust::make_zip_iterator(
                        thrust::make_tuple(A.end()+(bv1+N), A.end()+(bv2+N),temp.end())),
                    arbitrary_functor());

    thrust::inclusive_scan(temp.begin(),temp.end(),sum.begin());

    int b = thrust::lower_bound(sum.begin(),sum.end(),1) - sum.begin();

    if(a<=b)
        return 1;
    else
        return 0;
}

答案 1 :(得分:0)

我找到了一种合理的方法,可以最终击败CPU(不是在时间方面,而是在数据元素方面) 实际上我的新方法涉及使用thrust :: mismatch而且我附加了函数的代码

这个版本的好处是这个功能的运行时间约为2ms。有N = 1000000 to N = 1000等非常大量的数据,无论如何我发布了功能代码,如果你发现任何用户发现其他一些可以减少整体运行时间的改进,请告诉我

template<typename Ivec>    
int lexoMM(Ivec vec, int bv1, int bv2, int N){

  typedef thrust::device_vector<int>::iterator Iterator;
  thrust::pair<Iterator,Iterator> result;

  result = thrust::mismatch(vec.begin()+bv1, vec.begin()+(bv1+N-1), vec.begin()+bv2);

if(result.first == vec.end()){
      //cout<<"Both are equal (right order)"<<endl;
      return 1;
  }
else if(result.first>result.second){
    //cout<<"Wrong order"<<endl;
    //cout<<*result.first<<","<<*result.second;
    return 0;
}
else{
    //cout<<"Right order"<<endl;
    //cout<<*result.first<<","<<*result.second;
    return 1;
    }

}

PS:我觉得我真的浪费了我的时间来实现我自己的同一个版本,但thrust很棒:)