Усилитель C++: асинхронная передача данных и хранение данных на ускорителе
У меня есть часто вызываемая функция, которая отлично подходит для параллельной обработки, поэтому я для начала исследовал C++ amp. Функция принимает три входа:
- вектор с плавающей точкой, который является входными данными
- вектор постоянных коэффициентов, который остается неизменным на протяжении вызовов
- выходной вектор, в который записывается результат.
Теперь очевидно, что #1 должен копироваться в GPU каждый вызов. Для этого я использую управляемый стеком константный массив<>, который отлично работает.
Для #2 оптимальным вариантом было бы как-то сохранить вектор в памяти GPU, поскольку он постоянен. Возможно ли это с помощью усилителя? Или мне нужно копировать его каждый раз, когда я вызываю параллель_for_each, похожий на #1?
Для #3, возможно ли выделить буфер на GPU и скопировать его обратно, вместо создания пустого буфера в стеке процессора, скопировать его и скопировать обратно после записи результатов в него?
И последнее, так как вызов параллелизма в природе является асинхронным - и будет синхронизироваться либо деструктором #3, либо array_view::synchronize(), можно ли оставить текущую функцию (и пространство стеков), тем временем сделайте другие вещи GPU обрабатывает, а затем "синхронизируется" на более позднем этапе?
Это потребовало бы динамически распределенного array_view, чтобы избежать синхронизации () при разрушении, но функция, похоже, не будет компилироваться, когда я использую указатели вместо объектов, управляемых стеком:
error C3581: unsupported type in amp restricted code
pointer or reference is not allowed as pointed to type, array element type or data member type (except reference to concurrency::array/texture)
Кроме того, для тех, кто имеет опыт в других архитектурных проектах, таких как OpenCL, мне повезет больше?
1 ответ
1 - да. Если вы передаете const array_view
в качестве ввода он не будет скопирован обратно в память хоста.
std::vector<float> cpu_data(20000000, 0.0f);
array_view<const float, 1> cpu_data_view(cpu_data.size(), cpu_data);
2 - в зависимости от размера вашего массива коэффициентов вы можете сделать одну из нескольких вещей;
a - Храните его в локальном массиве внутри вашего parallel_for_each
лямбда. Это удобно, но потребляет (драгоценную) локальную память, поэтому является реалистичным, только если массив очень мал.
array<float, 1> gpu_data(400);
std::vector<float> cpu_data(gpu_data.extent.size(), 1.0f);
copy(cpu_data.begin(), gpu_data);
В этом случае gpu_data будет доступен для всего кода AMP при условии, что лямбда-код перехватывает его.
б - Создать array
и явно скопируйте ваши постоянные данные в него перед выполнением любого кода AMP.
c - рассмотреть возможность загрузки в tile_static
памяти, если к нему обращается много раз каждый поток.
3 - Вы все еще можете использовать array_view
чтобы сохранить ваши выходные данные, но вызов discard_data
на нем до выполнения parallel_for_each
предотвратит ненужное копирование в память графического процессора.
std::vector<float> cpu_output_data(20000000, 0.0f);
array_view<float, 1> output_data_view(cpu_output_data.size(), cpu_output_data);
output_data_view.discard_data();
** Async - ** Да, это вполне возможно сделать. Вы можете комбинировать AMP с фьючерсами C++ и асинхронными операциями для одновременного выполнения другой работы на CPU (или другом GPU). Помните, что ЦП участвует в управлении расписанием работы на GPU и перемещении данных в него и из него. Таким образом, если вы перегружаете процессор, производительность графического процессора может снизиться.
WRT к вашей ошибке компилятора, трудно сказать, в чем проблема, не видя код. Это нормально делать следующее:
std::unique_ptr<concurrency::array_view<int, 2>> data_view;
Возможно, вы захотите взглянуть на примеры, описанные в книге C++ AMP. Они доступны на CodePlex и охватывают многие из этих сценариев.