računanje na grafičkim karticamaarhitektura grafičkog procesora • do 240 skalarnih procesora...

32
Računanje na grafičkim karticama Jurica Teklić Prirodoslovno-matematički fakultet Sveučilište u Splitu

Upload: others

Post on 07-Jan-2020

9 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Računanje na grafičkim

karticama

Jurica TeklićPrirodoslovno-matematički fakultet

Sveučilište u Splitu

Page 2: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Arhitektura grafičkog procesora

• Do 240 skalarnih procesora

• Do 30 multiprocesora (streaming multi.)

– 8 skalarnih procesora

– Dijeljena memorija

Page 3: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Memorija

• Globalna memorija - 4GB

• Dijeljena memorija - 16384 bajta po

multiprocesoru

• Lokalna memorija - 16384 32-bitnih registara

po bloku (8192 bajta po jezgri)

Page 4: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

CUDAArhitektura za paralelno računanje na nVidia grafičkim

karticama

Page 5: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

CUDA osnove

• osnove upravljanja memorijom

• jednostavni kerneli i izvođenje na grafičkoj

kartici

Page 6: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Memorijski prostori

• CPU i GPU imaju odvojene memorije

– Podaci se prenose preko PCIe sabirnice

– Za alociranje, postavljanje i kopiranje se koriste

funkcije

• Pointeri su samo adrese

– Adresom nije određeno o kojoj se memoriji radi

– Oprez pri dereferenciranju

Page 7: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Alokacija i oslobadjanje GPU memorije

• CPU upravlja memorijom na GPU-u– cudaMalloc (void ** pointer, size_t nbytes)

– cudaMemset (void * pointer, int value, size_t count)

– cudaFree (void* pointer)

int n = 1024;

int nbytes = 1024*sizeof(int);

int * d_a = 0;

cudaMalloc( (void**)&d_a, nbytes );

cudaMemset( d_a, 0, nbytes);

cudaFree(d_a);

Page 8: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kopiranje podataka

• cudaMemcpy( void *dst, void *src, size_t nbytes,enum cudaMemcpyKind direction);

– Blokira CPU nit dok ne završi kopiranje

– Kopiranje će početi samo ako su svi prethodni CUDA pozivi završeni

• enum cudaMemcpyKind

– cudaMemcpyHostToDevice

– cudaMemcpyDeviceToHost

– cudaMemcpyDeviceToDevice

cudaMemcpy (p_cpu, p_gpu, byte_num, cudaMemcpyDeviceToHost);

• Postoje i neblokirajuće funkcije za kopiranje

Page 9: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

CUDA compiler driver

• CUDA kod ekstenzije .cu se kompajlira

naredbom

nvcc kod.cu

nvcc –o program kod.cu

nvcc kod.cu –arch=sm_13 (–arch=sm_11)

Page 10: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Zadatak prvi

• Alocirati memoriju za n cijelih brojeva na CPU

• Alocirati memoriju za n cijelih brojeva na GPU

• Inicijalizirati GPU memoriju

• Kopirati sa GPU na CPU

• Ispis

Page 11: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 1#include <stdio.h>

int main()

{

int dimx = 16;

int num_bytes = dimx*sizeof(int);

int *d_a=0, *h_a=0; // device and host pointers

Page 12: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 1#include <stdio.h>

int main()

{

int dimx = 16;

int num_bytes = dimx*sizeof(int);

int *d_a=0, *h_a=0; // device and host pointers

h_a = (int*)malloc(num_bytes);

cudaMalloc( (void**)&d_a, num_bytes );

if( 0==h_a || 0==d_a )

{

printf("couldn't allocate memory\n");

return 1;

}

Page 13: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 1#include <stdio.h>

int main()

{

int dimx = 16;

int num_bytes = dimx*sizeof(int);

int *d_a=0, *h_a=0; // device and host pointers

h_a = (int*)malloc(num_bytes);

cudaMalloc( (void**)&d_a, num_bytes );

if( 0==h_a || 0==d_a )

{

printf("couldn't allocate memory\n");

return 1;

}

cudaMemset( d_a, 0, num_bytes );

cudaMemcpy( h_a, d_a, num_bytes,

cudaMemcpyDeviceToHost );

Page 14: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 1#include <stdio.h>

int main(){

int dimx = 16;int num_bytes = dimx*sizeof(int);

int *d_a=0, *h_a=0; // device and host pointers

h_a = (int*)malloc(num_bytes);

cudaMalloc( (void**)&d_a, num_bytes );

if( 0==h_a || 0==d_a )

{

printf("couldn't allocate memory\n");

return 1;

}

cudaMemset( d_a, 0, num_bytes );

cudaMemcpy( h_a, d_a, num_bytes, cudaMemcpyDeviceToHost );

for(int i=0; i<dimx; i++)

printf("%d ", h_a[i] );

printf("\n");

free( h_a );

cudaFree( d_a );

return 0;

}

Page 15: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

CUDA programski model

• Na kartici se paralelni kod pokreće i izvršava

kroz mnogo niti

• Niti su grupirane u blokove

• Paralelni kod je pisan za nit

– Svaka nit se može drukčije izvršavati

– Ugrađeni su identifikatori niti i blokova

Page 16: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Hijerarhija niti

• Pokrenute niti su particionirane po blokovima

– mreža = svi blokovi u kernelu

• Blok je grupa niti koja može

– Sinhronizirati svoje izvođenje

– Komunicirati preko dijeljene memorije

Page 17: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Identifikatori i dimenzije

• Niti

– 3D identifikator, jedinstven unutar bloka

• Blokovi

– 2D identifikator, jedinstven unutar grid-a

• Dimenzije

– Mogu biti jedinstvene za svaki grid

• Ugrađene varijable

– threadIdx, blockIdx

– blockDim, gridDim

Page 18: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Izvršavanje koda na GPU

• C funkcija sa restrikcijama– Pristupa samo GPU memoriji

– Fiksni broj argumenata

– Bez statičkih varijabli

– Bez rekurzije

• Mora biti deklarirana sa kvalifikatorom– __global__ : CPU pokreće, ne može biti pozvana sa GPU-a,

vraća jedino void

– __device__ : poziva se iz drugih GPU funkcija, CPU je ne može pokrenuti

– __host__ : pokreće se na CPU-u

– __host__ i __device__ se mogu kombinirati

Page 19: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 2

• Temelji se na kodu 1

• Napisati kernel za inicijalizaciju cijelih brojeva

• Kopirati rezultat natrag na CPU

• Ispis

Page 20: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kernel (izvršava se na grafičkoj)

__global__ void kernel( int *a )

{

int idx = blockIdx.x*blockDim.x + threadIdx.x;

a[idx] = 7;

}

Page 21: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Pokretanje kernela

• Pokretački parametri

– Dimenzije grida su najviše 2D i tipa dim3

– Dimenzije bloka su najviše 3D i tipa dim3

– Dijeljena memorija (broj bajtova po bloku) i stream ID

• Nije nužno, inače je 0

dim3 grid(16, 16);

dim3 block(16,16);

kernel<<<grid, block, 0, 0>>>(...);

kernel<<<32, 512>>>(...);

Page 22: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

#include <stdio.h>

__global__ void kernel( int *a )

{

int idx = blockIdx.x*blockDim.x + threadIdx.x;

a[idx] = 7;

}

int main()

{

int dimx = 16;

int num_bytes = dimx*sizeof(int);

int *d_a=0, *h_a=0; // device and host pointers

h_a = (int*)malloc(num_bytes);

cudaMalloc( (void**)&d_a, num_bytes );

if( 0==h_a || 0==d_a )

{

printf("couldn't allocate memory\n");

return 1;

}

cudaMemset( d_a, 0, num_bytes );

dim3 grid, block;

block.x = 4;

grid.x = dimx / block.x;

kernel<<<grid, block>>>( d_a );

cudaMemcpy( h_a, d_a, num_bytes, cudaMemcpyDeviceToHost );

for(int i=0; i<dimx; i++)

printf("%d ", h_a[i] );

printf("\n");

free( h_a );

cudaFree( d_a );

return 0;

}

Page 23: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Varijacije kernela i izlaz

__global__ void kernel( int *a )

{

int idx = blockIdx.x*blockDim.x + threadIdx.x;

a[idx] = 7;

} Output: 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7

__global__ void kernel( int *a )

{

int idx = blockIdx.x*blockDim.x + threadIdx.x;

a[idx] = blockIdx.x;

} Output: 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3

__global__ void kernel( int *a )

{

int idx = blockIdx.x*blockDim.x + threadIdx.x;

a[idx] = threadIdx.x;

} Output: 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3

Page 24: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 3

• Računanje broja π

Page 25: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Kod 3

• Računanje broja π

Page 26: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena
Page 27: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Blokovi

• Neovisnost

– skalabilnost

• Postepenost i istodobnost

Page 28: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Sinkronizacija

• Pokretanje kernela je asinkrono– Kontrola se vraća CPU niti

– Kernel se pokreće ako su svi predhodni CUDA pozivi završili

• Memorijska kopiranja su sinkrona– Kontrola se vraća CPU niti kada je kopiranje završeno

– Kopiranje počinje tek kada su predhodni CUDA pozivi završili

• cudaThreadSynchronize()– Blokira nastavak dok svi CUDA pozivi nisu završili

• Postoje i asinkroni CUDA pozivi

Page 29: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Dijeljena memorija

• __shared__ kvalifikator

• On-chip memorija– Za dva reda veličine manja latencija nego globalnoj

memoriji

– Za red veličine veća propusnost nego globalnoj memoriji

– 16KB po multiprocesoru

• Alocira se za blok– Samo niti istog bloka joj mogu pristupiti

• Najčešće se koristi za komunikaciju među nitima iz istog bloka

• void __syncthreads();– Za sinkronizaciju niti unutar bloka

Page 30: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

SIMT arhitektura

Page 31: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

Revizije CUDA modela

Page 32: Računanje na grafičkim karticamaArhitektura grafičkog procesora • Do 240 skalarnih procesora • Do 30 multiprocesora (streaming multi.) – 8 skalarnih procesora – Dijeljena

O greškama i debuggeru

• Svako pozivanje CUDA funkcija vraća kod za

grešku

– Osim poziva kernela

– cudaError_t tip

• Postoji debugger ali za sada je bolje koristiti

emulator (u VS odabrati emulation)

– Smanjiti broj niti

nvcc –deviceemu kod.cu