Udostępnij za pośrednictwem


Używanie akceleratora i obiektów accelerator_view

Można użyć klas accelerator i accelerator_view do określenia urządzenia lub emulatora do uruchamiania kodu C++ AMP.System może mieć kilka urządzeń lub emulatorów różniących się ilością pamięci, obsługą pamięci wspólnej i debugowania lub wsparciem dla podwójnej precyzji.Biblioteka C++ Accelerated Massive Parallelism (C++ AMP) udostępnia interfejsy API, które można wykorzystać do analizy dostępnych akceleratorów, ustawienie jednego z nich jako domyślny, określenia wielu accelerator_views dla wielu wywołań parallel_for_each oraz wykonywania specjalnych zadań debugowania.

Używanie akceleratora domyślnego

Środowisko wykonawcze C++ AMP wybiera akcelerator domyślny, o ile nie zostanie napisany kod wybierający konkretny akcelerator.Środowisko wykonawcze wybiera akcelerator domyślny w następujący sposób:

  1. Jeśli aplikacja jest uruchomiona w trybie debugowania, akcelerator obsługuje debugowanie.

  2. W przeciwnym razie akcelerator, który jest określony przez zmienną środowiskową CPPAMP_DEFAULT_ACCELERATOR, jeśli jest ustawiona.

  3. W przeciwnym razie urządzenie nie jest emulowane.

  4. W przeciwnym razie urządzenie, które ma największą ilość dostępnej pamięci.

  5. W przeciwnym razie urządzenie, które nie jest dołączone do wyświetlania.

Ponadto środowisko wykonawcze określa access_type z access_type_auto dla akceleratora domyślnego.Oznacza to, że akcelerator domyślny używa pamięci współużytkowanej, jeśli jest obsługiwany i jeśli jego charakterystyka wydajności (przepustowość i czas oczekiwania) są znane jako takie same, jak te dla dedykowanej pamięci (nieudostępnianej).

Można określić właściwości domyślnego akceleratora przez skonstruowanie domyślnego akceleratora i zbadanie jego właściwości.Poniższy przykład kodu drukuje ścieżkę, ilość pamięci akceleratora, obsługę pamięci współdzielonej, obsługę podwójnej precyzji i obsługę ograniczonej podwójnej precyzji akceleratora domyślnego.

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

Zmienna środowiskowa CPPAMP_DEFAULT_ACCELERATOR

Można ustawić zmienną środowiskową CPPAMP_DEFAULT_ACCELERATOR, aby określić accelerator::device_path akceleratora domyślnego.Ścieżka jest zależna od sprzętu.Następujący kod używa funkcji accelerator::get_all, aby pobrać listę dostępnych akceleratorów, a następnie wyświetlić ścieżkę i charakterystykę każdego akceleratora.

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

Wybieranie akceleratora

Aby wybrać akcelerator, użyj metody accelerator::get_all do pobrania listy dostępnych akceleratorów, a następnie wybierz jeden na podstawie jego właściwości.Przykład pokazuje, jak wybrać akcelerator, który ma najwięcej pamięci:

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

[!UWAGA]

Jeden z akceleratorów, które są zwracane przez accelerator::get_all, to akcelerator procesora CPU.Nie można wykonywać kodu na akceleratorze procesora.Aby odfiltrować accelerator procesora CPU, porównaj wartość właściwości akceleratora device_path, który jest zwracany przez accelerator::get_all z wartością accelerator::cpu_accelerator.Aby uzyskać więcej informacji zobacz sekcję „Specjalne akceleratory” w niniejszym artykule.

Pamięci wspólna

Pamięć współużytkowana jest pamięcią, do której ma dostęp zarówno Procesor, jak i akcelerator.Wykorzystanie pamięci współdzielonej eliminuje lub znacznie zmniejsza obciążenie kopiowania danych między procesorem a akceleratorem.Mimo,że pamięć jest udostępniona, nie może uzyskać do niej dostępu ani procesor, ani akcelerator, a czynność ta powoduje niezdefiniowane zachowanie.Właściwość akceleratora supports_cpu_shared_memory zwraca true jeśli akcelerator obsługuje pamięci współużytkowane i właściwość default_cpu_access_type pobiera domyślny access_type dla pamięci przydzielonej na accelerator— na przykład, arrayzwiązane z obiektami accelerator, lub array_view z dostępem z accelerator.

Środowisko wykonawcze języka C++ AMP automatycznie wybiera najlepsze domyślne access_type dla każdego accelerator, ale cechy wydajności (przepustowość i czas oczekiwania) pamięci współużytkowanej mogą być gorsze niż w przypadku dedykowanego (nieudostępnianego) akceleratora pamięci podczas odczytu z CPU, zapisu z CPU lub dla obu tych przypadków.Jeśli pamięć współużytkowana działa równie dobrze jak dedykowana pamięć dla odczytu i zapisu z procesora, środowisko uruchomieniowe domyślnie przyjmuje tryb access_type_read_write; w przeciwnym wypadku środowisko wykonawcze wybiera bardziej ostrożny domyślny tryb access_type i pozwala aplikacji go zastąpić, jeśli wzorce dostępu do pamięci jej jąder obliczeniowych odniosą korzyści z innego trybu access_type.

Poniższy przykład kodu pokazuje, jak ustalić, czy akcelerator domyślny obsługuje pamięć współużytkowaną, a następnie zastępuje domyślny typ dostępu i tworzy z niego 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 zawsze odzwierciedla default_cpu_access_type z accelerator, jest z nim skojarzony i zapewnia interfejs do nadpisania lub jej zmiany access_type.

Zmienianie akceleratora domyślnego

Akcelerator domyślny można zmienić, wywołując metodę accelerator::set_default.Akcelerator domyślny można zmienić tylko raz na wykonanie aplikacji i należy go zmienić przed wykonaniem jakiegokolwiek kodu na procesorze GPU.Wszystkie kolejne wywołania funkcji zmiany akceleratora zwracają wartośćfalse.Jeśli chcesz użyć innego akceleratora w wywołaniu parallel_for_each, przeczytaj sekcję „Używanie wielu akceleratorów” w niniejszym artykule.Poniższy przykład kodu ustawia akcelerator domyślny, który nie jest emulowany, nie jest podłączony do wyświetlania i obsługuje podwójną precyzję.

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

Używanie wielu akceleratorów

Można użyć wielu akceleratorów w aplikacji na dwa sposoby:

  • Można przekazać obiekty accelerator_view do wywołań metody parallel_for_each.

  • Można skonstruować obiekt array za pomocą określonego obiektu accelerator_view.Środowisko wykonawcze C+AMP wybierze obiekt accelerator_view z przechwyconych obiektów array w wyrażeniu lambda.

Akceleratory specjalne

Ścieżki urządzenia dla trzech akceleratorów specjalnych są dostępne jako właściwości klasy accelerator:

  • accelerator::direct3d_ref — Członek danych: Ten akcelerator jednowątkowy używa oprogramowania CPU do emulowania rodzajowej karty graficznej.Jest używany domyślnie do debugowania, ale nie jest użyteczny podczas produkcji, ponieważ jest wolniejszy niż akceleratory sprzętowe.Ponadto jest dostępny tylko w zestawie DirectX SDK i SDK systemu Windows i jest mało prawdopodobne, aby był zainstalowany na komputerach klientów.Aby uzyskać więcej informacji, zobacz Debugowanie kodu GPU.

  • accelerator::direct3d_warp — Członek danych: Akcelerator ten dostarcza rozwiązanie alternatywne do wykonywania kodu C++ AMP na wielordzeniowych procesorach, które używają rozszerzenia SSE (Streaming SIMD).

  • accelerator::cpu_accelerator — Członek danych: Można wykorzystać ten akcelerator do tworzenia tablic tymczasowych.Nie może wykonywać kodu C++ AMP.Aby uzyskać więcej informacji, zobacz wpis Tablice tymczasowe w bibliotece C++ AMP na blogu dotyczącym programowania równoległego w kodzie natywnym.

Współdziałanie

Środowisko wykonawcze języka C++ AMP wspiera współdziałanie między klasą accelerator_view a występującym w Direct3D interfejsem ID3D11Device.Metoda create_accelerator_view pobiera interfejs IUnknown i zwraca obiekt accelerator_view.Metoda get_device pobiera obiekt accelerator_view i zwraca interfejs IUknown.

Zobacz też

Informacje

accelerator — Klasa

accelerator_view — Klasa

Inne zasoby

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

Debugowanie kodu GPU