如何在Thrust

时间:2019-06-29 16:30:50

标签: cuda gpgpu thrust

我有100000个数组,它们存储在一个大的1D数组中。 每个数组的大小为L = 1000,并按降序排列。

每个数组分为m = 5个段。(S1,S2,S3,S4,S5) 例如:

A1=[S1,S2,S3,S4,S5]
A2=[S1,S2,S3,S4,S5]
A3=[S1,S2,S3,S4,S5]
…
A100000=[S1,S2,S3,S4,S5]

以下是大容器数组的示例,如下所示: enter image description here

我的问题是:

对于w = 10个数组的每个窗口(例如),我想按以下方式重组10个数组: 首先将这10个数组中的每个数组的段S1放置,之后再放置S2段,S3段…。 以下是w = 6的示例: enter image description here

作为信息L,m和w是可以采用不同值的参数。

是否有使用Thrust的快速方法?

1 个答案:

答案 0 :(得分:1)

该方法将与所描述的here非常相似。

  1. 构造一个映射向量(即由迭代器产生的序列),该向量将输入映射到输出。我们将使用thrust::counting_iterator提供序数序列0、1、2,...,然后使用thrust::transform_iterator构造映射迭代器。挑战在于为传递给变换迭代器的操作创建正确的算法。下面的代码被广泛注释以解释这一点。
  2. 通过thrust::permutation_iterator将地图矢量传递到thrust::copy_n。请注意,有时候好的建议是不要复制数据。如果只使用一次数据的“转换视图”,则只需将该置换迭代器传递给您一次使用的推力算法,而不是实际复制数据。如果您需要多次使用数据的“转换视图”,则一次复制可能会更有效。

这是一个可行的示例:

$ cat t5.cu
#include <thrust/sequence.h>
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <iostream>

typedef int dtype;  // data type
typedef int itype;  // indexing type - change to size_t if L*m*s > int
const itype s = 3;  // segment_width
const itype m = 2;  // number of segments per sub-array
const itype L = 4;  // number of sub-arrays per array
const itype w = 2;  // width of group (# of sub-arrays) for segment reordering
// S1 S1 S2 S2 S1 S1 S2 S2
//  0  1  2  6  7  8  3  4  5  9 10 11 12 13 14 18 19 20 15 16 17 21 22 23

using namespace thrust::placeholders;

int main(){
// we require data that consists of L*m*s elements
// we also require L to be whole-number divisible by w
  thrust::device_vector<dtype> d_data(L*m*s);
  thrust::device_vector<dtype> d_result(L*m*s);
  thrust::sequence(d_data.begin(), d_data.end());
// we will build up the necessary map iterator progressively
// we will start with an target_index sequence i =              0, 1, 2, 3, 4, 5, ... which defines the location in the target vector
// seg_idx    (position within a segment) = i%s                 0, 1, 2, 0, 1, 2, ...
// which_seg  (which segment within sub-array) = (i/(w*s))%m    0, 0, 0, 0, 0, 0, 1, ...
// which_sub  (which sub-array in group) = (i/s)%w              0, 0, 0, 1, 1, 1, 0, ...
// which_grp  (which group in array) = i/(w*s*m)                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ...
// map index = which_grp*group_width + which_sub*subarray_width + which_seg*segment_width + seg_idx
// map index = (i/(w*s*m))*(w*s*m) + ((i/s)%w)*(s*m) + ((i/(w*s))%m)*s + i%s
  thrust::copy_n(thrust::make_permutation_iterator(d_data.begin(), thrust::make_transform_iterator(thrust::counting_iterator<itype>(0), (_1/(w*s*m))*(w*s*m) + ((_1/s)%w)*(s*m) + ((_1/(w*s))%m)*s + _1%s)), L*m*s, d_result.begin());
  thrust::copy(d_result.begin(), d_result.end(), std::ostream_iterator<dtype>(std::cout, ","));
  std::cout << std::endl;
}
$ nvcc -o t5 t5.cu
$ ./t5
0,1,2,6,7,8,3,4,5,9,10,11,12,13,14,18,19,20,15,16,17,21,22,23,
$

请注意,如果总数据长度(L*m*s)大于int所能容纳的长度,则必须重构以上代码以使用size_t int的{​​{1}}类型定义。