A GPU Drano é uma ferramenta de análise estática para programas de GPU. Uma das análises da GPU Drano é para encontrar acessos de memória desconectada no código CUDA. A outra análise suportada pela GPU Drano é a análise para provar a independência do tamanho de blocos dos programas de GPU.
Pacote de GPUs modernos tópicos em deformações. Todos os threads em uma urdidura realizam operações no Lockstep. Os acessos de memória a diferentes locais de memória podem ser unidos em uma única carga/armazenamento se a memória for adjacente ou próxima o suficiente na memória. Quando a memória acessada por uma urdidura está distante, várias lojas são necessárias para concluir a transação de memória e dizemos que o acesso não é coaguido .
Diz-se que um kernel de GPU é independente do tamanho de um bloco , se modificando o tamanho do bloco, mantendo o número total de threads iguais, não quebrar a funcionalidade do programa. Isso é essencial para o ajuste correto de tamanho de bloco nos programas de GPU, que geralmente é usado para melhorar o desempenho do programa.
Também implementamos uma análise dinâmica para identificar acessos descontraídos, está disponível neste repositório.
A GPU Drano é implementada como um passe do compilador para LLVM usando a implementação do CUDA de código aberto do Google: gpucc . Portanto, Drano é fortemente acoplado ao LLVM.
Drano requer LLVM versão 6.0 ou posterior. Também requer CUDA Toolkit (versão 7.5 ou posterior) da NVIDIA. Foi testado no Ubuntu 16.04 LTS, mas deve trabalhar com a maioria dos sistemas Linux existentes.
A análise estática em si não requer uma GPU. No entanto, para executar os programas e executar anlaysis dinâmicos, é necessária uma GPU da NVIDIA e drivers compatíveis. Verifique os requisitos do sistema da Nvidia para obter mais informações.
Os detalhes do algoritmo e das opções de design podem ser encontrados nos documentos a seguir:
O script installnrun.sh incluído no projeto detalha as etapas necessárias para criar e executar a GPU Drano em um sistema Ubuntu. Para executar o script,
ROOT_DIR no caminho para a pasta baixada.sh installnrun.shIsso instalaria automaticamente a GPU Drano em um sistema Linux. Descrevemos ainda as etapas de instalação para a instalação da análise de acesso desconhecido aqui. A instalação para análise de independência do tamanho de blocos (também conhecida como análise de invariância em tamanho de bloco) pode ser feita da mesma forma.
Obtenha a fonte LLVM:
Verifique se subversion está instalada. Baixe a versão mais recente do LLVM:
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
Obtenha a fonte do clang:
Altere seu diretório de trabalho atual para llvm/tools/ e confira clang do repositório SVN:
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
Adicione a GPU Drano ao LLVM:
Copie a pasta src/ Src/na GPU no diretório llvm/lib/Transforms/UncoalescedAnalysis em seu código -fonte:
cp -r src/abstract-execution/* llvm/lib/Transforms/UncoalescedAnalysis
cp -r src/uncoalesced-analysis/* llvm/lib/Transforms/UncoalescedAnalysis
Isso criará uma pasta chamada llvm/lib/Transforms/UncoalescedAnalysis/ . Devemos registrar nosso passe no sistema de construção LLVM, cmake . Portanto, APEND add_subdirectory(UncoalescedAnalysis) para llvm/lib/Transforms/CMakeLists.txt
Amostra cmakelists.txt arquivo:
$> more CMakeLists.txt
add_subdirectory(Utils)
add_subdirectory(Instrumentation)
add_subdirectory(InstCombine)
add_subdirectory(Scalar)
add_subdirectory(IPO)
add_subdirectory(Vectorize)
add_subdirectory(Hello)
add_subdirectory(ObjCARC)
add_subdirectory(Coroutines)
add_subdirectory(UncoalescedAnalysis)
Build LLVM e GPU Drano:
A partir do diretório raiz de Drano, crie um diretório build/ . Em seguida, altere o diretório para o diretório build/ . Verifique se o cmake está instalado no sistema. Execute os seguintes comandos aqui:
cmake ../llvm
make
Isso está cmake com o caminho para o diretório LLVM ( ../llvm ). O CMake configura o LLVM para o seu sistema. Ele deve gerar vários arquivos no seu diretório de trabalho atual ( build/ ). O comando make Builds LLVM e DRANO.
Idealmente, use make -j N onde n é o seu número de núcleos para construir em paralelo, pois o LLVM leva muito tempo para ser construído.
AVISO : O LLVM Build leva uma grande quantidade de memória para compilar, especificamente na etapa de vinculação. Se você tiver <8 gigabytes de RAM, a LLVM pode não conseguir construir. Nesse caso, você pode make novamente sem a opção -j . Isso recompilará apenas as partes com falha da construção e ainda economizará mais tempo do que não usar -j desde o início.
Instale o LLVM e o GPU DRANO Execute sudo make install . Isso deve instalar as bibliotecas e binários no local padrão (ou no local especificado). Se instalado localmente, este guia assume que o Bash pode encontrar o comando em seu caminho.
O acima é um guia de início rápido. Se você não estiver familiarizado com o LLVM, pode encontrar todos os detalhes para instalação em: http://llvm.org/docs/gettingstarted.html
O script installnrun.sh descreve brevemente o processo para criar drivers nvidia, kit de ferramentas e o SDK. O roteiro foi comentado para evitar o risco de substituir os motoristas da NVIDIA existentes. Observe que precisamos apenas do kit de ferramentas e do SDK para executar a análise estática. Também precisamos de motoristas e uma GPU em funcionamento para executar a análise dinâmica e os próprios programas CUDA.
Instale os drivers da NVIDIA, o CUDA Toolkit e o SDK: Consulte o Guia de instalação da NVIDIA para obter instruções.
Em resumo, se você usar uma distro Linux recente e popular, poderá usar a ferramenta de download automática para instalar os drivers e o SDK necessários.
Se você já possui os drivers necessários e o SDK instalado, poderá pular esta etapa. Provavelmente não é uma boa ideia substituir seus drivers existentes, pois isso pode tornar seu sistema inutilizável.
Você pode precisar de G ++-Multilib para instalar as bibliotecas necessárias pelo clang .
Esta etapa é opcional . Um programa CUDA simples como "Hello World" agora deve ser compilado usando clang ou clang++ :
clang -x cuda helloWorld.cu
A opção -x cuda declara explicitamente o idioma. Você também pode omitir e Clang inferirá isso como um programa CUDA.
Aviso: sua instalação de clang pode não precisar encontrar várias funções internas de LLVM; nesse caso, pode ser necessário incluir -lcudart . Você também pode precisar apontar para a localização do cudart.so .
Exemplo:
clang -x cuda -L /usr/local/cuda/targets/x86_64-linux/lib/ -lcudart helloWorld.cu
O caminho para o seu Cudart.São pode ser diferente, dependendo do seu sistema.
O LLVM deveria ter gerado um arquivo .so compartilhado, chamado LLVMUncoalescedAnalysis.so , sob o diretório build/lib/ .
O LLVM Complier clang gera um dispositivo separado (o código do kernel da GPU) e os arquivos do host (código executado nos CPU) ao compilar os programas CUDA. A GPU Drano analisa os arquivos LLVM IR para o código do dispositivo.
Como exemplo, vamos analisar o código do kernel Rodinia para o benchmark gaussian . Mudamos o diretório para rodinia_3.1/cuda/gaussian/ .
Primeiro, o CLANG Gereate LLVM IR Arquivos para o código em que estamos interessados:
clang++ -S -g -emit-llvm gaussian.cu
Observe que compilamos com o símbolo de depuração -g , para manter as informações de depuração sobre os locais do código -fonte no IR gerado. Isso é usado para apontar os locais do código -fonte com potenciais acessos desconhecidos da LLVM IR.
A compilação gera dois arquivos:
gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll
gaussian.ll
Em seguida, podemos executar a análise estática através da opt da LLVM, especificando o caminho para o binário binário da GPU e especificando -interproc-uncoalesced-analysis a ser executada. Este passe é uma análise interprocedural para detectar acessos desconectados. Começa com a análise da função mais importante no gráfico de chamada e depois prossegue com a análise de seus callees em uma ordem topológica. Ao analisar um Callee específico, considera a junção dos contextos de chamada de todos os seus chamadores. Para executar uma análise intraprocedural (que assume que todos os argumentos iniciais da função são independentes do ID do Thread), especifique -uncoalesced-analysis a ser executada, em vez de -interproc-uncoalesced-analysis .
opt -load ../../../build/lib/LLVMUncoalescedAnalysis.so -instnamer -interproc-uncoalesced-analysis < gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll > /dev/null 2> gpuDranoResults.txt
Observe opt lê o arquivo IR da entrada padrão. opt escreve sua própria saída desinteressante para o padrão, para redirecioná -lo para /dev/null gpu drano, a saída do DRANO é gravada em erro padrão que pode ser redirecionado para um arquivo.
Para gerar os resultados da análise detalhada (LLVM IR anotada com informações de análise), execute opt com um sinalizador -debug-only=uncoalesced-analysis .
O comando a seguir pode ser usado para executar a análise de independência do tamanho de bloco em um programa.
opt -load ../../../build/lib/LLVMBlockSizeInvarianceAnalysis.so - -instnamer -always-inline -interproc-bsize-invariance-analysis < gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll > /dev/null 2> gpuDranoResults.txt
Os resultados gerados para relatórios de análise de acesso desconectado que podem ser potencialmente desconhecidos em cada um dos núcleos da GPU. Por exemplo, aqui estão os resultados para a análise do gaussian.cu .
Analysis Results:
Function: _Z4Fan1PfS_ii
Uncoalesced accesses: #2
-- gaussian.cu:295:59
-- gaussian.cu:295:61
Analysis Results:
Function: _Z4Fan2PfS_S_iii
Uncoalesced accesses: #4
-- gaussian.cu:312:38
-- gaussian.cu:312:35
-- gaussian.cu:312:35
-- gaussian.cu:317:23
Cada item de resultado aponta para um acesso potencialmente desconhecido no código -fonte. Por exemplo, o acesso a m_cuda na linha 295, coluna 59 em gaussian.cu no método Fan1() não é desconhecido.
Da mesma forma, os resultados gerados para a análise de independência do tamanho de blocos identificam todos os kernels independentes do tamanho de blocos!
Rodinia é um conjunto de benchmark popular de programas de GPU que consistem em 22 programas de diferentes domínios. Analisamos a suíte e encontramos 111 acessos realmente desconhecidos usando análise estática. Para reproduzir os resultados, aqui estão as etapas envolvidas:
Atualize a configuração CUDA e DRANO em rodinia_3.1/common/make.config . Defina CUDA_DIR e SDK_DIR com os caminhos NVIDIA Toolkit e SDK. Atualizar pseudônimo opt com caminho para a GPU Drano Binário LLVMUncoalescedAnalysis.so .
Vá para o diretório de benchmarks rodinia_3.1/cuda .
Compilar benchmarks:
sh compile.sh
sh run-analysis.sh
A análise de cada benchmark gera resultados em sua respectiva pasta em arquivos de log denominados log_<filename> .
./summarize-results.sh
A NVIDIA fornece um conjunto de amostras de CUDA que podem ser usadas para várias aplicações. Analisamos a suíte para identificar kernels independentes do tamanho de blocos nas amostras. Para reproduzir os resultados, as etapas são:
Atualize a variável HOME em NVIDIA_CUDA-8.0_Samples/common/drano.mk no diretório raiz gpu drano.
Instale o OpenGL (necessário para compilar alguns benchmarks). No Ubuntu, o comando a seguir pode ser usado:
sudo apt-get install freeglut3-dev
Vá para o diretório NVIDIA_CUDA-8.0_Samples
Compilar benchmarks:
sh compile.sh
sh run-analysis.sh
A análise de cada benchmark gera resultados em sua respectiva pasta em arquivos de log denominados log_<filename> .
./summarize-bsize-independence.sh