У меня есть часто вызываемая функция, которая отлично подходит для параллельной обработки, поэтому я для начала исследовал усилитель C ++. Функция принимает три входа:
Теперь очевидно, что # 1 должен копироваться в GPU при каждом вызове. Для этого я использую управляемый стеком константный массив<>, который отлично работает.
Для # 2 оптимальным вариантом было бы как-то сохранить вектор в памяти графического процессора, поскольку он постоянен. Возможно ли это с помощью усилителя? Или мне нужно копировать его каждый раз, когда я вызываю параллель_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 — Да. Если вы передаете 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 — В зависимости от размера вашего массива коэффициентов вы можете сделать одну из нескольких вещей;
а — Храните его в локальном массиве в вашем 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.
с — Рассмотрите возможность загрузки в 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 и охватывают многие из этих сценариев.