C ++

GPU programmeerimine C ++ abil

GPU programmeerimine C ++ abil

Ülevaade

Selles juhendis uurime GP-ga programmeerimise jõudu koos C-ga++. Arendajad võivad C ++ abil oodata uskumatut jõudlust ja juurdepääs GPU fenomenaalsele jõule madala tasemega keelega võib anda mõned kõige kiiremini kasutatavad arvutused.

Nõuded

Kuigi iga masin, mis suudab käitada Linuxi kaasaegset versiooni, võib toetada C ++ kompilaatorit, vajate selle harjutuse järgimiseks NVIDIA-põhist GPU-d. Kui teil pole GPU-d, saate GPU-ga töötava eksemplari Amazon Web Servicesis või mõnes muus valitud pilvepakkujas üles keerata.

Kui valite füüsilise masina, veenduge, et installiksite NVIDIA varalised draiverid. Juhised leiate siit: https: // linuxhint.com / install-nvidia-drivers-linux /

Lisaks draiverile vajate CUDA tööriistakomplekti. Selles näites kasutame Ubuntu 16.04 LTS, kuid enamiku peamiste distributsioonide jaoks on saadaval allalaaditavad failid järgmisel URL-il: https: // developer.nvidia.com / cuda-downloads

Ubuntu jaoks valiksite .deb-põhine allalaadimine. Allalaaditud failil pole a .deb laiendus vaikimisi, nii et ma soovitan selle ümber nimetada .deb lõpus. Seejärel saate installida:

sudo dpkg -i paketi nimi.deb

Tõenäoliselt palutakse teil installida GPG-võti ja kui jah, järgige selleks antud juhiseid.

Kui olete seda teinud, värskendage oma hoidlaid:

sudo apt-get värskendus
sudo apt-get install cuda -y

Kui see on tehtud, soovitan taaskäivitada, et kõik oleks korralikult laaditud.

GPU arendamise eelised

Protsessorid töötlevad paljusid erinevaid sisendeid ja väljundeid ning sisaldavad suurt valikut funktsioone, et mitte ainult tegeleda paljude programmivajadustega, vaid ka mitmesuguste riistvarakonfiguratsioonide haldamiseks. Nad tegelevad ka mälu, vahemällu salvestamise, süsteemibussi, segmentimise ja IO funktsioonidega, muutes need kõigi ametite pistikupesaks.

GPU-d on vastupidised - need sisaldavad palju üksikuid protsessoreid, mis on keskendunud väga lihtsatele matemaatilistele funktsioonidele. Seetõttu töötlevad nad ülesandeid mitu korda kiiremini kui protsessorid. Spetsialiseerudes skalaarfunktsioonidele (funktsioon, mis võtab ühe või mitu sisendit, kuid tagastab ainult ühe väljundi), saavutavad nad äärmiselt suure jõudluse äärmise spetsialiseerumise hinnaga.

Koodinäide

Näitekoodis lisame vektorid kokku. Kiiruse võrdlemiseks olen lisanud koodi CPU ja GPU versiooni.
gpu-näide.cpp sisu allpool:

#include "cuda_runtime.h "
# kaasata
# kaasata
# kaasata
# kaasata
# kaasata
typedef std :: chrono :: high_resolution_clock Kell;
#define ITER 65535
// Funktsiooni vektori lisamise protsessori versioon
void vector_add_cpu (int * a, int * b, int * c, int n)
int i;
// Lisage vektorielemendid a ja b vektorisse c
jaoks (i = 0; i < n; ++i)
c [i] = a [i] + b [i];


// GPU versioon vektori lisamise funktsioonist
__global__ void vector_add_gpu (int * gpu_a, int * gpu_b, int * gpu_c, int n)
int i = threadIdx.x;
// Tsükli jaoks pole vaja, kuna CUDA käitusaeg
// lõimib selle ITERi korda
gpu_c [i] = gpu_a [i] + gpu_b [i];

int main ()
int * a, * b, * c;
int * gpu_a, * gpu_b, * gpu_c;
a = (int *) malloc (ITER * (int) suurus);
b = (int *) malloc (ITER * (int) suurus);
c = (int *) malloc (ITER * (int) suurus);
// Vajame GPU-le ligipääsetavaid muutujaid,
// nii pakub neid cudaMallocManaged
cudaMallocManaged (& gpu_a, ITER * sizeof (int));
cudaMallocManaged (& gpu_b, ITER * sizeof (int));
cudaMallocManaged (& gpu_c, ITER * sizeof (int));
jaoks (int i = 0; i < ITER; ++i)
a [i] = i;
b [i] = i;
c [i] = i;

// Helistage protsessori funktsioonile ja ajastage see
auto cpu_start = Kell :: nüüd ();
vektor_add_cpu (a, b, c, ITER);
auto cpu_end = Kell :: nüüd ();
std :: cout << "vector_add_cpu: "
<< std::chrono::duration_cast(cpu_end - cpu_start).loenda ()
<< " nanoseconds.\n";
// Helistage GPU funktsioonile ja ajastage see
// Kolmekordse nurga pidurid on CUDA käituse laiendus, mis võimaldab
// edastatava CUDA kerneli kõne parameetrid.
// Selles näites edastame ühe lõimeploki ITER-lõimedega.
auto gpu_start = Kell :: nüüd ();
vector_add_gpu <<<1, ITER>>> (gpu_a, gpu_b, gpu_c, ITER);
cudaDeviceSynchronize ();
auto gpu_end = Kell :: nüüd ();
std :: cout << "vector_add_gpu: "
<< std::chrono::duration_cast(gpu_end - gpu_start).loenda ()
<< " nanoseconds.\n";
// Vabastage GPU-funktsioonil põhinevad mälujaotused
cudaFree (a);
cudaFree (b);
cudaFree (c);
// Vabastage protsessori funktsioonil põhinevad mälujaotused
tasuta (a);
vaba (b);
vaba (c);
tagastama 0;

Makefile sisu allpool:

INC = -I / usr / local / cuda / include
NVCC = / usr / local / cuda / bin / nvcc
NVCC_OPT = -std = c ++ 11
kõik:
$ (NVCC) $ (NVCC_OPT) gpu-näide.cpp -o gpu-näide
puhas:
-rm -f gpu-näide

Näite käitamiseks koostage see:

tegema

Seejärel käivitage programm:

./ gpu-näide

Nagu näete, töötab protsessori versioon (vector_add_cpu) oluliselt aeglasemalt kui GPU versioon (vector_add_gpu).

Kui ei, siis peate võib-olla kohandama ITER-i määratlust gpu-example'is.cu suuremale arvule. Selle põhjuseks on asjaolu, et GPU seadistamise aeg on pikem kui mõnel väiksemal protsessorimahukal tsüklil. Leidsin, et 65535 töötab minu masinas hästi, kuid teie läbisõit võib erineda. Kui aga selle künnise tühjendate, on GPU dramaatiliselt kiirem kui protsessor.

Järeldus

Loodan, et olete palju õppinud meie sissejuhatusest graafikaprotsessorite koos C-ga++. Ülaltoodud näide ei anna palju tulemusi, kuid esitatud kontseptsioonid pakuvad raamistikku, mida saate kasutada oma ideede kaasamiseks GPU võimsuse vabastamiseks.

Kommertsmängumootorite avatud lähtekoodiga sadamad
Tasuta, avatud lähtekoodiga ja platvormidevaheliste mängumootorite puhkusereise saab kasutada nii vanade kui ka mõnede üsna hiljutiste mängude pealkir...
Parimad Linuxi käsurea mängud
Käsurida pole Linuxi kasutamisel lihtsalt teie suurim liitlane - see võib olla ka meelelahutusallikas, sest saate seda kasutada paljude lõbusate mängu...
Parimad Linuxi mängupuldi kaardistamise rakendused
Kui teile meeldib mängida Linuxis mänge tavalise klaviatuuri ja hiire sisestussüsteemi asemel mängupuldiga, on teie jaoks mõned kasulikud rakendused. ...