Introdução a GPU e CUDA
CPU X GPU CPU Execução sequencial Processamento genérico Maior quantidade de memória principal Poucos núcleos (cores) Poucas threads por núcleo GPU Execução paralela Processamento especifico (gráfico) Menor quantidade de memória Maior velocidade de tráfego de memória Muitos núcleos Várias threadas por núcleo
VELOCIDADE GPU
Vazão memória gpu
GPGPU General-purpose computing on Graphics Processing Units Programação de instruções para serem executadas diretamente na GPU Aplicações: simulação dinâmica de fluídos, análise sísmica, resolução de problemas matemáticos e segmentação de imagens.
GPGPU Linguagens GLSL (OpenGL Shading Language) HLSL (High Level Shading Languag) Cg (C for Graphics) CUDA (Compute Unified Device Archtecture) OpenCL (Open Computing Language)
GPGPU Dois fatores importantes para criação de um programa em GPU. Quais instrucões executarão em CPU e GPU Conjunto limitado de instrucões Funções matemáticas Organizacão e quais dados executarão em GPU Tamanho e tipos de memória da GPU Organizacão das threads Evitar trocas constantes entre a memória RAM e a memória da placa gráfica
CUDA Compute Unified Device Architecture Criada pela NVIDIA Novembro de 2006 Não necessita conhecimento de OpenGL, hardware gráfico ou uso de textura Proprietária Exclusiva para placas NVIDIA A partir da geração GeForce 8, Tesla e Quadro Sintaxe semelhante a C/C++ Fortran, Java (JaCUDA), Python (PyCUDA) e .Net (CUDA.NET)
CUDA Não suporta recursão Funções próprias para medição de tempo
Camadas CUDA CUDA Libraries Funções matemáticas Primitivas de computação gráfica Marcadores Diretivas especiais para linguagem C
Camadas CUDA CUDA Runtime CUDA Driver Gerencia as operações entre CPU (host) e a GPU (device) CUDA Driver Otimiza e gerencia os recursos da GPU
CUDA Stream Processor: streams e kernels Streams Kernels Fluxos de dados que são a entrada para os kernels Kernels Código executado em GPU Processa os dados e gera uma saída Pode ser usado como entrada para outro kernel
Organização processamento Cada kernel é executado em uma thread Os kernels são agrupados em blocos Cada bloco pode conter no máximo 512 threads Organizados em matriz: 512 x 1 ou 22 x 22 ou 8 x 8 x 8 Os blocos são organizados em grids Organizada em uma matriz bidimensional de tamanho máximo 65535 x 65535 A quantidade e organização das threads é feita pelo programados
Organização processamento A organização é feita com variáveis do tipo dim3 dim3 dimBlock(4,3) dim3 dimGrid(3,2)
Organização processamento Váriaveis pré-definidas usadas na organização Dimensões do bloco blockDim.x, blockDim.y e blockDim.z Dimensões do grid gridDim.x e gridDim.y Índice do bloco blockIdx.x e blockIdx.y, Índice da thread threadIdx.x, threadIdx.y e threadIdx.z As variáveis pré-definidas são usadas também para obtenção do índice nas matrizes de dados indice = dimensaoDoBloco * indiceDoBloco + indiceDaThread
Organização processamento Uma função para ser executada em GPU deve conter um dos marcadores _global_ : a função é invocada por uma função do host _device_ : a função é invocada por uma função da GPU Uma função para ser executada em CPU deve conter ou não o marcador _host_ Devem retornar void e ter uma configuração de execução
Hierarquia de memória marcadores especiais para variáveis _device_ Memória global _constant_ _shared_ Memória compartilhada (“shared”)
EXEMPLO #include <stdlib.h> #include <stdio.h> __global__void kernel(int*array) { //do work } Int main(void) { Int num_elements= 256; Int num_bytes= num_elements* sizeof(int); //ponteiro para a memória do host Int *host_array= 0; //aloca memória no host host_array= (int*)malloc(num_bytes); //ponteiro para a memória do device int* device_array= 0; //aloca memória no device cudaMalloc((void**)&device_array, num_bytes); // configuracao de bloco e grid Int block_size= 128; Int grid_size= num_elements/ block_size; //chamada do kernel kernel<<<grid_size,block_size>>>(device_array); //transfere os dados resultantes da GPU p/ CPU cudaMemcpy(host_array, device_array, num_bytes, cudaMemcpyDeviceToHost); //percorre os dados resultantes for(int i=0; i < num_elements; ++i){ printf("%d ", host_array[i]); } //libera a memória free(host_array); cudaFree(device_array);