O que é
CUDA (Compute Unified Device Architeture) é uma biblioteca proprietária da NVidia que consiste de uma extensão da linguagem C para possibilitar a programação de GPUs.
Para que serve
As GPUs são dispositivos massivamente paralelos e com alta densidade aritmética. Desta forma diversas aplicações podem ser aceleradas tirando proveito das vantagens que uma GPU oferece (veja mais em GPGPU). O intuito principal de CUDA é facilitar o desenvolvimento de aplicações GPGPU em placas de vídeo NVidia.
Certificação
Recentemente a NVidia lançou a possibilidade de poder se certificar em CUDA. (Colocar detalhes aqui)
O plano de ensino sugerido pela empresa se encontra em http://www.nvidia.com/object/io_1266605227307.html.
Conceitos básicos
Em CUDA o código-fonte de programas que irão executar na GPU tem a terminação .cu. Tais arquivos consistem de funções aderentes ao padrão C99 com certas extensões.
Estas extensões são necessárias para lidar com as especificidades do desenvolvimento na GPU. Antes de adentrar nas diferenças é necessário fazer alguns comentários
O código que executa na CPU é dito estar no hospedeiro (ou anfitrião) - host. Portanto, toda vez que fizermos menção a host ou a hospedeiro estamos nos referindo a código que executa na CPU
Por outro lado o código que executa na placa de vídeo é o código que está no dispositivo - device. Portanto, toda vez que fizermos menção a dispositivo/device estamos nos referindo a código que executa na GPU
Assim encontramos a primeira especficade. Funções em arquivos CUDA têm um especificador da função que diz de onde a função é acessivel, o que é denominado qualificador de função:
- global : A função pode ser chamada tanto pelo hospedeiro quanto pelo dispositivo. Neste caso a função executa na GPU
- host : A função executa apenas no hospedeiro. Este qualificador faz da função uma função C normal como nós veríamos em código C puro. Neste caso a função é acessível somente de funções presentes no hospedeiro.
- device: A função é acessível somente para õutras funções que executam no dispositivo, sendo vedado a sua chamada por funções host.
Quando se omite o qualificador de função, isto é não se menciona explicitamente qual dos três está sendo utilizado, o compilador da GPU assume que a função é executada no hospedeiro, estando o qualificador host implícito na função.
Outro detalhe importante é que como a GPU é um processador que apesar de atuar como escravo tem sua própria memória dedicada, é necessário alocar memória para as variáveis que vão ser passadas para funções que executam na GPU. A função que desempenha este papel é cudaMalloc. Tal função tem o seguinte protótipo
cudaMalloc( void **ptr, size_t numBytes );
O primeiro argumento é o endereço de memória do ponteiro que irá estar na GPU e o segundo argumento é o número de bytes a serem alocados para este ponteiro.
À semelhança do que acontece em C há uma função cudaMemcpy que igual à função C padrão copia memória para um certo lugar na memória. A diferença é que neste caso há um argumento adicional que diz de onde para onde está sendo copiada a memória. O protótipo para a função é:
cudaMemcpy( void *dest, void *src, size_t numBytes, enum cudaMemcpyKind tipo);
O primeiro argumento é o endereço de memória para onde os dados serão transferidos
O segundo argumento é de onde os dados serão copiados
O terceiro argumento define quantos bytes serão copiados
O último argumento é uma enumeração que diz de onde para onde a transferência está acontecendo. seus valores podem ser
- cudaMemcpyDeviceToHost : Especifica que a transferência acontece do dispositivo para o anfitrião
- cudaMemcpyHostToDevice: Especifica que a transferência acontece do anfitrião para o host
- cudaMemcpyHostToHost: Especifica que a transferência entre dois locais de memória residentes no hospedeiro
- cudaMemcpyDeviceToDevice: Especifica que a transferência entre dois locais de memória residentes no dispositivo
Compilando código CUDA
No Windows
Pré-requisitos
- Instale o Microsoft Visual Studio C++ - MSVC++ (Qualquer versão, mesmo a Express que é gratuita funciona) .
- Instale o CUDA Toolkit, tomando cuidado para que o número de bits seja igual ao da instalação do MSVC++ (32 ou 64bits)
Linha de comando
O procedimento realizado aqui se aplica a linha de comando.
O primeiro passo é abrir o prompt de comando - cmd.exe
Após feito isso assegure que o compilador do MSVC++ (cl) esteja no path, bem com o nvcc. Caso não estejam coloque-os no PATH.
Para colocar o cl no path há um jeito simples:
Navegue até o diretório de instalação do MSVC++ e na subpasta VC/bin execute o arquivo vcvars32.bat.
Crie um arquivo .cu com o código CUDA dentro. Pegue por exemplo um código simples como o primeiro exibido na próxima seção desta página do Wiki.
compile o arquivo em questão com a seguinte linha de comando
nvcc arquivo.cu -o arquivo
O arquivo.cu é o arquivo que contém o código-fonte CUDA e a opção -o permite que a gente defina o nome do executável a ser gerado, neste caso arquivo.exe
Microsoft Visual Studio 2008 C++
Basta seguir o tutorial disponível em: http://www.programmerfish.com/how-to-run-cuda-on-visual-studio-2008-vs08/
Funciona também para a edição Express do IDE
Exemplos em CUDA
Exemplo simples
Este arquivo demonstra um exemplo simples com cuda. Caso você queira testá-lo baixe o CUDA ToolKit e compile ele. As instruções para compilação estão disponíveis na seção anterior. Lembre-se que o arquivo CUDA deve terminar com a extensão .cu. Ex: teste.cu
#include <cstdio> #include <cstdlib> #include<cstring> __global__ void vecAdd( int *v1, int *v2, int *res ){ int i = threadIdx.x; res[i] = v1[i] + v2[i]; } // teste simples int main( int argc, char **argv ){ int array[]={1,2,3,4,5}; int array2[]={1,2,3,4,5}; int *cudaArr1, *cudaArr2, *resCuda; int res[5]; //cudaMemCpy( ); cudaMalloc( (void**) &cudaArr1, 5 * sizeof(int)); cudaMalloc( (void**) &cudaArr2, 5 * sizeof(int)); cudaMalloc( (void**) &resCuda, 5 * sizeof(int)); cudaMemcpy( cudaArr1, array, 5 * sizeof(int), cudaMemcpyHostToDevice ); cudaMemcpy( cudaArr2, array2, 5 * sizeof(int), cudaMemcpyHostToDevice ); vecAdd<<<1, 5>>>( cudaArr1, cudaArr2, resCuda ); //cudaMemcpy( res, cudaArr1, 5* sizeof(int), cudaMemcpyDeviceToHost ); cudaMemcpy( res, resCuda, 5* sizeof(int), cudaMemcpyDeviceToHost ); for( int i = 0; i < 5; i++ ){ printf( "%d ", res[i] ); } puts(""); return 0; }
Chamando código CUDA a partir do C++
Exemplo disponível em: http://www.4shared.com/file/jyxBlxfO/ConsoleTestCUDA.html
Configurando o seu IDE para aceitar código CUDA
CUDA + Codeblocks
Para configurar o Codeblocks para entender e compilar código CUDA basta seguir o guia disponível em http://forums.nvidia.com/index.php?showtopic=105206.
Outras informações importantes
Uma coisa que a saber antes de programar CUDA é a capacidade de computação que tua placa de vídeo NVidia suporta, pois certos recursos da API são disponíveis somente a partir de uma determinada capacidade de computação. Um link que faz um resumo de capacidades de computação para as placas de vídeo NVidia e o que elas suportam se encontra em: http://www.geeks3d.com/20100606/gpu-computing-nvidia-cuda-compute-capability-comparative-table/.
Há também um artigo publicado pela NVidia sobre como funciona a computação de ponto flutuante em hardware NVidia: http://goo.gl/lH0PP
Existem diversos artigos sobre supercomputação e computação paralela. Um site que disponibiliza diversos deles é o |HPCWire. Um exemplos de artigo pode ser visto em http://www.hpcwire.com/hpcwire/2011-06-09/top_10_objections_to_gpu_computing_reconsidered.html?featured=top&sf1611430=1.
CUDA zone
CUDA zone é uma seção que se encontra dentro do site da NVidia dedicada a mostrar o uso da tecnologia CUDA na área acadêmica, em prdutos e em diversos outros lugares. Há centenas de artigos, e até mesmo vários projetos de código-ote aberto.
Livros
Gpu Computing Gems
Mostra várias técnicas de computação na GPU com exemplos vindo de várias áreas
link: http://mkp.com/news/gpu-computing-gems-edited-by-wen-mei-w-hwu
CUDA by example
Dá um panorama sobre CUDA incluindo desde um capítulo sobre o que é CUDA e como funcionca a arquitetura, até a demonstração de características da API como manipulação de memória de textura e interopabilidade com as APIs gráficas DirectX e OpenGL.
link: http://developer.nvidia.com/object/cuda-by-example.html
Uma lista de livros sobre CUDA e OpenCL pode ser achada em http://www.nvidia.com/object/cuda_books.html
The CUDA Handbook: A Comprehensive Guide to GPU Programming
mais um livro de CUDA
link: http://my.safaribooksonline.com/9780133261516
Cuda handbook
mais um livro de CUDA
link: http://cudahandbook.com/
CUDA Programming: A Developer's Guide to Parallel Computing with GPUs (Applications of GPU Computing Series) [Paperback]
link: http://www.amazon.com/dp/0124159338/ref=cm_sw_r_tw_asp_-EroE.1JMC0QX
Programming Massively Parallel Processors, Second Edition: A Hands-on Approach
Segunda edição do livro de H Wen Mei. E David Kirk
link: http://www.amazon.com/dp/0124159923/ref=cm_sw_r_tw_asp_469NF.1S3VH55
Utilitários
Arion benchmark Software para fazer benchmark de hardware CUDA (placas de vídeo NVidia em outras palavras)
Link: http://www.randomcontrol.com/arionbench
Links
http://www.nvidia.com/object/cuda_home_new.html página da zona CUDA (CUDA zone)