Sdílet prostřednictvím


Použití akcelerátoru a objektů accelerator_view

Akcelerátor a třídy accelerator_view můžete použít k určení zařízení nebo emulátoru pro spuštění kódu C++ AMP. Systém může mít několik zařízení nebo emulátorů, které se liší množstvím paměti, podporou sdílené paměti, podporou ladění nebo podporou dvojité přesnosti. C++ Accelerated Massive Parallelism (C++ AMP) poskytuje API, která můžete použít k prozkoumání dostupných akcelerátorů, nastavení jednoho z nich jako výchozího, určení více accelerator_views pro více volání do parallel_for_each a provádění speciálních úloh ladění.

Poznámka:

Hlavičky C++ AMP jsou zastaralé od sady Visual Studio 2022 verze 17.0. Zahrnutím všech hlaviček AMP se vygenerují chyby sestavení. Před zahrnutím jakýchkoli hlaviček AMP definujte _SILENCE_AMP_DEPRECATION_WARNINGS, abyste ztlumili varování.

Použití výchozího akcelerátoru

Modul runtime C++ AMP vybere výchozí akcelerátor, pokud nezapíšete kód, který vybere konkrétní akcelerátor. Modul runtime zvolí výchozí akcelerátor následujícím způsobem:

  1. Pokud je aplikace spuštěná v režimu ladění, je k dispozici akcelerátor podporující ladění.

  2. Jinak akcelerátor určený proměnnou CPPAMP_DEFAULT_ACCELERATOR prostředí, pokud je nastavený.

  3. V opačném případě neemulované zařízení.

  4. V opačném případě zařízení, které má největší množství dostupné paměti.

  5. V opačném případě zařízení, které není připojené k displeji.

Navíc runtime určuje access_typeaccess_type_auto pro výchozí akcelerátor. To znamená, že výchozí akcelerátor využívá sdílenou paměť, pokud je tato paměť podporovaná systémem a pokud jsou její výkonové charakteristiky (šířka pásma a latence) obdobné jako u vyhrazené (nesdílené) paměti.

Vlastnosti výchozího akcelerátoru můžete určit tak, že vytvoříte výchozí akcelerátor a prozkoumáte jeho vlastnosti. Následující příklad kódu vytiskne cestu, velikost paměti akcelerátoru, podporu sdílené paměti, podporu dvojité přesnosti a omezenou podporu dvojité přesnosti výchozího akcelerátoru.

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";
}

proměnná prostředí CPPAMP_DEFAULT_ACCELERATOR

Proměnnou CPPAMP_DEFAULT_ACCELERATOR prostředí můžete nastavit tak, aby určila accelerator::device_path výchozí akcelerátor. Cesta je závislá na hardwaru. Následující kód pomocí accelerator::get_all funkce načte seznam dostupných akcelerátorů a pak zobrazí cestu a vlastnosti každého akcelerátoru.

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";
    }
}

Výběr akcelerátoru

Chcete-li vybrat akcelerátor, použijte metodu accelerator::get_all k načtení seznamu dostupných akcelerátorů a pak vyberte jeden na základě jeho vlastností. Tento příklad ukazuje, jak vybrat akcelerátor, který má nejvíce paměti:

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";
}

Poznámka:

Jedním z akcelerátorů vrácených accelerator::get_all je akcelerátor procesoru. V akcelerátoru procesoru nelze spustit kód. Chcete-li vyfiltrovat akcelerátor procesoru, porovnejte hodnotu vlastnosti device_path akcelerátoru vrácenou accelerator::get_all hodnotou akcelerátoru::cpu_accelerator. Další informace najdete v části Speciální akcelerátory v tomto článku.

Sdílená paměť

Sdílená paměť je paměť, ke které má přístup procesor i akcelerátor. Použití sdílené paměti eliminuje nebo výrazně snižuje režii při kopírování dat mezi procesorem a akcelerátorem. I když je paměť sdílená, nelze k ní přistupovat současně procesorem i akcelerátorem a tím způsobit nedefinované chování. Vlastnost akcelerátoru supports_cpu_shared_memory vrátí true, pokud akcelerátor podporuje sdílenou paměť, a vlastnost default_cpu_access_type získá výchozí access_type pro paměť přidělenou na accelerator – například pole přidružená k accelerator, nebo array_view objekty, ke kterým se přistupuje na accelerator.

Modul runtime C++ AMP automaticky vybere nejlepší výchozí hodnotu access_type pro každý accelerator, ale výkonové charakteristiky (šířka pásma a latence) sdílené paměti mohou být horší než ty vyhrazené (nesdílené) paměti při čtení z procesoru, při zápisu do procesoru, nebo obojí. Pokud sdílená paměť provádí stejně dobře jako vyhrazená paměť pro čtení a zápis z procesoru, modul runtime použije výchozí hodnotu access_type_read_write; jinak modul runtime zvolí konzervativnější výchozí hodnotu access_type a umožňuje aplikaci přepsat tuto výchozí hodnotu, pokud vzory přístupu k paměti svých výpočetních jader mají prospěch z jiného access_type.

Následující příklad kódu ukazuje, jak určit, zda výchozí akcelerátor podporuje sdílenou paměť, a poté přepíše jeho výchozí typ přístupu a vytvoří z něj 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 vždy odráží default_cpu_access_typeaccelerator, se kterým je spojen, a neposkytuje žádné rozhraní pro přepsání nebo změnu jeho access_type.

Změna výchozího akcelerátoru

Výchozí akcelerátor můžete změnit voláním accelerator::set_default metody. Výchozí akcelerátor můžete změnit jenom jednou na spuštění aplikace a před spuštěním jakéhokoli kódu na GPU ho musíte změnit. Všechna následující volání funkce pro změnu akcelerátoru vrátí false. Pokud chcete ve volání parallel_for_eachpoužít jiný akcelerátor, přečtěte si část Používání více akcelerátorů v tomto článku. Následující příklad kódu nastaví výchozí akcelerátor na ten, který není emulován, není připojen k displeji a podporuje dvojitou přesnost.

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;
}

Použití více akcelerátorů

V aplikaci můžete použít několik akcelerátorů dvěma způsoby:

  • Do volání accelerator_view můžete předat objekty.

  • Objekt pole můžete vytvořit pomocí konkrétního accelerator_view objektu. Modul runtime C++ AMP převezme accelerator_view objekt ze zachyceného pole objektu ve výrazu lambda.

Speciální akcelerátory

Cesty zařízení tří speciálních akcelerátorů jsou k dispozici jako vlastnosti accelerator třídy:

  • accelerator::direct3d_ref Data Member: Tento jednovláknový akcelerátor používá software na CPU k emulaci obecné grafické karty. Ve výchozím nastavení se používá k ladění, ale není užitečná v produkčním prostředí, protože je pomalejší než hardwarové akcelerátory. Kromě toho je k dispozici pouze v sadě DirectX SDK a sadě Windows SDK a je nepravděpodobné, že by se nainstalovala na počítače vašich zákazníků. Další informace najdete v tématu Ladění kódu GPU.

  • accelerator::direct3d_warp – Datový člen: Tento akcelerátor poskytuje náhradní řešení pro spouštění kódu C++ AMP na vícejádrových procesorech, které používají rozšíření SSE (Streaming SIMD Extensions).

  • accelerator::cpu_accelerator Datový člen: Tento akcelerátor můžete použít k nastavení přípravných polí. Nelze spustit kód C++ AMP. Další informace najdete v příspěvku O přípravných polích v C++ AMP v blogovém příspěvku Paralelní programování v nativním kódu.

Interoperability

Modul runtime C++ AMP podporuje interoperabilitu mezi třídou accelerator_view a rozhraním Direct3D ID3D11Device. Create_accelerator_view metoda přebírá IUnknown rozhraní a vrací accelerator_view objekt. Metoda get_device přebírá accelerator_view objekt a vrací IUnknown rozhraní.

Viz také

C++ AMP (akcelerovaný masivní paralelismus C++)
Ladění kódu GPU
Třída accelerator_view