GPU programozás C ++ - val

Gpu Programming With C



Ebben az útmutatóban megvizsgáljuk a GPU programozás erejét a C ++ segítségével. A fejlesztők hihetetlen teljesítményre számíthatnak a C ++ segítségével, és a GPU fenomenális erejének alacsony szintű nyelvvel való elérése a jelenleg elérhető leggyorsabb számításokat eredményezheti.

Követelmények

Bár minden olyan gép, amely képes a Linux modern verziójának futtatására, képes támogatni a C ++ fordítót, szüksége lesz egy NVIDIA-alapú GPU-ra a gyakorlat követéséhez. Ha nem rendelkezik GPU-val, létrehozhat egy GPU-alapú példányt az Amazon Web Services szolgáltatásban vagy egy másik választott felhőszolgáltatóban.







Ha fizikai gépet választ, győződjön meg arról, hogy telepítve vannak az NVIDIA szabadalmaztatott illesztőprogramjai. Erre itt találhat utasításokat: https://linuxhint.com/install-nvidia-drivers-linux/



Az illesztőprogramon kívül szüksége lesz a CUDA eszköztárra. Ebben a példában az Ubuntu 16.04 LTS -t fogjuk használni, de a legtöbb főbb disztribúcióhoz letölthetők az alábbi URL -címen: https://developer.nvidia.com/cuda-downloads



Ubuntu esetén a .deb alapú letöltést választja. A letöltött fájl alapértelmezés szerint nem rendelkezik .deb kiterjesztéssel, ezért azt javaslom, hogy nevezze át .deb -re a végén. Ezután telepítheti a következővel:





sudo dpkg -éncsomagnév.deb

Valószínűleg a rendszer felkérést kap egy GPG kulcs telepítésére, és ha igen, kövesse az erre vonatkozó utasításokat.

Ha ezt megtette, frissítse a tárolókat:



sudo apt-get frissítés
sudo apt-get installcsodák-és

Ha kész, javaslom az újraindítást, hogy minden megfelelően betöltődjön.

A GPU fejlesztésének előnyei

A CPU -k sokféle bemenetet és kimenetet kezelnek, és számos funkciót tartalmaznak nemcsak a programigények széles választékának kezelésére, hanem a különböző hardverkonfigurációk kezelésére is. Emellett kezelik a memóriát, a gyorsítótárazást, a rendszerbuszt, a szegmentálást és az IO funkciókat, így minden kereskedés aljzatává válnak.

A GPU az ellenkezője - sok egyedi processzort tartalmaz, amelyek nagyon egyszerű matematikai funkciókra összpontosítanak. Emiatt sokszor gyorsabban dolgozzák fel a feladatokat, mint a CPU -k. A skalárfüggvényekre specializálódva (egy vagy több bemenetet használó funkció, de csak egyetlen kimenetet ad vissza) extrém teljesítményt érnek el az extrém specializáció árán.

Példakód

A példakódban a vektorokat összeadjuk. A sebesség összehasonlítása érdekében hozzáadtam a kód CPU és GPU verzióját.
gpu-example.cpp tartalma alább:

#include 'cuda_runtime.h'
#befoglalni
#befoglalni
#befoglalni
#befoglalni
#befoglalni

typedefórák::kronó::high_resolution_clockÓra;

#define ITER 65535

// A vektor hozzáadása függvény CPU verziója
üresvector_add_cpu(int *nak nek,int *b,int *c,intn) {
intén;

// Adja hozzá az a és b vektor elemeket a c vektorhoz
számára (én= 0;én<n; ++én) {
c[én] =nak nek[én] +b[én];
}
}

// A vektor hozzáadása függvény GPU változata
__globális__üresvector_add_gpu(int *gpu_a,int *gpu_b,int *gpu_c,intn) {
intén=threadIdx.x;
// Nem szükséges a ciklushoz, mert a CUDA futási ideje
// ITER alkalommal fogom szálazni
gpu_c[én] =gpu_a[én] +gpu_b[én];
}

intfő-() {

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

nak nek= (int *)malloc(ITER* mérete(int));
b= (int *)malloc(ITER* mérete(int));
c= (int *)malloc(ITER* mérete(int));

// Szükségünk van a GPU -hoz hozzáférhető változókra,
// így a cudaMallocManaged biztosítja ezeket
cudaMallocManaged(&gpu_a, ITER* mérete(int));
cudaMallocManaged(&gpu_b, ITER* mérete(int));
cudaMallocManaged(&gpu_c, ITER* mérete(int));

számára (intén= 0;én<ITER; ++én) {
nak nek[én] =én;
b[én] =én;
c[én] =én;
}

// Hívja meg a CPU funkciót és állítsa be az időt
autocpu_start=Óra::Most();
vector_add_cpu(a, b, c, ITER);
autocpu_end=Óra::Most();
órák::költség << 'vector_add_cpu:'
<<órák::kronó::duration_cast<órák::kronó::nanosekundum>(cpu_end-cpu_start).számol()
<< 'nanoszekundum. n';

// Hívja meg a GPU funkciót és állítsa be az időt
// A hármas szögű fékbetétek egy CUDA futásidejű kiterjesztés, amely lehetővé teszi
// átadandó CUDA kernelhívás paraméterei.
// Ebben a példában egy szál blokkot adunk át ITER szálakkal.
autogpu_start=Óra::Most();
vector_add_gpu<<<1, ITER>>> (gpu_a, gpu_b, gpu_c, ITER);
cudaDeviceSynchronize();
autogpu_end=Óra::Most();
órák::költség << 'vector_add_gpu:'
<<órák::kronó::duration_cast<órák::kronó::nanosekundum>(gpu_end-gpu_start).számol()
<< 'nanoszekundum. n';

// Szabadítsa fel a GPU-alapú memóriakiosztásokat
cudaFree(nak nek);
cudaFree(b);
cudaFree(c);

// Szabadítsa fel a CPU-függvényen alapuló memóriakiosztásokat
ingyenes(nak nek);
ingyenes(b);
ingyenes(c);

Visszatérés 0;
}

Makefile tartalma alább:

INC= -Én/usr/helyi/csodák/tartalmazza
NVCC=/usr/helyi/csodák/am/nvcc
NVCC_OPT= -std = c ++tizenegy

összes:
$(NVCC)$(NVCC_OPT)gpu-example.cpp-vagygpu-példa

tiszta:
-rm -fgpu-példa

A példa futtatásához fordítsa le:

készíteni

Ezután futtassa a programot:

./gpu-példa

Amint láthatja, a CPU verzió (vector_add_cpu) lényegesen lassabban fut, mint a GPU verzió (vector_add_gpu).

Ha nem, akkor előfordulhat, hogy a gpu-example.cu fájlban megadott ITER értéket magasabbra kell állítania. Ez annak köszönhető, hogy a GPU beállítási ideje hosszabb, mint néhány kisebb CPU-igényes ciklus. Úgy találtam, hogy a 65535 jól működik a gépemen, de a futásteljesítmény változhat. Ha azonban törli ezt a küszöböt, a GPU drámaian gyorsabb, mint a CPU.

Következtetés

Remélem, sokat tanult a C ++ - os GPU programozás bevezetéséből. A fenti példa nem sokat ér, de a bemutatott koncepciók keretet biztosítanak, amellyel ötleteit beépítheti a GPU erejének felszabadítására.