Использование объектов accelerator и accelerator_view
С помощью акселератора и accelerator_view классов можно указать устройство или эмулятор для запуска кода C++ AMP. Система может иметь несколько устройств или эмуляторов, которые отличаются объемом памяти, поддержкой общей памяти, поддержкой отладки или поддержкой двойной точности. C++ Accelerated Massive Parallelism (C++ AMP) предоставляет API, которые можно использовать для изучения доступных акселераторов, задания одного в качестве значения по умолчанию, указания нескольких accelerator_views для нескольких вызовов для parallel_for_each и выполнения специальных задач отладки.
Примечание.
Заголовки C++ AMP устарели начиная с Visual Studio 2022 версии 17.0.
Включение всех заголовков AMP приведет к возникновению ошибок сборки. Определите _SILENCE_AMP_DEPRECATION_WARNINGS
перед включением всех заголовков AMP, чтобы замолчать предупреждения.
Использование акселератора по умолчанию
Среда выполнения C++ AMP выбирает акселератор по умолчанию, если только код не будет выбран для конкретного. Среда выполнения выбирает акселератор по умолчанию следующим образом:
Если приложение работает в режиме отладки, акселератор, поддерживающий отладку.
В противном случае ускоритель, заданный переменной
CPPAMP_DEFAULT_ACCELERATOR
среды, если он задан.В противном случае неэмулированное устройство.
В противном случае устройство с наибольшим объемом доступной памяти.
В противном случае устройство, которое не подключено к экрану.
Кроме того, среда выполнения указывает для access_type
access_type_auto
акселератора по умолчанию. Это означает, что акселератор по умолчанию использует общую память, если она поддерживается и если ее характеристики производительности (пропускная способность и задержка), как известно, совпадают с выделенной (необщей) памятью.
Свойства акселератора по умолчанию можно определить, создав акселератор по умолчанию и проверив его свойства. В следующем примере кода выводится путь, объем памяти акселератора, поддержка общей памяти, поддержка двойной точности и ограниченная поддержка двойной точности акселератора по умолчанию.
void default_properties() {
accelerator default_acc;
std::wcout << default_acc.device_path << "\n";
std::wcout << default_acc.dedicated_memory << "\n";
std::wcout << (accs[i].supports_cpu_shared_memory ?
"CPU shared memory: true" : "CPU shared memory: false") << "\n";
std::wcout << (accs[i].supports_double_precision ?
"double precision: true" : "double precision: false") << "\n";
std::wcout << (accs[i].supports_limited_double_precision ?
"limited double precision: true" : "limited double precision: false") << "\n";
}
переменная среды CPPAMP_DEFAULT_ACCELERATOR
Можно задать переменную среды CPPAMP_DEFAULT_ACCELERATOR, чтобы указать accelerator::device_path
акселератор по умолчанию. Путь зависит от оборудования. Следующий код использует accelerator::get_all
функцию для получения списка доступных акселераторов, а затем отображает путь и характеристики каждого акселератора.
void list_all_accelerators()
{
std::vector<accelerator> accs = accelerator::get_all();
for (int i = 0; i <accs.size(); i++) {
std::wcout << accs[i].device_path << "\n";
std::wcout << accs[i].dedicated_memory << "\n";
std::wcout << (accs[i].supports_cpu_shared_memory ?
"CPU shared memory: true" : "CPU shared memory: false") << "\n";
std::wcout << (accs[i].supports_double_precision ?
"double precision: true" : "double precision: false") << "\n";
std::wcout << (accs[i].supports_limited_double_precision ?
"limited double precision: true" : "limited double precision: false") << "\n";
}
}
Выбор акселератора
Чтобы выбрать акселератор, используйте accelerator::get_all
метод для получения списка доступных акселераторов, а затем выберите один из них на основе его свойств. В этом примере показано, как выбрать акселератор, имеющий большую память:
void pick_with_most_memory()
{
std::vector<accelerator> accs = accelerator::get_all();
accelerator acc_chosen = accs[0];
for (int i = 0; i <accs.size(); i++) {
if (accs[i].dedicated_memory> acc_chosen.dedicated_memory) {
acc_chosen = accs[i];
}
}
std::wcout << "The accelerator with the most memory is "
<< acc_chosen.device_path << "\n"
<< acc_chosen.dedicated_memory << ".\n";
}
Примечание.
Одним из акселераторов, возвращаемых с помощью accelerator::get_all
ЦП, является ускоритель ЦП. Невозможно выполнить код на акселераторе ЦП. Чтобы отфильтровать акселератор ЦП, сравните значение свойства device_path акселератора, возвращаемого accelerator::get_all
со значением акселератора::cpu_accelerator. Дополнительные сведения см. в разделе "Специальные акселераторы" в этой статье.
Общая память
Общая память — это память, доступ к которой осуществляется как ЦП, так и акселератором. Использование общей памяти устраняет или значительно сокращает затраты на копирование данных между ЦП и акселератором. Хотя память предоставляется совместно, доступ к ней не может одновременно выполняться как ЦП, так и акселератором, и это приводит к неопределенному поведению. Свойство акселератора supports_cpu_shared_memory возвращаетсяtrue
, если акселератор поддерживает общую память, а свойство default_cpu_access_type получает access_type по умолчанию для памяти, выделенной для accelerator
памяти, например массивов, связанных с accelerator
объектом или array_view
объектами, к которым обращается доступaccelerator
.
Среда выполнения C++ AMP автоматически выбирает оптимальное значение по умолчанию access_type
для каждого accelerator
, но характеристики производительности (пропускная способность и задержка) общей памяти могут быть хуже, чем выделенные (не общие) ускорители памяти при чтении из ЦП, записи из ЦП или обоих. Если общая память выполняется, а также выделенная память для чтения и записи из ЦП, среда выполнения по умолчанию имеет значение; в противном случае среда выполнения выбирает более консервативный параметр по умолчанию access_type_read_write
и позволяет приложению access_type
переопределить его, если шаблоны доступа к памяти его вычислительных ядер получают преимущество от другого access_type
.
В следующем примере кода показано, как определить, поддерживает ли акселератор по умолчанию общую память, а затем переопределяет тип доступа по умолчанию и создает accelerator_view
его из него.
#include <amp.h>
#include <iostream>
using namespace Concurrency;
int main()
{
accelerator acc = accelerator(accelerator::default_accelerator);
// Early out if the default accelerator doesn't support shared memory.
if (!acc.supports_cpu_shared_memory)
{
std::cout << "The default accelerator does not support shared memory" << std::endl;
return 1;
}
// Override the default CPU access type.
acc.set_default_cpu_access_type(access_type_read_write);
// Create an accelerator_view from the default accelerator. The
// accelerator_view reflects the default_cpu_access_type of the
// accelerator it's associated with.
accelerator_view acc_v = acc.default_view;
}
Всегда accelerator_view
отражает default_cpu_access_type
accelerator
связанный с ним интерфейс, и он не предоставляет интерфейс для переопределения или изменения его access_type
.
Изменение акселератора по умолчанию
Вы можете изменить акселератор по умолчанию, вызвав accelerator::set_default
метод. Акселератор по умолчанию можно изменить только один раз для каждого выполнения приложения и изменить его перед выполнением любого кода на GPU. Любые последующие вызовы функции для изменения возвращаемого false
акселератора. Если вы хотите использовать другой акселератор в вызове parallel_for_each
, ознакомьтесь с разделом "Использование нескольких акселераторов" в этой статье. В следующем примере кода акселератор по умолчанию присваивается одному, который не эмулируется, не подключен к экрану и поддерживает двойную точность.
bool pick_accelerator()
{
std::vector<accelerator> accs = accelerator::get_all();
accelerator chosen_one;
auto result = std::find_if(accs.begin(), accs.end(),
[] (const accelerator& acc) {
return !acc.is_emulated &&
acc.supports_double_precision &&
!acc.has_display;
});
if (result != accs.end()) {
chosen_one = *(result);
}
std::wcout <<chosen_one.description <<std::endl;
bool success = accelerator::set_default(chosen_one.device_path);
return success;
}
Использование нескольких акселераторов
Существует два способа использования нескольких акселераторов в приложении:
Объекты можно передать
accelerator_view
в вызовы метода parallel_for_each .Объект массива можно создать с помощью определенного
accelerator_view
объекта. Среда выполнения C+AMP будет собиратьaccelerator_view
объект из захваченного объекта массива в лямбда-выражении.
Специальные акселераторы
Пути к устройству трех специальных акселераторов доступны в качестве свойств accelerator
класса:
accelerator::d irect3d_ref Data Member: этот однопоточный акселератор использует программное обеспечение на ЦП для эмуляции универсальной графической карты. Он используется по умолчанию для отладки, но он не полезен в рабочей среде, так как он медленнее, чем аппаратные акселераторы. Кроме того, он доступен только в пакете SDK DirectX и пакете SDK для Windows, и вряд ли он будет установлен на компьютерах клиентов. Дополнительные сведения см. в разделе Отладка кода GPU.
accelerator::d irect3d_warp Data Member: этот акселератор предоставляет резервное решение для выполнения кода C++ AMP на многоядерных ЦП, использующих расширения ПОТОКОВой SIMD (SSE).
акселератор::cpu_accelerator элемент данных: этот акселератор можно использовать для настройки промежуточных массивов. Не удается выполнить код C++ AMP. Дополнительные сведения см . в записи staging Arrays in C++ AMP в блоге о параллельном программировании в машинном коде.
Совместимость
Среда выполнения C++ AMP поддерживает взаимодействие между accelerator_view
классом и интерфейсом Direct3D ID3D11Device. Метод create_accelerator_view принимает IUnknown
интерфейс и возвращает accelerator_view
объект. Метод get_device принимает accelerator_view
объект и возвращает IUnknown
интерфейс.
См. также
C++ AMP (C++ Accelerated Massive Parallelism)
Отладка кода GPU
Класс accelerator_view