Я использую C++ и cuda/thrust для выполнения вычисления на графическом процессоре, который для меня является новым полем. К сожалению, мой код (MCVE ниже) не очень эффективен, поэтому я хотел бы знать, как его оптимизировать. Код выполняет следующие операции:Cuda Thrust - Как оптимизировать код с помощью sort_by_key, merge_by_key и reduce_by_key
Существует два ключевых вектора и два вектора значений. Ключевые векторы содержат в основном i и j верхней треугольной матрицы (в этом примере: размер 4x4).
key1 {0, 0, 0, 1, 1, 2} value1: {0.5, 0.5, 0.5, -1.0, -1.0, 2.0}
key2 {1, 2, 3, 2, 3, 3} value2: {-1, 2.0, -3.5, 2.0, -3.5, -3.5}
Задача состоит в том, чтобы суммировать все значения, имеющие один и тот же ключ. Для этого я отсортировал второй вектор значений, используя sort_by_key. Результат:
key1 {0, 0, 0, 1, 1, 2} value1: {0.5, 0.5, 0.5, -1.0, -1.0, 2.0}
key2 {1, 2, 2, 3, 3, 3} value2: {-1.0, 2.0, 2.0, -3.5, -3.5, -3.5}
После этого я слился как вектор значений с помощью merge_by_key, что приводит к новому ключу и значению вектора с размером двойным, как большая, чем раньше.
key_merge {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3}
value_merge {0.5, 0.5, 0.5, -1.0, -1.0, -1.0, 2.0, 2.0, 2.0, -3.5, -3.5, -3.5}
Последний шаг - использовать reduce_by_key для суммирования по всем значениям с помощью того же ключа. Результат:
key {0, 1, 2, 3} value: {1.5, -3.0, 6.0, -10.5}
ниже код, который выполняет эти операции тихо, медленно, и я боюсь, что производительность для большего размера будет плохо. Как его можно оптимизировать? Возможно ли слияние sort_by_key, merge_by_key и reduce_by_key? Поскольку я знаю результирующий вектор ключа из sort_by_key заранее, можно ли преобразовать вектор значений «от старого к новому ключу»? Имеет ли смысл, объединить два вектора перед их уменьшением или же быстрее использовать reduce_by_key отдельно для каждой пары вектора ценности/ключа? Можно ли ускорить вычисление reduce_by_key, используя тот факт, что здесь известен номер различного значения ключа, а число равных ключей всегда одинаково?
#include <stdio.h>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/reduce.h>
#include <thrust/merge.h>
int main(){
int key_1[6] = {0, 0, 0, 1, 1, 2};
int key_2[6] = {1, 2, 3, 2, 3, 3};
thrust::device_vector<double> k1(key_1,key_1+6);
thrust::device_vector<double> k2(key_2,key_2+6);
double value_1[6] = {0.5, 0.5, 0.5, -1.0, -1.0, 2.0};
double value_2[6] = {-1, 2.0, -3.5, 2.0, -3.5, -3.5};
thrust::device_vector<double> v1(value_1,value_1+6);
thrust::device_vector<double> v2(value_2,value_2+6);
thrust::device_vector<double> mk(12);
thrust::device_vector<double> mv(12);
thrust::device_vector<double> rk(4);
thrust::device_vector<double> rv(4);
thrust::sort_by_key(k2.begin(), k2.end(), v2.begin());
thrust::merge_by_key(k1.begin(), k1.end(), k2.begin(), k2.end(),v1.begin(), v2.begin(), mk.begin(), mv.begin());
thrust::reduce_by_key(mk.begin(), mk.end(), mv.begin(), rk.begin(), rv.begin());
for (unsigned i=0; i<4; i++) {
double tmp1 = rk[i];
double tmp2 = rv[i];
printf("key value %f is related to %f\n", tmp1, tmp2);
}
return 0;
}
Результат:
key value 0.000000 is related to 1.500000
key value 1.000000 is related to -3.000000
key value 2.000000 is related to 6.000000
key value 3.000000 is related to -10.500000