То, о чем вы просите, является сегментированным сокращением. Это можно сделать с помощью thrust::reduce_by_key
В дополнение к вашему вектору данных длины N * K нам понадобится «ключевой» вектор, который определяет каждый сегмент - сегменты не должны быть одного размера, если ключевой вектор различает сегменты так:
data: 1 3 2 3 1 4 2 3 2 1 4 2 ...
keys: 0 0 0 1 1 1 0 0 0 3 3 3 ...
seg: 0 0 0 1 1 1 2 2 2 3 3 3 ...
ключи очертить новый сегмент в любое время ключевые изменения последовательности (заметим, что у меня есть два отдельных сегмента в приведенном выше примере, которые очерчены, используя тот же ключ - тяги не группируйте такие сегменты вместе, но обрабатывает их отдельно, потому что есть одно или несколько промежуточных значений ключа, которые различны). У вас на самом деле нет этих данных, но для скорости и эффективности, так как ваши сегменты имеют одинаковую длину, мы можем произвести необходимую последовательность клавиш «на лету», используя комбинацию тяги fancy iterators.
Причудливые итераторы будет сочетать:
- производить линейную последовательность 0 1 2 3 ... (через counting_iterator)
- делят каждый член линейной последовательности по K, длины сегмента (через transform_iterator). Я использую thrust placeholder methodology, поэтому мне не нужно писать функтор для итератора преобразования.
Это будет производить необходимую последовательность сегментных ключей.
Вот обработанный пример:
$ cat t1282.cu
#include <thrust/reduce.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/copy.h>
#include <thrust/execution_policy.h>
#include <iostream>
const int N = 1000; // sequences
const int K = 100; // length of sequence
typedef int mytype;
using namespace thrust::placeholders;
int main(){
thrust::device_vector<mytype> data(N*K, 1);
thrust::device_vector<mytype> sums(N);
thrust::reduce_by_key(thrust::device, thrust::make_transform_iterator(thrust::counting_iterator<int>(0), _1/K), thrust::make_transform_iterator(thrust::counting_iterator<int>(N*K), _1/K), data.begin(), thrust::discard_iterator<int>(), sums.begin());
// just display the first 10 results
thrust::copy_n(sums.begin(), 10, std::ostream_iterator<mytype>(std::cout, ","));
std::cout << std::endl;
}
$ nvcc -arch=sm_35 -o t1282 t1282.cu
$ ./t1282
100,100,100,100,100,100,100,100,100,100,
$
Спасибо, г-н Роберт, для отработанного примера. У меня вопрос только: он может быть реализован с использованием чистого CUDA? основанный на знаниях, что я имею прямо сейчас, я буду использовать вложенные ядра, это хорошая идея? или существует другой оптимальный способ. @Robert Crovella – alae
Конечно, его можно реализовать с использованием чистого CUDA .. Thrust использует чистый CUDA при работе на GPU, а Thrust - с открытым исходным кодом. Я не знаю, является ли вложенное ядро хорошей идеей, так как я не пытался реализовать чистую CUDA. –
Есть ли у вас какие-либо идеи о том, как это будет реализовано? Также Im думает запустить 1000 ядер в одно и то же время, каждый из которых вычисляет сокращение для последовательности 100. @Robert Crovella. Также мне интересно, знаете ли вы некоторые ссылки, которые могут помочь мне быть более комфортными с CUDA и параллелизмом. На самом деле параллелизм - это не мое поле. Заранее спасибо г-ну Роберту – alae