Você está na página 1de 23

Programao em Paralelo

CUDA

N. Cardoso & P. Bicudo Fsica Computacional - MEFT 2012/2013

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

1 / 23

CUDA

"Compute Unied Device Architecture" Parte 2

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

2 / 23

Outline

Kernel CUDA Qualicadores CUDA Organizao dos Threads Kernel, Congurao e Execuo Calcular o nmero correcto de threads Modelo de Execuo Sistema de Memria Global Memory 1o Programa em CUDA: Soma de dois vectores Sincronizao Gesto do Device

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

3 / 23

Kernel CUDA
Qualicadores CUDA

Executado no: __device__ float DeviceFunc() __global__ void __host__ KernelFunc() device device host

Apenas chamado no: device host host

float HostFunc()

__global__ dene uma funo kernel


tem de devolver void a funo kernel especica o cdigo para ser executado por todas as threads durante a fase de execuo paralela

__device__ dene uma funo que pode ser chamada dentro do kernel ou por outra funo device
__device__ e __host__ podem ser usados em conjunto, o compilador gera duas verses de cdigo)

O default todas as funes de um programa CUDA serem funes host (quando nenhum qualicador usado)
N. Cardoso & P. Bicudo Programao em Paralelo: CUDA 4 / 23

31

Kernel CUDA
Organizao dos Threads

Host

Device Grid 1

cdigo executado no GPU (device); executado por um array de threads paralelos; todos os threads correm o mesmo cdigo os lanamentos so hierrquicas:
threads so agrupados em blocos; blocos so agrupados em grids.
Kernel 2 Block (1, 1) Kernel 1

Block (0, 0) Block (0, 1)

Block (1, 0) Block (1, 1)

Grid 2

inclui variveis de identicao para threads e blocos. apenas os threads dentro de um determinado bloco podem sincronizar e comunicar atravs da memria partilhada, shared memory, __syncthreads();.

(0,0,1) (1,0,1) (2,0,1) (3,0,1)

Thread Thread Thread Thread (0,0,0) (1,0,0) (2,0,0) (3,0,0) Thread Thread Thread Thread (0,1,0) (1,1,0) (2,1,0) (3,1,0)
Nuno Cardoso

Courtesy:
5 / 23

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

Kernel CUDA
Organizao dos Threads

IDs e dimenses:
threads podem ter 3D IDs, nicos no mesmo bloco (threadIdx.x, threadIdx.y, threadIdx.z);
n mximo de threads num bloco varia dependendo da arquitectura.
o

Host

Device Grid 1

Kernel 1

Block (0, 0) Block (0, 1)

Block (1, 0) Block (1, 1)

blocos podem ter 2D IDs ou 3D dependendo da arquitectura e da verso do CUDA, nicos na mesma grid (blockIdx.x, blockIdx.y, blockIdx.z); Inclui ainda as dimenses do bloco, (blockDim.x, blockDim.y, blockDim.z), e dimenses da grid (gridDim.x, gridDim.y, , gridDim.z). dimenses so denidas pelo utilizador/programador aquando do lanamento do kernel; Para obter as dimenses suportadas pelo vosso GPU: ./deviceQuery "/NVIDIA_GPU_Computing_SDK/C/bin/linux/release"

Grid 2 Kernel 2 Block (1, 1)


(0,0,1) (1,0,1) (2,0,1) (3,0,1)

os blocos devem ser independentes e podem correr em qualquer ordem.

Thread Thread Thread Thread (0,0,0) (1,0,0) (2,0,0) (3,0,0) Thread Thread Thread Thread (0,1,0) (1,1,0) (2,1,0) (3,1,0)
Nuno Cardoso

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

6 / 23

Kernel CUDA
Execution conguration

uma funo kernel deve ser chamada da seguinte forma: __global__ void KernelFunc ( . . . ) ; dim3 DimGrid ( 1 0 0 , 5 0 ) ; / / 5000 t h r e a d b l o c k s dim3 DimBlock ( 4 , 8 , 8 ) ; / / 256 t h r e a d s per b l o c k s i z e _ t SharedMemBytes = 6 4 ; / / 64 b y t e s o f shared memory KernelFunc <<< DimGrid , DimBlock , SharedMemBytes > > > ( . . . ) ;

Calcular Y = aX + Y em paralelo usando CUDA:


__global__ void calc_par(int n, float a, float *x, float *y){ int i = blockIdx.x * blockDim.x + threadIdx.x; if(i<n) y[i] = a * x[i] + y[i]; } //invocao da funo com (256 threads por bloco) int nblocks = (n+255) / 256; calc_par <<<nblocks,256>>> (n, 2.0, X, Y);
N. Cardoso & P. Bicudo Programao em Paralelo: CUDA 7 / 23

CUDA Kernel Divide monolithicthreadarrayintomultipleblocks


Execution conguration

Threadswithinablockcooperateviasharedmemory, atomicoperationsandbarriersynchronization Identicador dos threads em CUDA Threads in different blockscannotcooperate


No caso de 1D:

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


Thread Block 0
threadID
0 1 2 3 4 5 6 7 0

Thread Block 1
1 2 3 4 5 6 7

Thread Block N - 1
0 1 2 3 4 5 6 7

float x = input[threadID]; float y = func(x); output[threadID] = y;

float x = input[threadID]; float y = func(x); output[threadID] = y;

float x = input[threadID]; float y = func(x); output[threadID] = y;

David Kirk/NVIDIA and Wen-mei W. Hwu, 2007-2010 ECE 498AL, University of Illinois, Urbana-Champaign

22

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

8 / 23

Calcular o nmero correcto de threads

Objectivo: Obter o nmero mximo de threads possvel num SM. Limitaes


nmero mximo de threads por bloco: 512 nmero mximo de threads por SM: 1024 nmero mximo de blocos por SM: 8

Example: Tiled Matrix Multiplication


threadIdx.x blockIdx.x blockDim.x

tamanho do bloco: 8 8
64 threads por bloco 8 64 = 512 threads 50% de ocupao do SM.

d_P
blockDim.y

blockIdx.y

tamanho do bloco: 16 16
256 threads por bloco 1024/256 = 4 4 blocos por SM.

19 threadIdx.y

assigned to a thread assigned to a thread block

tamanho do bloco: 32 32
1024 threads por bloco > 512 excede a capacidade do SM.

     

  !!" #  !$ % &

X e ed de f

Goal: To have as many threads on an SM as possible Limitations:

N. Cardoso & P. Bicudo

Maximum Number of Threads per Block: 512 Programao em Paralelo: CUDA

9 / 23

Modelo de Execuo



Threads so executados por "thread processors"

Blocos de threads so executados em multiprocessadores, SM.

Alguns blocos de threads podem

o residir num nico SM -on limitado pelos recursos do SM tais como shared memory e registos

Um kernel lanado como uma

Programao em Paralelo: CUDA

grid de blocos de threads


10 / 23

N. Cardoso & P. Bicudo

' Programmable, but requires knowledge on computer

Sistema de Memria graphics


&

Stream Processing Platforms

CPU e GPU tm espaos de memria separados


Os dados so movidos atravs do barramento PCIe Ponteiros so apenas endereos

' High-level programming interface ' No knowledge on Computer Graphics is required ' Examples: NVIDIAs CUDA, OpenCL     !" # $ %

So fornecidas funes para alocar/inicializar/copiar memria no GPU No possvel distinguir se um ponteiro do CPU ou do GPU simplesmente inspecionando o seu valor. How does it work? necessrio ter muito cuidado quando se usam os ponteiros
d 69oo )p70@9@q)8

CPU

r 63@ 018

GPU

j6)7k l870@ m9@9

PC Memory

n 6)7k 3(0o@

GPU Memory

    !" # $ %


N. Cardoso & P. Bicudo Programao em Paralelo: CUDA 11 / 23

Paralelismo do Sistema de Memria


Memria local:
privada;

Cache L1 e L2:
apenas disponvel na arquitectura Fermi e Kepler.

Shared memory:
por bloco; partilhada por threads no mesmo bloco; comunicao entre threads.

Texture memory:
est "ligada" global memory; permite ser usada como cache; no pode ser escrita por threads, apenas acessvel para leitura; actualizada entre chamadas de kernels.
Thread Local Memory Block Shared Memory

Global memory:
por aplicao; partilhada por todos os threads; comunicao inter-Grid.

Constant memory:
lida e escrita pelo CPU; acessvel a qualquer thread apenas para leitura.
Grid 0

Registers Shared memory Global memory Constant memory Texture memory


N. Cardoso & P. Bicudo

por thread por bloco por grid por grid por grid

Read-Write Read-Write Read-Write Read-only Read-only

... Grid 1 ...


118

Global Memory

Sequential Grids in Time

Programao em Paralelo: CUDA

12 / 23

Global Memory, Reserva de Memria no GPU

Cpias Host-Device so muito mais lentas que Device-Device


8 GB/s peak (PCI-e x16 Gen 2) vs. 102 GB/s peak (Tesla C1060)

Minimizar as transferncias Host-Device


Dados intermedirios podem ser alocados, operados em, e libertados sem nunca ser necessrio copiar para a memria do host

Agrupar transferncias
Uma grande transferncia muito melhor do que muitas pequenas

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

13 / 23

Global Memory, Reserva de Memria no GPU


cudaMalloc(), procedimento semelhante ao CPU
CPU: malloc f l o a t a r r a y _ h =( f l o a t ) malloc (N s i z e o f ( f l o a t ) ) ; GPU: cudaMalloc(), reserva de memria na Global Memory f l o a t array_d ; cudaMalloc ( ( void )& array_d , N s i z e o f ( f l o a t ) ) ;
Grid Block (0, 0) Block (1, 0)

Shared Memory Registers Registers

Shared Memory Registers Registers

Thread (0, 0) Thread (1, 0)

Thread (0, 0) Thread (1, 0)

Host

Global Memory

cudaFree(), liberta a memria reservada


cudaFree ( a r r a y _ d ) ;
2

necessrio libertar sempre a memria no nal.


N. Cardoso & P. Bicudo Programao em Paralelo: CUDA 14 / 23

Global Memory, Transferncia de Memria

cudaMemcpy()
requer 4 parmetros
ponteiro de destino ponteiro da fonte nmero de bytes para copiar tipo de transferncia:
Host to Host cudaMemcpyHostToHost Host to Device cudaMemcpyHostToDevice Device to Host cudaMemcpyDeviceToHost Device to Device cudaMemcpyDeviceToDevice

Exemplo:
cudaMemcpy ( array_d , array_h , s i z e o f ( f l o a t ) N, cudaMemcpyHostToDevice ) ; cudaMemcpy ( array_h , array_d , s i z e o f ( f l o a t ) N, cudaMemcpyDeviceToHost ) ;

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

15 / 23

1o Programa em CUDA
Exemplo: Soma de dois vectores

How does it work?


d 69oo )p70@9@q)8

CPU

r 63@ 018

GPU

Implementao:
1 2 3 4

Criar 3 arrays no host; Inicializar os 3 arrays no host; Criar 3 arrays no device; Copiar os 3 arrays do host para o device; Chamar o kernel; Copiar os 3 arrays do device para o host; Vericar resultado; Libertar os recursos.

j6)7k l870@ m9@9

PC Memory

n 6)7k 3(0o@

GPU Memory

 !" # $    % j6)7k l870@ m9@9 d 69oo 3183o qp3 r 63@ 018 n 6)7k 3(0o@

5 6

7 8

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

16 / 23

Exemplo: Soma de dois vectores

/ / Includes # include < s t d i o . h> # include < c u t i l _ i n l i n e . h> / / Functions void RandomInit ( f l o a t , i n t ) ; void VectorAdd ( ) ; / / Device code __global__ void VecAdd ( const f l o a t A , const f l o a t B , f l o a t C, i n t N ) ; / / Host code i n t main ( i n t argc , char argv ) { p r i n t f ( " Vector a d d i t i o n \ n " ) ; VectorAdd ( ) ; exit (0); } / / F i l l an a r r a y w i t h random f l o a t e n t r i e s . void RandomInit ( f l o a t data , i n t n ) { f o r ( i n t i = 0 ; i < n ; ++ i ) data [ i ] = rand ( ) / ( f l o a t )RAND_MAX; }

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

17 / 23

Exemplo: Soma de dois vectores (Cont. 1)

void VectorAdd ( ) { i n t N = 50000; siz e_t size = N sizeof ( f l o a t ) ; / / Host a r r a y s f l o a t h_A , h_B , h_C ; / / Device a r r a y s f l o a t d_A , d_B , d_C ; / / Allocate input vectors h_A = ( f l o a t ) m a l l o c ( s i z e h_B = ( f l o a t ) m a l l o c ( s i z e h_C = ( f l o a t ) m a l l o c ( s i z e h_A , h_B and h_C i n h o s t memory ); ); );

/ / I n i t i a l i z e input vectors RandomInit ( h_A , N ) ; RandomInit ( h_B , N ) ; / / A l l o c a t e v e c t o r s i n d e v i c e memory c u t i l S a f e C a l l ( cudaMalloc ( ( void )&d_A , s i z e ) ) ; c u t i l S a f e C a l l ( cudaMalloc ( ( void )&d_B , s i z e ) ) ; c u t i l S a f e C a l l ( cudaMalloc ( ( void )&d_C , s i z e ) ) ; / / Copy v e c t o r s from h o s t memory t o d e v i c e memory c u t i l S a f e C a l l ( cudaMemcpy ( d_A , h_A , s i z e , cudaMemcpyHostToDevice ) ) ; c u t i l S a f e C a l l ( cudaMemcpy ( d_B , h_B , s i z e , cudaMemcpyHostToDevice ) ) ; (...)

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

18 / 23

Exemplo: Soma de dois vectores (Cont. 2)


void VectorAdd ( ) { (...) / / C a l c u l a t e Number o f t h r e a d s per b l o c k and number o f b l o c k s per g r i d i n t t h r e a d s P e r B l o c k = 256; i n t b l o c k s P e r G r i d = (N + t h r e a d s P e r B l o c k 1 ) / t h r e a d s P e r B l o c k ; / / Invoke k e r n e l VecAdd<<< b l o c k s P e r G r i d , threadsPerBlock >>>(d_A , d_B , d_C , N ) ; cutilCheckMsg ( " k e r n e l launch f a i l u r e " ) ; c u t i l S a f e C a l l ( cudaThreadSynchronize ( ) ) ; / / Copy r e s u l t from d e v i c e memory t o h o s t memory c u t i l S a f e C a l l ( cudaMemcpy ( h_C , d_C , s i z e , cudaMemcpyDeviceToHost ) ) ; / / Verify result int i ; f o r ( i = 0 ; i < N; ++ i ) { f l o a t sum = h_A [ i ] + h_B [ i ] ; i f ( f a b s ( h_C [ i ] sum ) > 1e5) break ; } p r i n t f ( "%s \ n " , ( i == N) ? "PASSED" : " FAILED " ) ; / / Free d e v i c e memory cudaFree ( d_A ) ; cudaFree ( d_B ) ; cudaFree ( d_C ) ; / / Free h o s t memory f r e e ( h_A ) ; f r e e ( h_B ) ; f r e e ( h_C ) ; c u t i l S a f e C a l l ( cudaThreadExit ( ) ) ; }
N. Cardoso & P. Bicudo Programao em Paralelo: CUDA 19 / 23

Exemplo: Soma de dois vectores (Cont. 3)


/ / Device code __global__ void VecAdd ( const f l o a t A , const f l o a t B , f l o a t C, i n t N ) { i n t i = blockDim . x blockIdx . x + threadIdx . x ; / / Necessary c o n d i t i o n i n case : T o t a l Number o f Threads > a r r a y dimension i f ( i < N) C[ i ] = A[ i ] + B[ i ] ; }

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

20 / 23

Exemplo: Soma de dois vectores (Cont. 4) Makele


# Add source f i l e s here EXECUTABLE : = sum2vec # CUDA source f i l e s ( compiled w i t h cudacc ) CUFILES : = sum2vec . cu # CUDA dependency f i l e s CU_DEPS : = # C / C++ source f i l e s ( compiled w i t h gcc / c ++) CCFILES : = # common . mk by d e f a u l t w i l l always add sm_10 and sm_20 u n l e s s o v e r r i d d e n by CUFILES GENCODE_ARCH := ptxaso p t i o n s=v gencode=arch=compute_13 , code = \ " sm_13 , compute_13 \ " ################################################################################ # Rules and t a r g e t s i n c l u d e . . / . . / common / common . mk

Para quem usar os servidores:


adicionar os PATHs descritos na 1a aula de CUDA; necessrio substituir no Makele include ../../ common/common.mk por: i n c l u d e / u s r / l o c a l / NVIDIA / C / common / common . mk o binrio do projecto ca na pasta "release" onde est o vosso projecto.

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

21 / 23

Sincronizao em CUDA CUDA permite threads do mesmo bloco sincronizarem suas aces usando: __syncthreads()
Quando uma thread chama essa funo, ela bloqueada at todos os threads do bloco executarem a mesma chamada "Sincronizao por barreira" um mtodo simples e usual de coordenar atividades paralelas A opo CUDA de no permitir que threads em blocos distintos executem sincronizao por barreira, possibilita a execuo dos blocos em qualquer ordem: nenhum deles precisa esperar pelo outro!

Sincronizao no Host
Todos os lanamentos de Kernel so assncronos:
o controlo retorna para o CPU imediatamente, o kernel executado quando todas as chamadas anteriores forem completadas

cudaMemcpy sncrono
retorna o controlo para o CPU apenas aquando do cpia completa a cpia comea quando todas as chamadas anteriores estiverem completas

cudaThreadSynchronize()
bloqueia at todas as chamadas CUDA anteriores estiverem completas
N. Cardoso & P. Bicudo Programao em Paralelo: CUDA 22 / 23

Gesto do Device

O CPU pode consultar e seleccionar dispositivos GPU


cudaGetDeviceCount( int count ) cudaSetDevice( int device ) cudaGetDevice( int current_device ) cudaGetDeviceProperties( cudaDeviceProp prop, int device ) cudaChooseDevice( int device, cudaDeviceProp prop ) (...)

Gesto da memria
cudaMalloc() cudaFree() cudaMemcpy() (...)

N. Cardoso & P. Bicudo

Programao em Paralelo: CUDA

23 / 23

Você também pode gostar