GPU Drano es una herramienta de análisis estático para programas de GPU. Uno de los análisis en GPU Drano es encontrar accesos de memoria sin coal en el código CUDA. El otro análisis respaldado por GPU Drano es el análisis para probar la independencia del tamaño de un bloque de los programas de GPU.
Los GPU modernos agrupan hilos en urdimbres. Todos los hilos en una urdimbre realizan operaciones en Lockstep. Los accesos de memoria a diferentes ubicaciones de memoria se pueden fusionar en una sola carga/tienda si la memoria es adyacente o lo suficientemente cercana en la memoria. Cuando la memoria a la que se accede una urdimbre está muy separada, se requieren múltiples cargas/tiendas para completar la transacción de memoria, y decimos que el acceso no está coal .
Se dice que un núcleo de GPU es independiente del tamaño de un bloque , si modifica el tamaño del bloque mientras mantiene el número total de hilos iguales, no rompe la funcionalidad del programa. Esto es esencial para una correcta ajuste del tamaño de un bloque en programas de GPU, que a menudo se usa para mejorar el rendimiento del programa.
También hemos implementado un análisis dinámico para identificar accesos sin coal, está disponible en este repositorio.
GPU Drano se implementa como un pase de compilador para LLVM utilizando la implementación CUDA de código abierto de Google: gpucc . Por lo tanto, Drano está bien acoplado con LLVM.
Drano requiere LLVM versión 6.0 o posterior. También requiere CUDA Toolkit (versión 7.5 o posterior) de NVIDIA. Se ha probado en Ubuntu 16.04 LTS, pero debería funcionar con la mayoría de los sistemas Linux existentes.
El análisis estático en sí no requiere una GPU. Sin embargo, para ejecutar los programas y ejecutar anlaysis dinámico, se requiere una GPU NVIDIA y controladores compatibles. Consulte los requisitos del sistema de NVIDIA para obtener más información.
Los detalles del algoritmo y las opciones de diseño se pueden encontrar en los siguientes documentos:
El script installnrun.sh incluyó con los detalles del proyecto los pasos necesarios para construir y ejecutar GPU Drano en un sistema Ubuntu. Para ejecutar el guión,
ROOT_DIR en la ruta a la carpeta descargada.sh installnrun.shEsto instalaría automáticamente GPU Drano en un sistema Linux. Además, describimos los pasos de instalación para instalar el análisis de acceso sin coal aquí. La instalación para el análisis de independencia del tamaño de un bloque (también denominado análisis de invariancia del tamaño de un bloque) se puede hacer de manera similar.
Obtener LLVM Fuente:
Asegúrese de que se instale subversion . Descargue la versión más nueva de LLVM:
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
Obtenga la fuente de Clang:
Cambie su directorio de trabajo actual a llvm/tools/ y consulte clang desde el repositorio SVN:
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
Agregue GPU Drano a LLVM:
Copie la carpeta src/ GPU en el directorio llvm/lib/Transforms/UncoalescedAnalysis en su código fuente:
cp -r src/abstract-execution/* llvm/lib/Transforms/UncoalescedAnalysis
cp -r src/uncoalesced-analysis/* llvm/lib/Transforms/UncoalescedAnalysis
Esto creará una carpeta llamada llvm/lib/Transforms/UncoalescedAnalysis/ . Debemos registrar nuestro pase con el sistema de compilación LLVM, cmake . Por lo tanto, agregue add_subdirectory(UncoalescedAnalysis) a llvm/lib/Transforms/CMakeLists.txt
Muestra cmakelists.txt archivo:
$> 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)
Construir llvm y gpu drano:
Desde el directorio raíz de Drano, cree una build/ directorio. Luego, cambie el directorio a la build/ directorio. Asegúrese de que Cmake esté instalado en el sistema. Ejecute los siguientes comandos aquí:
cmake ../llvm
make
Ese es cmake con el directorio de ruta a LLVM ( ../llvm ). CMake configura LLVM para su sistema. Debe generar varios archivos en su directorio de trabajo actual ( build/ ). El comando make construcciones LLVM y Drano.
Idealmente, use make -j N donde n es su número de núcleos para construir en paralelo a medida que LLVM lleva mucho tiempo construir.
Aviso : la compilación LLVM toma una gran cantidad de memoria para compilar, específicamente en el paso de enlace. Si tiene <8 gigabytes de RAM, LLVM puede no construir. Si es así, puede volver a make sin la opción -j . Esto solo recompilará las partes fallidas de la compilación y aún así ahorrará más tiempo que no usar -j desde el principio.
Instale LLVM y GPU Drano Realice sudo make install . Esto debe instalar las bibliotecas y binarios en la ubicación predeterminada (o la ubicación especificada). Si se instala localmente, esta guía asume que Bash puede encontrar el comando en su ruta.
Lo anterior es una guía de inicio rápido. Si no está familiarizado con LLVM, puede encontrar todos los detalles para la instalación en: http://lllvm.org/docs/gettingstarted.html
El script installnrun.sh describe brevemente el proceso para construir controladores NVIDIA, kit de herramientas y el SDK. Se ha comentado el guión para evitar el riesgo de anular los conductores de NVIDIA existentes. Tenga en cuenta que solo necesitamos el kit de herramientas y el SDK para ejecutar el análisis estático. También necesitamos conductores y una GPU que funcione para ejecutar análisis dinámicos y programas CUDA mismos.
Instale los controladores NVIDIA, CUDA Toolkit y SDK: consulte la Guía de instalación de NVIDIA para obtener instrucciones.
En resumen, si utiliza una distribución de Linux reciente y popular, debería poder usar la herramienta de descarga automática para instalar los controladores requeridos y el SDK.
Si ya tiene los controladores requeridos y SDK instalados, puede omitir este paso. Probablemente no sea una buena idea anular a sus controladores existentes, ya que esto podría hacer que su sistema sea inutilizable.
Puede necesitar G ++-Multilib para instalar las bibliotecas necesarias requeridas por clang .
Este paso es opcional . Un programa CUDA simple como "Hello World" ahora debería compilar usando clang o clang++ :
clang -x cuda helloWorld.cu
La opción -x cuda establece explícitamente el idioma. También puede omitirlo y Clang inferirá esto como un programa CUDA.
AVISO: Es posible que su instalación de Clang no pueda encontrar varias funciones LLVM internas, de ser así, es posible que deba incluir -lcudart . También es posible que deba señalar la ubicación del cudart.so .
Ejemplo:
clang -x cuda -L /usr/local/cuda/targets/x86_64-linux/lib/ -lcudart helloWorld.cu
La ruta a su CUDART, por lo que puede ser diferente dependiendo de su sistema.
LLVM build/lib/ haber generado un archivo LLVMUncoalescedAnalysis.so objeto compartido .so
El LLVM cumplió clang genera un dispositivo separado (el código del núcleo GPU) y los archivos IR de host (código ejecutado en CPU) al compilar programas CUDA. GPU Drano analiza los archivos IR LLVM para el código del dispositivo.
Como ejemplo, analicemos el código del núcleo Rodinia para el punto de referencia gaussian . Cambiamos el directorio en rodinia_3.1/cuda/gaussian/ .
Primero tenemos a los archivos IR LLVM de Clang Generate para el código que nos interesa:
clang++ -S -g -emit-llvm gaussian.cu
Observe que compilamos con el símbolo de depuración -g , para mantener la información de depuración sobre las ubicaciones del código fuente en el IR generado. Esto se utiliza para señalar ubicaciones de código fuente con posibles accesos sin coal de LLVM IR.
La compilación genera dos archivos:
gaussian-cuda-nvptx64-nvidia-cuda-sm_20.ll
gaussian.ll
Luego podemos ejecutar el análisis estático a través de opt de LLVM especificando la ruta al binario DRANO GPU y especificando -interproc-uncoalesced-analysis . Este pase es un análisis interprocedural para detectar accesos sin coal. Comienza con el análisis de la función más importante en el gráfico de llamadas y luego continúa con el análisis de sus calorías en un orden topológico. Mientras analiza una Callee específica, considera la unión de los contextos de llamadas de todas sus personas que llaman. Para ejecutar un análisis intraprocedural (que supone que todos los argumentos de la función inicial son independientes de la identificación de Thread), especifique -uncoalesced-analysis para ejecutar, en lugar del -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 lee el archivo IR de la entrada estándar. opt escribe su propia salida poco interesante para la salida estándar, por lo que la redirigimos a /dev/null GPU La salida de Drano se escribe en un error estándar que puede redirigirse a un archivo.
Para generar resultados de análisis verboso (LLVM IR anotado con información de análisis), ejecute opt con un indicador adicional -debug-only=uncoalesced-analysis .
El siguiente comando se puede utilizar para ejecutar el análisis de independencia del tamaño de un bloque en un 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
Los resultados generados para el análisis de acceso sin coal informan todos los accesos que podrían ser potencialmente sin coal en cada uno de los núcleos GPU. Por ejemplo, aquí están los resultados para el análisis de 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 elemento de resultado apunta a un acceso potencialmente sin coal en el código fuente. Por ejemplo, el acceso a m_cuda en la línea 295, columna 59 en gaussian.cu en el método Fan1() está sin coal.
Del mismo modo, los resultados generados para el análisis de independencia del tamaño de un bloque identifican todos los núcleos que son independientes del tamaño de un bloque.
Rodinia es el popular conjunto de referencia de programas de GPU que consisten en 22 programas de diferentes dominios. Analizamos la suite y encontramos 111 accesos no coalcados reales utilizando el análisis estático. Para reproducir los resultados, aquí están los pasos involucrados:
Actualice la configuración de Cuda y Drano en rodinia_3.1/common/make.config . Establezca CUDA_DIR y SDK_DIR con rutas NVIDIA Toolkit y SDK. Actualizar alias opt con ruta a GPU Drano Binary LLVMUncoalescedAnalysis.so .
Vaya al directorio de Benchmarks rodinia_3.1/cuda .
Compilar puntos de referencia:
sh compile.sh
sh run-analysis.sh
El análisis de cada punto de referencia genera resultados en su carpeta respectiva en archivos log llamados log_<filename> .
./summarize-results.sh
NVIDIA proporciona un conjunto de muestras de CUDA que se pueden usar para varias aplicaciones. Analizamos la suite para identificar núcleos independientes del tamaño de un bloque en las muestras. Para reproducir los resultados, los pasos son:
Actualice la variable HOME en NVIDIA_CUDA-8.0_Samples/common/drano.mk al directorio Root GPU Drano.
Instale OpenGL (requerido para compilar algunos puntos de referencia). En Ubuntu, se puede usar el siguiente comando:
sudo apt-get install freeglut3-dev
Vaya al directorio NVIDIA_CUDA-8.0_Samples
Compilar puntos de referencia:
sh compile.sh
sh run-analysis.sh
El análisis de cada punto de referencia genera resultados en su carpeta respectiva en archivos log llamados log_<filename> .
./summarize-bsize-independence.sh