Introducción a CUDA

 

Embed or link this publication

Description

Tutorial introductorio a la tecnologia propuesta por NVIDIA basada en GPGPU.

Popular Pages


p. 1

escola d enginyeria uab tecnologia nvidia cuda introducciÓ a cuda eficiència en gpus memòria octubre 2009 rafael moreno hermosilla

[close]

p. 2

tecnologia nvidia cuda introducció a cuda eficiència en gpus escola d enginyeria uab versió data 1.0 octubre 2009 taula de continguts 1 2 3 4 5 6 7 sobre cuda i sobre les gpus aproximació històrica a la programació paral·lela aspectes positius i negatius de cuda comparativa cuda vs opencl components de cuda i nocions sobre el funcionament intern estructura d una aplicació en cuda primers passos en cuda 7.1 7.2 7.3 8 9 introducció 1r codi cuda a més a més cuda error handling 12 15 19 20 22 22 28 31 33 33 35 37 37 38 38 39 40 42 3 3 5 7 7 11 12 elements de memòria i aspectes de rendiment tipus de memòries en cuda 9.1 9.2 9.3 shared memory front global memory resum principal memòries cuda mapeig de memòria en cuda llibreries en cuda 10.1 10.2 10.3 cublas cufft cudpp extensions cuda a llenguatges d alt nivell swig annexes 12.1 12.2 12.3 12.4 annex 1 descàrrega i instal·lació annex 2 integració programa cuda en entorn microsoft visual studio 2008 annex 4 highlihting i intellisense cuda visual studio annex 5 resultats obtinguts en l apartat de shared memory 10 11 12 introducció a cuda escola d enginyeria uab pàg 2

[close]

p. 3

memòria 1 sobre cuda i sobre les gpus per parlar de cuda compute unified device architecture primer hem de fer referència al concepte que dóna sentit a la seva existència la gpu graphics processor unit element que podem entendre com una analogia de la cpu central processing unit però en aquest cas dirigida específicament al tractament gràfic aquest nou concepte ha donat lloc a una nova filosofia de desenvolupament gpgpu general purpose computing on graphics processing units és a dir una computació de propòsit general basada en l ús de gpus en comptes de cpus És evident doncs que existeix un motiu vital per inclinar-se en l ús de les gpus i no és més que el fet que ofereixen un major rendiment computacional que les cpus és a dir ens confereixen un major grau de paral·lelisme gràcies al major nombre de nuclis de processament que disposen en aquest context apareix cuda amb l objectiu d aprofitar la potencia de les gpus de manera que es pugui explotar l alt nivell de paral·lelisme que ofereixen i així poder processar en temps real operacions que en cpu no serien viables l avantatge principal que presenta cuda és que els programes s escriuen en llenguatge d alt nivell en c i ofereix un paral·lelisme totalment transparent al programador el programador escriu el codi com si només s executés en un únic fil sense preocupar-se de tractament de threads ni de sincronització i després el codi es reparteix entre els diferents fils de manera transparent al programador així doncs ens trobem davant d una tecnologia desenvolupada per nvidia a principis de 2007 que suposa un entorn de programació en c i que es presenta com a vehicle per a realitzar programació no gràfica sobre un dispositiu gràfic desenvolupant noves tècniques de programació massivament paral·leles en gpu 2 aproximació històrica a la programació paral·lela la programació paral·lela té els seu moment d esplendor a principis dels 90 i d ençà ha experimentat un fort creixement pel que fa al seu interès sobretot en l aspecte relatiu a programació paral·lela de dades on una instrucció pot ser executada sobre diferents elements generalment elements individuals d un vector en aquest període inicial les arquitectures paral·leles van ser fortament explorades i es van desenvolupar grans i potents supercomputadors el principal inconvenient és que estaven dirigits a un sector minúscul de la població laboratoris nacionals i universitats bàsicament tot i el difícil accés aquesta època destaca per l aparició de gran quantitat d articles llenguatges de programació paral·lels i nous dissenys d arquitectura paral·lela degut al baix impacte dels supercomputadors paral·lels la tendència va variar cap a clústers d ordinadors més econòmics la principal raó de canvi radica en que els multiprocessadors formen part d economia d escala cosa que els va portar a incrementar la velocitat i a retirar a les companyies de supercomputadors no podien oferir competència tot i això a principis del segle xxi el rendiment dels microprocessadors pateix una sensible davallada que els porta a incrementar la mida del clúster per obtenir més potència aquest fet esdevé un efecte negatiu pel que fa temes d escalabilitat espai i requeriments energètics introducció a cuda escola d enginyeria uab pàg 3

[close]

p. 4

tot això ens porta a fets contemporanis l arribada de microprocessadors multi-nucli que tot i suposar un salt qualitatiu estan patint les conseqüències de basar l increment de rendiment en l augment de freqüència aquesta via de guanyar rendiment amb la millora de freqüència actualment està força sobre-explotada i en mig d aquesta situació és on apareixen les gpus graphics processing unit així doncs les gpus deixen de ser dispositius focalitzats en el tractament de píxels i obren el ventall d actuació esdevenint una alternativa per aplicacions no gràfiques les gpus són dispositius massivament paral·lels que ofereixen una alta capacitat de paral·lelisme operatiu mitjançant la targeta gràfica en el següent gràfic podem apreciar com l increment de freqüència de la cpu resulta irrisori en comparació a la potencialitat que ens ofereix la programació paral·lela per gpu figura 1 `operacions per segon en punt flotant figura 2 `evolució del bandwidth de cpu i de gpu introducció a cuda escola d enginyeria uab pàg 4

[close]

p. 5

el fet que la gpu hagi desbancat a la cpu es deu a que es troba especialitzada en computació intensiva altament paral·lela aspecte que interessa molt pel que fa al render de gràfics això té efectes en el seu disseny ja que és caracteritza per tenir més transistors dedicats al processament de dades que cache de dades i control de tasques així doncs la gpu es troba orientada a solucionar problemes que poden ser expressats sota el paradigma de la programació paral·lela donant lloc a una alta intensitat aritmètica figura 3 `gpu aposta per més transistors sacrificant cache i control 3 aspectes positius i negatius de cuda la idea essencial que perseguim amb cuda és desenvolupar solucions basades en paral·lelisme de dades massiu sense la necessitat d haver de recorre a clústers de pcs és a dir un cop que tenim saturada la via d optimització per software optem per l optimització hardware a partir d aquest paral·lelisme el que fa concretament l entorn d execució de cuda és aprofitar aquest paral·lelisme de dades és a dir dividir la informació que tenim a l entrada en tants blocs com nuclis de processament tenim a la gpu de manera que cada nucli executa part del codi i rep com a paràmetres la zona de dades on ha d operar així tenim la possibilitat de programar en c algoritmes que més tard s executin de manera paral·lela a la gpu sense la necessitat de conèixer l arquitectura ni el llenguatge de més baix nivell ensamblador tot i això cuda presenta una sèrie de mancances que calen tenir en compte i comentem seguidament es necessari disposar d un adaptador de vídeo d última generació i una quantitat important de memòria per treballar amb cuda no permet utilitzar recursivitat apuntadors a funcions variables estàtiques dins de funcions o funcions amb un nombre de paràmetres variables es pot donar la situació de coll d ampolla entre la cpu i la gpu degut a l ample de banda dels bussos i les seves latències introducció a cuda escola d enginyeria uab pàg 5

[close]

p. 6

a més cal tenir en compte que cuda només el podem fer anar sobre una sèrie de targetes gràfiques concretes bàsicament les geforce més noves a continuació tenim una taula amb les targetes que suporten cuda figura 4 `targetes gràfiques compatibles amb cuda introducció a cuda escola d enginyeria uab pàg 6

[close]

p. 7

4 comparativa cuda vs opencl cuda no és la única opció que tenim front el paral·lelisme que ofereixen les gpu com a alternativa tenim opencl opencl és un llenguatge de programació obert no com nvidia cuda que també ens permet realitzar programació paral·lela però en aquest cas amb compatibilitat ati i nvidia es tracta d un model basat en c com en el cas de cuda i utilitza tots els recursos computacionals del sistema suportant tant programació de dades paral·lela com programació paral·lela de tasques en definitiva es tracta de tecnologia molt semblants amb la salvetat que opencl ofereix també suport per ati tot i això en el cas de treballar amb opencl sobre hardware nvidia aquest només ens ofereix una interfície per accedir a la api de cuda a més tal i com podem observar en la següent figura nvidia ens ofereix un major rendiment que ati figura 5 `operacions per segon en punt flotant nvidia ati ­ intel 5 components de cuda i nocions sobre el funcionament intern abans de tot cal matissar sobre els llenguatges d alt nivell relacionats amb cuda tal i com hem comentat anteriorment cuda és actualment suportat només per c tot i això existeixen solucions que ofereixen suport en java python o matlab però d entrada i oficialment cuda és suportat només en c per a començar a treballar amb cuda haurem de descarregar els 3 components que el http www.nvidia.es/cuda conformen de la següent web aquests tres components ens permeten definir l entorn de treball necessari per treure el màxim rendiment a la gpu i consta de · per una banda tenim el controlador cuda que és l encarregat de facilitar l execució dels programes i la comunicació entre cpu i gpu requerim una geforce 8xx 9xx o gtx 2xx i com a mínim 256 mb de memòria gràfica d altre banda tenim el toolkit cuda format per un compilador de c que s anomena nvcc un depurador específic per gpu un perfilador de codi i una escola d enginyeria uab pàg 7 · introducció a cuda

[close]

p. 8

sèrie de biblioteques amb funcions d utilitat predefinides com poden ser la implementació de la fft o subrutines bàsiques d àlgebra lineal [blas també inclou un manual introductori de programació en cuda · per últim tenim el cuda developer sdk un paquet format bàsicament per codi d exemple i documentació al final del document trobem un annex sobre la descàrrega i instal·lació dels components pel que fa al funcionament intern tal com hem vist abans la base radica en escalar paral·lelisme de manera transparent per incrementar el nombre de nuclis computacionals la idea per damunt de tot serà destripar algoritmes de gran quantitat de computació com per exemple els orientats a operacions a nivell de píxel i paral·lelitzar aquelles parts que ho permetin abandonant el càlcul intensiu per cpu l estructura utilitzada en aquest model està definida per un grid dins el qual hi ha blocs de fils que estan formats com a màxim per 512 fils diferents cada fil està identificat amb un id única a la que accedim amb la variable threadldx es tracta d una variable molt útil de cara a la repartició de tasques entre fils threadlx està conformada per 3 components x,y,z coincidint amb les dimensions de blocs de fils al igual que els fils els blocs s identifiquen mitjançant blockldx en aquest cas només 2 components x,y altre paràmetre a tenir en compte és blockdim per accedir a la mida de cada bloc figura 6 `elements bàsics estructura cuda grid block thread introducció a cuda escola d enginyeria uab pàg 8

[close]

p. 9

avui dia tenim dues arquitectures en funció a la tecnologia a la que pertanyi la nostra targeta gràfica aquestes arquitectures no són més que resultat de l avanç tecnològic de les targetes gràfiques i suposen un canvi pel que fa a la quantitat d elements destinats al càlcul major potència de càlcul per una banda tenim l arquitectura g80 que fa referència a les targetes més antigues les 7xxx 8xxx o 9xxx i que es caracteritzen perquè consten de 128 threads repartits en 16 multiprocessadors tenim doncs 8 threads per cada un i una zona dedicada a memòria shared memory que més endavant veurem figura 7 `multiprocessador arquitectura g80 d altra banda tenim la sèrie 10 les targetes 2xx on en aquest cas contem amb 240 threads repartits en 30 multiprocessadors ara també tenim 8 threads per multiprocessador i es diferencien fortament de les anteriors per disposar d una unitat de double precission en aquest cas tenim tants registres de double precission com en les g80 de single precission a més les targetes de la sèrie 10 incorporen operacions d execució atòmica atomicadd figura 8 `multiprocessador sèrie 10 introducció a cuda escola d enginyeria uab pàg 9

[close]

p. 10

en acabar aquest apartat podríem plantejar una analogia entre software i hardware pel que fa els elements principals que defineixen l arquitectura cuda d entrada tenim els threads que equivalen a processadors que s executen de manera independent i suposen la unitat més bàsica de processament en un segon estadi els blocs que equivalen als multiprocessadors conjunt de processadors junt amb la memòria i demés per últim tenim el grid que equival al device en si com a conjunt de multiprocessadors en la següent figura podem veure la relació software hardware que hem comentat figura 9 `analogia software hardware introducció a cuda escola d enginyeria uab pàg 10

[close]

p. 11

6 estructura d una aplicació en cuda d entrada cal tenir en compte que un programa en cuda sempre estarà format per 2 parts la primera part és aquella on la seva execució queda en mans de la cpu i s anomena codi pel host en la segona part el codi s executarà en la gpu i s anomena codi pel dispositiu així doncs el codi serà processat pel compilador nvcc on es generarà codi objecte per la gpu i codi font per la cpu el codi objecte per la gpu rep el nom de cubin mentre que el segon serà processat per un compilador de c enllaçant el codi cubin com si d un recurs es tractés la finalitat del codi host és iniciar l aplicació transferir el codi cubin a la gpu reservar la memòria necessària en el dispositiu i portar a la gpu les dades de partida amb les que treballarem part programada en c o c el codi del dispositiu ha de seguir estrictament una sintaxis en c i normalment s estructura en funcions que anomenem kernel és a dir funcions on les seves sentències s executen en paral·lel segons la configuració hardware del dispositiu final on s apliqui en definitiva el kernel suposa la unitat bàsica executable en el dispositiu i equival a una funció de c amb la diferència de que una funció kernel s executa n vegades en paral·lel mitjançant n threads un cop aclarits un parell de conceptes necessaris podem fer un avanç del que serà la programació en cuda per això comencem amb les funcions kernel que tal i com hem vist es tracta de funcions que s executen en n fils diferents en comptes de fer-ho seqüencialment per definir-les inclourem global en la declaració definició del kernel global void fint a int b int c l identificador global ens indica que el kernel es cridat des d un codi host cpu i s executa en el dispositiu gràfic gpu en cas de que volguéssim que el kernel fos cridat des d un altre kernel utilitzaríem l identificador device o pel contrari si volem crida i execució en el host host si volem que la nostra funció f calculi la diferencia entre dos vectors aibi el resultat vagi a parar a un tercer vector c aleshores haurem d utilitzar un índex per indicar les posicions del vector aquí és on entra en joc la variable threadidx global void fint a int b int c int i threadidx.x c[i a[i b[i introducció a cuda escola d enginyeria uab pàg 11

[close]

p. 12

tenim una funció que s executarà una vegada en cada fil reduint la complexitat de l algoritme ja que en seqüencial suposaria una complexitat on pel cas de matrius entraria en acció el següent component de threadidx global void fint a int b int c int i threadidx.x int j threadidx.y c[i j a[i j b[i j per últim podem veure com funciona la crida a un kernel És important tenir en compte que cal passar-li la mida del grid i del bloc els grids estan formats per blocs i els blocs estan formats per fils dim3 blocn n dim3 gridm m f grid bloc a b c en el moment en que s invoqui la funció els blocs d un grid s enumeren i es distribueixen pels diferents multiprocessadors lliures tot i això com els diferents fils col·laboren entre ells i poden compartir dades requerim certes directives de sincronització com podria ser syncthreads que ens permet que tots els fils s esperin en un punt concret destaquem la presència de l estructura de dades dim3 que està formada per tres atributs x y i z 7 7.1 primers passos en cuda introducció 1r codi cuda abans de tot ens cal obtenir el software del website de nvidia concretament ens referim als tres components esmentats anteriorment un cop descarregats els 3 components els instal·lem i ja podem començar a programar en cuda no estem davant d una tecnologia gaire llunyana a tot el que coneixem ja que per una banda el compilador nvcc s encarrega de passar el codi de c a un executable per córrer sobre la gpu i d altre banda muntar i executar una aplicació en cuda suposa seguir els mateixos passos que per qualsevol aplicació en c 1 muntar el codi de cuda amb un editor qualsevol extensió .cu 2 compilar el codi amb el nvcc per tenir l executable make 3 fer anar l executable com a primera aproximació al codi tenim una petita aplicació example1.cu on tenim un parell d arrays host i device i podem veure com funcionen els dos conceptes i algunes funcions concretes pròpies de cuda el codi és el següent introducció a cuda escola d enginyeria uab pàg 12

[close]

p. 13

codi example1.cpp 1r codi exemple testejant cuda #include stdafx.h #include

[close]

p. 14

arribats a aquest punt reprenem el concepte de kernel si recordem bé es tracta de funcions que es criden des del host i s executen en el cuda device de manera simultània a partir de varis threads paral·lel així tindrem per una banda la funció host main que és la funció principal on tenim les inicialitzacions i a més cridem a la funció kernel square_array recordem que tota funció kernel ha de començar per global i ha de retornar sempre el tipus void a més cada thread s identifica amb un únic id que ens pot permetre moure ns per l array com a índex o utilitzar com a control de flux així veiem com en square_array calculem aquesta id en la variable idx que després usem per referenciar cada element de l array i incrementar-lo així tenim un exemple de control sobre si cal seguir incrementant o no en funció de si superem la mida de l array n la mecànica que segueix és ben simple la idea és que la main es comporta de manera seqüencial definint els arrays reservant espai a memòria inicialitzant el host en canvi quan cridem a la square_array la càrrega de treball és reparteix entre diferents blocs que actuen en paral·lel calculant el quadrat de cada element en el cas de square_array com es tracta d un kernel hem d especificar la mida i el nombre de blocs entre els símbols i seguits dels paràmetres que requereix la funció així doncs veiem que hi ha una sèrie de paràmetres concrets que poden necessitar les kernels per a la seva configuració com són · · · blockidx que referència l índex de bloc threadidx que referència l índex de thread blockdim que referència el número de threads per bloc aquestes variables són estructures que contenen atributs enters de les variables per exemple en el cas dels blocs tenim x y i z atributs enters que donen lloc a l estructura tridimensional que segueix el bloc en el cas dels grids bidimensional si ens fixem en la nostra funció kernel veiem que per direccionar l array utilitzem un índex de thread idx en la següent línia int idx blockidx.x blockdim.x threadidx.x És important tenir en compte que cada un dels threads pot accedir a tot l array a_d del device així és cosa del programador identificar i explotar el paral·lelisme en les a la següent figura podem observar com calculem idx definim una mida de bloc de 4 block_size i al tenir 10 elements ens queden 3 blocs de 4 on l últim només usarà 2 posicions així en cas de que n no sigui divisible per la mida de bloc com és el cas l últim element de n_blocks afegeix un bloc extra que suposa que alguns threads del bloc són inútils introducció a cuda escola d enginyeria uab pàg 14

[close]

p. 15

figura 10 `paral·lelisme a nivell de blocs i threads per últim hem de tenir en compte que les crides als kernels son asíncrones després d executar-se el kernel el control passa immediatament al host cpu el kernel correrà en el device de cuda un cop totes les crides cuda hagin finalitzat aquesta asincronia ens dona una bona avantatge pel tema del paral·lelisme computacional en host i device al final del document trobem un annex sobre la configuració de microsoft visual studio 2008 per a poder executar els samples de cuda 7.2 a més a més arribats a aquest punt ja hem vist un primer codi en cuda amb una sèrie de funcions pròpies i un conjunt de conceptes com el de bloc grid kernel etc ara podem aprofundir una mica més veient un segon exemple on tenim una funció host i un kernel que fan el mateix tal i com podem veure en aquest segon exemple la sintaxi pel que fa a les instruccions pròpies de cuda varia una mica i a més a més els kernels els tenim situats en un arxiu a part exclusiu per ells codi arxiu host `project1.cu includes system #include

[close]

Comments

no comments yet

YOUBLISHER
About
What Others Say
Sitemap
Impressum

PUBLISHERS
Login
Signup
Tutorials
FAQ
Support

BUSINESS
Overview
Advertising
Support

DEVELOPERS
API

LEGAL
Report a Copyright Violation
Copyright FAQ
Terms of Use
Privacy Policy