Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
È possibile usare l'acceleratore e le classi accelerator_view per specificare il dispositivo o l'emulatore in cui eseguire il codice AMP C++. Un sistema potrebbe avere diversi dispositivi o emulatori che differiscono in base alla quantità di memoria, al supporto della memoria condivisa, al supporto del debug o al supporto a precisione doppia. C++ Accelerated Massive Parallelism (C++ AMP) fornisce API che è possibile usare per esaminare gli acceleratori disponibili, impostarne uno come predefinito, specificare più accelerator_views per più chiamate a parallel_for_each ed eseguire attività di debug speciali.
Nota
Le intestazioni C++ AMP sono deprecate a partire da Visual Studio 2022 versione 17.0.
L'inclusione di eventuali intestazioni AMP genererà errori di compilazione. Definire _SILENCE_AMP_DEPRECATION_WARNINGS prima di includere eventuali intestazioni AMP per disattivare gli avvisi.
Uso dell'acceleratore predefinito
Il runtime C++ AMP seleziona un acceleratore predefinito, a meno che non si scriva codice per sceglierne uno specifico. Il runtime sceglie l'acceleratore predefinito come segue:
Se l'app è in esecuzione in modalità di debug, un acceleratore che supporta il debug.
In caso contrario, l'acceleratore specificato dalla
CPPAMP_DEFAULT_ACCELERATORvariabile di ambiente, se impostato.In caso contrario, un dispositivo non emulato.
In caso contrario, il dispositivo con la massima quantità di memoria disponibile.
In caso contrario, un dispositivo non collegato allo schermo.
Inoltre, il runtime specifica un access_type di access_type_auto per l'acceleratore predefinito. Ciò significa che l'acceleratore predefinito usa la memoria condivisa se è supportata e se le relative caratteristiche di prestazioni (larghezza di banda e latenza) sono note come la memoria dedicata (non condivisa).
È possibile determinare le proprietà dell'acceleratore predefinito creando l'acceleratore predefinito ed esaminandone le proprietà. Nell'esempio di codice seguente viene stampato il percorso, la quantità di memoria dell'acceleratore, il supporto della memoria condivisa, il supporto a precisione doppia e il supporto limitato a precisione doppia dell'acceleratore predefinito.
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";
}
variabile di ambiente CPPAMP_DEFAULT_ACCELERATOR
È possibile impostare la CPPAMP_DEFAULT_ACCELERATOR variabile di ambiente per specificare l'acceleratore accelerator::device_path predefinito. Il percorso è dipendente dall'hardware. Il codice seguente usa la accelerator::get_all funzione per recuperare un elenco degli acceleratori disponibili e quindi visualizza il percorso e le caratteristiche di ogni acceleratore.
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";
}
}
Selezione di un acceleratore
Per selezionare un acceleratore, usare il accelerator::get_all metodo per recuperare un elenco degli acceleratori disponibili e quindi selezionarne uno in base alle relative proprietà. Questo esempio mostra come selezionare l'acceleratore con la maggior quantità di memoria:
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";
}
Nota
Uno degli acceleratori restituiti da accelerator::get_all è l'acceleratore di CPU. Non è possibile eseguire codice sull'acceleratore cpu. Per filtrare l'acceleratore della CPU, confrontare il valore della proprietà device_path dell'acceleratore restituito da accelerator::get_all con il valore dell'acceleratore ::cpu_accelerator. Per altre informazioni, vedere la sezione "Acceleratori speciali" in questo articolo.
Memoria condivisa
La memoria condivisa è la memoria a cui è possibile accedere sia la CPU che l'acceleratore. L'uso della memoria condivisa elimina o riduce significativamente il sovraccarico di copia dei dati tra la CPU e l'acceleratore. Anche se la memoria è condivisa, non è possibile accedervi contemporaneamente sia dalla CPU che dall'acceleratore e in questo modo causa un comportamento indefinito. La proprietà dell'acceleratore supports_cpu_shared_memory restituisce true se l'acceleratore supporta la memoria condivisa, mentre la proprietà default_cpu_access_type ottiene il tipo di accesso predefinito per la memoria allocata su , come ad esempio gli accelerator associati con o gli oggetti accelerator a cui si accede su array_view.
Il runtime C++ AMP sceglie automaticamente il valore predefinito access_type migliore per ogni accelerator, ma le caratteristiche delle prestazioni (larghezza di banda e latenza) della memoria condivisa possono essere peggiori rispetto a quelle della memoria dell'acceleratore dedicata (non condivisa) durante la lettura dalla CPU, la scrittura dalla CPU o entrambi. Se la memoria condivisa esegue e memoria dedicata per la lettura e la scrittura dalla CPU, il runtime usa access_type_read_writeper impostazione predefinita ; in caso contrario, il runtime sceglie un valore predefinito access_typepiù conservativo e consente all'app di eseguirne l'override se i modelli di accesso alla memoria dei kernel di calcolo traggono vantaggio da un diverso access_type.
Nell'esempio di codice seguente viene illustrato come determinare se l'acceleratore predefinito supporta la memoria condivisa e quindi esegue l'override del tipo di accesso predefinito e ne crea uno 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;
}
Un accelerator_view oggetto riflette sempre l'oggetto default_cpu_access_type dell'oggetto accelerator a cui è associato e non fornisce alcuna interfaccia per eseguire l'override o modificare il relativo access_typeoggetto .
Modifica dell'acceleratore predefinito
È possibile modificare l'acceleratore predefinito chiamando il accelerator::set_default metodo . È possibile modificare l'acceleratore predefinito una sola volta per ogni esecuzione dell'app ed è necessario modificarlo prima dell'esecuzione di qualsiasi codice nella GPU. Tutte le chiamate di funzione successive per modificare l'acceleratore restituiscono false. Per usare un acceleratore diverso in una chiamata a parallel_for_each, leggere la sezione "Uso di più acceleratori" in questo articolo. L'esempio di codice seguente imposta l'acceleratore predefinito su un acceleratore non emulato, non è connesso a uno schermo e supporta la precisione doppia.
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;
}
Uso di più acceleratori
Esistono due modi per usare più acceleratori nell'app:
È possibile passare oggetti alle chiamate
accelerator_viewal metodo parallel_for_each.È possibile costruire un oggetto matrice usando un oggetto specifico
accelerator_view. Il runtime C++ AMP rileverà l'oggettoaccelerator_viewdall'oggetto matrice acquisito nell'espressione lambda.
Acceleratori speciali
I percorsi dei dispositivi di tre acceleratori speciali sono disponibili come proprietà della accelerator classe :
accelerator::direct3d_ref Data Member: Questo acceleratore a thread singolo utilizza il software della CPU per emulare una scheda grafica generica. Viene usato per impostazione predefinita per il debug, ma non è utile nell'ambiente di produzione perché è più lento rispetto agli acceleratori hardware. Inoltre, è disponibile solo in DirectX SDK e Windows SDK ed è improbabile che sia installato nei computer dei clienti. Per altre informazioni, vedere Debug del codice GPU.
Membro dati accelerator::direct3d_warp: questo acceleratore offre una soluzione di fallback per l'esecuzione di codice AMP C++ su CPU multi-core che utilizzano le estensioni SIMD Streaming (SSE).
accelerator::cpu_accelerator membro dei dati: puoi usare questo acceleratore per configurare le matrici di staging. Non è possibile eseguire codice C++ AMP. Per ulteriori informazioni, vedere il post Le matrici di staging in C++ AMP sul blog Programmazione Parallela in Codice Nativo.
Interoperabilità
Il runtime C++ AMP supporta l'interoperabilità tra la accelerator_view classe e l'interfaccia Direct3D ID3D11Device. Il metodo create_accelerator_view accetta un'interfaccia IUnknown e restituisce un accelerator_view oggetto . Il metodo get_device accetta un accelerator_view oggetto e restituisce un'interfaccia IUnknown .
Vedi anche
C++ AMP (parallelismo massivo accelerato C++)
Debug del codice GPU
Classe accelerator_view