This shows you the differences between two versions of the page.
|
asc:laboratoare:05 [2026/02/23 18:48] giorgiana.vlasceanu |
asc:laboratoare:05 [2026/04/01 04:23] (current) alexandru.bala [Warp-uri și modelul SIMT] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Laboratorul 05 - Arhitecturi de tip GPGPU ====== | + | ====== Laboratorul 5 - Arhitecturi GPGPU și Programare CUDA ====== |
| ===== Introducere ===== | ===== Introducere ===== | ||
| Line 86: | Line 86: | ||
| Dezvoltarea de cod pentru laboratoarele de GPU se va face folosind CUDA. | Dezvoltarea de cod pentru laboratoarele de GPU se va face folosind CUDA. | ||
| + | |||
| + | |||
| + | {{https://docs.nvidia.com/cuda/cuda-programming-guide/_images/gpu-devotes-more-transistors-to-data-processing.png?800|The GPU Devotes More Transistors to Data Processing}} | ||
| + | {{https://docs.nvidia.com/cuda/cuda-programming-guide/_images/gpu-cpu-system-diagram.png?600|A GPU has many streaming multiprocessors (SMs), each of which contains many functional units. Graphics processing clusters (GPCs) are collections of SMs. A GPU is a set of GPCs connected to the GPU memory. A CPU typically has several cores and a memory controller which connects to the system memory. A CPU and a GPU are connected by an interconnect such as PCIe or NVLINK}} | ||
| + | {{https://developer-blogs.nvidia.com/wp-content/uploads/2020/06/memory-hierarchy-in-gpus-1.png?600|Memory hierarchy in GPUs}} | ||
| ==== De ce CUDA? ==== | ==== De ce CUDA? ==== | ||
| Line 94: | Line 99: | ||
| Un standard alternativ la CUDA este **OpenCL**, suportat de Khronos și implementat de majoritatea producătorilor de GPU (inclusiv Nvidia ca o extensie la CUDA). OpenCL suferă de următoarele lipsuri: | Un standard alternativ la CUDA este **OpenCL**, suportat de Khronos și implementat de majoritatea producătorilor de GPU (inclusiv Nvidia ca o extensie la CUDA). OpenCL suferă de următoarele lipsuri: | ||
| - | * suportul este fragmentat | + | * suportul este fragmentat |
| - | * standardul este mult mai restrictiv (decât CUDA) | + | * standardul este mult mai restrictiv (decât CUDA) |
| - | * mai complicat de scris programe (decât CUDA) | + | * mai complicat de scris programe (decât CUDA) |
| ===== Arhitectura Nvidia CUDA ===== | ===== Arhitectura Nvidia CUDA ===== | ||
| - | CUDA (**C**ompute **U**nified **D**evice **A**rchitecture) permite utilizarea limbajului C pentru programarea pe GPU-urile Nvidia cât și extensii pentru alte limbaje (exp. Python). Deoarece una din zonele țintă pentru CUDA este HPC (**H**igh **P**erformance **C**omputing), în care limbajul Fortran este foarte popular, PGI ofera un compilator de Fortran ce permite generarea de cod și pentru GPU-urile Nvidia. Există binding-uri pentru Java (jCuda), Python (PyCUDA) și .NET (CUDA.NET). | + | CUDA (**C**ompute **U**nified **D**evice **A**rchitecture) permite utilizarea limbajului C pentru programarea pe GPU-urile Nvidia cât și extensii pentru alte limbaje (ex. Python). Deoarece una din zonele țintă pentru CUDA este HPC (**H**igh **P**erformance **C**omputing), în care limbajul Fortran este foarte popular, PGI ofera un compilator de Fortran ce permite generarea de cod și pentru GPU-urile Nvidia. Există binding-uri pentru Java (jCuda), Python (PyCUDA) și .NET (CUDA.NET). |
| {{:asc:lab7:cuda-software.png?800|}} | {{:asc:lab7:cuda-software.png?800|}} | ||
| Line 123: | Line 128: | ||
| Un kernel se definește folosind specificatorul ''__global__'' iar execuția sa se face printr-o configurație de execuție folosind <nowiki> <<<...>>> </nowiki>. Configurația de execuție denotă numarul de blocuri și numărul de thread-uri dintr-un block. Fiecare thread astfel poate fi identificat unic prin ''blockIdx'' și ''threadIdx''. | Un kernel se definește folosind specificatorul ''__global__'' iar execuția sa se face printr-o configurație de execuție folosind <nowiki> <<<...>>> </nowiki>. Configurația de execuție denotă numarul de blocuri și numărul de thread-uri dintr-un block. Fiecare thread astfel poate fi identificat unic prin ''blockIdx'' și ''threadIdx''. | ||
| - | {{:asc:lab7:cuda-scalability.png?640|}} | + | {{https://docs.nvidia.com/cuda/cuda-programming-guide/_images/grid-of-thread-blocks.png?600|Grid of Thread Blocks. Each arrow represents a thread (the number of arrows is not representative of actual number of threads)}} |
| + | {{https://developer-blogs.nvidia.com/wp-content/uploads/2017/01/Even-easier-intro-to-CUDA-image.png?700|Grid, Block and Thread indexing in CUDA kernels (one-dimensional)}} | ||
| + | {{:asc:lab7:cuda-scalability.png?600|}} | ||
| + | {{https://docs.nvidia.com/cuda/cuda-programming-guide/_images/thread-block-scheduling.png?400|When clusters are specified, the thread blocks in a cluster are arranged in their cluster shape within the grid. The thread blocks of a cluster are scheduled simultaneously on the SMs of a single GPC}} | ||
| Mai jos avem definit un kernel, ''vector_add'', care are ca argumente pointeri de tip ''float'', respectiv ''size_t''. Acesta calculează $ f(x) = 2x + 1/(x + 1) $, pentru fiecare element din vector. Numărul total de thread-uri este dimensiunea vectorului. | Mai jos avem definit un kernel, ''vector_add'', care are ca argumente pointeri de tip ''float'', respectiv ''size_t''. Acesta calculează $ f(x) = 2x + 1/(x + 1) $, pentru fiecare element din vector. Numărul total de thread-uri este dimensiunea vectorului. | ||
| Line 341: | Line 350: | ||
| cudaFree(device_array_b); | cudaFree(device_array_b); | ||
| </code> | </code> | ||
| + | |||
| + | ===== Warp-uri și modelul SIMT ===== | ||
| + | |||
| + | În arhitectura CUDA, thread-urile dintr-un bloc sunt organizate în grupuri de cate 32, numite ''warps''. Acestea funcționează conform paradigmei SIMT (Single-Instruction Multiple-Threads), în care toate firele dintr-un warp execută aceeași instrucțiune simultan, dar pot urma căi de execuție diferite prin cod. Atunci când firele dintr-un warp urmează ramuri diferite ale unui bloc condițional, cele care nu se încadrează în ramura activă sunt "mascate" temporar — fenomen cunoscut drept "warp divergence". Utilizarea eficientă a GPU-ului este maximizată atunci când toate firele dintr-un warp urmează același flux de control, motiv pentru care numărul total de fire dintr-un bloc ar trebui să fie un multiplu de 32. | ||
| + | |||
| + | {{https://docs.nvidia.com/cuda/cuda-programming-guide/_images/active-warp-lanes.png?600|In this example, only threads with even thread index execute the body of the if statement, the others are masked off while the body is executed. | ||
| + | }} | ||
| + | |||
| + | Deși SIMT este adesea comparat cu SIMD (Single Instruction Multiple Data), există o diferență esențială: în SIMD există un singur control flow path, pe când în SIMT fiecare fir poate urma propriul control flow path. Tocmai de asta SIMT nu are un data-width fix, precum la SIMD. Este esențial să ținem cont de warp-uri atunci când scriem cod CUDA, deoarece înțelegerea acestui model ajută la optimizarea accesului la memoria globală, partajată și a altor tehnici avansate. De asemenea, programele care încalcă modelul de programare SIMT pot genera comportament nedefinit, care poate varia în funcție de hardware-ul GPU utilizat. | ||
| ===== Aplicații ===== | ===== Aplicații ===== | ||
| Line 384: | Line 402: | ||
| * Documentatie CUDA: | * Documentatie CUDA: | ||
| + | * [[https://docs.nvidia.com/cuda/cuda-programming-guide/index.html|CUDA Programming]] | ||
| * [[https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html|CUDA C Programming]] | * [[https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html|CUDA C Programming]] | ||
| * [[https://docs.nvidia.com/cuda/pdf/CUDA_Compiler_Driver_NVCC.pdf| CUDA NVCC compiler]] | * [[https://docs.nvidia.com/cuda/pdf/CUDA_Compiler_Driver_NVCC.pdf| CUDA NVCC compiler]] | ||