Upload
trynt
View
28
Download
1
Embed Size (px)
DESCRIPTION
GPGPU. GPU. GPU – Quebra de paradigma radical. Você mudaria todo o teu paradigma de desenvolvimento e hardware apenas para ganhar 5% de desempenho?. GPGPU – a evolução. Há 3 fases históricas das GPUs: Fixed Function GPU Programmable GPU Arquitetura Unificada. Fixed Function GPUs. - PowerPoint PPT Presentation
Citation preview
GPU – Quebra de paradigma radical
Você mudaria todo o teu paradigma de desenvolvimento e hardware apenas para ganhar 5% de desempenho?
GPGPU – a evolução ...
Há 3 fases históricas das GPUs:
-Fixed Function GPU
- Programmable GPU
- Arquitetura Unificada
Fixed Function GPUs
-Arquitetura incapaz de aceitar programação-Impossível realizar cálculos sem ser de computação gráfica-Incapacidade de acesso ao processador- Conceito de APIs
Fixed Function GPUs
InterfaceCPU - GPU
CPU
InterfaceGPU - Video
Enginede
Geometria
Engines de Rasterização
FrontBuffer
BackBuffers
ZBuffer
StencilBuffer
Texture Buffer
Memória
de
vídeo
Processador(es)
Back Buffer
Front Buffer
Programmable GPU
- Vertex and Pixel Shaders- Arquitetura orientada a estrutura de dados de computação gráfica
Programmable GPU
-Limitações:-Shaders-Modo de endereçamento limitado-Pequeno grupo de instruções-Dificuldade de comunicação entre processadores e processos
GPGPU
- Problema de ter que mapear tudo para APIs- Usar funções OpenGL ou DirectX para efetuar todo tipo de operações
Por que mais rápido? Tarefa 100 vezes mais rápido
Tarefa de 1 ano de duração cai para 3 dias
Tarefa de 1 dia cai para 15 minutos
Tarefa de 3 segundos cai para 30 vezes por segundo
Threads
Porque programar em Threads?
-Para fazer distribuição de carga em arquitetura single core
- Para fazer distribuição de carga entre múltiplos núcleos
- Desafio de ter que manter o máximo de uso de cada núcleo
Threads – Custo de gerenciamento
Em CPU, como fazemos pouca troca de threads, podemos achar natural gastar 1000 instruções para fazer a troca de uma thread para outra. Em CUDA há outro paradigma....
Não é necessário gerenciar as threads, a priori.
Sincronismo deve ser explicito
Modelo de Programação
CUDA estende a linguagem C através de kernels
Kernels equivalem a funções, que serão executadas N vezes em paralelo
N é o número de threads
Funções em CUDA
-Não pode haver recursão no __device__-Sem variáveis estáticas-Sem numero variável de parâmetros-A chamada do kernel é assíncrona-Sincronismo deve ser feito explicitamente- __device__ __host__ : podem ser usados juntos
Threads, Blocos e Grids
Um kernel corresponde a um grid de Blocos
Cada Bloco é composto por threads
Todas as threads compartilham a mesma área de memória
As threads de um mesmo bloco podem compartilhar umas com as outras
Threads de blocos diferentes não podem compartilhar memória entre si
Hierarquia de Threads
Todos os threads de um bloco usam da mesma memória compartilhada.
O número de threads num bloco é limitado pela memória: GPUs atuais possuem até 512 threads.
Funções em CUDA
__ global__ void KernelFunction (...)
dim3 DimGrid (100, 10); // Grid com 1000 blocosdim3 DimBlock (4, 8, 8); // Cada bloco tem 256 threadsSize_t SharedMemBytes = 32
KernelFun << DimGrid, DimBlock, SharedMemBytes>> (...);
Kernel – será compilado para a GPU
// Kernel definition__global__ void vecAdd(float* A, float* B, float* C){}int main(){
// Kernel invocationvecAdd<<<1, N>>>(A, B, C);
}
__global define que é um kernel
kernel
__global__ void vecAdd(float* A, float* B, float* C){
int i = threadIdx.x;C[i] = A[i] + B[i];
}
int main(){
vecAdd<<<1, N>>>(A, B, C);}
threadIdx define um ID de um dos threads<< n, m>> numero de blocos (n) e threads (m) solicitados para o kernel
Hierarquia de Threads
threadIdx é um vetor de 3 componentes
Threads podem ser identificados com índices de 1, 2 ou 3 dimensões (formando thread blocks de uma, duas ou três dimensões)
Índice de uma thread:-Se for um bloco 1D: é a mesma coisa-Se for um bloco 2D (Dx, Dy): threadId de um thread de índice (x, y) é x + yDx
-Se for um bloco 3D (Dx, Dy, Dz): threadId de uma thread de índice (x, y, z) é x + yDx + zDxDy
Exercicio – Julia set (Fractais em GPU)
Idéia do Julia Set: iterar uma equação para pontos no espaço dos numeros complexos.
Um ponto não pertence ao conjunto, se depois de infinitas iterações o valor cresce para o infinito. Caso contrário, ele está preso a uma região.
A Equação de iteração será dada por Z(n+1) = Z(n)*Z(n) + C
Versao em CPU
int main (void){
CPUBitmap bitmap (DIM, DIM);unsigned char *ptr = bitmap.get_ptr();
kernel (ptr);
bitmap.display_and_exit ();}
Versao em CPU (2)
void kernel (unsigned char *ptr){
for (int y = 0; y<DIM; y++) {for (int x=0; x<DIM; x++){
int offset = x + y * DIM;int juliaValue = julia (x, y);
ptr [offset*3 + 0] = 255 * juliaValue;ptr [offset*3 + 1] = 255 * juliaValue;ptr [offset*3 + 1] = 255 * juliaValue;
}}
}
Versao em CPU (3)
int julia (int x, int y){
cont float scale = 1.5;float jx = scale * (float) (DIM/2 – x)/(DIM/2);float jy = scale * (float) (DIM/2 – y)/(DIM/2);
// assumimos que o complexo C = -0.6, 0.121i// assumimos que o complexo a = jx, jy i ;
int i = 0;for (i=0; i<200; i++) {
a = a * a + c; // multiplicacao de complexos: a.real*C.real – a.i*C.i, a.i*C.real + a.real*C.i// soma de complexos: a.real + C.real, a.i +C.iif (a.magnitude() > 1000) // magnitude = a.r*a.r + a.i*a.i
return 0;}return 1;
}
Versao em GPU (1)
Int main (void){
CPUBitmap bitmap (DIM, DIM);unsigned char *dev_bitmap;
cudaMalloc ( (void**)&dev_bitmap, bitmap.image_size() ) );
dim3 grid (DIM, DIM);
kernel <<<grid, 1>>> (dev_bitmap);
cudaMemcpy (bitmap.get_ptr(), dev_bitmapo, bitmap.image_size(), cudaMemcpyDeviceToHost ) );
bitmap.display_and_exit();
cudaFree (dev_bitmap);}
Versao em GPU (2)
__global__ void kernel (unsigned char *ptr){
int x = blockIdx.xint y = blockIdx.y;int offset = x+y*gridDim.x
int juliaValue = julia (x, y);
ptr[offset*3 +0] = 255 *juliaValue;ptr[offset*3 +1] = 255 *juliaValue;ptr[offset*3 +2] = 255 *juloaValue;
cudaMalloc ( (void**)&dev_bitmap, bitmap.image_size() ) );
}
Versao em GPU (3)
__device__ int julia (int x, int y){
cont float scale = 1.5;float jx = scale * (float) (DIM/2 – x)/(DIM/2);float jy = scale * (float) (DIM/2 – y)/(DIM/2);
// assumimos que o complexo C = -0.6, 0.121i// assumimos que o complexo a = jx, jy i ;
int i = 0;for (i=0; i<200; i++) {
a = a * a + c; // multiplicacao de complexos: a.real*C.real – a.i*C.i, a.i*C.real +
a.real*C.i// soma de complexos: a.real + C.real, a.i +C.iif (a.magnitude() > 1000) // magnitude = a.r*a.r + a.i*a.i
return 0;}return 1;
}