CUDA:在 GPU 上对矢量<矢量>进行排序<int>

CUDA: Sorting a vector< vector<int> > on the GPU

本文关键字:gt lt GPU 排序 int 矢量 CUDA      更新时间:2023-10-16

我已经为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允许您定义自己的比较器,但是在我昨天提出的一个问题中,我了解到创建host_vector < host_vector<int> >是不可能的。

我想把向量的向量变换成一个向量对我没有多大帮助,因为我不知道如何实现比较器类。

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

  1. 我该如何处理这个问题?
  2. Thrust可以实现吗?
  3. 在GPU上做它会给我的整体代码一个更好的性能吗?请注意,向量的向量可以是巨大的,数百万行,但只有几个(5-10)列。
  4. 是设计自己的排序还是更改已经可用的排序函数更好?虽然这听起来是个好主意,但在实践中,我觉得这需要我付出很多努力才能实现。使用一个简单的比较器和一个库中的排序函数对我来说是最好的,但是Thrust的限制不允许我这样做。

提前感谢

我看到你正试图实现一个字典排序技术(但我已经用一个1D巨大的向量),好吧,我一直在那里,我已经实现了一个排序向量的函数,但实际上它落后于字典排序,无论如何,我不确定我是否可以在这里发布代码,所以如果你需要任何帮助,我会很乐意帮助

PS:查看lexicographical_sort的实现。Cu在推力示例代码(我也调整了它,但那一个也落后)为了检查1D vector(包含所有数据)中的两个不同位置,您可能需要比较器函数列在下面(顺便说一下,这种技术比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;
}

我找到了一个合理的方法,最终可以击败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是很棒的:)