Вот возможный метод с использованием тяги . Это примерно соответствует последовательности, изложенной в комментариях. Основная идея c состоит в том, чтобы сгладить все и уменьшить элементы, которые добавляют к одному и тому же векторному элементу вместе:
- умножьте каждый элемент
vector
на его соответствующий alpha
. - создание индексации, позволяющей сортировать элементы
vector
для объединения элементов индекса сходства - sort_by_key, для объединения элементов индекса сходства
- redu_by_key для объединения как -index элементы вместе
- добавляют уменьшенные значения к соответствующим элементам в
matrix
В следующем примере показан вышеупомянутый метод и сравнивается его с точки зрения синхронизации с l oop -сакшпи-метод. На моем Tesla V100, CUDA 10.1, «параллельный» метод примерно в 3 раза быстрее, чем метод l oop -saxpy, для BATCH_SIZE
из 1000 и index
, ограниченный относительно небольшой площадью:
$ cat t1714.cu
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/sort.h>
#include <thrust/reduce.h>
#include <thrust/fill.h>
#include <thrust/generate.h>
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/copy.h>
#include <cstdlib>
#include <time.h>
#include <sys/time.h>
#define USECPSEC 1000000ULL
unsigned long long dtime_usec(unsigned long long start){
timeval tv;
gettimeofday(&tv, 0);
return ((tv.tv_sec*USECPSEC)+tv.tv_usec)-start;
}
typedef float dt;
const int BATCH_SIZE = 1000;
const int ds = 3000;
const int RANGE = 10;
struct my_gen
{
int range;
my_gen(int r) : range(r) {};
__host__
int operator ()(){
return rand()%range;
}
};
//struct my_seq
using namespace thrust::placeholders;
int main(){
// data setup
thrust::device_vector<dt> matrix(ds*ds);
thrust::device_vector<dt> result1 = matrix;
thrust::device_vector<dt> vector(ds*BATCH_SIZE);
thrust::host_vector<int> h_index(BATCH_SIZE);
thrust::device_vector<dt> alpha(BATCH_SIZE);
thrust::generate(h_index.begin(), h_index.end(), my_gen(RANGE));
thrust::fill(vector.begin(), vector.end(), 1.0);
thrust::fill(alpha.begin(), alpha.end(), 1.0);
// first, time serial op
thrust::host_vector<dt> h_alpha = alpha;
unsigned long long my_dt = dtime_usec(0);
for (int i = 0; i < BATCH_SIZE; i++)
thrust::transform(vector.begin()+(i*ds), vector.begin()+((i+1)*ds), result1.begin()+(h_index[i]*ds), result1.begin()+(h_index[i]*ds), _1*h_alpha[i]+_2);
cudaDeviceSynchronize();
my_dt = dtime_usec(my_dt);
std::cout << "serial time: " << my_dt/(float)USECPSEC << " seconds" << std::endl;
// now time parallel op
thrust::device_vector<int> vi(ds*BATCH_SIZE);
thrust::device_vector<int> index = h_index;
thrust::device_vector<int> keys(ds*BATCH_SIZE);
thrust::device_vector<dt> vr(ds*BATCH_SIZE);
auto my_ti = thrust::make_transform_iterator(thrust::counting_iterator<int>(0), _1%ds);
my_dt = dtime_usec(0);
thrust::transform(vector.begin(), vector.end(), thrust::make_permutation_iterator(alpha.begin(), thrust::make_transform_iterator(thrust::counting_iterator<int>(0), _1/ds)), vector.begin(), _1*_2); // multiply by alpha
thrust::transform(my_ti, my_ti+(ds*BATCH_SIZE), thrust::make_transform_iterator(thrust::make_permutation_iterator(index.begin(), thrust::make_transform_iterator(thrust::counting_iterator<int>(0), _1/ds)), _1*ds), vi.begin(), _1 + _2);
thrust::sort_by_key(vi.begin(), vi.end(), vector.begin()); // collect like indices
int key_size = (thrust::reduce_by_key(vi.begin(), vi.end(), vector.begin(), keys.begin(), vr.begin())).first - keys.begin(); // add like indices together
auto my_pi = thrust::make_permutation_iterator(matrix.begin(), keys.begin());
thrust::transform(vr.begin(), vr.begin()+key_size, my_pi, my_pi, _1 + _2); // perform final add
cudaDeviceSynchronize();
my_dt = dtime_usec(my_dt);
std::cout << "parallel time: " << my_dt/(float)USECPSEC << " seconds" << std::endl;
thrust::host_vector<dt> h_matrix = matrix;
thrust::host_vector<dt> h_result1 = result1;
for (int i = 0; i < ds*ds; i++) if (h_matrix[i] != h_result1[i]) {std::cout << " mismatch at " << i << " was: " << h_matrix[i] << " should be: " << h_result1[i] << std::endl; return 0;}
}
$ nvcc -o t1714 t1714.cu -std=c++11
$ ./t1714
serial time: 0.018015 seconds
parallel time: 0.005337 seconds
$
Я не претендую на правильность этого кода или любого другого кода, который я публикую. Любой, кто использует любой код, который я публикую, делает это на свой страх и риск. Я просто утверждаю, что я попытался ответить на вопросы в первоначальной публикации и дать некоторые объяснения их. Я не утверждаю, что мой код не имеет дефектов или что он подходит для какой-либо конкретной цели. Используйте его (или нет) на свой страх и риск.