Русский
Русский
English
Статистика
Реклама

Из песочницы Boost.Compute или параллельные вычисления на GPUCPU. Часть 1

Привет, Хабр!

По моим меркам я уже достаточно давно пишу код на C++, но до этого времени ещё не сталкивался с задачами, связанными с параллельными вычислениями. Я не увидел ни одной статьи о библиотеке Boost.Compute, поэтому эта статья будет именно о ней.

Содержание


  • Что такое boost.compute
  • Проблемы с подключением boost.compute к проекту
  • Введение в boost.compute
  • Основные классы compute
  • Приступаем к работе
  • Заключение

Что такое boost.compute


Данная c++ библиотека предоставляет простой высокоуровневый интерфейс для взаимодействия с многоядерными CPU и GPU вычислительными устройствами. Эта библиотека была впервые добавлена в boost в версии 1.61.0 и поддерживается до сих пор.

Проблемы с подключением boost.compute к проекту


И так, я столкнулся с некоторыми проблемами при использовании этой библиотеки. Одной из них было то, что без OpenCL библиотека попросту не работает. Компилятор выдаёт следующую ошибку:

image

После подключения всё должно скомпилироваться корректно.

На счёт библиотеки boost, её можно скачать и подключить к проекту Visual Studio с помощью менеджера пакетов NuGet.

Введение в boost.compute


После установки всех необходимых компонентов можно рассмотреть простые куски кода. Для корректной работы достаточно включить модуль compute таким образом:

#include <boost/compute.hpp>using namespace boost;

Стоит подметить, что обычные контейнеры из stl не подойдут для использования в алгоритмах пространства имён compute. Вместо них существуют специально созданные контейнеры которые не конфликтуют с стандартными. Пример кода:

std::vector<float> std_vector(10);compute::vector<float> compute_vector(std_vector.begin(), std_vector.end(), queue); // пока не обращайте внимания на третий аргумент, к нему мы вернёмся позже.

Для конвертации обратно в std::vector можно использовать функцию copy():

compute::copy(compute_vector.begin(), compute_vector.end(), std_vector.begin(), queue);

Основные классы compute


Библиотека насчитывает в себе три вспомогательных класса, которых для начала хватит для вычислений на видеокарте и/или процессоре:

  • compute::device (будет определять с каким именно устройством мы будем работать)
  • compute::context (объект данного класса хранит в себе ресурсы OpenCL, включая буферы памяти и другие объекты)
  • compute::command_queue (предоставляет интерфейс для взаимодействия с вычислительным устройством)

Объявить это всё дело можно таким образом:

auto device = compute::system::default_device(); // устройство по умолчанию это видеокартаauto context = compute::context::context(device); // обычное объявление переменнойauto queue = compute::command_queue(context, device); // аналогично к предыдущему

Даже только с помощью первой строчки кода выше можно убедится что всё работает как нужно, запустив следующий код:

std::cout << device.name() << std::endl; 

Таким образом мы получили имя устройства, на котором будем производить вычисления. Результат (у вас может быть что-то другое):

image

Приступаем к работе


Рассмотрим функции trasform() и reduce() на примере:

std::vector<float> host_vec = {1, 4, 9};compute::vector<float> com_vec(host_vec.begin(), host_vec.end(), queue);// передавая в аргументы начальный и конечный указатель предыдущего вектора можно не//использовать функцию copy()compute::vector<float> buff_result(host_vec.size(), context);transform(com_vec.begin(), com_vec.end(), buff_result.begin(), compute::sqrt<float>(), queue);std::vector<float> transform_result(host_vec.size());compute::copy(buff_result.begin(), buff_result.end(), transform_result.begin(), queue);cout << "Transforming result: ";for (size_t i = 0; i < transform_result.size(); i++){cout << transform_result[i] << " ";}cout << endl;float reduce_result;compute::reduce(com_vec.begin(), com_vec.end(), &reduce_result, compute::plus<float>(),queue);cout << "Reducing result: " << reduce_result << endl;

При запуске приведённого выше кода, вы должны увидеть такой результат:

image

Я остановился именно на этих двух методах потому, что они хорошо показывают примитивную работу с параллельными вычислениями без всего лишнего.

И так, функция transform() используется для того, чтобы изменить массив данных,(или два массива, если мы их передаём) применяя одну функцию ко всем значениям.

transform(com_vec.begin(),    com_vec.end(),    buff_result.begin(),    compute::sqrt<float>(),    queue);

Перейдём к разбору аргументов, первыми двумя аргументами мы передаём вектор входных данных, третьим аргументом передаём указатель на начало вектора, в который мы запишем результат, следующим аргументом мы указываем, что нам нужно сделать. В примере выше мы используем одну из стандартных функций обработки векторов, а именно извлекаем квадратный корень. Конечно, можно написать и кастомную функцию, boost предоставляет нам целых два способа, но это уже материал для следующей части(если такая вообще будет). Ну и последним аргументом мы передаём объект класса compute::command_queue, про который я рассказывал выше.

Следующая функция reduce(), тут все немного интереснее. Этот метод возвращает результат применения четвёртого аргумента ко всем элементам вектора.

compute::reduce(com_vec.begin(),    com_vec.end(),    &reduce_result,    compute::plus<float>(),   queue);

Сейчас поясню на примере, код выше можно сравнить с таким уравнением:
$inline$1 + 4 + 9$inline$
В нашем случае мы получаем суму всех элементов массива.

Заключение


Ну вот и всё, думаю этого хватит для того, чтоб проводить простые операции над большими данными. Теперь вы можете использовать примитивный функционал библиотеки boost.compute, а также можете предотвратить некоторые ошибки при работе с этой библиотекой.

Буду рад позитивному фидбэку. Спасибо за уделённое время.

Всем удачи!
Источник: habr.com
К списку статей
Опубликовано: 15.08.2020 18:06:03
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

C++

C++17

Boost::compute

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru