Dela via


Använda accelerator- och accelerator_view-objekt

Du kan använda acceleratorn och accelerator_view klasser för att ange vilken enhet eller emulator du vill köra C++ AMP-koden på. Ett system kan ha flera enheter eller emulatorer som skiljer sig åt beroende på mängden minne, stöd för delat minne, felsökningsstöd eller stöd för dubbel precision. C++ Accelerated Massive Parallelism (C++ AMP) tillhandahåller API:er som du kan använda för att undersöka tillgängliga acceleratorer, ange en som standard, ange flera accelerator_views för flera anrop till parallel_for_each och utföra särskilda felsökningsuppgifter.

Anmärkning

C++ AMP-huvuden är inaktuella från och med Visual Studio 2022 version 17.0. Om du inkluderar AMP headers uppstår byggfel. Definiera _SILENCE_AMP_DEPRECATION_WARNINGS innan du inkluderar AMP-huvuden för att undvika varningarna.

Använda standardacceleratorn

C++ AMP-körningen väljer en standardaccelerator, såvida du inte skriver kod för att välja en specifik. Programmet väljer standardaccelerator enligt följande sätt.

  1. Om appen körs i felsökningsläge, en accelerator som stöder felsökning.

  2. I annat fall den accelerator som anges av CPPAMP_DEFAULT_ACCELERATOR miljövariabeln, om den har angetts.

  3. I annat fall en icke-emulerad enhet.

  4. I annat fall den enhet som har störst mängd tillgängligt minne.

  5. I annat fall en enhet som inte är ansluten till skärmen.

Dessutom anger exekveringsmiljön en access_typeaccess_type_auto för standardacceleratorn. Det innebär att standardacceleratorn använder delat minne om det stöds och om dess prestandaegenskaper (bandbredd och svarstid) är kända för att vara samma som dedikerat (icke-delat) minne.

Du kan fastställa egenskaperna för standardacceleratorn genom att konstruera standardacceleratorn och undersöka dess egenskaper. I följande kodexempel skrivs sökvägen ut, mängden acceleratorminne, stöd för delat minne, stöd för dubbel precision och begränsat stöd för dubbel precision för standardacceleratorn.

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 miljövariabel

Du kan ange CPPAMP_DEFAULT_ACCELERATOR miljövariabeln för att ange accelerator::device_path standardacceleratorn. Sökvägen är maskinvaruberoende. Följande kod använder accelerator::get_all funktionen för att hämta en lista över tillgängliga acceleratorer och visar sedan sökvägen och egenskaperna för varje accelerator.

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älja en accelerator

Om du vill välja en accelerator använder du accelerator::get_all metoden för att hämta en lista över tillgängliga acceleratorer och väljer sedan en baserat på dess egenskaper. Det här exemplet visar hur du väljer den accelerator som har mest minne:

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

Anmärkning

En av de acceleratorer som returneras av accelerator::get_all är PROCESSORacceleratorn. Du kan inte köra kod på PROCESSORacceleratorn. Om du vill filtrera bort CPU-acceleratorn jämför du värdet för device_path-egenskapen för acceleratorn som returneras av accelerator::get_all med värdet av accelerator::cpu_accelerator. Mer information finns i avsnittet "Specialacceleratorer" i den här artikeln.

Delat minne

Delat minne är minne som kan nås av både processorn och acceleratorn. Användningen av delat minne eliminerar eller minskar avsevärt kostnaderna för att kopiera data mellan processorn och acceleratorn. Även om minnet delas kan det inte nås samtidigt av både processorn och acceleratorn, och detta orsakar odefinierat beteende. Acceleratoregenskapen supports_cpu_shared_memory returnerar true om acceleratorn stöder delat minne, och egenskapen default_cpu_access_type hämtar standardvärdet access_type för det minne som allokerats på accelerator, till exempel matriser som är associerade med accelerator, eller objekt som array_view används på accelerator.

C++ AMP-körningen väljer automatiskt det bästa standardvärdet access_type för varje accelerator, men prestandaegenskaperna (bandbredd och svarstid) för delat minne kan vara sämre än för dedikerade (icke-delade) acceleratorminnen när du läser från processorn, skriver från processorn eller båda. Om delat minne fungerar lika bra som dedikerat minne för läsning och skrivning från processorn, är standardvärdet för programmets körning access_type_read_write. Annars väljer körningen ett mer konservativt standardvärde access_type och låter appen åsidosätta det om minnesåtkomstmönstren för dess beräkningsprocessorer drar nytta av en annan konfiguration access_type.

I följande kodexempel visas hur du avgör om standardacceleratorn stöder delat minne och sedan åsidosätter dess standardåtkomsttyp och skapar en accelerator_view från den.

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

En accelerator_view återspeglar alltid den default_cpu_access_type som accelerator den är associerad med, och den innehåller inget gränssnitt för att åsidosätta eller ändra dess access_type.

Ändra standardacceleratorn

Du kan ändra standardacceleratorn genom att anropa accelerator::set_default metoden. Du kan bara ändra standardacceleratorn en gång per appkörning och du måste ändra den innan någon kod körs på GPU:n. Eventuella efterföljande funktionsanrop för att ändra acceleratorn returnerar false. Om du vill använda en annan accelerator i ett anrop till parallel_for_eachläser du avsnittet "Använda flera acceleratorer" i den här artikeln. I följande kodexempel anges standardacceleratorn till en som inte emuleras, inte är ansluten till en skärm och stöder dubbel precision.

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

Använda flera acceleratorer

Det finns två sätt att använda flera acceleratorer i din app:

  • Du kan skicka accelerator_view objekt till anropen av metoden parallel_for_each.

  • Du kan konstruera ett matrisobjekt med hjälp av ett specifikt accelerator_view objekt. C++ AMP-runtime accelerator_view hämtar objektet från det fångade matrisobjektet i lambda-uttrycket.

Speciala acceleratorer

Enhetssökvägarna för tre specialacceleratorer är tillgängliga som egenskaper av klassen accelerator:

  • accelerator::direct3d_ref Data Member: Den här enkeltrådade acceleratorn använder programvara på CPU:n för att emulera ett allmänt grafikkort. Det används som standard för felsökning, men det är inte användbart i produktion eftersom det är långsammare än maskinvaruacceleratorerna. Dessutom är det endast tillgängligt i DirectX SDK och Windows SDK, och det är osannolikt att det kommer att installeras på dina kunders datorer. Mer information finns i Felsöka GPU-kod.

  • accelerator::direct3d_warp Data Member: Den här acceleratorn tillhandahåller en reservlösning för att köra C++ AMP-kod på flerkärniga processorer som använder Streaming SIMD Extensions (SSE).

  • accelerator::cpu_accelerator Data Member: Du kan använda denna accelerator för att konfigurera stagingarrayer. Det går inte att köra C++ AMP-kod. För mer information, se Mellanlagringsmatriser i C++ AMP-inlägget på bloggen Parallell programmering med inbyggd kod.

Samverkan

C++ AMP-körningen stöder samverkan mellan accelerator_view klassen och Direct3D ID3D11Enhetsgränssnittet. Metoden create_accelerator_view tar ett IUnknown gränssnitt och returnerar ett accelerator_view objekt. Metoden get_device tar ett accelerator_view objekt och returnerar ett IUnknown gränssnitt.

Se även

C++ AMP (C++ Accelererad massiv parallellitet)
Felsöka GPU-kod
AcceleratorView-klass