通过


使用加速器和accelerator_view对象

可以使用 加速器accelerator_view 类指定要运行 C++ AMP 代码的设备或模拟器。 系统可能有多个设备或模拟器,这些设备或仿真器因内存量、共享内存支持、调试支持或双精度支持而异。 C++ 加速大规模并行(C++ AMP)提供了一些 API,您可以使用它们检查可用的加速器,将其中一个设置为默认加速器,为多次调用 parallel_for_each 指定多个 accelerator_views,以及执行特殊的调试任务。

注释

从 Visual Studio 2022 版本 17.0 开始,已弃用 C++ AMP 标头。 包含任何 AMP 标头都会引发构建错误。 应在包含任何 AMP 标头之前定义 _SILENCE_AMP_DEPRECATION_WARNINGS,以使警告静音。

使用默认加速器

除非编写代码来选取特定加速器,否则 C++ AMP 运行时会选取默认加速器。 运行时选择默认加速器,如下所示:

  1. 如果应用程序在调试模式下运行,则需要一个支持调试功能的加速器。

  2. 否则,使用由环境变量 CPPAMP_DEFAULT_ACCELERATOR 指定的加速器(如果已设置)。

  3. 否则为非模拟设备。

  4. 否则,具有最大可用内存量的设备。

  5. 否则,未连接到显示器的设备。

此外,运行时为默认加速器指定了access_typeaccess_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 的加速器之一是 CPU 加速器。 不能在 CPU 加速器上执行代码。 若要筛选掉 CPU 加速器,请将返回的加速器的 accelerator::get_all 属性的值与快捷键::cpu_accelerator的值进行比较。 有关详细信息,请参阅本文中的“特殊加速器”部分。

共享内存

共享内存是 CPU 和加速器可以访问的内存。 使用共享内存可以消除或显著减少在 CPU 和加速器之间复制数据的开销。 尽管内存是共享的,但 CPU 和加速器不能同时访问内存,这样做会导致未定义的行为。 如果加速器属性supports_cpu_shared_memory支持共享内存,则返回true,并且default_cpu_access_type属性获取在accelerator上分配的内存的默认access_type,例如,与accelerator相关联的数组,或在accelerator上访问的array_view

C++ AMP 运行时自动为每个access_type内存选择最佳默认值accelerator,但共享内存的性能特征(带宽和延迟)可能比从 CPU 读取、从 CPU 写入或同时读取专用(非共享)加速器内存的性能特征(带宽和延迟)更差。 如果共享内存执行得与专用内存一样好,从 CPU 进行读取和写入时,运行时会默认使用 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反映与accelerator关联的default_cpu_access_type,并且不提供替代或更改其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 运行时将从 lambda 表达式中捕获的accelerator_view对象中选取该对象。

特殊加速器

特殊加速器的三个设备路径作为accelerator类的属性是可用的:

Interoperability

C++ AMP 运行时支持类与 accelerator_view之间的互操作性。 create_accelerator_view方法采用接口IUnknown并返回对象accelerator_viewget_device方法采用对象accelerator_view并返回IUnknown接口。

另请参阅

C++ AMP(C++加速大规模并行度)
调试 GPU 代码
accelerator_view 类