# GPGPU

A Unidade de Processamento Gráfico de Propósito Geral ou GPGPU (General Purpose Graphics Processing Unit) utiliza a GPU (graphics processing unit) para além de renderização gráfica tais como: processamento de imagem, visão computacional, inteligência artificial, cálculo numérico dentre outras aplicações. Ou seja, é a utilização da GPU para realizar a computação em aplicações que antes eram tratada pela CPU (Unidade Central de Processamento).

## Visão Geral e Histórico

A Unidade de Processamento Gráfico de Propósito Geral se tornou prático e popular depois dos anos de 2001, por causa do advento de duas programáveis shaders e ponto flutuante. A partir dali a comunidade de computação cientifica começou a fazer testes com o hardware, seu primeiro teste foi com uma multiplicação de matrizes de rotina, um dos primeiros códigos científicos simples a correr mais rápido em GPUs era a implementação da fatoração LU.
Para os primeiros esforços de se utilizar GPUs com processadores de uso geral, foi necessário reformular problemas computacionais em termos gráficos, foram apoiados por dois APIs(Interfaces de Programação de Aplicativos) principais OpenGL e DirectX. Os mais atuais fornecedores independentes de hardware incluem Microsoft DirectCompute e Apple/Grupo Khronos OpenCL.

## DirectX

DirectX é um conjunto de APIs responsável pela comunicação entre hardware e software durante a execução de vídeos e principalmente games.Algumas das suas versões são: DirectX 8 introdução Shader Model 1.1, DirectX 8.1 Pixel Shader Models 1.2, 1.3 e 1.4 e DirectX 9 definindo Shader Model 2.x e 3.0. Cada modelo de shader aumentou as flexibilidades e capacidades do modelo de programação, garantindo o hardware conforme segue o exemplo. A especificação DirectX 10 Shader Model 4.0 introduz que unifica a especificação de programação para vértice, geometria (Geometry "Shaders" é novo para DirectX 10) e processamento fragmento permitindo um melhor ajuste para hardware de shader unificada, proporcionando assim uma piscina computacional de recurso programável.

## OpenGl

O OpenGL (Open Graphics Library) é uma API livre utilizada na computação gráfica, para desenvolvimento de aplicativos gráficos, ambientes 3D, jogos, entre outros.
O OpenGL é um conjunto de algumas centenas de funções, que fornecem acesso a praticamente todos os recursos do hardware de vídeo. Internamente, ele age como uma máquina de estados, que de maneira bem específica dizem ao OpenGL o que fazer. Usando as funções da API, você pode ligar ou desligar vários aspectos dessa máquina, tais como a cor atual, se transparência será usada, se cálculos de iluminação devem ser feitos, se haverá ou não o efeito de neblina, e assim por diante.
O núcleo do OpenGL é conhecido como “rendering pipeline” ou dutos de renderização. É importante notar que o OpenGL lida tanto com o desenhos na forma vetorial, definidos por vértices, como com mapas de bits, definidos pixel-a-pixel.

## Conceitos de Programação GPGPU

As GPU são processadores com múltiplos núcleos, que tem uma capacidade muito maior de processamentos de dados do que a CPU.
Ela é encarregada do processamentos de múltiplos dados, para que isso aconteça, a GPU utiliza-se de um conjunto de stream(grande conjunto ordenado de dados) de maneira paralela. Para que isso seja eficiente o hardware dela é implementado seguindo um pipeline gráfico, ou seja, o pipeline foi implementado em varias unidades fazendo que a computação paralela seja a nível de dado. Outro aspecto importante é a sua velocidade de acesso a memoria que é muito mais rápidas que a CPU, pois a GPU se importa com o principio da localidade da memoria ao invés da computação genérica.

### Processamento de Fluxo

GPUs só pode processar vértices e fragmentos independentes, mas pode processar muitos deles em paralelo. Isto é especialmente eficaz quando o programador quer processar muitas vértices ou fragmentos da mesma maneira. Neste sentido, as GPUs são processadores stream - processadores que podem operar em paralelo, executando um kernel em muitos registros em um fluxo de uma só vez.
A stream é simplesmente um conjunto de registros que requerem computação similar. Streams fornecer paralelismo de dados. Kernels são as funções que são aplicadas a cada elemento no córrego. Nos GPUs, vértices e fragmentos são os elementos em córregos e shaders de vértice e fragmento são os grãos a serem executados neles. Desde os elementos do processo GPUs independentemente não há nenhuma maneira de ter shaders ou dados estáticos. Para cada elemento só pode ler a partir da entrada, realizar operações sobre ele, e escrever para a saída. É possível ter várias entradas e várias saídas, mas nunca um pedaço de memória que é ser lidos e escritos.
Intensidade Aritmética é definida com o número de operações realizadas por palavra de memória transferida. É importante para aplicações GPGPU ter alta intensidade aritmética mais a latência de acesso à memória limitará aceleração computacional.
Aplicações GPGPU ideais têm grandes conjuntos de dados, alto paralelismo e dependência mínima entre elementos de dados.

### Conceitos de Programação GPU
#### Recursos Computacionais

Há uma variedade de recursos computacionais disponíveis na GPU:
* Processadores programáveis - vértice, primitivos, e dutos de fragmentos permitem programador para realizar kernel em fluxos de dados
* Rasterizer - cria fragmentos e interpola constantes por vértice, como coordenadas de textura e cor, ou seja, junta o conjunto de vértices para que sejam processadas e recebam o contexto geométrico para que possam se tornar em cores e no que mais for necessário, e para que no final torne-se elementos de um pixel.
* Unidade de textura – os fragmentos são processados pelo mesmo programa, são escritos na memoria de acordo com a localização do fragmento no framebuffer.
* Framebuffer – é quando as informações já prontas são enviadas para memoria de vídeo e depois quando o conteúdo já estiver concluído é enviada para a tela do computador.

#### Texturas como fluxo

A forma mais comum para um fluxo de tomar em GPGPU é uma grade 2D porque este se encaixa naturalmente com o modelo de prestação construído em GPUs. Muitos cálculos mapear naturalmente em grades: álgebra matricial, processamento de imagem, a simulação de base física, e assim por diante.
Desde texturas são usados ​​como memória, pesquisas de textura são utilizados como memória lê. Algumas operações podem ser feitas automaticamente pelo GPU por causa disso.

#### Kernels

Kernels pode ser pensado como o corpo de loops. Por exemplo, um programador de operar em um grid sobre a CPU e pode ter um código que se parece com isso:

#### Controle de Fluxo

Nas linguagens atuais o controle de fluxo e feito por if-then-else, for e while. Tais estruturas de controle de fluxo foram recentemente adicionadas ao GPUs. Como as CPU tem comando muito longos é necessário que elas sejam bem estruturadas e controladas, já que a cada falha na previsão de uma ocorrência, ira ocorrer uma penalidade. De maneira parecida a GPU da NVIDIA GeForce 6 funciona.
Atualmente as arquiteturas paralelas possuem alguns tipos de controle de fluxo, como instruções unicas ,dados múltiplos (SIMD) e instruções múltiplas e dados múltiplos(MIMD). Para que uma GPU possa implementar uma ramificação e necessário três SIMD ramificação, MIMD ramificação e códigos de condição.
Mas as ramificações tem um custo, ou seja, elas diminuem a performance das GPUs. Para que elas possam fazer as ramificações internas sem o suporte do hardware e necessário se utilizar de técnicas como Static Branch Resolution, Pre-computation, Z-Cull, Data-Dependent Looping With Occlusion Queries.

### Métodos GPU
#### Mapa

A operação mapa simplesmente aplica a função dada (o kernel) para cada elemento na stream. Um exemplo simples é multiplicar cada valor na stream por uma constante (aumentando o brilho de uma imagem). A operação de mapa é simples de implementar na GPU. O programador gera um fragmento para cada pixel na tela e aplica-se um fragmento de programa para cada um. O resultado da stream que é do mesmo tamanho é armazenado no buffer de saida.

#### Reduzir

Alguns cálculos requerem o cálculo de uma stream menor (possivelmente uma stream de apenas um elemento) a partir de uma stream maior. Isto é chamado uma redução do fluxo. Geralmente uma redução pode ser realizada em vários passos. Os resultados da etapa anterior são usados ​​como a entrada para a etapa atual e o intervalo no qual a operação é aplicada é reduzida até que apenas um elemento da stream continua.

#### Filtragem de Fluxo

Filtragem de fluxo é essencialmente uma redução não uniforme. Filtragem envolve a remoção de itens do fluxo com base em alguns critérios.

#### Varredura

Consiste basicamente em um algoritmo que irra fazer uma varredura para detectar colisões, ou em outros casos na retirada de dados que não são importantes.

#### Scatter and Gather

No acesso a memoria de GPU existe duas operações de grande importância elas são a operação de escrita e leitura quando acessão de forma indireta a memoria, elas são denominadas como scatter e gather respectivamente.
A operação gather ira ler valores contidos em um lugar qualquer na memoria, para isso ela irá fazer acesso as texturas contidas na GPU.
Já a operação de scatter irá escrever um valor em qualquer posição da memoria. Sendo assim ela é mais complicada, ou seja, ela não pode ser utilizada em um programa de fragmentos, porque em cada fragmento tem implícito o endereço de onde ele veio, e para onde ele deve retornar através do mapeamento em framebuffer. Para que isso não ocorra é utilizado o programa de vértices, em que uma operação de scatter é feita por vértice.

#### Classificação

A operação de classificação transforma um conjunto não ordenado de elementos em um conjunto ordenado de elementos. A aplicação mais comum em GPUs está sendo usado redes de classificação.
A classificação de rede vai ter um numero fixo de etapas nas quais os dados não vão ter relação, elas também terão um padrão de comunicação que será o de gather ao em vez scatter.

#### Pesquisa

A operação de busca permite que o programador para encontrar um determinado elemento dentro do fluxo, ou, eventualmente, encontrar vizinhos de um elemento especificado, nesse caso e utilizado bastante em pesquisa a banco de dados. A GPU não é usada para acelerar a busca por um elemento individual, mas em vez disso é usada para executar várias pesquisas em paralelo. Dois exemplos de pesquisa são:
* Pesquisa Binaria:É a forma de pesquisa mais simples, consiste em pegar o elemento que se deseja encontrar e comparar com o elemento central que contem na lista, conforme for o resultado ele ira para direita ou esquerda ate encontrar o elemento ou determinar que o elemento não existe.
* Vizinho mais próximo:Nesta pesquisa será procurado os vizinhos mais próximos de um elemento, para isso usa-se o método de pesquisa em árvore, onde os vizinhos serão armazenados em uma fila de acordo com a sua distancia.

#### As Estruturas de Dados

Uma variedade de estruturas de dados podem ser representados na GPU:
* Densas matrizes
* Matrizes esparsas - estáticos ou dinâmicos
* Estruturas adaptativas ( tipo de união )

## Linguagens que se beneficiam de GPGPU

* CUDA (Compute Unified Device Architecture) criada pela NVIDIA para programação GPGPU.
* FireStream Linguagem da AMD para GPGPU.
* OpenCL (Open Compute Language) Línguagem de programação livre que também utiliza GPGPU.
* DirectCompute API criada pela Microsoft para GPGPU.
* C++ AMP API da Microsoft para facilitar a programação GPGPU em C++. Necessita de placa de video que suporte directcompute.

## Principais Linguagens de Programação GPU

Na programação GPU existem diversas linguagens, mas somente duas tem maior ênfase, são elas CUDA e OpenCL. Ambas fornecem paralelismo de dados, e também uma linguagem de baixo nível para fazer a comunicação com o hardware. Apesar da CUDA ter maior desempenho, a OpenCL vem sendo olhada com maior interesse por se tratar de uma linguagem de programação aberta.

### OpenCl

OpenCL (Open Computing Language) é uma plataforma para escrever programas que funcionam em plataformas heterogêneas, consistindo em CPUs, GPUs, processadores de sinal digital ( DSPs ), field-programmable gate arrays (FPGAs) e outros processadores. OpenCL inclui uma linguagem (baseada em C99) para escrever kernels (funções executadas em dispositivos OpenCL), além de APIs que são usadas para definir e depois controlar as plataformas heterogênea. OpenCL permite programação paralela usando, tanto o paralelismo de tarefas, como de dados. Ela é um padrão aberto mantido pela organização sem fins lucrativos tecnologia consórcio Khronos Group.
A proposta OpenCL é similar às propostas OpenGL e OpenAL, que são padrões abertos da indústria para gráficos 3D e áudio, respectivamente. Ela possui alguns versões a mais recente é OpenCl 2.0.
Algumas empresas que implementam são IBM Corporation, NVIDIA, Intel, Aplle Inc dentre outras.

### CUDA

CUDA (Compute Unified Device Architecture) é uma plataforma de computação paralela de propósito geral que tira proveito das unidades de processamento gráfico (GPUs) NVIDIA para resolver muitos problemas computacionais complexos em uma fração do tempo necessário em uma CPU. Ela inclui a arquitetura de conjunto de instruções CUDA ISA (Instruction Set Architecture) e o mecanismo de computação paralela na GPU.
Para programar segundo a arquitetura CUDA™, os desenvolvedores hoje em dia podem usar C - uma das mais amplamente utilizadas linguagens de programação capaz de operações de baixo nível, que pode ser então executada com alta performance em um processador compatível com CUDA™.
Atualmente cientistas e desenvolvedores estão aplicando a GPU CUDA em controle de tráfego aéreo e em simulações da corrente sanguínea, para encontrar placas ocultas em artérias.

## Áreas que utilizam GPGPU

* Clusters de computadores ou uma variação de uma computação paralela (utilizando tecnologia cluster GPU ) para tarefas de grande intensidade de cálculo:
** Clusters de computação de alto desempenho (clusters HPC) (muitas vezes chamados supercomputadores )
*** Incluindo tecnologias de cluster, como Message Passing Interface , e imagem de sistema único (SSI), computação distribuída , e Beowulf
** Computação em grid (uma forma de computação distribuída) ( networking muitos computadores heterogêneos para criar uma arquitetura de computador virtual)
** Clusters de balanceamento de carga (às vezes chamado de farm de servidores )
* Segmentação - 2D e 3D
* Processamento de imagem digital
* A iluminação global - o traçado de raios , mapeamento de fótons , radiosity entre outros, espalhamento de subsuperfície
* Computação geométrica - geometria sólida construtiva , campos de distância, detecção de colisão , a transparência computação, geração de sombra
* Computação científica
** Simulação de Monte Carlo de propagação da luz
** A previsão do tempo
** Pesquisa de clima
** A modelagem molecular na GPU
** Mecânica quântica física
** Astrofísica
* As redes neurais