• Nenhum resultado encontrado

A unidade de processamento gráfico ou GPU (Graphics Processing Unit) é um exemplo de processador many-core e foi primeiramente projetada pela NVIDIA em 1999. A GPU surgiu devido à indústria do video game, na sua intensa busca por gráficos cada vez mais reais. A partir de 2003, sua evolução contou também com esforços da indústria para possibilitar o uso de GPU em aplicações não gráficas. Todos os esforços a partir de então contribuíram para que a GPU se tornasse um microprocessador de alto desempenho em

operações de ponto flutuante [42][61].

Enquanto que a evolução dos microprocessadores utilizados para propósito geral (CPUs) desacelerou significativamente, as GPUs vêm crescendo continuamente. Com a GPU, o potencial dos desktops transformou-se em bilhões de operações em ponto

flutuante por segundo (GFLOPS). A Figura4.8, ilustra a grande diferença de performance

entre eles. Em 2009, a razão entre o pico de desempenho em operações de ponto flutuante por segundo, era de 10 para 1.

O grande ganho de desempenho oferecido pela execução paralela nas GPUs tem motivado muitos desenvolvedores a migrarem a parte computacionalmente intensiva

de suas aplicações para a GPU. A Figura 4.9 ilustra a diferença de arquitetura dos

dois processadores. A CPU com uma grande estrutura de controle e cache para uma quantidade pequena de ALUs. A GPU por outro lado, possui controle e cache distribuídos em pequenas módulos que controlam diversas ALUs.

No mercado de HPC, a escolha de um processador para execução de aplicações deve se basear não só no fator desempenho, outros fatores são tão importantes quanto, tais como, presença de mercado e acessibilidade. Os fabricantes de GPUs, em especial a

4.2. PROCESSADORES GRÁFICOS (GPUS)

Fonte: HWU, W.; KIRK, D. Programming Massively Parallel Processors. Special Edition, 2009. Fonte: Hwu, W.; Kirk, D. (2009). Programming Massively Parallel Processors.

Figura 4.8 Crescente diferença de desempenho entre GPUs e CPUs

Fonte: HWU, W.; KIRK, D. Programming Massively Parallel Processors. Special Edition, 2009. Fonte: Hwu, W.; Kirk, D. (2009). Programming Massively Parallel Processors.

ARQUITETURAS

NVIDIA, realizaram grandes avanços para tornar a GPU mais acessível e difundida. Até 2006, as GPUs eram muito difíceis de serem usadas por conta da dificuldade em programá-las através de APIs em OpenGL ou Direct3D. Esta técnica denominada GPGPU (general-purpose programming using a graphics processing unit), mesmo com um ambiente em um nível mais alto de programação, ainda limitava os tipos de aplicações que podiam realmente serem escritas nestes chips. Por esta razão, esta técnica não ficou amplamente difundida. Apenas algumas pessoas possuíam o conhecimento da arquitetura da GPU e da API gráfica, para obter alto desempenho em um conjunto limitado de aplicações. Os problemas tinham que ser expressos em termos de coordenadas, texturas e shaders, que aumentavam e muito a complexidade do problema.

Para resolver estes problemas, em 2007 a NVIDIA introduziu duas tecnologias chaves: • A G80 unified graphics and compute architecture, introduzida nas GPUs GeForce

8800, Quadro FX 5600, e Tesla C870;

• e CUDA, uma arquitetura de software e hardware, que permite a GPU ser progra- mada com uma variedade de linguagens de programação de alto nível.

Juntas, estas novas tecnologias representam uma nova forma de usar a GPU. O uso de unidades gráficas programadas com APIs gráficas, deu lugar a um ambiente onde o programador pode agora escrever programas em C e executá-los em um processador paralelo de propósito geral. Essa nova forma de se programar a GPU passou a se chamar “GPU Computing”.

Na arquitetura da GPU Tesla, os processadores shader passaram a ser inteiramente programáveis com uma grande memória de instruções, cache de instruções, e controle lógico de instrução seqüencial. O custo deste hardware foi reduzido ao compartilhar a cache de instruções e o controle lógico, entre vários processadores shader. A NVIDIA adicionou carga de memória e armazenamento de instruções com capacidade de ende- reçamento randômico para suportar programas em C. Para aplicações não gráficas, a GPU Tesla introduziu um modelo de programação paralela genérico com uma hierarquia de threads paralelas, sincronização de barreira (barrier synchronization), e operações atômicas para disparar e gerenciar tarefas com alto grau de paralelismo. A NVIDIA também desenvolveu compilador CUDA C/C++, bibliotecas, e ambientes de execução para permitir acesso ao novo modelo. O chip G80 foi baseado na arquitetura Tesla e foi usado na GeForce 8800 GTX, que foi seguida pelas gerações G92 e GT200.

Nos chips G80 e seus sucessores, os programas em CUDA passaram a usar uma nova interface de programação que eliminou a necessidade de usar as APIs gráficas para

4.2. PROCESSADORES GRÁFICOS (GPUS)

desenvolver as aplicações. Todas as camadas de software foram refeitas, permitindo que os usuários utilizassem as ferramentas de desenvolvimento em C/C++, as quais, estavam habituados.

Em 2009, algumas das maiores indústrias da computação, incluindo Apple, Intel, AMD e NVIDIA desenvolveram juntos um modelo de programação paralelo padronizado,

chamado OpenCL[32]. Bastante similar a CUDA, o modelo de programação da NVI-

DIA, o modelo OpenCL define extensões de linguagem e APIs de tempo de execução permitindo que os desenvolvedores gerenciem o paralelismo e o acesso a dados em processadores massivamente paralelos. OpenCL também pretende fornecer portabilidade (cross-platform environment), ou seja, aplicações desenvolvidas em OpenCL são capazes de rodar, sem qualquer modificação, em outros processadores que ofereçam suporte a linguagem.

Apesar da linguagem ser bastante recente, sua evolução tem sido rápida. Em Junho de

2010 a especificação 1.1 da linguagem foi liberada[47]. Já em Novembro de 2011, apenas

dezoito meses depois, uma nova versão da especificação foi lançada, OpenCL 1.2[48].

Todas estas novas versões trazem melhorias tanto na flexibilidade de uso da linguagem quanto no desempenho. Novos processadores e arquiteturas passaram a dar suporte a linguagem. A Altera começou a desenvolver sua SDK para dar suporte a OpenCL em

FPGA e os primeiros resultados já começaram a ser publicados [5][3]. A linguagem

OpenCL foi a escolhida para a implementação da modelagem sísmica 2D na plataforma GPU.

Na implementação em OpenCL para a GPU, o paralelismo é explorado distribuindo os cálculos em um grande número de threads denominadas work-items. Em tempo de execução estes work-items são mapeados nos processadores em stream da GPU. Devido à arquitetura extremamente paralela da GPU, normalmente há centenas de threads disponíveis capazes de explorar massivamente o paralelismo. Ao executar um kernel, o host determina o número de work-groups de acordo com a dimensão dos dados de entrada. Um work-group contém 16 x 16 work-items que operam em paralelo. O work-group é então mapeado para uma unidade de computação do dispositivo OpenCL.

Com relação à hierarquia de memória em OpenCL, a memória local é compartilhada por um work-group, ou seja, todos os work-items têm acesso aos mesmos dados e a mesma velocidade. Como regra geral, os tempos de acesso para a memória local e global da GPU são de mesma ordem de magnitude em comparação com tempos de acesso à cache da CPU e à memória, respectivamente. O ambiente de execução OpenCL (OpenCL runtime) é responsável por alocar os work-groups para as unidades de computação do dispositivo.

ARQUITETURAS

Caso existam menos work-groups do que unidades de computação, o dispositivo não pode ser utilizado completamente. Portanto, o ideal é que o número de work-groups seja maximizado.

Na implementação da modelagem sísimica 2D o host sincroniza todos os work-groups a cada iteração do laço temporal. Sendo assim, a cada time step o host invoca o kernel de processamento que paraleliza totalmente os laços espaciais. As matrizes utilizados no processamento da modelagem sísmica 2D foram armazenadas em objetos disponíveis na API de OpenCL. Na GPU estes objetos são alocados na memória de textura, que corresponde a uma cache otimizada para acessos não lineares. Os buffers image foram declarados como somente leitura ou somente escrita. Isto se aplica aos buffers de entrada (CPF, PPF e VEL) e ao buffer de saída (NPF), respectivamente. Naturalmente a GPU tem limites com relação ao tamanho máximo dos buffers image. No sistema utilizado, a Tesla C1060, o tamanho máximo permitido é de 8192 x 8192. No entanto, os modelos processados nos experimentos não ultrapassam este limite. Caso fossem executados problemas maiores, uma estratégia para particionar os dados adequadamente precisaria ser definida.

Na implementação da modelagem sísmica 2D em OpenCL para a GPU, o problema é paralelizado apenas espacialmente. Contudo, o número de pontos computados em paralelo na matriz são tantos quantos forem as unidades de processamento disponíveis. A

Figura4.10ilustra esta característica.

work-group 1 work-group 2 work-group ('n'-1) work-group 'n'