VexCL: подсчитать количество значений в векторе выше минимума
Используя VexCL в C++, я пытаюсь подсчитать все значения в векторе выше определенного минимума, и я хотел бы выполнить этот подсчет на устройстве. Редукторы по умолчанию предоставляют только методы для MIN, MAX и SUM, и примеры не очень ясно показывают, как выполнить такую операцию. Этот код медленный, так как он, вероятно, выполняется на хосте, а не на устройстве:
int amount = 0;
int minimum = 5;
for (vex::vector<int>::iterator i = vector.begin(); i != vector.end(); ++i)
{
if (*i >= minimum)
{
amount++;
}
}
Вектор, который я использую, будет состоять из большого количества значений, скажем, миллионов и в основном нулей. Помимо количества значений, которые выше минимума, я также хотел бы получить список векторных идентификаторов, который содержит эти значения. Это возможно?
2 ответа
Если вам нужно только посчитать элементы выше минимума, это будет так же просто, как
vex::Reductor<int, vex::SUM> sum(ctx);
int amount = sum( vec >= minimum );
vec >= minimum
выражение приводит к последовательности единиц и нулей, и sum
затем считает
Теперь, так как вам также нужно получить позиции элементов выше минимума, все становится немного сложнее:
#include <iostream>
#include <vexcl/vexcl.hpp>
int main() {
vex::Context ctx(vex::Filter::Env && vex::Filter::Count(1));
// Input vector
vex::vector<int> vec(ctx, {1, 3, 5, 2, 6, 8, 0, 2, 4, 7});
int n = vec.size();
int minimum = 5;
// Put result of (vec >= minimum) into key, and element indices into pos:
vex::vector<int> key(ctx, n);
vex::vector<int> pos(ctx, n);
key = (vec >= minimum);
pos = vex::element_index();
// Get number of interesting elements in vec.
vex::Reductor<int, vex::SUM> sum(ctx);
int amount = sum(key);
// Sort pos by key in descending order.
vex::sort_by_key(key, pos, vex::greater<int>());
// First 'amount' of elements in pos now hold indices of interesting
// elements. Lets use slicer to extract them:
vex::vector<int> indices(ctx, amount);
vex::slicer<1> slice(vex::extents[n]);
indices = slice[vex::range(0, amount)](pos);
std::cout << "indices: " << indices << std::endl;
}
Это дает следующий вывод:
indices: {
0: 2 4 5 9
}
@ddemidov
Спасибо за вашу помощь, это работает. Однако это намного медленнее, чем мой оригинальный код, который копирует вектор устройства на хост и сортирует его с помощью Boost. Ниже приведен пример кода с некоторыми временами:
#include <iostream>
#include <cstdio>
#include <vexcl/vexcl.hpp>
#include <vector>
#include <boost/range/algorithm.hpp>
int main()
{
clock_t start, end;
// initialize vector with random numbers
std::vector<int> hostVector(1000000);
for (int i = 0; i < hostVector.size(); ++i)
{
hostVector[i] = rand() % 20 + 1;
}
// copy to device
vex::Context cpu(vex::Filter::Type(CL_DEVICE_TYPE_CPU) && vex::Filter::Any);
vex::Context gpu(vex::Filter::Type(CL_DEVICE_TYPE_GPU) && vex::Filter::Any);
vex::vector<int> vectorCPU(cpu, 1000000);
vex::vector<int> vectorGPU(gpu, 1000000);
copy(hostVector, vectorCPU);
copy(hostVector, vectorGPU);
// sort results on CPU
start = clock();
boost::sort(hostVector);
end = clock();
cout << "C++: " << (end - start) / (CLOCKS_PER_SEC / 1000) << " ms" << endl;
// sort results on OpenCL
start = clock();
vex::sort(vectorCPU, vex::greater<int>());
end = clock();
cout << "vexcl CPU: " << (end - start) / (CLOCKS_PER_SEC / 1000) << " ms" << endl;
start = clock();
vex::sort(vectorGPU, vex::greater<int>());
end = clock();
cout << "vexcl GPU: " << (end - start) / (CLOCKS_PER_SEC / 1000) << " ms" << endl;
return 0;
}
что приводит к:
C++: 17 ms
vexcl CPU: 737 ms
vexcl GPU: 1670 ms
с использованием процессора i7 3770 и (медленной) видеокарты HD4650. Как я уже читал, OpenCL должен уметь выполнять быструю сортировку по большим вершинам. Есть ли у вас какие-либо советы, как выполнить быструю сортировку с использованием OpenCL и vexcl?