Поделиться через


Использование объектов accelerator и accelerator_view

Можно использовать классы accelerator и accelerator_view для определения устройства или эмулятора, на котором будет выполняться код C++ AMP. Система может иметь несколько устройств или эмуляторов, которые отличаются объемом памяти, поддержкой общей памяти, поддержкой отладки или поддержкой чисел с плавающей запятой двойной точности. C++ Accelerated Massive Parallelism (C++ AMP) предоставляет интерфейсы API, позволяющие просмотреть все доступные ускорители, задать один из них как ускоритель по умолчанию, использовать несколько представлений ускорителей для множественных вызовов parallel_for_each и выполнять специальные задачи отладки.

Использование ускорителя по умолчанию

Среда выполнения C++ AMP выбирает ускоритель по умолчанию, если только не был написан код для выбора конкретного ускорителя. Среда выполнения выбирает ускоритель по умолчанию следующим образом:

  1. Если приложение выполняется в режиме отладки, то выбирается ускоритель, поддерживающий отладку.

  2. В противном случае выбирается ускоритель, который определяется с помощью переменной среды CPPAMP_DEFAULT_ACCELERATOR, если она задана.

  3. В противном случае — неэмулированное устройство.

  4. В противном случае — устройство с наибольшим объемом доступной памяти.

  5. В противном случае — устройство, которое не подсоединено к дисплею.

Кроме того, среда выполнения задает 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, со значением accelerator::cpu_accelerator.Дополнительные сведения см. в разделе "Специальные ускорители" в этой статье.

Общая память

Общая память — это память, доступ к которой может осуществляться и ЦП, и акселератором. Использование общей памяти исключает или значительно снижает нагрузку копирования данных между ЦП и сочетаниями клавиш. Хотя память является общей, к ней не могут одновременно обращаться и ЦП, и ускоритель, и попытка это сделать приводит к неопределенному поведению. Свойство supports_cpu_shared_memory сочетания клавиш возвращает значение true, если сочетание клавиш поддерживает общей памяти, а свойство default_cpu_access_type получает по умолчанию access_type для памяти, выделенной для accelerator— пример, связанного с array, 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.

  • Можно создать объект array с помощью указанного объекта accelerator_view. Среда выполнения C++ AMP выберет объект accelerator_view из перехваченного объекта array в лямбда-выражении.

Специальные ускорители

Пути трех специальных ускорителей доступны в виде свойств класса accelerator:

  • Элемент данных accelerator::direct3d_ref: Этот однопоточный ускоритель использует программное обеспечение на ЦП для эмуляции универсальной видеокарты. Он используется по умолчанию для отладки, но он неэффективен в рабочей среде, поскольку он медленнее, чем аппаратные ускорители. Кроме того, он доступен только в DirectX SDK и Windows SDK и вряд ли будет установлен на компьютерах клиентов. Дополнительные сведения см. в разделе Отладка кода GPU.

  • Элемент данных accelerator::direct3d_warp: Этот ускоритель предоставляет резервное решение для выполнения кода C++ AMP на многоядерных ЦП, которые используют набор инструкций Streaming SIMD Extensions (SSE).

  • Элемент данных accelerator::cpu_accelerator: Этот ускоритель можно использовать для установки массивов промежуточного хранения. Он не может выполнять код C++ AMP. Дополнительные сведения см. в записи Staging Arrays in C++ AMP в блоге Parallel Programming in Native Code.

Взаимодействие

Среда выполнения C++ AMP поддерживает взаимодействие между классом accelerator_view и Direct3D Интерфейс ID3D11Device. Метод create_accelerator_view принимает интерфейс IUnknown и возвращает объект accelerator_view. Метод get_device принимает объект accelerator_view и возвращает интерфейс IUknown.

См. также

Ссылки

Класс accelerator

Класс accelerator_view

Другие ресурсы

C++ AMP (C++ Accelerated Massive Parallelism)

Отладка кода GPU