CUB选择是否返回索引

时间:2014-03-18 10:09:05

标签: c++ cuda thrust cub

使用Thrust库时,我最近遇到了性能问题。这些来自在大型嵌套循环结构的基础上的推力分配内存。这显然是不需要的,使用预先分配的全局存储器板进行理想的执行。我想通过以下三种方式之一删除或改进有问题的代码:

  1. 实施自定义推力内存分配器
  2. 用CUB代码替换推力代码(使用预先分配的临时存储空间)
  3. 编写自定义内核以执行我想要的操作
  4. 虽然第三个选项是我的正常首选,但我想要执行的操作是copy_if / select_if类型操作,其中返回数据和索引。编写自定义内核可能会重新发明轮子,所以我更愿意选择其他两个选项之一。

    我一直听到很多关于CUB的事情,所以我认为这是一个在愤怒中使用它的理想机会。我想知道的是:

    如何使用返回的索引实现CUB select_if

    可以使用ArgIndexInputIterator和像这样的仿函数来完成吗?

    struct GreaterThan
    {
        int compare;
    
        __host__ __device__ __forceinline__
        GreaterThan(int compare) : compare(compare) {}
    
        __host__ __device__ __forceinline__
        bool operator()(const cub::ArgIndexInputIterator<int> &a) const {
            return (a.value > compare);
        }
    };
    

    代码正文中有以下内容:

    //d_in = device int array
    //d_temp_storage = some preallocated block
    
    
    int threshold_value;
    GreaterThan select_op(threshold_value);
    
    cub::ArgIndexInputIterator<int> input_itr(d_in);
    cub::ArgIndexInputIterator<int> output_itr(d_out); //????
    
    
    CubDebugExit(DeviceSelect::If(d_temp_storage, temp_storage_bytes, input_itr, output_itr, d_num_selected, num_items, select_op));
    

    这会尝试在引擎盖下进行任何内存分配吗?

    修改

    因此,关于Robert Crovella的评论,仿函数应该采用解除引用cub::ArgIndexInputIterator<int>的产品,该cub::ItemOffsetPair<int>应该是struct GreaterThan { int compare; __host__ __device__ __forceinline__ GreaterThan(int compare) : compare(compare) {} __host__ __device__ __forceinline__ bool operator()(const cub::ItemOffsetPair<int,int> &a) const { return (a.value > compare); } }; 现在制作仿函数:

    d_out

    并且在代码中,cub::ItemOffsetPair<int,int>应该是//d_in = device int array //d_temp_storage = some preallocated block cub::ItemOffsetPair<int,int> * d_out; //allocate d_out int threshold_value; GreaterThan select_op(threshold_value); cub::ArgIndexInputIterator<int,int> input_itr(d_in); CubDebugExit(DeviceSelect::If(d_temp_storage, temp_storage_bytes, input_itr, d_out, d_num_selected, num_items, select_op)); 的设备数组:

    {{1}}

2 个答案:

答案 0 :(得分:3)

  

使用Thrust库时,我最近遇到了性能问题。这些   来自在大型嵌套循环结构的基础上推力分配内存。这是   显然是不需要的,使用预先分配的全局内存板进行理想的执行。

Thrust允许您自定义在算法执行期间临时内存的分配方式。

请参阅custom_temporary_allocation example,了解如何为预先分配的平板创建缓存。

答案 1 :(得分:2)

经过一番摆弄和询问后,我能够得到一个简单的代码,就像你建议的那样:

$ cat t348.cu
#include <cub/cub.cuh>
#include <stdio.h>
#define DSIZE 6

struct GreaterThan
{

    __host__ __device__ __forceinline__
    bool operator()(const cub::ItemOffsetPair<int, ptrdiff_t> &a) const {
        return (a.value > DSIZE/2);
    }
};

int main(){

  int num_items = DSIZE;
  int *d_in;
  cub::ItemOffsetPair<int,ptrdiff_t> * d_out;
  int *d_num_selected;
  int *d_temp_storage = NULL;
  size_t temp_storage_bytes = 0;

  cudaMalloc((void **)&d_in, num_items*sizeof(int));
  cudaMalloc((void **)&d_num_selected, sizeof(int));
  cudaMalloc((void **)&d_out, num_items*sizeof(cub::ItemOffsetPair<int,ptrdiff_t>));

  int h_in[DSIZE] = {5, 4, 3, 2, 1, 0};
  cudaMemcpy(d_in, h_in, num_items*sizeof(int), cudaMemcpyHostToDevice);

  cub::ArgIndexInputIterator<int *> input_itr(d_in);


  cub::DeviceSelect::If(d_temp_storage, temp_storage_bytes, input_itr, d_out, d_num_selected, num_items, GreaterThan());

  cudaMalloc(&d_temp_storage, temp_storage_bytes);

  cub::DeviceSelect::If(d_temp_storage, temp_storage_bytes, input_itr, d_out, d_num_selected, num_items, GreaterThan());
  int h_num_selected = 0;
  cudaMemcpy(&h_num_selected, d_num_selected, sizeof(int), cudaMemcpyDeviceToHost);
  cub::ItemOffsetPair<int, ptrdiff_t> h_out[h_num_selected];
  cudaMemcpy(h_out, d_out, h_num_selected*sizeof(cub::ItemOffsetPair<int, ptrdiff_t>), cudaMemcpyDeviceToHost);
  for (int i =0 ; i < h_num_selected; i++)
    printf("index: %d, offset: %d, value: %d\n", i, h_out[i].offset, h_out[i].value);

  return 0;
}
$ nvcc -arch=sm_20 -o t348 t348.cu
$ ./t348
index: 0, offset: 0, value: 5
index: 1, offset: 1, value: 4
$

RHEL 6.2,cub v1.2.2,CUDA 5.5