Differences

This shows you the differences between two versions of the page.

Link to this comparison view

asc:laboratoare:07 [2023/04/26 15:33]
emil.slusanschi [Exercitii]
asc:laboratoare:07 [2024/04/15 00:13] (current)
mihnea.mitroi
Line 1: Line 1:
-====== Laboratorul 07 - Arhitecturi de tip GPGPU ======+====== Laboratorul 07 - CUDA ======
  
-===== Intro =====+===== Teorie ​=====
  
-Procesorul grafic (GPU graphics processing unit) reprezinta un circuit electronic specializat in crearea si manipularea imaginilor trimise catre o unitate de display (e.g. monitor). Termenul GPGPU (general purpose graphics processing unit) denota un procesor grafic cu o flexibilitate ridicata de programare, capabil de rezolva si probleme generale. In executie, o arhitectura de tip GPU foloseste paradigma SIMD (single instruction multiple data, taxonomia Flynn), ceea ce presupune, schimb rapid de context intre thread-uri, planificarea in grupuri de thread-uri si orientare catre prelucrari masive de date. Procesorul grafic dispune si de un spatiu propriu de memorie (GPU dedicat -> VRAM, GPU integrat -> RAM). +Scopul acestui laborator este aprofundarea și îmbinarea noțiunilor pe care le-ați învățat deja la APD și în laburile trecute ​(poate și la IA).
  
-Unitatile tip GPU sunt potrivite pentru paralelismul ​de date, intensiv computationaleDatorita faptului ca aceleasi instructiuni sunt executate pentru fiecare element, nu sunt necesare mecanisme complexe pentru controlul fluxului. Ierarhia ​de memorie este simplificata comparativ cu cea a unui procesor x86/ARM. Deoarece calculele sunt intensive computational,​ latenta accesului la memorie poate fi ascunsa prin paralelism (massive multithreading,​ SIMT sau Single Instruction Multiple Threads) in locul folosirii extensive ​memoriei cache.+Vă încurajăm să profitați ​de acest laborator ca să vă clarificați posibile nelămuriri din laburile trecuteSaude ce nu, să vă șlefuiți abilitatea ​de a optimiza programe CUDA dacă terminați mai devreme:P
  
-<note important>​ +==== Odd-Even Transposition Sort ====
-Nu orice algoritm paralel ruleaza optim pe o arhitectura GPGPU. De principiu probleme de tip SIMD sau MIMD se preteaza rularii pe GPU-uri. +
-</​note>​+
  
-In multe cazuri, termenul de GPGPU apare atunci cand unitatea GPU este folosita ca si coprocesor matematic. In ziua de azimajoritatea unitatilor de tip GPU sunt si GPGPUIn ultimii ani folosirea unitatilor GPGPU a luat amploare. Acest lucru se datoreaza:​ +Bubble Sort este un algoritm secvențial în care se parcurge șirul ​de sortat element cu elementcomparând elementul curent cu vecinul din dreaptaDacă numărul din dreapta este mai mic, se realizează o interschimbare între elementul curent și cel din dreapta sa.
-  * diferentelor de putere de procesare bruta dintre CPU si GPU in favoarea acestora ​din urma +
-  * standardizarea de API-uri care usureaza munca programatorilor pentru a folosi GPU-ul +
-  * raspandirea aplicatiilor ce pot beneficia de pe urma paralelismului tip SIMD +
-  * regasirea unitatilor GPU atat in unitatile computationale consumer (PC, Smartphone, TV etc) cat si cele industriale (Automotive,​ HPC etc).+
  
-Principalii producatori ​de core-uri IP (intellectual propertytip GPU sunt+Operațiile pe elemente adiacente nu se pot realiza simultan, pentru că se poate ajunge la un race condition. Din acest motiv, un mod de a paraleliza Bubble Sort este Odd-Even Transposition Sort, un algoritm in 2 două faze. În faza pară, elementele de pe poziții pare din șirul de sortat sunt comparate ​(și eventual interschimbatecu vecinii din dreapta. După ce se termină faza pară (adică după ce toate elementele pare au fost procesate), urmează faza impară, în care elementele impare ​sunt analizate și comparate cu vecinii din dreapta.
-  * Intel http://​en.wikipedia.org/​wiki/​List_of_Intel_graphics_processing_units +
-  * Nvidia http://​en.wikipedia.org/​wiki/​List_of_Nvidia_graphics_processing_units +
-  * Amd http://​en.wikipedia.org/​wiki/​List_of_AMD_graphics_processing_units +
-  * Apple https://​en.wikipedia.org/​wiki/​Apple_silicon +
-  * Imagination http://​en.wikipedia.org/​wiki/​List_of_PowerVR_products +
-  * Qualcomm http://​en.wikipedia.org/​wiki/​Adreno +
-  * Vivante http://​en.wikipedia.org/​wiki/​Vivante_Corporation+
  
-Daca un IP de GPU este integrat pe aceeasi pastila de siliciu a unui SoC (system on chip), acesta se numeste GPU integrat (integrated GPU). Exemple de SoC-uri cu IP de GPU integrat includ procesoarele x86 Intel si Amd cat si majoritatea SoC-urilor pentru dispozitive mobile bazate pe arhitectura ARM (ex. Qualcomm Snapdragon). Un GPU integrat imparte mare parte din ierarhia de memorie cu alte IP-uri (ex core-uri ARM/x86, controller PCIe/​USB/​SATA/​ETH). Pe de alta parte un GPU dedicat (discrete GPU) presupunea integrarea IP-ului de GPU pe o placa cu memorie dedicata (VRAM) cat si o magistrala PCIe/​AGP8x/​USB pentru comunicare cu sistemul. Exemple de GPU-uri dedicate sunt seriile de placi grafice Geforce (Nvidia) si Radeon (Amd).+{{:​asc:​lab7:​oets.png?200 | OETS}}
  
-{{:​asc:​lab10:​dgpu_igpu.png?​direct&​750|}}+==== Merge Sort ====
  
-==== Aplicatii arhitecturi GPGPU ====+Merge sort (sau sortarea prin interclasare) este un algoritm de sortare de tip divide et impera care presupune următorii pași generali: 
 +  * se împarte șirul de N elemente de sortat în N șiruri de lungime 1 
 +  * se aplica operația de interclasare ("​merge"​) între câte două astfel de șiruri de lungime 1, rezultând N/2 șiruri sortate de lungime 2 
 +  * se repetă pașii de mai sus realizând interclasări între șiruri din ce în ce mai mari, până se ajunge la un șir sortat de N elemente.
  
-Exemple ​de domenii ce folosesc procesare GPGPU: prelucrari video si de imaginisimulari ​de fizicafinante, dinamica fluidelor, criptografie,​ design electronic ​(VLSI). Exemple ​de aplicatii ​pentru ​GPGPU: +Pentru a paraleliza acest algoritm, putem observa că operațiile ​de interclasare ​de la fiecare pas se pot realiza în paralel. Totușioperațiile ​de "​merge"​ de la fiecare pas trebuie terminate în totalitate înainte de a trece la următorul pasdeci avem nevoie de o barieră ​(sau un mecanism similardupă fiecare pas de interclasareSe poate observa că gradul ​de paralelism de la un pas de interclasări este din ce în ce mai mic pe măsură ce avansăm în algoritm, ​pentru ​că numărul de operații de "​merge"​ de la fiecare pas scade.
-Automotive - self driving cars (BMW, Continental etc) +
-  * https://www.nvidia.com/​en-us/​self-driving-cars/​partners/​bmw/​ +
-  * https://​blogs.nvidia.com/​blog/​2018/​09/​18/​audi-unveils-e-tron-electric-suv/​ +
-Inteligenta artificala - antrenare retele neurale, inferenta +
-  * https://​www.forbes.com/​sites/​forbestechcouncil/​2017/​12/​01/​for-machine-learning-its-all-about-gpus/​ +
-  * https://​www.quora.com/​Why-are-GPUs-well-suited-to-deep-learning +
-Criptomonede - mining via hashing +
-  * https://​coincentral.com/​best-gpu-for-mining-2018-edition/​ +
-SmartTV, Smartphone - accelerare video, recunoastere faciala/​audio +
-Simulari fizice - NVIDIA Physx, Folding@Homel +
-  * https://​blogs.nvidia.com/​blog/​2018/​11/​13/​weather-predicted-sc18-gpu-hpc-jensen-huang/​ +
-Prelucrari multimedia - filtre imagini GIMP/​Photoshop +
-Alte domenii - arhivare (WinZip), encriptare+
  
-{{:asc:lab10:gpu-use.png?direct&​700|}}+{{:asc:lab7:mergesort.png?300 Mergesort}}
  
-===== Programarea GPGPU =====+==== Gaussian Blur ====
  
-In cadrul unui sistem ce contine o unitate IP de tip GPUprocesorul general care coordoneaza executia ​este numit "​HOST"​ (CPU) pe cand unitatea care efectueaza calculele este numita "​DEVICE"​ (GPU). O unitate GPU contine un procesor de comanda ("​command processor"​) care citeste comenzile scrise de catre HOST (CPU) in anumite zone din RAM mapate spre access atat catre unitatea GPU cat si catre unitatea CPU. Toate schimbarile de stare in cadrul unui GPU, alocarile/​transferurile de memorie si evenimentele ce tin de sistemul de operare sunt controlate de catre CPU (HOST)+În prelucrarea imaginilorblurarea gaussiană ​este rezultatul estomparii unei imagini printr-o funcție gaussiană.
  
-In general, o prelucrare de date folosind unitatea GPU, necesita in prealabil ​un transfer din spatiul de memorie de la CPU catre spatiul de memorie de la GPU. In cazul unui procesor ​grafic ​dedicat acest transfer se face printr-o magistrala (PCIe, AGPUSB…)Viteza ​de transfer RAM-VRAM via magistrala ​este inferioara vitezei RAM sau VRAM. O potentiala optimizare in transferul RAM<->VRAM ar fi intercalarea cu procesareaIn cazul unui procesor integrate transferul RAM<​->​VRAM presupune ​mapare ​de memorie, ​de multe ori translatata printr-o operatie de tip zero copy+Este un efect larg utilizat în software-ul ​grafic, ​în mod tipic pentru a reduce zgomotul imaginii și pentru a reduce detaliileEfectul vizual al acestei tehnici ​de estompare ​este un blur neted care seamănă cu cel obținut privind imaginea printr-un ecran translucidEstomparea gaussiană este de asemenea folosită ca etapă ​de prelucrare în algoritmi ​de viziune artificială pentru a îmbunătăți structurile imaginii la diferite scări.
  
-Programarea unui GPU se face printr-un API (Application Programming Interface). Cele mai cunoscute API-uri orientate catre folosirea unui GPU ca coprocesor matematic sunt: Cuda, OpenCL, DirectCompute,​ OpenACC, Vulkan. Dezvoltarea de cod pentru laboratoarele de GPU se va face folosind Cuda.+Aplicarea unei estompări gaussiene asupra unei imagini este echivalentă cu convoluția imaginii cu o funcție gaussiană. Transformarea ​(funcțiade aplicat fiecărui pixel din imagine este urmatoarea:​ 
 +\[ G(x) = \frac{1}{\sqrt{2\pi \sigma^2}} e^{-\frac{x^2}{2\sigma^2}} \]
  
-//De ce CUDA ?//+{{:​asc:​lab7:​gaussian-blur.png?400 | Gaussian Blur}}
  
-CUDA este un API introdus in 2006 de catre NVIDIA pentru GPU-urile sale. In prezent CUDA este standardul de facto pentru folosirea unitatilor GPU in industrie si cercetare. Aceasta se datoreaza faptului ca este o platforma stabila cu multe facilitati. O noua versiune de CUDA introduce noi functiontionalitati dar acestea uneori necesita versiuni recente ale arhitecturilor fiind dezactivate daca nu exista suport hardware. O versiune noua de CUDA extinde versiunea mai veche - de exemplu versiunea CUDA 9.0 reprezinta in mare o extensie/​update asupra versiunii CUDA 8.0. In mare toate GPU-urile oferite de NVIDIA sunt suportate, diferenta fiind la facilitatile suportate. Singura limitare majora a platformei CUDA este ca suporta numai unitati de procesare de tip GPU de la NVIDIA.+===== Exercitii =====
  
-Un standard alternativ la CUDA este OpenCL, suportata ​de Khronos ca standard si implementata de majoritatea producatorilor de GPU (inclusiv NVIDIA ca o extensie la CUDA)Problema majora la OpenCL este ca suportul este fragmentat si standardul este mult mai restrictiv decat CUDA si mai complicat de scris programe.+Urmăriți instrucțiunile ​de pe [[https://​gitlab.cs.pub.ro/​asc/​asc-public/​-/​tree/​master/​labs/​cuda/​practice|GitLab]].
  
-===== Arhitectura NVIDIA CUDA ===== +<note important>​ 
- +Puteți găsi materiale ajutătoare în cadrul [[https://mobylab.docs.crescdi.pub.ro/docs/parallelAndDistributed/laboratory3|laboratorului ​3 de la APD]] șîn videoclipul ​[[https://www.youtube.com/watch?v=KuXjwB4LzSA&​t=512s|Gaussian Blur]]. 
-Implementarea NVIDIA pentru GPGPU se numeste CUDA (Compute Unified Device Architecture) ​si permite utilizarea limbajului C pentru programarea pe GPU-urile proprii cat si extensii pentru alte limbaje (ex Python). Deoarece una din zonele tinta pentru CUDA este HPC (High Performance Computing), in care limbajul Fortran este foarte popular, PGI ofera un compilator de Fortran ce permite generarea de cod si pentru GPU-urile Nvidia. Exista binding-uri pana si pentru Java (jCuda), Python (PyCUDA) sau .NET (CUDA.NET). Framework-ul/​arhitectura CUDA expune si API-ul de OpenCL prin intermediul caruia vom interactiona cu GPGPU-ul Nvidia Tesla disponibil pe dp. +</note>
- +
-{{:​asc:​lab7:​cuda-software.png?​800|}} +
- +
-Arhitectura CUDA (toate GPU-urile, seriile Geforce (consumer), Tesla (HPC), Jetson (automotive)). +
-Driver cu suport Windows, Linux, ce suporta atat CUDA API cat si OpenCL API. +
-Framework/​toolkit compilator cu suport CUDA/OpenCL API (nvcc), debugger/​profiler (CUDA API only) +
-Numeroase biblioteci si exemple CUDA/OpenCL API +
- +
-Unitatea de baza in cadrul ​arhitecturii CUDA este numita SM (Streaming Multiprocessor). Ea contine in functie de generatie un numar variabil de Cuda Cores sau SP (Stream Processors) - de regula intre 8SP si 128SP. Unitatea de baza in scheduling este denumita "​warp"​ si alcatuita din 32 de thread-uri. Vom aborda mai amanuntit arhitectura CUDA in laboratorul urmator. Ultima versiune de CUDA 8.0 suport OpenCL 1.2. +
- +
-===== Compute capability ===== +
- +
-Versiunea de "​compute capability"​ a unui SM (Streaming Multiprocessor),​ in cadrul arhitecturii CUDA, este reprezentat de un format X.Y, unde X este versiunea majora pe cand Y este versiunea minora. Partea majora identifica generatia din care face parte arhitectura. Astfel revizia 7 denota arhitectura Volta, 6 este pentru arhitectura Pascal, 5 pentru arhitectura Maxwell, 3 pentru arhitectura Kepler, 2 pentru Fermi iar 1 pentru Tesla. Partea minora identifica diferente incrementale in arhitectura si posibile noi functionalitati. Stiind versiunea majora si cea minora cunoastem facilitatile hardware oferite de catre arhitectura. GPU-urile care au aceasi versiune suporta aceleasi capabilitati. +
- +
-O lista a GPU-urile NVIDIA si versiunile lor majore/​minore se regaseste ​[[https://developer.nvidia.com/​cuda-gpus|aici]]. +
-In cadrul cozii hpsl se regasesc GPU-uri [[https://​www.nvidia.com/​content/​pdf/​kepler/​tesla-k40-active-board-spec-bd-06949-001_v03.pdf|Tesla K40M]], iar in cadrul cozii dp GPU-uri [[https://​www.nvidia.com/​docs/​IO/​43395/​NV_DS_Tesla_C2050_C2070_jul10_lores.pdf|Tesla 2070]]. +
- +
-===== Programarea in CUDA ===== +
- +
-CUDA extinde limbajul C prin faptul ca permite unui programator sa defineasca functii C, denumite kernels, care urmeaza a fi execute de N ori in paralel de N thread-uri CUDAScopul este de a abstractiza arhitectura GPU astfel incat partea de scheduling cat si gestiunea resurselor se face de catre stack-ul software CUDA impreuna cu suportul hardware. Figura de mai jos denota distribuirea thread-urilor catre 2 arhitecturi partitionate diferit. +
- +
-Un kernel se defineste folosind specificatorul __global__ iar executia sa se face printr-o configuratia de executie folosind <​nowiki>​ <<<​...>>>​ </​nowiki>​. Configuratia de executie denota numarul de blocks si numarul de thread-uri dintr-un block. Fiecare thread astfel poate fi identificat unic prin blockIdx si threadIdx. +
- +
-{{:​asc:​lab7:​cuda-scalability.png?​640|}} +
- +
-Mai jos avem definit un kernel, vector_add, care are ca argumente pointers de tip float respectiv size_t. Acesta calculeaza f(x) = 2x + 1/(x + 1), pentru fiecare elemente din vector. Numarul total de thread-uri este dimensiunea vectorului. +
- +
-<code C> +
-__global__ void vector_add(const float *a, float *b, const size_t n) { +
-   // Compute the global element index this thread should process +
-   ​unsigned int i = threadIdx.x + blockDim.x * blockIdx.x;​ +
- +
-   // Avoid accessing out of bounds elements +
-   if (i < n) { +
-      b[i] = 2.0 * a[i] + 1.0 / (a[i] + 1.0); +
-   } +
-+
-</​code>​ +
- +
-Configuratia de executie denota maparea intre date si instructiuni. In functia de kernel, se defineste setul de instructiuni ce se va executa repetat pe date. Mai jos vector_add este lansat in executie cu N thread-uri (blocks_no x block_size) organizate cate block_size thread-uri per block. +
- +
-<code C> +
-  // Launch the kernel +
-  vector_add<<<​blocks_no,​ block_size>>>​(device_array_a,​ device_array_b,​ num_elements);​ +
-</​code>​ +
- +
-===== Aplicatie HelloWorld CUDA ===== +
- +
-<code C> +
-#include <​stdio.h>​ +
- +
-__global__ void kernel_example(int value) { +
-   /** +
-   * This is a kernel; a kernel is a piece of code that +
-   * will be executed by each thread from each block in +
-   * the GPU device. +
-   */ +
-   ​printf("​[GPU] Hello from the GPU!\n"​);​ +
-   ​printf("​[GPU] The value is %d\n", value); +
-   ​printf("​[GPU] blockDim=%d,​ blockId=%d, threadIdx=%d\n",​blockDim.x,​ blockIdx.x, threadIdx.x);​ +
-+
- +
-int main(void) { +
-   /** +
-   * Here, we declare and/or initialize different values or we +
-   * can call different functions (as in every C/C++ program); +
-   * In our case, here we also initialize the buffers, copy +
-   * local data to the device buffers, etc (you'​ll see more about +
-   * this in the following exercises). +
-   */ +
-   int nDevices; +
-   ​printf("​[HOST] Hello from the host!\n"​);​ +
- +
-   /** +
-   * Get the number of compute-capable devices. See more info  +
-   * about this function in the Cuda Toolkit Documentation. +
-   */ +
-   ​cudaGetDeviceCount(&​nDevices);​ +
-   ​printf("​[HOST] You have %d CUDA-capable GPU(s)\n",​ nDevices);​ +
- +
-   /**  +
-   * Launching the above kernel with a single block, each block +
-   * with a single thread. The syncrhonize and the checking functions +
-   * assures that everything works as expected. +
-   */ +
-   ​kernel_example<<<​1,​1>>>​(25);​ +
-   ​cudaDeviceSynchronize();​ +
- +
-   /** +
-   * Here we can also deallocate the allocated memory for the device +
-   */ +
-   ​return 0; +
-+
- +
- +
-</​code>​ +
- +
-===== Aplicatie compute CUDA ===== +
- +
-O aplicatie CUDA are ca scop executia de cod pe GPU-uri NVIDIA CUDA. +
-In cadrul laboratoarelor partea de CPU (host) va fi folosita exclusiv pentru managementul executiei partii de GPU (device). +
-Aplicatiilor vor viza executia folosind un singur GPU NVIDIA CUDA. +
- +
-==== 0. Definire functie kernel ==== +
- +
-In codul prezentat mai jos, functia vector_add este marcata cu "​__global__"​ si va fi compilata de catre [[https://docs.nvidia.com/cuda/pdf/​CUDA_Compiler_Driver_NVCC.pdfCUDA NVCC compiler]] pentru GPU-ul de pe sistem (in cazul cozii hpsl va fi NVIDIA Tesla K40M). +
- +
-<code C> +
-/** +
- * This kernel computes the function f(x) = 2x + 1/(x + 1) for each +
- * element in the given array. +
- */ +
-__global__ void vector_add(const float *a, float *b, const size_t n) { +
-  // Compute the global element index this thread should process +
-  unsigned int i = threadIdx.x + blockDim.x * blockIdx.x;​ +
- +
-  // Avoid accessing out of bounds elements +
-  if (i < n) { +
-    b[i] = 2.0 * a[i] + 1.0 / (a[i] + 1.0); +
-  } +
-+
-</​code>​ +
- +
-==== 1. Definire zone de memorie host si device ==== +
- +
-Din punct de vedere hardware, partea de host (CPU) are ca memorie principala RAM (chip-uri memorie instalate pe placa de baza via slot-uri memorie) iar partea de device (GPU) are VRAM (chip-uri de memorie prezente pe placa video). Cand vorbim de memoria host (CPU) ne referim la RAM, iar in cazul memoriei device (GPU) la VRAM. +
- +
-La versiunile mai recente de CUDA, folosind limbajul C/C++, un pointer face referire la spatiul virtual care este unificat pentru host (CPU) si device (GPU). Adresele virtuale insa sunt translatate catre adrese fizice ce rezida ori in memoria RAM (CPU) ori in memoria VRAM (GPU). Astfel este important cum alocam memoria (fie cu malloc pentru CPU sau cudaMalloc pentru GPU) si respectiv sa facem cu atentie transferurile de memorie intre zonele virtuale definite (de la CPU la GPU si respectiv de la GPU la CPU). +
- +
-<code C> +
-// Declare variable to represent ~1M float values and +
-// computes the amount of bytes necessary to store them +
-const int num_elements = 1 << 16; +
-const int num_bytes = num_elements * sizeof(float);​ +
- +
-// Declaring the 'host arrays':​ a host array is the classical +
-// array (static or dynamically allocated) we worked before. +
-float *host_array_a = 0; +
-float *host_array_b = 0; +
- +
-// Declaring the '​device array':​ this array is the equivalent +
-// of classical array from C, but specially designed for the GPU +
-// devices; we declare it in the same manner, but the allocation +
-// process is going to be different +
-float *device_array_a = 0; +
-float *device_array_b = 0; +
-</​code>​ +
- +
-==== 2. Alocare memorie host (CPU) ==== +
- +
-Functia malloc va intoarce o adresa virtuala ce va avea corespondent o adresa fizica din RAM. +
- +
-<code C> +
-// Allocating the host array +
-host_array_a = (float *) malloc(num_bytes);​ +
-host_array_b = (float *) malloc(num_bytes);​ +
-</​code>​ +
- +
-==== 3. Alocare memorie device (GPU) ==== +
- +
-Functia cudaMalloc va intoarce o adresa virtuala ce va avea corespondent o adresa fizica din VRAM. +
- +
-<code C> +
-// Allocating the device'​s array; notice that we use a special +
-// function named cudaMalloc that takes the reference of the +
-// pointer declared above and the number of bytes. +
-cudaMalloc((void **) &​device_array_a,​ num_bytes);​ +
-cudaMalloc((void **) &​device_array_b,​ num_bytes);​ +
- +
-// If any memory allocation failed, report an error message +
-if (host_array_a == 0 || host_array_b == 0|| device_array_a == 0 || device_array_b == 0) { +
-  printf("​[HOST] Couldn'​t allocate memory\n"​);​ +
-  return 1; +
-+
-</​code>​ +
- +
-==== 4. Initializare memorie host (CPU) si copiere pe device (GPU) ==== +
- +
-{{:​asc:​lab10:​cpu_to_gpu.png?​720|}} +
- +
-<code C> +
-// Initialize the host array by populating it with float values ​  +
-for (int i = 0; i < num_elements;​ ++i) { +
-  host_array_a[i] = (float) i; +
-+
- +
-// Copying the host array to the device memory space; notice the +
-// parameters of the cudaMemcpy function; the function default +
-// signature is cudaMemcpy(dest,​ src, bytes, flag) where +
-// the flag specifies the transfer type. +
-// +
-// host -> device: cudaMemcpyHostToDevice +
-// device -> host: cudaMemcpyDeviceToHost +
-// device -> device: cudaMemcpyDeviceToDevice +
-cudaMemcpy(device_array_a,​ host_array_a,​ num_bytes, cudaMemcpyHostToDevice);​ +
-</​code>​ +
- +
-==== 5. Executie kernel ==== +
- +
-{{:​asc:​lab10:​exec_gpu.png?​720|}} +
- +
-<code C> +
-// Compute the parameters necessary to run the kernel: the number +
-// of blocks and the number of threads per block; also, deal with +
-// a possible partial final block +
-const size_t block_size = 256; +
-size_t blocks_no = num_elements / block_size;​ +
- +
-if (num_elements % block_size)  +
-  ++blocks_no;​ +
- +
-// Launch the kernel +
-vector_add<<<​blocks_no,​ block_size>>>​(device_array_a,​ device_array_b,​ num_elements);​ +
-cudaDeviceSynchronize();​ +
-</​code>​ +
- +
- +
-==== 6. Copiere date inapoi ​de la device (GPU) catre host (CPU) ==== +
- +
-<code C> +
-// Copy the result back to the host memory space +
-cudaMemcpy(host_array_b,​ device_array_b,​ num_bytes, cudaMemcpyDeviceToHost);​ +
- +
-// Print out the first 10 results +
-for (int i = 0; i < 10; ++i) { +
-  printf("​Result %d: 2 * %1.1f + 1.0/(%1.1f + 1.0)= %1.3f\n",​  +
-  i, host_array_a[i], host_array_a[i], host_array_b[i]); +
-+
-</​code>​ +
- +
-{{:​asc:​lab10:​gpu_to_cpu.png?​720|}} +
- +
-==== 7. Cleanup ==== +
- +
-<code C> +
-// Deallocate memory +
-free(host_array_a);​ +
-free(host_array_b);​ +
-cudaFree(device_array_a);​ +
-cudaFree(device_array_b);​ +
-</​code>​ +
- +
-===== Compilare si executie ===== +
- +
-Desi pentru un programator partile de host/CPU respectiv device/GPU pot fi in acelasi fisier *.cu, compilatorul CUDA (nvcc) le separa facand o compilare diferita pentru partea de host/CPU respectiv device/GPU. Figura de mai jos denota acest aspect. +
- +
-{{:​asc:​lab7:​cuda-nvcc.png?​480|}} +
- +
-Intrati pe frontend-ul ''​fep8.grid.pub.ro''​ folosind contul de pe curs.upb.ro. Executati comanda +
- +
-<code sh> +
-srun --pty -p hpsl /bin/bash +
-</​code>​ +
- +
-pentru a accesa una din statiile cu GPU-uri. Cozile ce au unitati GPU NVIDIA Tesla sunt {{:​asc:​lab10:​hpsl-wn0x.pdf|hpsl}} si {{:​asc:​lab10:​dp-wn0x.pdf|dp}}. +
- +
-<code sh> +
-[@fep8 ~]$ srun --pty -p hpsl /bin/bash +
-[@hpsl-wn01 ~]$ nvidia-smi ​      # NVIDIA System Management Interface program +
-+-----------------------------------------------------------------------------+ +
-| NVIDIA-SMI 470.82.01 ​   Driver Version: 470.82.01 ​   CUDA Version: 11.4     | +
-|-------------------------------+----------------------+----------------------+ +
-| GPU  Name        Persistence-M| Bus-Id ​       Disp.A | Volatile Uncorr. ECC | +
-| Fan  Temp  Perf  Pwr:​Usage/​Cap| ​        ​Memory-Usage | GPU-Util ​ Compute M. | +
-|                               ​| ​                     |               MIG M. | +
-|===============================+======================+======================| +
-|   ​0 ​ Tesla K40m          Off  | 00000000:​08:​00.0 Off |                    0 | +
-| N/A   ​40C ​   P0    63W / 235W |      0MiB / 11441MiB |      0%      Default | +
-|                               ​| ​                     |                  N/A | +
-+-------------------------------+----------------------+----------------------+ +
-|   ​1 ​ Tesla K40m          Off  | 00000000:​24:​00.0 Off |                    0 | +
-| N/A   ​44C ​   P0    64W / 235W |      0MiB / 11441MiB |      0%      Default | +
-|                               ​| ​                     |                  N/A | +
-+-------------------------------+----------------------+----------------------+ +
-|   ​2 ​ Tesla K40m          Off  | 00000000:​27:​00.0 Off |                    0 | +
-| N/A   ​40C ​   P0    62W / 235W |      0MiB / 11441MiB |     ​52% ​     Default | +
-|                               ​| ​                     |                  N/A | +
-+-------------------------------+----------------------+----------------------+ +
- +
-</​code>​ +
- +
-Pentru laboratoarele de GP-GPU Computing vom folosi CUDA 9.1 [[https://developer.download.nvidia.com/compute/​cuda/​9.1/​Prod/​docs/​sidebar/​CUDA_Toolkit_Release_Notes.pdf|aici]]. +
- +
-SDK-ul CUDA de la NVidia include atat implementarea de CUDA API cat si cea de OpenCL API. In cadrul laboratoarelor vom programa numai folosind CUDA. Verificam mai jos ca scheletul laboratorului compileaza. +
- +
-<code sh> +
-[@hpsl-wn01 ~]$ wget -O lab7_skl.tar.gz https://​ocw.cs.pub.ro/​courses/​_media/​asc/​lab7/​lab7_skl.tar.gz +
---2020-03-22 18:​52:​14-- ​ http://​ocw.cs.pub.ro/​courses/​_media/​asc/​lab7/​lab7_skl.tar.gz +
-Resolving ocw.cs.pub.ro (ocw.cs.pub.ro)... 141.85.227.65 +
-Connecting to ocw.cs.pub.ro (ocw.cs.pub.ro)|141.85.227.65|:​80... connected. +
-HTTP request sent, awaiting response... 302 Found +
-Location: https://​ocw.cs.pub.ro/​courses/​_media/​asc/​lab7/​lab7_skl.tar.gz [following] +
---2020-03-22 18:​52:​14-- ​ https://​ocw.cs.pub.ro/​courses/​_media/​asc/​lab7/​lab7_skl.tar.gz +
-Connecting to ocw.cs.pub.ro (ocw.cs.pub.ro)|141.85.227.65|:​443... connected. +
-HTTP request sent, awaiting response... 200 OK +
-Length: 4884 (4.8K) [application/​octet-stream] +
-Saving to: '​lab7_skl.tar.gz'​ +
- +
-100%[==================================================================================================>​] 4,884       ​--.-K/​s ​  in 0s       +
- +
-2020-03-22 18:52:14 (11.1 MB/s) - '​lab7_skl.tar.gz'​ saved [4884/​4884] +
- +
-[@hpsl-wn01 ~]$ tar -xvzf lab7_skl.tar.gz +
-task1/ +
-task1/​task1.cu +
-task1/​Makefile +
-task1/​Makefile_Cluster +
-task2/ +
-task2/​task2.cu +
-task2/​Makefile +
-task2/​Makefile_Cluster +
-... +
-[@hpsl-wn01 ~]$ cd task1/ +
-</​code>​ +
- +
-<code sh> +
-[@hpsl-wn01 ~]$ apptainer run --nv docker://​gitlab.cs.pub.ro:​5050/​asc/​asc-public/​cuda-labs:​1.9.1 +
-INFO:    Using cached SIF image +
-Apptainer>​ +
-</​code>​ +
- +
-În cadrul imaginei CUDA avem compilatorul nvcc.  +
- +
-<code Makefile>​ +
-COMPILER=nvcc +
-LIBS=-lm +
- +
-%: %.cu +
- $(COMPILER) $^ -o $@ $(LIBS) +
- +
-clean: +
- rm -rf task0 +
-</​code>​ +
- +
-Exemplu de compilare si rulare interactiva pe coada hpsl +
-<code sh> +
-Apptainer>​ make task1 +
-nvcc task1.cu -o task1 -lm +
-Apptainer>​ ./task1 +
-[HOST] Hello from the host! +
-[HOST] You have 3 CUDA-capable GPU(s) +
-Apptainer>​ make clean +
-rm -rf task1 +
-Apptainer>​ cd ../task2 +
-Apptainer>​ make task2 +
-nvcc task2.cu -o task2 -lm +
-Apptainer>​ ./task2 +
-Result 0: 2 * 0.0 + 1.0/(0.0 + 1.0)= 0.000 +
-Result 1: 2 * 1.0 + 1.0/(1.0 + 1.0)= 0.000 +
-Result 2: 2 * 2.0 + 1.0/(2.0 + 1.0)= 0.000 +
-Result 3: 2 * 3.0 + 1.0/(3.0 + 1.0)= 0.000 +
-Result 4: 2 * 4.0 + 1.0/(4.0 + 1.0)= 0.000 +
-Result 5: 2 * 5.0 + 1.0/(5.0 + 1.0)= 0.000 +
-Result 6: 2 * 6.0 + 1.0/(6.0 + 1.0)= 0.000 +
-Result 7: 2 * 7.0 + 1.0/(7.0 + 1.0)= 0.000 +
-Result 8: 2 * 8.0 + 1.0/(8.0 + 1.0)= 0.000 +
-Result 9: 2 * 9.0 + 1.0/(9.0 + 1.0)= 0.000 +
-Apptainer>​  +
-</​code>​ +
- +
-Exemplu executie program CUDA folosind rularea ne-interactiva pe coada de executia hpsl (apelul trebuie facut de pe fep8.grid.pub.ro):​ +
-<code sh> +
-[fep8 ~]$ cd task2/ +
-[fep8 task2]$ cat ../​utils/​batch_run.sh  +
-#​!/​bin/​bash +
-apptainer exec --nv $CONTAINER_IMAGE ​ \ +
-./$TASK +
-[fep8 task2]$ sbatch --time 01:00:00 -p hpsl --export=TASK=task2,​CONTAINER_IMAGE=docker://​gitlab.cs.pub.ro:​5050/​asc/​asc-public/​cuda-labs:​1.9.1 ../​utils/​batch_run.sh +
-Submitted batch job 1816 +
-[fep8 task2]$ squeue ​grep 1816 +
-              1816      hpsl batch_ru stefan_d ​ R       ​0:​07 ​     1 hpsl-wn01 +
-[fep8 task2]$ cat slurm-1816.out  +
-INFO:    Using cached SIF image +
-Result 0: 2 * 0.0 + 1.0/(0.0 + 1.0)= 1.000 +
-Result 1: 2 * 1.0 + 1.0/(1.0 + 1.0)= 2.500 +
-Result 2: 2 * 2.0 + 1.0/(2.0 + 1.0)= 4.333 +
-Result 3: 2 * 3.0 + 1.0/(3.0 + 1.0)= 6.250 +
-Result 4: 2 * 4.0 + 1.0/(4.0 + 1.0)= 8.200 +
-Result 5: 2 * 5.0 + 1.0/(5.0 + 1.0)= 10.167 +
-Result 6: 2 * 6.0 + 1.0/(6.0 + 1.0)= 12.143 +
-Result 7: 2 * 7.0 + 1.0/(7.0 + 1.0)= 14.125 +
-Result 8: 2 * 8.0 + 1.0/(8.0 + 1.0)= 16.111 +
-Result 9: 2 * 9.0 + 1.0/(9.0 + 1.0)= 18.100 +
-</​code>​ +
- +
- +
-Puteți folosi Makefile_Cluster:​ +
-<code sh> +
-[fep8 ~]$ cd task2/ +
-[fep8 task2]$ make -f Makefile_Cluster clean +
-rm -rf task2 +
-rm -rf slurm-* +
-[fep8 task2]$ make -f Makefile_Cluster task2 +
-sbatch --time 01:00:00 -p hpsl --export=TASK=task2,​CONTAINER_IMAGE=docker://​gitlab.cs.pub.ro:​5050/​asc/​asc-public/​cuda-labs:​1.9.1 ../​utils/​batch_build.sh | ../​utils/​batch_wait.sh +
-INFO:    Using cached SIF image +
-nvcc task2.cu -o task2 -lm +
-[fep8 task2]$ make -f Makefile_Cluster run_task1 +
-sbatch --time 01:00:00 -p hpsl --export=TASK=task2,​CONTAINER_IMAGE=docker://​gitlab.cs.pub.ro:​5050/​asc/​asc-public/​cuda-labs:​1.9.1 ../​utils/​batch_run.sh | ../​utils/​batch_wait.sh +
-INFO:    Using cached SIF image +
-Result 0: 2 * 0.0 + 1.0/(0.0 + 1.0)= 1.000 +
-Result 1: 2 * 1.0 + 1.0/(1.0 + 1.0)= 2.500 +
-Result 2: 2 * 2.0 + 1.0/(2.0 + 1.0)= 4.333 +
-Result 3: 2 * 3.0 + 1.0/(3.0 + 1.0)= 6.250 +
-Result 4: 2 * 4.0 + 1.0/(4.0 + 1.0)= 8.200 +
-Result 5: 2 * 5.0 + 1.0/(5.0 + 1.0)= 10.167 +
-Result 6: 2 * 6.0 + 1.0/(6.0 + 1.0)= 12.143 +
-Result 7: 2 * 7.0 + 1.0/(7.0 + 1.0)= 14.125 +
-Result 8: 2 * 8.0 + 1.0/(8.0 + 1.0)= 16.111 +
-Result 9: 2 * 9.0 + 1.0/(9.0 + 1.0)= 18.100 +
-</code>+
  
 <note important>​ <note important>​
 Recomandăm sa va delogati mereu de pe serverele din cluster dupa terminarea sesiunii, utilizand comanda ''​exit''​ Recomandăm sa va delogati mereu de pe serverele din cluster dupa terminarea sesiunii, utilizand comanda ''​exit''​
  
-Alternativ, daca ati uitat sesiuni deschise, puteti verifica acest lucru de pe fep8.grid.pub.ro,​ utilizand comanda ''​squeue''​. In cazul in care identificati astfel de sesiuni "​agatate",​ le puteti sterge (si va rugam sa faceti asta), utilizand comanda ''​scancel ​ ID''​ unde ID-ul il identificati din comanda anterioara ''​squeue''​. Puteți folosi mai precis ''​squeue -u username''​ (username de pe fep8.grid.pub.ro) pentru a vedea doar sesiunile care vă interesează.+Alternativ, daca ati uitat sesiuni deschise, puteti verifica acest lucru de pe fep8.grid.pub.ro,​ utilizand comanda ''​squeue''​. In cazul in care identificati astfel de sesiuni "​agatate",​ le puteti sterge (si va rugam sa faceti asta), utilizand comanda ''​scancel ​ ID''​ unde ID-ul il identificati din comanda anterioara ''​squeue''​. Puteți folosi mai precis ''​squeue -u username''​ (username de pe fep8.grid.pub.ro) pentru a vedea doar sesiunile care vă interesează. (Sau ''​squeue --me''​).
  
 Daca nu veti face aceasta delogare, veti putea ajunge in situatia in care sa nu va mai puteti loga pe nodurile din cluster. Daca nu veti face aceasta delogare, veti putea ajunge in situatia in care sa nu va mai puteti loga pe nodurile din cluster.
-</​note> ​ 
- 
-<note important>​ 
-Pentru editarea fișierelor pe cluster, recomandam sa va montați sistemul de pe fep8 pe mașină locală. Pașii sunt detaliați mai jos - multumiri lui Radu Millo pentru redactare. 
- 
-Tutorial chei ssh: https://​www.ssh.com/​academy/​ssh/​keygen 
- 
-Tutorial montare filesystem din fep pe local - comenzi date pe local: 
-<code sh> 
-mkdir /mnt/asc 
-sudo chown -R <​user>​ /mnt/asc 
-decomentam linia '​user_allow_other'​ din /​etc/​fuse.conf 
-sshfs -o allow_other <​user.moodle>​@fep8.grid.pub.ro:/​ /mnt/asc 
-</​code>​ 
 </​note>​ </​note>​
  
-===== Exercitii ===== +* Responsabili laborator: ​Matei BarbuMihnea Mitroi
- +
-Pentru inceput: +
-  - Logati-va pe ''​fep8.grid.pub.ro''​ folosind contul de pe ''​curs.upb.ro''​ +
-  - Executați comanda: +
-<​code>​wget -O lab7_skl.tar.gz http://​ocw.cs.pub.ro/​courses/​_media/​asc/​lab7/​lab7_skl.tar.gz</​code>​ +
-  - Dezarhivati folosind comanda ''​tar -xzvf lab7_skl.tar.gz''​ +
- +
-<note tip> +
-Debug aplicatii CUDA [[https://​docs.nvidia.com/​cuda/​cuda-gdb/​index.html#​introduction|aici]] +
-</​note>​ +
-     +
-Modificarile se vor face acolo unde este necesar in ''​task_<​i>​.cu''​ unde ''<​i>''​ este numarul taskului. Urmariti indicatiile ''​TODO''​ din cod. De asemenea, va recomandam sa folositi documentatia oficiala CUDA Toolkit Documentation de la adresa: https://​docs.nvidia.com/​cuda/​. Aici veti gasi informatii despre majoritatea functiilor de care aveti nevoie (folositi functia search). +
- +
-**Task 1**  - Rulați task1 ca exemplu pentru a verifica funcționalitatea CUDA pe GPU +
- +
-**Task 2**  - Rulați task2 ca exemplu pentru efectuarea unor operații pe GPU +
- +
-**Task 4**  - Efectuați adunarea a doi vectori folosind CUDA în task4.cu +
-    * Sugestia este de a face intai taskul 4 si apoi taskul 3 pentru ca are sens dpdv logic - e mai usor de inteles ce se intampla. +
-             +
-**Task 3**  - Urmăriți TODO--uri din taks3.cu +
-    * Listați informații despre device-urile existente și selectați primul device +
-    * Completați și rulați kernelul kernel_parity_id +
-    * Completați și rulați kernelul kernel_block_id;​ explicați rezultatul +
-    * Completați și rulați kernelul kernel_thread_id;​ explicați rezultatul +
- +
-**Task 5**  - Urmăriți instrucțiunile din task5.cu pentru a realiza interschimbarea a doi vectori +
- +
-<note important>​ +
-Recomandăm sa folosiți pentru compilarea și rularea task-urilor ''​sbatch''​ sau Makefile_Cluster +
-</​note>​  +
- +
- +
-===== Resurse ===== +
- +
-{{:​asc:​lab7:​lab7_skl.tar.gz|Schelet Laborator 7}} +
- +
-<​hidden>​ +
-{{:​asc:​lab7:​sol:​lab7_sol.tar.gz|Soluție Laborator 7}} +
-</​hidden>​ +
- +
-{{:​asc:​lab7:​asc_lab7.pdf|Enunt Laborator 7}} +
- +
-  ​* Responsabili laborator: ​Grigore Lupescu, Ștefan-Dan CiocîrlanCostin Carabaș+
  
 ==== Referinte ==== ==== Referinte ====
 +  * Bibliografie 
 +    * [[https://​booksite.elsevier.com/​9780124077263/​downloads/​advance_contents_and_appendices/​appendix_C.pdf|Graphics and Computing GPUs]]
   * Documentatie CUDA:   * Documentatie CUDA:
     * [[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]]
     * [[https://​docs.nvidia.com/​cuda/​profiler-users-guide/​index.html| CUDA Visual Profiler]]     * [[https://​docs.nvidia.com/​cuda/​profiler-users-guide/​index.html| CUDA Visual Profiler]]
-    * [[https://developer.download.nvidia.com/​compute/cuda/9.1/​Prod/​docs/​sidebar/​CUDA_Toolkit_Release_Notes.pdf|CUDA 9.1 Toolkit]]+    * [[https://docs.nvidia.com/​cuda/cuda-toolkit-release-notes/index.html|CUDA Dev Toolkit]]
     * [[https://​developer.nvidia.com/​cuda-gpus|CUDA GPUs]]     * [[https://​developer.nvidia.com/​cuda-gpus|CUDA GPUs]]
-  * Acceleratoare ​hpsl (hpsl-wn01, hpsl-wn02, hpsl-wn03+  * Acceleratoare ​xl (NVidia P100
-    * [[http://international.download.nvidia.com/​tesla/pdf/tesla-k40-passive-board-spec.pdf|NVIDIA Tesla K40M]] +    * [[https://www.nvidia.com/​en-us/data-center/tesla-p100/​|NVIDIA ​Pascal P100]]
-    * [[https://​en.wikipedia.org/​wiki/​Nvidia_Tesla|NVIDIA ​Tesla]] +
-  * Acceleratoare dp (dp-wn01, dp-wn02, dp-wn03, dp-wn04) +
-    * [[https://​www.nvidia.com/​docs/​IO/​43395/​NV_DS_Tesla_C2050_C2070_jul10_lores.pdf|NVIDIA Tesla C2070]] +
-    * [[http://​www.nvidia.com/​docs/​io/​43395/​nv_ds_tesla_c2050_c2070_apr10_final_lores.pdf|NVIDIA Tesla 2050/​2070]] +
-    * [[https://​cseweb.ucsd.edu/​classes/​fa12/​cse141/​pdf/​09/​GPU_Gahagan_FA12.pdf|NVIDIA CUDA Fermi/Tesla]]+
   * Advanced CUDA   * Advanced CUDA
-    * [[https://​devblogs.nvidia.com/​gpu-pro-tip-cuda-7-streams-simplify-concurrency/​|CUDA Streams]] 
-    * [[https://​devblogs.nvidia.com/​introduction-cuda-dynamic-parallelism/​|CUDA Dynamic Parallelism]] 
- 
-  * Extra 
     * [[http://​www-personal.umich.edu/​~smeyer/​cuda/​grid.pdf | CUDA Thread Basics]]     * [[http://​www-personal.umich.edu/​~smeyer/​cuda/​grid.pdf | CUDA Thread Basics]]
     * [[https://​devblogs.nvidia.com/​even-easier-introduction-cuda/​ | An Even Easier Introduction to CUDA]]     * [[https://​devblogs.nvidia.com/​even-easier-introduction-cuda/​ | An Even Easier Introduction to CUDA]]
-    * [[https://www.nvidia.com/​docs/IO/116711/sc11-cuda-c-basics.pdf Supercomputing 2011 Tutorial ​]] +    * [[https://developer.download.nvidia.com/​CUDA/training/StreamsAndConcurrencyWebinar.pdf|CUDA Streams 1]] 
 +    * [[https://​devblogs.nvidia.com/​gpu-pro-tip-cuda-7-streams-simplify-concurrency/​|CUDA Streams 2]] 
 +    * [[https://​devblogs.nvidia.com/​introduction-cuda-dynamic-parallelism/​|CUDA Dynamic Parallelism]] 
 +    * [[https://​developer.nvidia.com/​blog/​how-overlap-data-transfers-cuda-cc/​|How to Overlap Data Transfers in CUDA C/C++]]
asc/laboratoare/07.1682512385.txt.gz · Last modified: 2023/04/26 15:33 by emil.slusanschi
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0