Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Opmerking
C++ AMP-headers worden afgeschaft vanaf Visual Studio 2022 versie 17.0.
Als u AMP-headers opneemt, zullen er buildfouten optreden. Definieer _SILENCE_AMP_DEPRECATION_WARNINGS voordat u AMP-headers opneemt om de waarschuwingen te onderdrukken.
C++ Accelerated Massive Parallelism (C++ AMP) versnelt de uitvoering van C++-code door gebruik te maken van gegevensparallel hardware zoals een GPU (Graphics Processing Unit) op een discrete grafische kaart. Met behulp van C++ AMP kunt u multidimensionale gegevensalgoritmen codeeren, zodat de uitvoering kan worden versneld met behulp van parallelle uitvoering op heterogene hardware. Het C++ AMP-programmeermodel bevat multidimensionale matrices, indexering, geheugenoverdracht, tegeling en een wiskundige functiebibliotheek. U kunt C++ AMP-taalextensies gebruiken om te bepalen hoe gegevens worden verplaatst van de CPU naar de GPU en terug, zodat u de prestaties kunt verbeteren.
Systeemvereisten
Windows 7 of hoger
Windows Server 2008 R2 tot en met Visual Studio 2019.
DirectX 11-hardware met Feature Level 11.0 of hoger
Voor foutopsporing in de softwareemulator is Windows 8 of Windows Server 2012 vereist. Voor foutopsporing op de hardware moet u de stuurprogramma's voor uw grafische kaart installeren. Zie Debugging GPU-code voor meer informatie.
Opmerking: AMP wordt momenteel niet ondersteund in ARM64.
Introductie
In de volgende twee voorbeelden ziet u de primaire onderdelen van C++ AMP. Stel dat u de bijbehorende elementen van twee eendimensionale matrices wilt toevoegen. U kunt bijvoorbeeld {1, 2, 3, 4, 5} en {6, 7, 8, 9, 10} toevoegen om {7, 9, 11, 13, 15} te verkrijgen. Zonder C++ AMP te gebruiken, kunt u de volgende code schrijven om de getallen toe te voegen en de resultaten weer te geven.
#include <iostream>
void StandardMethod() {
int aCPP[] = {1, 2, 3, 4, 5};
int bCPP[] = {6, 7, 8, 9, 10};
int sumCPP[5];
for (int idx = 0; idx < 5; idx++)
{
sumCPP[idx] = aCPP[idx] + bCPP[idx];
}
for (int idx = 0; idx < 5; idx++)
{
std::cout << sumCPP[idx] << "\n";
}
}
De belangrijke onderdelen van de code zijn als volgt:
Gegevens: De gegevens bestaan uit drie matrices. Ze hebben allemaal dezelfde rang (één) en lengte (vijf).
Iteratie: De eerste
forlus biedt een mechanisme voor het herhalen van de elementen in de matrices. De code die u wilt uitvoeren om de som te berekenen, bevindt zich in het eersteforblok.Index: De
idxvariabele heeft toegang tot de afzonderlijke elementen van de matrices.
Met C++ AMP kunt u in plaats daarvan de volgende code schrijven.
#include <amp.h>
#include <iostream>
using namespace concurrency;
const int size = 5;
void CppAmpMethod() {
int aCPP[] = {1, 2, 3, 4, 5};
int bCPP[] = {6, 7, 8, 9, 10};
int sumCPP[size];
// Create C++ AMP objects.
array_view<const int, 1> a(size, aCPP);
array_view<const int, 1> b(size, bCPP);
array_view<int, 1> sum(size, sumCPP);
sum.discard_data();
parallel_for_each(
// Define the compute domain, which is the set of threads that are created.
sum.extent,
// Define the code to run on each thread on the accelerator.
[=](index<1> idx) restrict(amp) {
sum[idx] = a[idx] + b[idx];
}
);
// Print the results. The expected output is "7, 9, 11, 13, 15".
for (int i = 0; i < size; i++) {
std::cout << sum[i] << "\n";
}
}
Dezelfde basiselementen zijn aanwezig, maar C++ AMP-constructies worden gebruikt:
Gegevens: U gebruikt C++-matrices om drie C++ AMP-array_view-objecten samen te stellen. U geeft vier waarden op om een
array_viewobject samen te stellen: de gegevenswaarden, de rang, het elementtype en de lengte van hetarray_viewobject in elke dimensie. De rang en het type worden doorgegeven als typeparameters. De gegevens en lengte worden doorgegeven als constructorparameters. In dit voorbeeld is de C++-matrix die wordt doorgegeven aan de constructor ééndimensionaal. De rang en lengte worden gebruikt om de rechthoekige vorm van de gegevens in hetarray_viewobject samen te stellen en de gegevenswaarden worden gebruikt om de matrix te vullen. De runtimebibliotheek bevat ook de matrixklasse, die een interface heeft die lijkt op dearray_viewklasse en verderop in dit artikel wordt besproken.Iteratie: De parallel_for_each-functie (C++ AMP) biedt een mechanisme voor het doorlopen van de gegevenselementen of het rekendomein. In dit voorbeeld wordt het rekendomein opgegeven door
sum.extent. De code die u wilt uitvoeren, bevindt zich in een lambda-expressie of kernelfunctie. Hiermeerestrict(amp)wordt aangegeven dat alleen de subset van de C++-taal die C++ AMP kan versnellen, wordt gebruikt.Index: de variabele indexklasse ,
idxwordt gedeclareerd met een rang van één die overeenkomt met de rang van hetarray_viewobject. Met behulp van de index hebt u toegang tot de afzonderlijke elementen van dearray_viewobjecten.
Gegevens vormgeven en indexeren: index en omvang
U moet de gegevenswaarden definiëren en de vorm van de gegevens declareren voordat u de kernelcode kunt uitvoeren. Alle gegevens worden gedefinieerd als een matrix (rechthoekig) en u kunt de matrix definiëren om een willekeurige rang (aantal dimensies) te hebben. De gegevens kunnen elke grootte hebben in een van de dimensies.
indexklasse
De indexklasse geeft een locatie in het array of array_view object op door de verschuiving van de oorsprong in elke dimensie in één object in te kapselen. Wanneer u een locatie in de matrix opent, geeft u een index object door aan de indexeringsoperator, []in plaats van een lijst met gehele getallen. U kunt de elementen in elke dimensie openen met behulp van de operator matrix::operator() of de operator array_view::operator().
In het volgende voorbeeld wordt een eendimensionale index gemaakt die het derde element in een eendimensionaal array_view object aangeeft. De index wordt gebruikt om het derde element in het array_view object af te drukken. De uitvoer is 3.
int aCPP[] = {1, 2, 3, 4, 5};
array_view<int, 1> a(5, aCPP);
index<1> idx(2);
std::cout << a[idx] << "\n";
// Output: 3
In het volgende voorbeeld wordt een tweedimensionale index gemaakt waarmee het element wordt opgegeven waarin de rij = 1 en de kolom = 2 in een tweedimensionaal array_view object staan. De eerste parameter in de index constructor is het rijonderdeel en de tweede parameter is het kolomonderdeel. De uitvoer is 6.
int aCPP[] = {1, 2, 3, 4, 5, 6};
array_view<int, 2> a(2, 3, aCPP);
index<2> idx(1, 2);
std::cout <<a[idx] << "\n";
// Output: 6
In het volgende voorbeeld wordt een driedimensionale index gemaakt die het element aangeeft waarbij de diepte = 0, de rij = 1 en de kolom = 3 in een driedimensionaal array_view object zijn opgegeven. U ziet dat de eerste parameter het diepteonderdeel is, de tweede parameter het rijonderdeel is en de derde parameter het kolomonderdeel is. De uitvoer is 8.
int aCPP[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
array_view<int, 3> a(2, 3, 4, aCPP);
// Specifies the element at 3, 1, 0.
index<3> idx(0, 1, 3);
std::cout << a[idx] << "\n";
// Output: 8
Extentieklasse
De omvangklasse bepaalt de lengte van de gegevens in elke dimensie van het array of array_view object. U kunt een omvang maken en deze gebruiken om een array of array_view object te maken. U kunt ook de omvang van een bestaand array of array_view object ophalen. In het volgende voorbeeld wordt de lengte van de omvang in elke dimensie van een array_view object afgedrukt.
int aCPP[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// There are 3 rows and 4 columns, and the depth is two.
array_view<int, 3> a(2, 3, 4, aCPP);
std::cout << "The number of columns is " << a.extent[2] << "\n";
std::cout << "The number of rows is " << a.extent[1] << "\n";
std::cout << "The depth is " << a.extent[0] << "\n";
std::cout << "Length in most significant dimension is " << a.extent[0] << "\n";
In het volgende voorbeeld wordt een array_view object gemaakt dat dezelfde dimensies heeft als het object in het vorige voorbeeld, maar in dit voorbeeld wordt een extent object gebruikt in plaats van expliciete parameters in de array_view constructor te gebruiken.
int aCPP[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
extent<3> e(2, 3, 4);
array_view<int, 3> a(e, aCPP);
std::cout << "The number of columns is " << a.extent[2] << "\n";
std::cout << "The number of rows is " << a.extent[1] << "\n";
std::cout << "The depth is " << a.extent[0] << "\n";
Gegevens verplaatsen naar de accelerator: array en array_view
Twee gegevenscontainers die worden gebruikt om gegevens naar de accelerator te verplaatsen, worden gedefinieerd in de runtimebibliotheek. Dit zijn de matrixklasse en de array_view Klasse. De array klasse is een containerklasse die een diepe kopie van de gegevens maakt wanneer het object wordt samengesteld. De array_view klasse is een wrapper-klasse waarmee de gegevens worden gekopieerd wanneer de kernelfunctie toegang heeft tot de gegevens. Wanneer de gegevens nodig zijn op het bronapparaat, worden de gegevens terug gekopieerd.
arrayklasse
Wanneer een array object wordt samengesteld, wordt een diepe kopie van de gegevens op de accelerator gemaakt als u een constructor gebruikt die een aanwijzer bevat naar de gegevensset. De kernelfunctie wijzigt de kopie op de accelerator. Wanneer de uitvoering van de kernelfunctie is voltooid, moet u de gegevens terug kopiëren naar de brongegevensstructuur. In het volgende voorbeeld wordt elk element in een vector vermenigvuldigd met 10. Nadat de kernelfunctie is voltooid, wordt deze vector conversion operator gebruikt om de gegevens terug te kopiëren naar het vectorobject.
std::vector<int> data(5);
for (int count = 0; count <5; count++)
{
data[count] = count;
}
array<int, 1> a(5, data.begin(), data.end());
parallel_for_each(
a.extent,
[=, &a](index<1> idx) restrict(amp) {
a[idx] = a[idx]* 10;
});
data = a;
for (int i = 0; i < 5; i++)
{
std::cout << data[i] << "\n";
}
array_view-klasse
Het array_view heeft bijna dezelfde leden als de array klasse, maar het onderliggende gedrag is niet hetzelfde. Gegevens die worden doorgegeven aan de array_view constructor, worden niet gerepliceerd op de GPU, net als bij een array constructor. In plaats daarvan worden de gegevens gekopieerd naar de accelerator wanneer de kernelfunctie wordt uitgevoerd. Als u daarom twee array_view objecten maakt die dezelfde gegevens gebruiken, verwijzen beide array_view objecten naar dezelfde geheugenruimte. Wanneer u dit doet, moet u alle multithreaded-toegang synchroniseren. Het belangrijkste voordeel van het gebruik van de array_view klasse is dat gegevens alleen worden verplaatst als dit nodig is.
Vergelijking van matrix en array_view
De volgende tabel bevat een overzicht van de overeenkomsten en verschillen tussen de array en array_view klassen.
| Beschrijving | arrayklasse | array_view klasse |
|---|---|---|
| Wanneer rang wordt bepaald | Tijdens het compileren. | Tijdens het compileren. |
| Wanneer de omvang wordt bepaald | Tijdens uitvoering. | Tijdens uitvoering. |
| Vorm | Rechthoekig. | Rechthoekig. |
| Gegevensopslag | Is een gegevenscontainer. | Is een gegevenswrapper. |
| Kopiëren | Expliciete en diepe kopie maken bij het definiëren. | Impliciete kopie wanneer deze wordt geopend door de kernelfunctie. |
| Gegevens ophalen | Door de matrixgegevens terug te kopiëren naar een object op de CPU-thread. | Door directe toegang tot het array_view object of door de methode array_view::sync aan te roepen om toegang te blijven krijgen tot de gegevens in de oorspronkelijke container. |
Gedeeld geheugen met array en array_view
Gedeeld geheugen is geheugen dat toegankelijk is voor zowel de CPU als de accelerator. Het gebruik van gedeeld geheugen elimineert of vermindert de overhead van het kopiëren van gegevens tussen de CPU en de accelerator aanzienlijk. Hoewel het geheugen wordt gedeeld, kan het niet gelijktijdig worden geopend door zowel de CPU als de accelerator, en zorgt dit voor niet-gedefinieerd gedrag.
array objecten kunnen worden gebruikt om nauwkeurige controle op te geven over het gebruik van gedeeld geheugen als de bijbehorende accelerator dit ondersteunt. Of een accelerator gedeeld geheugen ondersteunt, wordt bepaald door de supports_cpu_shared_memory eigenschap van de accelerator, die retourneert true wanneer gedeeld geheugen wordt ondersteund. Als gedeeld geheugen wordt ondersteund, wordt de standaard-access_type Opsomming voor geheugentoewijzingen op de accelerator bepaald door de default_cpu_access_type eigenschap. Standaard nemen array en array_view objecten dezelfde access_type aan als het primaire gekoppelde accelerator.
Door de eigenschap cpu_access_type van een gegevenslid expliciet in te stellen, kunt u fijnmazige controle uitoefenen over hoe gedeeld geheugen wordt gebruikt, zodat u de app kunt optimaliseren voor de prestatiekenmerken van de hardware, gebaseerd op de geheugentoegangspatronen van zijn rekenkernels. Een array_view weerspiegelt hetzelfde cpu_access_type als de array waarmee het is geassocieerd; of, als de array_view zonder gegevensbron is samengesteld, weerspiegelt zijn access_type de omgeving die ervoor zorgt dat het als eerste opslag toewijst. Dat wil zeggen, als het eerst wordt geopend door de host (CPU), gedraagt het zich alsof het is gemaakt via een CPU-databron en deelt het de access_type van de accelerator_view die wordt geassocieerd door capture; echter, als het eerst wordt geopend door een accelerator_view, gedraagt het zich alsof het is gemaakt via een op die array gemaakte accelerator_view en deelt het de array van access_type.
In het volgende codevoorbeeld ziet u hoe u kunt bepalen of de standaardversneller gedeeld geheugen ondersteunt en vervolgens verschillende matrices met verschillende cpu_access_type configuraties maakt.
#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.default_cpu_access_type = access_type_read_write
// Create an accelerator_view from the default accelerator. The
// accelerator_view inherits its default_cpu_access_type from acc.
accelerator_view acc_v = acc.default_view;
// Create an extent object to size the arrays.
extent<1> ex(10);
// Input array that can be written on the CPU.
array<int, 1> arr_w(ex, acc_v, access_type_write);
// Output array that can be read on the CPU.
array<int, 1> arr_r(ex, acc_v, access_type_read);
// Read-write array that can be both written to and read from on the CPU.
array<int, 1> arr_rw(ex, acc_v, access_type_read_write);
}
Code uitvoeren op gegevens: parallel_for_each
De functie parallel_for_each definieert de code die u op de accelerator wilt uitvoeren op de gegevens in het array of array_view object. Bekijk de volgende code uit de introductie van dit onderwerp.
#include <amp.h>
#include <iostream>
using namespace concurrency;
void AddArrays() {
int aCPP[] = {1, 2, 3, 4, 5};
int bCPP[] = {6, 7, 8, 9, 10};
int sumCPP[5] = {0, 0, 0, 0, 0};
array_view<int, 1> a(5, aCPP);
array_view<int, 1> b(5, bCPP);
array_view<int, 1> sum(5, sumCPP);
parallel_for_each(
sum.extent,
[=](index<1> idx) restrict(amp)
{
sum[idx] = a[idx] + b[idx];
}
);
for (int i = 0; i < 5; i++) {
std::cout << sum[i] << "\n";
}
}
De parallel_for_each methode heeft twee argumenten, een rekendomein en een lambda-expressie.
Het rekendomein is een extent object of een tiled_extent object dat de set threads definieert die moet worden gemaakt voor parallelle uitvoering. Er wordt één thread gegenereerd voor elk element in het rekendomein. In dit geval is het extent object eendimensionaal en heeft vijf elementen. Daarom worden er vijf threads gestart.
De lambda-expressie definieert de code die op elke thread moet worden uitgevoerd. De captureclausule, [=], geeft aan dat de hoofdtekst van de lambda-expressie toegang heeft tot alle vastgelegde variabelen bij waarde, die in dit geval a, b, en sum zijn. In dit voorbeeld maakt de lijst met parameters een eendimensionale index variabele met de naam idx. De waarde van de idx[0] is 0 in de eerste thread en neemt met één toe in elke volgende thread. Hiermee restrict(amp) wordt aangegeven dat alleen de subset van de C++-taal die C++ AMP kan versnellen, wordt gebruikt. De beperkingen voor functies met de beperkingsaanpassing worden beschreven in restrict (C++ AMP). Zie de syntaxis van lambda-expressie voor meer informatie.
De lambda-expressie kan de code bevatten die moet worden uitgevoerd of kan een afzonderlijke kernelfunctie aanroepen. De kernelfunctie moet de restrict(amp) wijzigingsfunctie bevatten. Het volgende voorbeeld is gelijk aan het vorige voorbeeld, maar roept een afzonderlijke kernelfunctie aan.
#include <amp.h>
#include <iostream>
using namespace concurrency;
void AddElements(
index<1> idx,
array_view<int, 1> sum,
array_view<int, 1> a,
array_view<int, 1> b) restrict(amp) {
sum[idx] = a[idx] + b[idx];
}
void AddArraysWithFunction() {
int aCPP[] = {1, 2, 3, 4, 5};
int bCPP[] = {6, 7, 8, 9, 10};
int sumCPP[5] = {0, 0, 0, 0, 0};
array_view<int, 1> a(5, aCPP);
array_view<int, 1> b(5, bCPP);
array_view<int, 1> sum(5, sumCPP);
parallel_for_each(
sum.extent,
[=](index<1> idx) restrict(amp) {
AddElements(idx, sum, a, b);
}
);
for (int i = 0; i < 5; i++) {
std::cout << sum[i] << "\n";
}
}
Codeversnelling: tegels en obstakels
U kunt extra versnelling krijgen met behulp van tiling. Met de tegel worden de threads verdeeld in gelijke rechthoekige subsets of tegels. U bepaalt de juiste tegelgrootte op basis van uw gegevensset en het algoritme dat u codeert. Voor elke thread hebt u toegang tot de globale locatie van een gegevenselement ten opzichte van het geheel array of array_view toegang tot de lokale locatie ten opzichte van de tegel. Het gebruik van de lokale indexwaarde vereenvoudigt uw code omdat u de code niet hoeft te schrijven om indexwaarden van globaal naar lokaal te vertalen. Als u gebruik wilt maken van tegels, roept u de methode extent::tile aan op het berekeningsdomein in de parallel_for_each methode en gebruikt u een tiled_index-object in de lambda-expressie.
In typische toepassingen zijn de elementen in een tegel op een of andere manier gerelateerd en moet de code waarden op de tegel openen en bijhouden. Gebruik het trefwoord tile_static en de tile_barrier::wait-methode om dit te bereiken. Een variabele met het trefwoord tile_static heeft een bereik over een hele tegel en er wordt een exemplaar van de variabele gemaakt voor elke tegel. U moet de synchronisatie van de toegang door tegelthreads tot de variabele afhandelen. De methode tile_barrier::wait stopt de uitvoering van de huidige thread totdat alle threads in de tegel de aanroep naar tile_barrier::waithebben bereikt. U kunt dus waarden op de tegel verzamelen met behulp van tile_static variabelen. Vervolgens kunt u alle berekeningen voltooien waarvoor toegang tot alle waarden is vereist.
Het volgende diagram vertegenwoordigt een tweedimensionale matrix met steekproevengegevens die in tegels zijn gerangschikt.
In het volgende codevoorbeeld worden de steekproefgegevens uit het vorige diagram gebruikt. De code vervangt elke waarde in de tegel door het gemiddelde van de waarden in de tegel.
// Sample data:
int sampledata[] = {
2, 2, 9, 7, 1, 4,
4, 4, 8, 8, 3, 4,
1, 5, 1, 2, 5, 2,
6, 8, 3, 2, 7, 2};
// The tiles:
// 2 2 9 7 1 4
// 4 4 8 8 3 4
//
// 1 5 1 2 5 2
// 6 8 3 2 7 2
// Averages:
int averagedata[] = {
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
};
array_view<int, 2> sample(4, 6, sampledata);
array_view<int, 2> average(4, 6, averagedata);
parallel_for_each(
// Create threads for sample.extent and divide the extent into 2 x 2 tiles.
sample.extent.tile<2,2>(),
[=](tiled_index<2,2> idx) restrict(amp) {
// Create a 2 x 2 array to hold the values in this tile.
tile_static int nums[2][2];
// Copy the values for the tile into the 2 x 2 array.
nums[idx.local[1]][idx.local[0]] = sample[idx.global];
// When all the threads have executed and the 2 x 2 array is complete, find the average.
idx.barrier.wait();
int sum = nums[0][0] + nums[0][1] + nums[1][0] + nums[1][1];
// Copy the average into the array_view.
average[idx.global] = sum / 4;
});
for (int i = 0; i <4; i++) {
for (int j = 0; j <6; j++) {
std::cout << average(i,j) << " ";
}
std::cout << "\n";
}
// Output:
// 3 3 8 8 3 3
// 3 3 8 8 3 3
// 5 5 2 2 4 4
// 5 5 2 2 4 4
Wiskundige bibliotheken
C++ AMP bevat twee wiskundige bibliotheken. De dubbel-precisiebibliotheek in de Concurrency::precise_math-naamruimte biedt ondersteuning voor dubbel-precisiefuncties. Het biedt ook ondersteuning voor functies met één precisie, hoewel ondersteuning voor dubbele precisie op de hardware nog steeds vereist is. Het voldoet aan de C99-specificatie (ISO/IEC 9899). De accelerator moet volledige dubbele precisie ondersteunen. U kunt vaststellen wanneer dit het geval is door de waarde van het accelerator::supports_double_precision Gegevenslid te controleren. De snelle wiskundebibliotheek, in de Concurrency::fast_math-naamruimte, bevat een andere set wiskundefuncties. Deze functies, die alleen float operanden ondersteunen, worden sneller uitgevoerd, maar zijn niet zo nauwkeurig als die in de wiskundige bibliotheek met dubbele precisie. De functies bevinden zich in het <headerbestand amp_math.h> en alle functies worden gedeclareerd met restrict(amp). De functies in het <cmath-headerbestand> worden geïmporteerd in zowel de fast_math als de precise_math naamruimten. Het restrict trefwoord wordt gebruikt om de <cmath-versie> en de C++ AMP-versie te onderscheiden. Met de volgende code wordt de logaritme met grondtal 10 berekend, met behulp van de snelle methode, van elke waarde die zich in het rekendomein bevindt.
#include <amp.h>
#include <amp_math.h>
#include <iostream>
using namespace concurrency;
void MathExample() {
double numbers[] = { 1.0, 10.0, 60.0, 100.0, 600.0, 1000.0 };
array_view<double, 1> logs(6, numbers);
parallel_for_each(
logs.extent,
[=] (index<1> idx) restrict(amp) {
logs[idx] = concurrency::fast_math::log10(numbers[idx]);
}
);
for (int i = 0; i < 6; i++) {
std::cout << logs[i] << "\n";
}
}
Grafische bibliotheek
C++ AMP bevat een grafische bibliotheek die is ontworpen voor versneld programmeren van afbeeldingen. Deze bibliotheek wordt alleen gebruikt op apparaten die systeemeigen grafische functionaliteit ondersteunen. De methoden bevinden zich in de Concurrency::graphics Namespace en staan in het headerbestand <amp_graphics.h>. De belangrijkste onderdelen van de grafische bibliotheek zijn:
texture Class: U kunt de structuurklasse gebruiken om patronen te maken op basis van het geheugen of vanuit een bestand. Patronen lijken op matrices omdat ze gegevens bevatten en ze lijken op containers in de standaardbibliotheek van C++ met betrekking tot toewijzing en kopieerconstructie. Zie C++ Standard Library Containers voor meer informatie. De sjabloonparameters voor de
textureklasse zijn het elementtype en de rang. De rang kan 1, 2 of 3 zijn. Het elementtype kan een van de korte vectortypen zijn die verderop in dit artikel worden beschreven.writeonly_texture_view Klasse: biedt alleen schrijftoegang tot een textuur.
Short Vector Library: Definieert een set van korte vectortypen met lengtes van 2, 3 en 4 die zijn gebaseerd op
int,uint,float,double, norm of unorm.
UWP-apps (Universele Windows Platform)
Net als andere C++-bibliotheken kunt u C++ AMP gebruiken in uw UWP-apps. In deze artikelen wordt beschreven hoe u C++ AMP-code opneemt in apps die zijn gemaakt met C++, C#, Visual Basic of JavaScript:
Overzicht: Een eenvoudig Windows Runtime-onderdeel maken in C++ en het aanroepen vanuit JavaScript
Bing Maps Trip Optimizer, een Window Store-app in JavaScript en C++
C++ AMP en Gelijktijdigheid visualiseren
De Concurrency Visualizer biedt ondersteuning voor het analyseren van de performance van C++ AMP-code. In deze artikelen worden de volgende functies beschreven:
Aanbevelingen voor prestaties
Modulus en deling van niet-ondertekende gehele getallen hebben aanzienlijk betere prestaties dan modulus en deling van ondertekende gehele getallen. U wordt aangeraden indien mogelijk niet-ondertekende gehele getallen te gebruiken.
Zie ook
C++ AMP (C++ Versneld massaal parallellisme)
Syntaxis van lambda-expressie
Referentie (C++ AMP)
Parallel programmeren in systeemeigen codeblog