CUDA Thrust: нахождение индекса первого элемента в векторе, удовлетворяющего предикату (например, нулю или отрицательному) [синтаксис Matlab min(find(x‹=0))]

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

for (int i = StartIndex; i <= ArrayLimitIndex; i++) 
{ 
    if (Array[i] <= 0) { DesiredIndex = i; break; } 
}

Я думаю, что самый простой способ сделать это на графическом процессоре — использовать функцию find_if в библиотеке Thrust.

Массив уже находится на графическом процессоре, и я пытаюсь найти индекс в этом массиве, используя Thrust как таковой:

struct less_than_or_eq_zero
{
__host__ __device__
bool operator() (double x)
{
    return x <= 0;
}
};

thrust::device_vector<double>::iterator iter;
thrust::device_ptr<double> dev_ptr_Col46 = thrust::device_pointer_cast(dev_Col46);
iter = thrust::find_if(thrust::device, dev_ptr_Col46, dev_ptr_Col46 + size,less_than_or_eq_zero());

Теперь я хотел бы использовать значение iter в качестве аргумента для моего следующего ядра:

newKernel<<<size, 1>>>(*dev_array, iter)

где определение newKernel имеет форму:

__global__ void newKernel(double *dev_array, iter)
{
     int x = blockIdx.x;
     if(x <= iter)
     {
         //process data here...
     }
}

Я знаю, что приведенный здесь код неверен, и у меня есть несколько вопросов относительно использования iter. Во-первых, iter это device_vector. Есть ли способ сделать iter только одним значением, а не вектором? Кроме того, когда я выполнил find_if, как я могу использовать значение iter в моем следующем вызове ядра?

Любая помощь в этом будет принята с благодарностью.

Спасибо


person user2736519    schedule 06.01.2014    source источник
comment
iter не является device_vector - это итератор, указывающий на device_vector. Вы можете использовать его непосредственно в newKernel.   -  person Jared Hoberock    schedule 06.01.2014
comment
В ПОРЯДКЕ. Спасибо. Есть ли способ создать этот итератор без использования device_vector? Я думаю, что мог бы получить лучшую производительность без использования device_vector.   -  person user2736519    schedule 06.01.2014
comment
@Jared Hoberock: Кроме того, как мне объявить iter в определении моего ядра? Как типа double?   -  person user2736519    schedule 06.01.2014
comment
Объявите его так же, как в своем коде: thrust::device_vector<double>::iterator iter   -  person Jared Hoberock    schedule 06.01.2014
comment
@JaredHoberock: я предполагаю, что OP означает ядро, а не код хоста. Я не думаю, что он или она понимает, что значение итератора не является индексом массива, это значение массива.   -  person talonmies    schedule 06.01.2014
comment
@talonmies: вы правы, я неправильно прочитал, что происходит в newKernel.   -  person Jared Hoberock    schedule 06.01.2014


Ответы (3)


Я обобщаю комментарии talonmies и Джареда Хоберока выше, а также ответ Себастьяна Дресслера в полностью компилируемом и исполняемом примере. Код вычисляет с помощью CUDA Thrust индекс первого элемента вектора, удовлетворяющего предикату (в данном случае x<=0.), надеюсь, он будет полезен будущим читателям.

#include <thrust/device_vector.h>
#include <stdio.h>

struct less_than_or_eq_zero
{
    __host__ __device__ bool operator() (double x) { return x <= 0.; }
};

int main(void)
{
    int N = 6;

    thrust::device_vector<float> D(N);

    D[0] = 3.;
    D[1] = 2.3;
    D[2] = -1.3;
    D[3] = 0.;
    D[4] = 3.;
    D[5] = -44.;

    thrust::device_vector<float>::iterator iter1    = D.begin();
    thrust::device_vector<float>::iterator iter2    = thrust::find_if(D.begin(), D.begin() + N, less_than_or_eq_zero());
    int d = thrust::distance(iter1, iter2);

    printf("Index = %i\n",d);

    getchar();

    return 0;
}
person Vitality    schedule 06.04.2014

Поскольку вы используете не device_vector в своем ядре, а необработанный массив, вы должны передать ему индекс, а не итератор. Вы можете получить индекс, используя thrust::distance для вычисления расстояния между dev_ptr_Col46 и iter.

Вы также можете прочитать документацию по thrust iterators, где distance описан.

person Sebastian Dressler    schedule 06.01.2014
comment
Благодарю за ваш ответ. Я смог заставить это работать с обычным device_vector, но не смог, когда я передал device_ptr. Когда я использую следующее выражение int index = thrust::distance(dev_ptr_Col46, iter);, компилятор сообщает мне, что ни один экземпляр шаблона функции distance не соответствует списку аргументов. Можно ли использовать этот device_ptr в качестве аргумента функции thrust::distance? - person user2736519; 07.01.2014
comment
Вы должны измерить расстояния между итераторами, т.е. использовать член begin() вашего device_vector. Чтобы использовать device_vector в пользовательском ядре, вы можете получить из него необработанный указатель. - person Sebastian Dressler; 08.01.2014

Попробуй это:

 thrust::device_ptr<double> val_ptr = thrust::find_if(dev_ptr_Col46, dev_ptr_Col46 + size,less_than_or_eq_zero());
 double * val = thrust::raw_pointer_cast(val_ptr);
 newKernel<<<size, 1>>>(dev_array, val)

Ваше ядро ​​должно иметь подпись

 __global__ void newKernel(double * dev_array, double * val)
person ngimel    schedule 07.01.2014
comment
посмотрите код ядра в исходном вопросе. как передача значения из массива в ядро ​​​​решает проблему? весь вопрос в том, как получить из итератора индекс, а не значение. - person talonmies; 08.01.2014
comment
@talonmies Хорошо, я неправильно прочитал ядро. Если ему нужно получить индекс, он может сделать int iter = val_ptr - dev_ptr_Col46. - person ngimel; 08.01.2014