Cuda 作为两个约化向量的函数,通过_key()从reduce_输出

Cuda 作为两个约化向量的函数,通过_key()从reduce_输出,cuda,thrust,Cuda,Thrust,我正在通过将AoS方法转换为SoA方法来重构推力代码,以利用内存合并。为此,我有两个向量,它们被一个公共键缩减,然后用于计算输出向量的值。最初的代码是用一个函子实现的,我想模拟一下 基本上: Oᵢ = Rᵢ / sᵢ, R在哪里ᵢ 和Sᵢ 向量是否由相同的键减少,以及Oᵢ 是对应的输出向量 下面的代码举例说明了我要做的事情: typedef tuple<int,int> Tuple; struct BinaryTupleOp : public thrust::binary_func

我正在通过将AoS方法转换为SoA方法来重构推力代码,以利用内存合并。为此,我有两个向量,它们被一个公共键缩减,然后用于计算输出向量的值。最初的代码是用一个函子实现的,我想模拟一下

基本上:

Oᵢ = Rᵢ / sᵢ, R在哪里ᵢ 和Sᵢ 向量是否由相同的键减少,以及Oᵢ 是对应的输出向量

下面的代码举例说明了我要做的事情:

typedef tuple<int,int> Tuple;

struct BinaryTupleOp : public thrust::binary_function<Tuple const &, Tuple const &, int>
{
  __host__ __device__
  int operator()(Tuple const & lhs, Tuple const & rhs) const {
    // get<0> = vals, get<1> = other_vals                                                                                           

    return (get<0>(lhs) + get<0>(rhs)) / (get<1>(lhs) + get<1>(rhs));
  }

};


int main(int argc, char ** argv)
{
  const int N = 7;

  device_vector<int> keys(N);

  keys[0] = 1; // represents sorted keys                                                                                            
  keys[1] = 1;
  keys[2] = 2;
  keys[3] = 2;
  keys[4] = 3;
  keys[5] = 3;
  keys[6] = 3;

  device_vector<int> vals(N);

  vals[0] = 6; // just some random numbers                                                                                          
  vals[1] = 3;
  vals[2] = 9;
  vals[3] = 4;
  vals[4] = 6;
  vals[5] = 1;
  vals[6] = 5;

  device_vector<int> other_vals(N);

  other_vals[0] = 4; // more randomness                                                                                             
  other_vals[1] = 1;
  other_vals[2] = 3;
  other_vals[3] = 6;
  other_vals[4] = 2;
  other_vals[5] = 5;
  other_vals[6] = 7;


  device_vector<int> new_keys(N);
  device_vector<int> output(N);

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

  thrust::equal_to<int> binary_pred;

  new_end = thrust::reduce_by_key(keys.begin(), keys.end(),
                                  make_zip_iterator(make_tuple(vals.begin(), other_vals.begin())),
                                  new_keys.begin(),
                                  output.begin(),
                                  binary_pred,
                                  BinaryTupleOp() );

  Iterator i = new_keys.begin();
  Iterator j = output.begin();

  for (;
       i != new_end.first;
       i++, j++ ) {
    std::cout << "key " << *i << " sum " << *j << endl;
  }

  return 0;
}
typedef元组;
struct BinaryTupleOp:公共推力::二进制函数
{
__主机设备__
int运算符()(元组常量和lhs,元组常量和rhs)常量{
//get=VAL,get=其他值
返回(get(lhs)+get(rhs))/(get(lhs)+get(rhs));
}
};
int main(int argc,字符**argv)
{
常数int N=7;
设备_向量键(N);
键[0]=1;//表示已排序的键
键[1]=1;
键[2]=2;
键[3]=2;
键[4]=3;
键[5]=3;
键[6]=3;
设备向量VAL(N);
VAL[0]=6;//只是一些随机数
VAL[1]=3;
VAL[2]=9;
VAL[3]=4;
VAL[4]=6;
VAL[5]=1;
VAL[6]=5;
设备向量其他值(N);
其他值[0]=4;//更多随机性
其他值[1]=1;
其他价值[2]=3;
其他价值[3]=6;
其他价值[4]=2;
其他价值[5]=5;
其他价值[6]=7;
设备向量新密钥(N);
设备_矢量输出(N);
typedef设备_向量::迭代器迭代器;
推力:配对新的_端;
推力:等于二进制pred;
new_end=推力::按键减少(keys.begin(),keys.end(),
make_-zip_迭代器(make_元组(vals.begin(),other_-vals.begin()),
新的_键。开始(),
output.begin(),
二元pred,
BinaryTupleOp());
迭代器i=新的_键。开始();
迭代器j=output.begin();
对于(;
i!=new_end.first;
i++,j++){
标准::cout
与此同时,我做错了什么

struct::reduce
(或
struct::reduce_by_key
)将执行并行缩减。此并行缩减需要一个可成对应用的缩减运算符。举一个非常简单的示例,假设我们要缩减3个元素(
E1
E2
E3
),并且我们有一个二进制操作(
bOp
),我们将使用它来定义减速操作。推力可能会执行以下操作:

E1       E2      E3
 \        /
    bOp
     \           /
          bOp
           |
         result
也就是说,二进制运算将用于组合或“减少”元素
E1
E2
为单个临时部分结果,并且该结果将反馈到与元素
E3
组合的二进制运算中,以产生最终的
结果

这意味着二进制op的输出(以及值输出迭代器的输出类型)必须与其输入类型(以及值输入迭代器的输入类型)匹配

但是您的二进制op不满足此要求,您为值输入和值输出传递的迭代器类型也不满足此要求:

  new_end = thrust::reduce_by_key(keys.begin(), keys.end(),
                              make_zip_iterator(make_tuple(vals.begin(), other_vals.begin())),
     /* dereferencing the above iterator produces an <int, int> tuple */
                              new_keys.begin(),
                              output.begin(),
     /* dereferencing the above iterator produces an int  */
                              binary_pred,
                              BinaryTupleOp() );
其他人可能对如何创造你想要的结果有更好的想法

与此同时,我做错了什么

struct::reduce
(或
struct::reduce_by_key
)将执行并行缩减。此并行缩减需要一个可成对应用的缩减运算符。举一个非常简单的示例,假设我们要缩减3个元素(
E1
E2
E3
),并且我们有一个二进制操作(
bOp
),我们将使用它来定义减速操作。推力可能会执行以下操作:

E1       E2      E3
 \        /
    bOp
     \           /
          bOp
           |
         result
也就是说,二进制运算将用于组合或“减少”元素
E1
E2
为单个临时部分结果,并且该结果将反馈到与元素
E3
组合的二进制运算中,以产生最终的
结果

这意味着二进制op的输出(以及值输出迭代器的输出类型)必须与其输入类型(以及值输入迭代器的输入类型)匹配

但是您的二进制op不满足此要求,您为值输入和值输出传递的迭代器类型也不满足此要求:

  new_end = thrust::reduce_by_key(keys.begin(), keys.end(),
                              make_zip_iterator(make_tuple(vals.begin(), other_vals.begin())),
     /* dereferencing the above iterator produces an <int, int> tuple */
                              new_keys.begin(),
                              output.begin(),
     /* dereferencing the above iterator produces an int  */
                              binary_pred,
                              BinaryTupleOp() );

其他人可能有更好的想法来设计你想要的结果。

谢谢你及时、冗长、恰当的回答,罗伯特。你提出的解决方案确实正是我想要的。当我为
reduce\u by\u key
做RTFD时,我错过了你善意强调的这个细节:
inputierator2的值类型是con可转换为OutputIterator2的值\u类型。
而且,直接将元组分配给单个POD自然有点困难,这正是我无意中尝试的。我现在正在对原始代码进行适当的更改。再次感谢。感谢您及时、长时间和适当的响应,Robert。谢谢您的回复注意确实是我一直在寻找的东西。当我被RTFD用于
reduce\u by\u key
时,我错过了您善意地强调的这个细节:
InputIterator2的value\u类型可以转换为OutputIterator2的value\u类型。
而且,自然地,直接将元组分配给单个POD有点困难,这是我不愿意看到的我正在尝试。我正在对原始代码进行适当的更改。再次感谢。