Freigeben über


Verwenden von Accelerator- und accelerator_view-Objekten

Sie können die Beschleuniger- und accelerator_view-Klassen verwenden, um das Gerät oder den Emulator anzugeben, auf dem Ihr C++-AMP-Code ausgeführt werden soll. Ein System verfügt möglicherweise über mehrere Geräte oder Emulatoren, die sich je nach Speichermenge, Unterstützung für gemeinsam genutztem Arbeitsspeicher, Debuggingunterstützung oder Unterstützung mit doppelter Genauigkeit unterscheiden. C++ Accelerated Massive Parallelism (C++ AMP) stellt APIs bereit, mit denen Sie die verfügbaren Beschleuniger untersuchen, einen als Standard festlegen, mehrere accelerator_views für mehrere Aufrufe an parallel_for_each angeben und spezielle Debugging-Aufgaben ausführen können.

Hinweis

C++AMP-Header sind ab Visual Studio 2022, Version 17.0, veraltet. Wenn alle AMP-Header einbezogen werden, führt dies zu Buildfehlern. Definieren Sie _SILENCE_AMP_DEPRECATION_WARNINGS , bevor Sie AMP-Header einschließen, um die Warnungen zu stillen.

Verwenden des Standardbeschleunigers

Die C++ AMP-Laufzeit wählt einen Standardbeschleuniger aus. Es sei denn, Sie schreiben Code, um einen bestimmten auszuwählen. Die Runtime wählt den Standardbeschleuniger wie folgt aus:

  1. Wenn die App im Debugmodus ausgeführt wird, unterstützt ein Beschleuniger das Debuggen.

  2. Andernfalls wird das durch die CPPAMP_DEFAULT_ACCELERATOR Umgebungsvariable angegebene Tastenkürzel verwendet, wenn es festgelegt ist.

  3. Andernfalls wird ein nicht-emuliertes Gerät verwendet.

  4. Andernfalls das Gerät mit der größten Menge an verfügbarem Arbeitsspeicher.

  5. Andernfalls handelt es sich um ein Gerät, das nicht an das Display angeschlossen ist.

Darüber hinaus gibt die Laufzeit einen access_type von access_type_auto für die Standardbeschleuniger an. Dies bedeutet, dass der Standardbeschleuniger freigegebenen Speicher verwendet, wenn er unterstützt wird und die Leistungsmerkmale (Bandbreite und Latenz) als gleich zu denen des dedizierten (nicht gemeinsam genutzten) Speichers bekannt sind.

Sie können die Eigenschaften des Standardbeschleunigers ermitteln, indem Sie den Standardbeschleuniger erstellen und seine Eigenschaften untersuchen. Im folgenden Codebeispiel werden der Pfad, die Menge des Beschleunigerspeichers, die Unterstützung für gemeinsamen Arbeitsspeicher, die Unterstützung für doppelte Genauigkeit und die eingeschränkte Unterstützung für doppelte Genauigkeit des Standardbeschleunigers ausgegeben.

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-Umgebungsvariable

Sie können die CPPAMP_DEFAULT_ACCELERATOR Umgebungsvariable festlegen, um den accelerator::device_path Standard-Beschleuniger anzugeben. Der Pfad ist hardwareabhängig. Der folgende Code verwendet die accelerator::get_all Funktion, um eine Liste der verfügbaren Beschleuniger abzurufen und zeigt dann den Pfad und die Eigenschaften jedes Beschleunigers an.

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

Auswählen eines Beschleunigers

Um einen Beschleuniger auszuwählen, verwenden Sie die accelerator::get_all Methode, um eine Liste der verfügbaren Beschleuniger abzurufen, und wählen Sie dann eine basierend auf deren Eigenschaften aus. In diesem Beispiel wird gezeigt, wie Sie den Beschleuniger auswählen, der den meisten Speicherplatz hat.

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

Hinweis

Einer der Beschleuniger, die von accelerator::get_all zurückgegeben werden, ist der CPU-Beschleuniger. Code kann nicht auf dem CPU-Beschleuniger ausgeführt werden. Um den CPU-Beschleuniger herauszufiltern, vergleichen Sie den Wert der device_path-Eigenschaft des Beschleunigers, der von accelerator::get_all zurückgegeben wird, mit dem Wert von accelerator::cpu_accelerator. Weitere Informationen finden Sie im Abschnitt "Special Accelerators" in diesem Artikel.

Freigegebener Speicher

Gemeinsamer Speicher ist Speicher, auf den sowohl die CPU als auch der Beschleuniger zugreifen können. Durch die Verwendung des gemeinsam genutzten Speichers wird der Mehraufwand für das Kopieren von Daten zwischen der CPU und dem Accelerator beseitigt oder erheblich reduziert. Obwohl der Arbeitsspeicher gemeinsam genutzt wird, kann nicht gleichzeitig von der CPU und dem Beschleuniger darauf zugegriffen werden, und dies führt zu einem nicht definierten Verhalten. Die Beschleunigereigenschaft supports_cpu_shared_memory gibt true zurück, wenn der Beschleuniger gemeinsam genutzten Speicher unterstützt, und die default_cpu_access_type-Eigenschaft holt den Standard-access_type für den auf den zugewiesenen Speicher ab, z.B. für accelerator, die mit dem verbunden sind, oder für Objekte, auf die auf der accelerator zugegriffen wird.

Die C++ AMP-Laufzeit wählt automatisch die beste Standardeinstellung access_type für jedes accelerator aus. Die Leistungsmerkmale (Bandbreite und Latenz) des gemeinsam genutzten Speichers können jedoch schlechter sein als die des dedizierten (nicht gemeinsam genutzten) Beschleunigerspeichers, wenn von der CPU gelesen oder geschrieben wird, oder beides. Wenn der gemeinsam genutzte Speicher für das Lesen und Schreiben von der CPU genauso gut wie dedizierter Speicher ist, setzt die Laufzeit standardmäßig auf access_type_read_write; andernfalls wählt die Laufzeit einen konservativeren Standardwert access_typeaus und ermöglicht der App, diesen zu überschreiben, wenn die Speicherzugriffsmuster ihrer Rechenkerne von einem anderen access_typeprofitieren.

Im folgenden Codebeispiel wird gezeigt, wie Sie ermitteln, ob der Standardbeschleuniger gemeinsamen Speicher unterstützt, dann seinen Standardzugriffstyp überschreiben und daraus ein accelerator_view erstellen.

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

Eine accelerator_view spiegelt immer den default_cpu_access_type des accelerator wider, mit dem sie verbunden ist, und bietet keine Schnittstelle zum Überschreiben oder Ändern ihres access_type.

Ändern des Standardbeschleunigers

Sie können den Standardbeschleuniger ändern, indem Sie die accelerator::set_default Methode aufrufen. Sie können den Standardbeschleuniger nur einmal pro App-Ausführung ändern, und Sie müssen ihn ändern, bevor code auf der GPU ausgeführt wird. Alle nachfolgenden Funktionsaufrufe, um den Beschleuniger zu ändern, geben false zurück. Wenn Sie bei einem Aufruf von parallel_for_each eine andere Zugriffstaste verwenden möchten, lesen Sie den Abschnitt "Verwenden mehrerer Zugriffstasten" in diesem Artikel. Im folgenden Codebeispiel wird der Standardbeschleuniger auf einen festgelegt, der nicht emuliert ist, nicht mit einem Display verbunden ist und doppelte Genauigkeit unterstützt.

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

Verwendung mehrerer Beschleuniger

Es gibt zwei Möglichkeiten, mehrere Beschleuniger in Ihrer App zu verwenden:

  • Sie können accelerator_view Objekte an die Aufrufe der Methode parallel_for_each übergeben.

  • Sie können ein Arrayobjekt mithilfe eines bestimmten accelerator_view Objekts erstellen. Die C++ AMP-Laufzeit nimmt das accelerator_view-Objekt aus dem im Lambda-Ausdruck erfassten Array-Objekt auf.

Besondere Beschleuniger

Die Gerätepfade von drei speziellen Beschleunigern sind als Eigenschaften der accelerator Klasse verfügbar.

  • accelerator::direct3d_ref Data Member: Dieser Singlethread-Accelerator verwendet Software auf der CPU, um eine generische Grafikkarte zu emulieren. Sie wird standardmäßig für das Debuggen verwendet, ist aber in der Produktion nicht nützlich, da sie langsamer als die Hardwarebeschleuniger ist. Darüber hinaus ist es nur im DirectX SDK und im Windows SDK verfügbar, und es ist unwahrscheinlich, dass es auf den Computern Ihrer Kunden installiert wird. Weitere Informationen finden Sie unter Debuggen von GPU-Code.

  • accelerator::direct3d_warp Data Member: Dieser Beschleuniger bietet eine Ausweichlösung zum Ausführen von C++ AMP Code auf Multi-Core-CPUs, die Streaming SIMD-Erweiterungen (SSE) verwenden.

  • accelerator::cpu_accelerator Data Member: Sie können diesen Beschleuniger zum Einrichten von Zwischenarrays verwenden. C++-AMP-Code kann nicht ausgeführt werden. Weitere Informationen finden Sie im Beitrag " Stagingarrays in C++AMP " im Blog "Parallel Programming in Native Code".

Interoperabilität

Die C++AMP-Laufzeit unterstützt die Interoperabilität zwischen der accelerator_view Klasse und der Direct3D ID3D11Device-Schnittstelle. Die create_accelerator_view-Methode verwendet eine IUnknown Schnittstelle und gibt ein accelerator_view Objekt zurück. Die get_device-Methode verwendet ein accelerator_view Objekt und gibt eine IUnknown Schnittstelle zurück.

Siehe auch

C++ AMP (C++-Beschleunigter massiver Parallelismus)
Debuggen von GPU-Code
Accelerator-View-Klasse