GPU programmeerimine C ++ abil

Gpu Programming With C



Selles juhendis uurime GPU programmeerimise võimsust C ++ abil. Arendajad võivad oodata C ++ abil uskumatut jõudlust ja juurdepääs GPU fenomenaalsele võimsusele madala taseme keelega võib anda mõned kiireimad praegu saadaval olevad arvutused.

Nõuded

Kuigi iga masin, mis suudab käitada Linuxi kaasaegset versiooni, toetab C ++ kompilaatorit, on teil selle harjutuse tegemiseks vaja NVIDIA-põhist GPU-d. Kui teil pole GPU-d, saate GPU-toega eksemplari Amazoni veebiteenustes või mõnes muus pilveteenuse pakkujas kokku panna.







Kui valite füüsilise masina, veenduge, et olete installinud NVIDIA varalised draiverid. Juhised selle kohta 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 allalaadimised järgmisel URL -il: https://developer.nvidia.com/cuda-downloads



Ubuntu jaoks peaksite valima .deb -põhise allalaadimise. Allalaaditud failil ei ole vaikimisi laiendit .deb, seega soovitan selle ümber nimetada nii, et selle lõpus oleks .deb. Seejärel saate installida järgmiselt:





sudo dpkg -minapaketi nimi.deb

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

Kui olete seda teinud, värskendage oma hoidlaid:



sudo apt-get update
sudo apt-get installimesid-ja

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

GPU arendamise eelised

Protsessorid käitlevad paljusid erinevaid sisendeid ja väljundeid ning sisaldavad suurt valikut funktsioone, mis ei võimalda mitte ainult lahendada laia valikut programmivajadusi, vaid ka hallata erinevaid riistvara konfiguratsioone. Samuti käsitlevad nad mälu, vahemällu salvestamist, süsteemibussi, segmenteerimist ja IO funktsioone, muutes need kõigi tehingute pistikupesaks.

GPU -d on vastupidi - 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 äärmise spetsialiseerumise hinnaga ülima jõudluse.

Näite kood

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

#include 'cuda_runtime.h'
#kaasake
#kaasake
#kaasake
#kaasake
#kaasake

typedeftundi::krono::high_resolution_clockKell;

#defineeri ITER 65535

// Vektori lisamise funktsiooni CPU versioon
tühinevector_add_cpu(int *,int *b,int *c,intn) {
inti;

// Lisage vektori elemendid a ja b vektorile c
eest (i= 0;i<n; ++i) {
c[i] =et[i] +b[i];
}
}

// Vektori lisamise funktsiooni GPU versioon
__global__tühinevector_add_gpu(int *gpu_a,int *gpu_b,int *gpu_c,intn) {
inti=threadIdx.x;
// Ei vaja tsüklit, kuna CUDA käitusaeg
// teeme seda ITER korda
gpu_c[i] =gpu_a[i] +gpu_b[i];
}

intpeamine() {

int *,*b,*c;
int *gpu_a,*gpu_b,*gpu_c;

et= (int *)malloc(ITER* suurus(int));
b= (int *)malloc(ITER* suurus(int));
c= (int *)malloc(ITER* suurus(int));

// Vajame GPU -le juurdepääsetavaid muutujaid,
// nii pakub neid cudaMallocManaged
cudaMallocManaged(&gpu_a, ITER* suurus(int));
cudaMallocManaged(&gpu_b, ITER* suurus(int));
cudaMallocManaged(&gpu_c, ITER* suurus(int));

eest (inti= 0;i<ITER; ++i) {
et[i] =i;
b[i] =i;
c[i] =i;
}

// Helistage CPU funktsioonile ja määrake see
autocpu_start=Kell::nüüd();
vector_add_cpu(a, b, c, ITER);
autocpu_end=Kell::nüüd();
tundi::maksma << 'vector_add_cpu:'
<<tundi::krono::kestev saade<tundi::krono::nanosekundit>(cpu_end-cpu_start).loendama()
<< 'nanosekundit. n';

// Helistage GPU funktsioonile ja määrake see
// Kolmekordse nurgaga pidurid on CUDA käitusaja pikendus, mis võimaldab
// edastatavad CUDA kerneli kõne parameetrid.
// Selles näites edastame ühe lõimeploki ITERi lõimedega.
autogpu_start=Kell::nüüd();
vector_add_gpu<<<1, ITER>>> (gpu_a, gpu_b, gpu_c, ITER);
cudaDeviceSynchronize();
autogpu_end=Kell::nüüd();
tundi::maksma << 'vector_add_gpu:'
<<tundi::krono::kestev saade<tundi::krono::nanosekundit>(gpu_end-gpu_start).loendama()
<< 'nanosekundit. n';

// Vabastage GPU-põhised mälu eraldised
cudaFree(et);
cudaFree(b);
cudaFree(c);

// Vabastage CPU-funktsioonil põhinevad mälu eraldised
tasuta(et);
tasuta(b);
tasuta(c);

tagasi 0;
}

Tee fail sisu allpool:

INC= -Ma/usr/kohalik/imesid/kaasata
NVCC=/usr/kohalik/imesid/olen/nvcc
NVCC_OPT= -std = c ++üksteist

kõik:
$(NVCC)$(NVCC_OPT)gpu-example.cpp-võigpu-näide

puhas:
-rm -fgpu-näide

Näite käivitamiseks koostage see:

tegema

Seejärel käivitage programm:

./gpu-näide

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

Kui ei, siis peate võib-olla muutma gpu-example.cu ITER-i määratluse suuremaks. See on tingitud sellest, et GPU seadistamise aeg on pikem kui mõned väiksemad protsessorimahukad ahelad. Leidsin, et 65535 töötab minu masinal hästi, kuid teie läbisõit võib varieeruda. Kui aga selle läve tühjendate, on GPU dramaatiliselt kiirem kui protsessor.

Järeldus

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