CUDA

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)

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.