Această notă conține informații care vor ajuta la înțelegerea principiilor generale ale programării GPU.
Introducere în arhitectura GPU
Separați cele două tipuri de dispozitive - cel care controlează logica generală - gazdă. și care este capabil să execute rapid un set de instrucțiuni pe o cantitate mare de dispozitive de date.
Programare pentru GPU
Programele sunt scrise în extensiile limbajului C de la nVidia / OpenCL și compilat cu ajutorul compilator speciale incluse în SDK. Fiecare producător are propriul său. Există două variante ale ansamblului - pentru platforma țintă - așa cum este indicat în mod clar pe ce hardware vor fi îndeplinite la un cod sau un cod intermediar care, atunci când rula pe driverul hardware-ul țintă va fi transformat într-un set de instrucțiuni specifice pentru arhitectura (ajustat pentru calcul capacitățile de hardware).
Programul care rulează pe GPU se numește kernel - kernel - care pentru CUDA că pentru OpenCL acesta va fi setul de instrucțiuni care se aplică tuturor datelor. Funcția este una, iar datele pe care este executată sunt diferite - principiul SIMD.Driverul CUDA / OpenCL împarte datele de intrare în mai multe părți (fluxuri de execuție combinate în blocuri) și atribuie fiecărui procesor flux pentru execuție. Un programator poate și trebuie să spună șoferului cum să maximizeze utilizarea resurselor de calcul existente, specificând dimensiunile blocurilor și numărul de fire din ele. Desigur, valorile maxime admise variază de la dispozitiv la dispozitiv. Este o practică bună - înainte de a executa să solicite parametrii fierului, pe care va fi executat nucleul și pe baza acestora pentru a calcula dimensiunile optime ale blocurilor.
Schematic, distribuția sarcinilor pe GPU este după cum urmează:
Rularea programului pe GPU
elementul de lucru (OpenCL) sau firul (CUDA) - nucleul și setul de date, este executat pe procesorul de flux (element de procesare în cazul dispozitivelor ATI).
grupul de lucru (OpenCL) sau blocul de filet (CUDA) se efectuează pe Procesorul Multi (motor SIMD)
Grid (blocuri setat astfel de concept este doar Nvidia) = efectuat pe întregul dispozitiv - GPU. Pentru execuție pe GPU toate fluxurile sunt combinate în urzeală (urzeală - CUDA) sau veyffronty (Wavefront - OpenCL) - piscina fir alocat pentru a efectua o singură multiprocesor. Aceasta este, în cazul în care numărul de unități sau grupuri de lucru a fost mai mare decât numărul de multiprotsessorov - de fapt, la un moment dat se execută un grup (sau grupuri), urzeala combinat - toți ceilalți așteaptă rândul lor.
Un nucleu poate fi rulat pe mai multe dispozitive GPU (atât pentru CUDA, cât și pentru OpenCL, atât pentru carduri ATI, cât și pentru NVidia).
Un dispozitiv GPU poate executa simultan mai multe nuclee (pentru CUDA și OpenCL, pentru NVidia - începând cu arhitectura 20 și mai mult). Pentru referințe cu privire la aceste aspecte, consultați sfârșitul acestui articol.
Modelul de memorie OpenCL (terminologia CUDA în paranteze)
Aici este cel mai important lucru de reținut despre timpul de acces la fiecare tip de memorie. Cel mai lent este memoria globală - cardurile video moderne au o capacitate de până la 6 GB. Mai mult, viteza este o memorie partajată (partajată - CUDA, locale - OpenCL) - comun pentru toate firele din bloc (bloc fir - CUDA, lucru de grup - OpenCL) - dar niciodată nu este suficient - 32-48 KB pentru multiprocesor. Cel mai rapid este memoria locală, datorită utilizării registrelor și a memoriei cache, dar noi trebuie să înțelegem că tot ceea ce nu se încadrează în cache-urile \ registrele - vor fi stocate în memoria globală, cu toate consecințele.
Modele de programare paralelă pentru GPU
Harta - model paralel GPU
Aici totul este simplu - luăm matricea de date de intrare și aplicăm fiecărui element un anumit operator - kernelul - care nu afectează în nici un fel celelalte elemente - adică citiți și scrieți în locații specifice de memorie.
Raportul este unul la unu.
exemplu - multiplicarea matricelor, operatorul de incrementare sau de decrementare aplicat fiecărui element al unei matrice etc.
Scatter - model paralel GPU
Pentru fiecare element al matricei de intrare, se calculează poziția din matricea de ieșire, la care va afecta (prin aplicarea operatorului corespunzător).
Raportul este unul-la-multe.
3. Transpuneți
Transpunere - model paralel GPU
Acest model poate fi considerat un caz special al modelului de scatter.
Folosit pentru optimizarea calculelor - redistribuirea elementelor în memorie poate duce la o creștere semnificativă a performanței.
Adunați - model paralel GPU
Este inversul modelului Scatter - pentru fiecare element al matricei de ieșire, calculăm indiciile elementelor din matricea de intrare care o vor afecta:
Raportul este de la mai multe la unul (multi-la-unul).
Stencil - model paralel GPU
Acest model poate fi considerat un caz special al modelului de strângere. Aici, pentru a obține valoarea în fiecare celulă a matricei de ieșire, un anumit șablon este utilizat pentru a calcula toate elementele matricei de intrare care vor afecta valoarea finală. Toate tipurile de filtre sunt construite pe acest principiu.
Raportul dintre mai multe și unul (mai multe-la-unu)
Exemplu: un filtru Gaussian.
Reduceți - model paralel GPU
Raportul total la unu
Un exemplu este calculul sumei sau maximului într-o matrice.
La calcularea valorii în fiecare celulă a matricei de ieșire, trebuie luate în considerare valorile fiecărui element de intrare. Există două implementări principale - Hillis și Steele și Blelloch.
out [i] = F [i] = operatorul (F [i-1], în [i])
Atitudine față de toți (toate la toate).
Exemple sunt sortarea datelor.
Link-uri utile
Introducere în CUDA: