Sorting 使用CUDA推力并行排序多个阵列

Sorting 使用CUDA推力并行排序多个阵列,sorting,cuda,thrust,Sorting,Cuda,Thrust,我需要对GPU上已经存在的20+数组进行排序,每个数组的长度相同,使用相同的键。我不能直接使用sort\u by\u key(),因为它也会对键进行排序(使它们无法对下一个数组进行排序)。以下是我尝试过的: thrust::device_vector<int> indices(N); thrust::sequence(indices.begin(),indices.end()); thrust::sort_by_key(keys.begin(),keys.end(),indice

我需要对GPU上已经存在的
20+
数组进行排序,每个数组的长度相同,使用相同的键。我不能直接使用
sort\u by\u key()
,因为它也会对键进行排序(使它们无法对下一个数组进行排序)。以下是我尝试过的:

thrust::device_vector<int>  indices(N); 
thrust::sequence(indices.begin(),indices.end());
thrust::sort_by_key(keys.begin(),keys.end(),indices.begin());

thrust::gather(indices.begin(),indices.end(),a_01,a_01);
thrust::gather(indices.begin(),indices.end(),a_02,a_02);
...
thrust::gather(indices.begin(),indices.end(),a_20,a_20);

但是,我不希望为此任务分配额外的数组。我知道有一种解决方案使用了一个推力::tuple、推力::zip_迭代器和推力::sort_by_keys(),类似于。但是,我最多只能将
10
数组组合成一个元组,即s.t。我需要再次复制键向量。您将如何处理此任务?

如果您可以操作指向
device\u vector
的指针,那么您实际上只需要分配一个额外的数组:

thrust::device_vector<int>  indices(N); 
thrust::sequence(indices.begin(),indices.end());
thrust::sort_by_key(keys.begin(),keys.end(),indices.begin());

thrust::device_vector<int> temp(N);
thrust::device_vector<int> *sorted = &temp;
thrust::device_vector<int> *pa_01 = &a_01;
thrust::device_vector<int> *pa_02 = &a_02;
...
thrust::device_vector<int> *pa_20 = &a_20;

thrust::gather(indices.begin(), indices.end(), *pa_01, *sorted);
pa_01 = sorted; sorted = &a_01;
thrust::gather(indices.begin(), indices.end(), *pa_02, *sorted);
pa_02 = sorted; sorted = &a_02;
...
thrust::gather(indices.begin(), indices.end(), *pa_20, *sorted);
pa_20 = sorted; sorted = &a_20;
推力::装置的矢量指数(N);
序列(index.begin(),index.end());
推力::按键排序(keys.begin()、keys.end()、index.begin());
推力:装置的矢量温度(N);
推力::设备_向量*排序=&temp;
推力::装置_矢量*pa_01=&a_01;
推力:装置矢量*pa_02=&a_02;
...
推力:装置矢量*pa\U 20=&a\U 20;
推力::聚集(index.begin()、index.end()、*pa_01、*sorted);
pa_01=已排序;排序=&a_01;
推力::聚集(index.begin()、index.end()、*pa_02、*sorted);
pa_02=已排序;排序=&a_02;
...
推力::聚集(index.begin()、index.end()、*pa_20、*sorted);
pa_20=已排序;排序=&a_20;

或者类似的事情无论如何都应该管用。您需要修复它,以便临时设备向量在超出范围时不会自动解除分配--我建议使用cudaMalloc分配CUDA设备指针,然后使用设备ptr包装它们,而不是使用自动设备向量。

我认为对多个数组进行排序的经典方法是所谓的背对背方法使用两次
struch::stable_sort_by_key
。您需要创建一个键向量,以便同一数组中的元素具有相同的键。例如:

Elements: 10.5 4.3 -2.3 0. 55. 24. 66.
Keys:      0    0    0  1   1   1   1
在本例中,我们有两个数组,第一个带有
3
元素,第二个带有
4
元素

您首先需要调用
stress::stable\u sort\u by\u key
,使矩阵值与键类似

thrust::stable_sort_by_key(d_matrix.begin(),
                           d_matrix.end(),
                           d_keys.begin(),
                           thrust::less<float>());
这意味着数组元素是有序的,而键不是有序的。然后,您需要一秒钟的时间来调用
推力::稳定\u按\u键排序

thrust::stable_sort_by_key(d_keys.begin(),
                           d_keys.end(),
                           d_matrix.begin(),
                           thrust::less<int>());
这是最终想要的结果

下面是考虑以下问题的完整工作示例:分别对矩阵的每一行进行排序。这是一种特殊情况,其中所有数组都具有相同的长度,但该方法适用于可能具有不同长度的数组

#include <cublas_v2.h>

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/generate.h>
#include <thrust/sort.h>
#include <thrust/functional.h>
#include <thrust/random.h>
#include <thrust/sequence.h>

#include <stdio.h>
#include <iostream>

#include "Utilities.cuh"

/**************************************************************/
/* CONVERT LINEAR INDEX TO ROW INDEX - NEEDED FOR APPROACH #1 */
/**************************************************************/
template <typename T>
struct linear_index_to_row_index : public thrust::unary_function<T,T> {

    T Ncols; // --- Number of columns

    __host__ __device__ linear_index_to_row_index(T Ncols) : Ncols(Ncols) {}

    __host__ __device__ T operator()(T i) { return i / Ncols; }
};

/********/
/* MAIN */
/********/
int main()
{
    const int Nrows = 5;     // --- Number of rows
    const int Ncols = 8;     // --- Number of columns

    // --- Random uniform integer distribution between 10 and 99
    thrust::default_random_engine rng;
    thrust::uniform_int_distribution<int> dist(10, 99);

    // --- Matrix allocation and initialization
    thrust::device_vector<float> d_matrix(Nrows * Ncols);
    for (size_t i = 0; i < d_matrix.size(); i++) d_matrix[i] = (float)dist(rng);

    // --- Print result
    printf("Original matrix\n");
    for(int i = 0; i < Nrows; i++) {
        std::cout << "[ ";
        for(int j = 0; j < Ncols; j++)
            std::cout << d_matrix[i * Ncols + j] << " ";
        std::cout << "]\n";
    }

    /*************************/
    /* BACK-TO-BACK APPROACH */
    /*************************/
    thrust::device_vector<float> d_keys(Nrows * Ncols);

    // --- Generate row indices
    thrust::transform(thrust::make_counting_iterator(0),
                      thrust::make_counting_iterator(Nrows*Ncols),
                      thrust::make_constant_iterator(Ncols),
                      d_keys.begin(),
                      thrust::divides<int>());

    // --- Back-to-back approach
    thrust::stable_sort_by_key(d_matrix.begin(),
                               d_matrix.end(),
                               d_keys.begin(),
                               thrust::less<float>());

    thrust::stable_sort_by_key(d_keys.begin(),
                               d_keys.end(),
                               d_matrix.begin(),
                               thrust::less<int>());

    // --- Print result
    printf("\n\nSorted matrix\n");
    for(int i = 0; i < Nrows; i++) {
        std::cout << "[ ";
        for(int j = 0; j < Ncols; j++)
            std::cout << d_matrix[i * Ncols + j] << " ";
        std::cout << "]\n";
    }

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括“Utilities.cuh”
/**************************************************************/
/*将线性索引转换为行索引-方法#1所需*/
/**************************************************************/
模板
结构线性索引到行索引:公共推力::一元函数{
T Ncols;//--列数
__主机设备线性索引到行索引(T Ncols):Ncols(Ncols){
__主机设备操作符()(ti){return i/Ncols;}
};
/********/
/*主要*/
/********/
int main()
{
常量int Nrows=5;//--行数
常量int Ncols=8;//--列数
//---10到99之间的随机均匀整数分布
推力:默认随机发动机转速;
推力:均匀分布区(10,99);
//---矩阵分配和初始化
推力:设备矢量d矩阵(Nrows*Ncols);
对于(size_t i=0;istd::我不能确定我是否正确理解了你的解决方案(出了什么问题?你需要临时向量做什么?为什么在pa_01排序后将排序设置为a_01?)。但是,从我能理解的角度来看,我的想法是只使用一个附加向量,并在每次排序后将其内容复制回来。这当然比我的尝试要好得多(不知道我在想什么,漫长的一天),但仍然需要在每次排序后将完整的临时数组复制回来,这相当昂贵…有一个输入错误,已更正。这些分配是指针分配,而不是副本。因此没有昂贵的副本。由于您指出的原因,您至少需要一个额外的数组--
推力::聚集
是在不适当的位置执行的,而不是在pl中执行的但是在写入temp向量后,可以将其分配给pa_01,然后将第一次聚集的输入用作下一次聚集的输出缓冲区,以此类推。
thrust::stable_sort_by_key(d_keys.begin(),
                           d_keys.end(),
                           d_matrix.begin(),
                           thrust::less<int>());
Elements: -2.3 4.3 10.5 0 24. 55. 66.
Keys:       0   0   0   1  1   1   1
#include <cublas_v2.h>

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/generate.h>
#include <thrust/sort.h>
#include <thrust/functional.h>
#include <thrust/random.h>
#include <thrust/sequence.h>

#include <stdio.h>
#include <iostream>

#include "Utilities.cuh"

/**************************************************************/
/* CONVERT LINEAR INDEX TO ROW INDEX - NEEDED FOR APPROACH #1 */
/**************************************************************/
template <typename T>
struct linear_index_to_row_index : public thrust::unary_function<T,T> {

    T Ncols; // --- Number of columns

    __host__ __device__ linear_index_to_row_index(T Ncols) : Ncols(Ncols) {}

    __host__ __device__ T operator()(T i) { return i / Ncols; }
};

/********/
/* MAIN */
/********/
int main()
{
    const int Nrows = 5;     // --- Number of rows
    const int Ncols = 8;     // --- Number of columns

    // --- Random uniform integer distribution between 10 and 99
    thrust::default_random_engine rng;
    thrust::uniform_int_distribution<int> dist(10, 99);

    // --- Matrix allocation and initialization
    thrust::device_vector<float> d_matrix(Nrows * Ncols);
    for (size_t i = 0; i < d_matrix.size(); i++) d_matrix[i] = (float)dist(rng);

    // --- Print result
    printf("Original matrix\n");
    for(int i = 0; i < Nrows; i++) {
        std::cout << "[ ";
        for(int j = 0; j < Ncols; j++)
            std::cout << d_matrix[i * Ncols + j] << " ";
        std::cout << "]\n";
    }

    /*************************/
    /* BACK-TO-BACK APPROACH */
    /*************************/
    thrust::device_vector<float> d_keys(Nrows * Ncols);

    // --- Generate row indices
    thrust::transform(thrust::make_counting_iterator(0),
                      thrust::make_counting_iterator(Nrows*Ncols),
                      thrust::make_constant_iterator(Ncols),
                      d_keys.begin(),
                      thrust::divides<int>());

    // --- Back-to-back approach
    thrust::stable_sort_by_key(d_matrix.begin(),
                               d_matrix.end(),
                               d_keys.begin(),
                               thrust::less<float>());

    thrust::stable_sort_by_key(d_keys.begin(),
                               d_keys.end(),
                               d_matrix.begin(),
                               thrust::less<int>());

    // --- Print result
    printf("\n\nSorted matrix\n");
    for(int i = 0; i < Nrows; i++) {
        std::cout << "[ ";
        for(int j = 0; j < Ncols; j++)
            std::cout << d_matrix[i * Ncols + j] << " ";
        std::cout << "]\n";
    }

    return 0;
}