CUB выберите, если с возвращенными индексами

Я недавно столкнулся с проблемами производительности при использовании Thrust библиотека. Это происходит из-за выделения памяти в основании большой структуры вложенных циклов. Это, очевидно, нежелательно, при идеальном выполнении с использованием предварительно выделенной плиты глобальной памяти. Я хотел бы удалить или улучшить нарушающий код одним из трех способов:

  1. Реализация собственного распределителя памяти
  2. Замена кода тяги на код CUB (с предварительно выделенным временным хранилищем)
  3. Напишите собственное ядро, чтобы делать то, что я хочу

Хотя третий вариант был бы моим обычным предпочтительным выбором, операция, которую я хочу выполнить, 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 blockint 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));

Будет ли это попытаться сделать какое-либо распределение памяти под капотом?

РЕДАКТИРОВАТЬ:

Таким образом, исходя из комментария Роберта Кровеллы, функтор должен взять продукт разыменования 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

Решение

После некоторой возни и раздумий, я смог получить простой код в соответствии с тем, что вы предлагаете работать:

$ 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

2

Другие решения

Недавно я столкнулся с проблемами производительности при использовании библиотеки Thrust. Эти
исходить из тяги, выделяющей память в основании большой структуры вложенного цикла. Это
очевидно нежелательный, с идеальным исполнением с использованием предварительно выделенной плиты глобальной памяти.

Thrust позволяет настроить распределение временной памяти при выполнении алгоритма.

Увидеть Пример нестандартной_распределения чтобы увидеть, как создать кеш для предварительно выделенной плиты.

3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector