C ++ తో GPU ప్రోగ్రామింగ్

Gpu Programming With C



ఈ గైడ్‌లో, మేము C ++ తో GPU ప్రోగ్రామింగ్ శక్తిని అన్వేషిస్తాము. డెవలపర్లు C ++ తో అద్భుతమైన పనితీరును ఆశించవచ్చు మరియు తక్కువ స్థాయి భాషతో GPU యొక్క అసాధారణ శక్తిని యాక్సెస్ చేయడం వలన ప్రస్తుతం అందుబాటులో ఉన్న వేగవంతమైన గణనను పొందవచ్చు.

అవసరాలు

లైనక్స్ యొక్క ఆధునిక వెర్షన్‌ని అమలు చేయగల సామర్థ్యం ఉన్న ఏ యంత్రం అయినా C ++ కంపైలర్‌కు మద్దతు ఇవ్వగలదు, ఈ వ్యాయామంతో పాటుగా మీకు NVIDIA- ఆధారిత GPU అవసరం. మీకు GPU లేకపోతే, మీరు అమెజాన్ వెబ్ సర్వీసెస్ లేదా మీకు నచ్చిన మరొక క్లౌడ్ ప్రొవైడర్‌లో GPU- ఆధారిత ఉదాహరణను స్పిన్ చేయవచ్చు.







మీరు భౌతిక యంత్రాన్ని ఎంచుకుంటే, దయచేసి మీరు NVIDIA యాజమాన్య డ్రైవర్‌లను ఇన్‌స్టాల్ చేసారని నిర్ధారించుకోండి. దీని కోసం మీరు ఇక్కడ సూచనలను కనుగొనవచ్చు: https://linuxhint.com/install-nvidia-drivers-linux/



డ్రైవర్‌తో పాటు, మీకు CUDA టూల్‌కిట్ అవసరం. ఈ ఉదాహరణలో, మేము ఉబుంటు 16.04 ఎల్‌టిఎస్‌ని ఉపయోగిస్తాము, కానీ కింది URL లో చాలా పెద్ద పంపిణీల కోసం డౌన్‌లోడ్‌లు అందుబాటులో ఉన్నాయి: https://developer.nvidia.com/cuda-downloads



ఉబుంటు కోసం, మీరు .deb ఆధారిత డౌన్‌లోడ్‌ను ఎంచుకుంటారు. డౌన్‌లోడ్ చేసిన ఫైల్‌లో డిఫాల్ట్‌గా .deb పొడిగింపు ఉండదు, కాబట్టి చివర్లో .deb ఉండేలా పేరు మార్చాలని నేను సిఫార్సు చేస్తున్నాను. అప్పుడు, మీరు దీనితో ఇన్‌స్టాల్ చేయవచ్చు:





సుడో dpkg -ఐప్యాకేజీ- name.deb

మీరు GPG కీని ఇన్‌స్టాల్ చేయమని ప్రాంప్ట్ చేయబడతారు, అలా అయితే, అలా చేయడానికి అందించిన సూచనలను అనుసరించండి.

మీరు దాన్ని పూర్తి చేసిన తర్వాత, మీ రిపోజిటరీలను అప్‌డేట్ చేయండి:



సుడో apt-get అప్‌డేట్
సుడో apt-get installఅద్భుతాలు-మరియు

పూర్తయిన తర్వాత, ప్రతిదీ సరిగ్గా లోడ్ చేయబడిందని నిర్ధారించడానికి రీబూట్ చేయాలని నేను సిఫార్సు చేస్తున్నాను.

GPU అభివృద్ధి యొక్క ప్రయోజనాలు

CPU లు అనేక విభిన్న ఇన్‌పుట్‌లు మరియు అవుట్‌పుట్‌లను నిర్వహిస్తాయి మరియు ప్రోగ్రామ్ అవసరాల విస్తృత కలగలుపుతో వ్యవహరించడమే కాకుండా విభిన్న హార్డ్‌వేర్ కాన్ఫిగరేషన్‌లను నిర్వహించడానికి కూడా పెద్ద సంఖ్యలో ఫంక్షన్లను కలిగి ఉంటాయి. వారు మెమరీ, క్యాషింగ్, సిస్టమ్ బస్, సెగ్మెంటింగ్ మరియు IO కార్యాచరణను కూడా నిర్వహిస్తారు, వాటిని అన్ని ట్రేడ్‌ల జాక్‌గా మారుస్తారు.

GPU లు వ్యతిరేకం - అవి చాలా సాధారణ గణిత విధులపై దృష్టి సారించిన అనేక వ్యక్తిగత ప్రాసెసర్‌లను కలిగి ఉంటాయి. ఈ కారణంగా, వారు CPU ల కంటే చాలా రెట్లు వేగంగా పనులను ప్రాసెస్ చేస్తారు. స్కేలార్ ఫంక్షన్లలో ప్రత్యేకించడం ద్వారా (ఒకటి లేదా అంతకంటే ఎక్కువ ఇన్‌పుట్‌లను తీసుకునే ఫంక్షన్ కానీ ఒకే అవుట్‌పుట్ మాత్రమే అందిస్తుంది), అవి విపరీతమైన స్పెషలైజేషన్ ఖర్చుతో విపరీతమైన పనితీరును సాధిస్తాయి.

ఉదాహరణ కోడ్

ఉదాహరణ కోడ్‌లో, మేము కలిసి వెక్టర్‌లను జోడిస్తాము. స్పీడ్ పోలిక కోసం నేను కోడ్ యొక్క CPU మరియు GPU వెర్షన్‌ను జోడించాను.
gpu-example.cpp దిగువ విషయాలు:

#'cuda_runtime.h' ని చేర్చండి
#చేర్చండి
#చేర్చండి
#చేర్చండి
#చేర్చండి
#చేర్చండి

typedefగంటలు::క్రోనో::అధిక_పరిష్కారం_ గడియారంగడియారం;

#ITER 65535 ను నిర్వచించండి

// వెక్టర్ యాడ్ ఫంక్షన్ యొక్క CPU వెర్షన్
శూన్యంvector_add_cpu(int *కు,int *b,int *c,intఎన్) {
inti;

// వెక్టర్ సికి వెక్టర్ ఎలిమెంట్స్ ఎ మరియు బి జోడించండి
కోసం (i= 0;i<ఎన్; ++i) {
c[i] =కు[i] +బి[i];
}
}

// వెక్టర్ యాడ్ ఫంక్షన్ యొక్క GPU వెర్షన్
__ప్రపంచ__శూన్యంvector_add_gpu(int *gpu_a,int *gpu_b,int *gpu_c,intఎన్) {
inti=threadIdx.x;
// లూప్ అవసరం లేదు ఎందుకంటే CUDA రన్‌టైమ్
// దీనిని ITER సార్లు థ్రెడ్ చేస్తుంది
gpu_c[i] =gpu_a[i] +gpu_b[i];
}

intప్రధాన() {

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

కు= (int *)malloc(ITER* పరిమాణం(int));
బి= (int *)malloc(ITER* పరిమాణం(int));
c= (int *)malloc(ITER* పరిమాణం(int));

// మాకు GPU కి అందుబాటులో ఉండే వేరియబుల్స్ అవసరం,
// కాబట్టి cudaMallocManaged వీటిని అందిస్తుంది
cudaMallocManaged(&gpu_a, ITER* పరిమాణం(int));
cudaMallocManaged(&gpu_b, ITER* పరిమాణం(int));
cudaMallocManaged(&gpu_c, ITER* పరిమాణం(int));

కోసం (inti= 0;i<ITER; ++i) {
కు[i] =i;
బి[i] =i;
c[i] =i;
}

// CPU ఫంక్షన్‌కు కాల్ చేయండి మరియు సమయం కేటాయించండి
దానంతట అదేcpu_start=గడియారం::ఇప్పుడు();
vector_add_cpu(a, b, c, ITER);
దానంతట అదేcpu_end=గడియారం::ఇప్పుడు();
గంటలు::ఖరీదు << 'vector_add_cpu:'
<<గంటలు::క్రోనో::వ్యవధి_కాస్ట్<గంటలు::క్రోనో::నానో సెకన్లు>(cpu_end-cpu_start).లెక్క()
<< 'నానో సెకన్లు. n';

// GPU ఫంక్షన్‌కు కాల్ చేయండి మరియు సమయం కేటాయించండి
// ట్రిపుల్ యాంగిల్ బ్రాకెట్‌లు అనుమతించే CUDA రన్‌టైమ్ ఎక్స్‌టెన్షన్
// CUDA కెర్నల్ కాల్ యొక్క పారామితులు పాస్ చేయబడతాయి.
// ఈ ఉదాహరణలో, మేము ITER థ్రెడ్‌లతో ఒక థ్రెడ్ బ్లాక్‌ను పాస్ చేస్తున్నాము.
దానంతట అదేgpu_start=గడియారం::ఇప్పుడు();
vector_add_gpu<<<1, ITER>>> (gpu_a, gpu_b, gpu_c, ITER);
cudaDeviceSynchronize();
దానంతట అదేgpu_end=గడియారం::ఇప్పుడు();
గంటలు::ఖరీదు << 'vector_add_gpu:'
<<గంటలు::క్రోనో::వ్యవధి_కాస్ట్<గంటలు::క్రోనో::నానో సెకన్లు>(gpu_end-gpu_start).లెక్క()
<< 'నానో సెకన్లు. n';

// GPU- ఫంక్షన్ ఆధారిత మెమరీ కేటాయింపులను ఉచితం చేయండి
cudaFree(కు);
cudaFree(బి);
cudaFree(c);

// CPU- ఫంక్షన్ ఆధారిత మెమరీ కేటాయింపులను ఉచితం చేయండి
ఉచిత(కు);
ఉచిత(బి);
ఉచిత(c);

తిరిగి 0;
}

మేక్ఫైల్ దిగువ విషయాలు:

INC= -నేను/usr/స్థానిక/అద్భుతాలు/చేర్చండి
NVCC=/usr/స్థానిక/అద్భుతాలు/am/nvcc
NVCC_OPT= -std = సి ++పదకొండు

అన్ని:
$(NVCC)$(NVCC_OPT)gpu-example.cpp-లేదాgpu- ఉదాహరణ

శుభ్రంగా:
-ఆర్మ్ -fgpu- ఉదాహరణ

ఉదాహరణను అమలు చేయడానికి, దాన్ని కంపైల్ చేయండి:

తయారు

అప్పుడు ప్రోగ్రామ్‌ను అమలు చేయండి:

./gpu- ఉదాహరణ

మీరు గమనిస్తే, CPU వెర్షన్ (vector_add_cpu) GPU వెర్షన్ (vector_add_gpu) కంటే చాలా నెమ్మదిగా నడుస్తుంది.

కాకపోతే, మీరు gpu-example.cu లో ITER నిర్వచనాన్ని అధిక సంఖ్యకు సర్దుబాటు చేయాల్సి ఉంటుంది. GPU సెటప్ సమయం కొన్ని చిన్న CPU- ఇంటెన్సివ్ లూప్‌ల కంటే ఎక్కువ ఉండటం దీనికి కారణం. నా మెషీన్‌లో 65535 బాగా పనిచేస్తుందని నేను కనుగొన్నాను, కానీ మీ మైలేజ్ మారవచ్చు. అయితే, మీరు ఈ పరిమితిని క్లియర్ చేసిన తర్వాత, GPU CPU కంటే నాటకీయంగా వేగంగా ఉంటుంది.

ముగింపు

C ++ తో GPU ప్రోగ్రామింగ్‌పై మా పరిచయం నుండి మీరు చాలా నేర్చుకున్నారని నేను ఆశిస్తున్నాను. పై ఉదాహరణ గొప్పగా సాధించలేదు, కానీ ప్రదర్శించబడిన భావనలు మీ GPU యొక్క శక్తిని వెలికితీసేందుకు మీ ఆలోచనలను చేర్చడానికి ఉపయోగించే ఫ్రేమ్‌వర్క్‌ను అందిస్తాయి.