scieee AI-readable full text Open interactive document viewer

Creación de múltiples instancias lógicas de GPU sobre una única GPU física

Cámara Miró, Julián

Abstract

El presente trabajo desarrolla una evaluación experimental de las tecnologías que actualmente permiten compartir un procesador gráfico (GPU) entre distintos procesos. Específicamente, el trabajo profundiza en el estudio de la tecnología Nvidia MIG, introducida con la generación Ampere de procesadores gráficos de Nvidia para, a través de la evaluación de cargas de trabajo con distintas características ejecutadas concurrentemente, evaluar los beneficios que dicha tecnología presenta para reducir la contención en el acceso a recursos compartidos. Los resultados obtenidos revelan que MIG es, actualmente, la única tecnología que permite aislar instancias virtuales dentro de una GPU física, permitiendo la compartición de recursos sin interferencias, y a la vez aumentando la estabilidad en los resultados obtenidos, independientemente de la naturaleza de las cargas de trabajo evaluadas.

Full text

Creación de múltiples instancias lógicas de GPU sobre una única GPU física Creating multiple virtual GPU instances over one physical GPU Trabajo de Fin de Grado Curso 2022–2023 Autor Julián Cámara Miró Directores Francisco D. Igual Peña Luis M. Costero Valero Grado en Ingeniería Informática Facultad de Informática Universidad Complutense de Madrid Creación de múltiples instancias lógicas de GPU sobre una única GPU física Creating multiple virtual GPU instances over one physical GPU Trabajo de Fin de Grado en Ingeniería Informática Autor Julián Cámara Miró Director Francisco D. Igual Peña Luis M. Costero Valero Convocatoria: Junio 2023 Grado en Ingeniería Informática Facultad de Informática Universidad Complutense de Madrid Junio de 2023 Resumen Creación de múltiples instancias lógicas de GPU sobre una única GPU física El presente trabajo desarrolla una evaluación experimental de las tecnologías que actualmente permiten compartir un procesador gráfico (GPU) entre distintos procesos. Específicamente, el trabajo profundiza en el estudio de la tecnología Nvidia MIG, introducida con la generación Ampere de procesadores gráficos de Nvidia para, a través de la evaluación de cargas de trabajo con distintas características ejecutadas concurrentemente, evaluar los beneficios que dicha tecnología presenta para reducir la contención en el acceso a recursos compartidos. Los resultados obtenidos revelan que MIG es, actualmente, la única tecnología que permite aislar instancias virtuales dentro de una GPU física, permitiendo la compartición de recursos sin interferencias, y a la vez aumentando la estabilidad en los resultados obtenidos, independientemente de la naturaleza de las cargas de trabajo evaluadas. Palabras clave GPU, MIG, Nvidia, MPS, Cloud Computing, rendimiento, gestión de recursos. v Abstract Creating multiple virtual GPU instances over one physical GPU This project develops an experimental evaluation of the technologies that currently allow the sharing of a graphics processor (GPU) between different processes. Specifically, the project focuses on the study of Nvidia MIG technology, introduced with the Ampere generation of Nvidia graphics processors. The performed experiments aim to evaluate the improvements to the contention in the access to shared resources, obtainable by MIG, through the evaluation of workloads with different characteristics executed concurrently. The obtained results reveal that MIG is currently the only technology that allows to have completely isolated virtual instances over one physical GPU, allowing resource sharing without interference, and increasing the stability of the obtained results, regardless of the characteristics of the workloads being evaluated. Keywords GPU, MIG, Nvidia, MPS, Cloud Computing, performance, resource sharing. vii Índice 1. Introducción 1 1.1. Introducción................................ 1 1.2. Objetivos ................................. 2 1.3. Estructura del documento . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Marco teórico 5 2.1. Arquitectura de las GPUs . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2. Modelo de programación CUDA . . . . . . . . . . . . . . . . . . . . . 7 2.3. Compartición de GPU entre procesos . . . . . . . . . . . . . . . . . . 8 2.3.1. NvidiaMPS............................ 8 2.3.2. NvidiaMIG............................ 10 3. Metodología 13 3.1. Objetivos ................................. 13 3.2. Cargasdetrabajo............................. 14 3.3. Diseño de los experimentos . . . . . . . . . . . . . . . . . . . . . . . . 14 3.3.1. Ejecuciones aisladas . . . . . . . . . . . . . . . . . . . . . . . 19 3.3.2. Ejecuciones combinadas . . . . . . . . . . . . . . . . . . . . . 19 3.3.3. Combinación de ejecuciones, usando MPS . . . . . . . . . . . 20 3.3.4. Combinación de ejecuciones, usando MIG . . . . . . . . . . . 20 4. Resultados experimentales 23 4.1. Descripción de la arquitectura objetivo . . . . . . . . . . . . . . . . . 23 4.2. Metodología experimental . . . . . . . . . . . . . . . . . . . . . . . . 24 4.3. Ejecucionesaisladas............................ 25 4.3.1. GEMM .............................. 25 4.3.2. GEMV............................... 26 4.3.3. Conclusiones ........................... 27 4.4. Ejecución concurrente . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4.4.1. GPU entera (4g.24gb) . . . . . . . . . . . . . . . . . . . . . . 29 4.4.2. Un medio de la GPU (2g.12gb) . . . . . . . . . . . . . . . . . 30 4.4.3. Conclusiones ........................... 30 ix 2Capítulo 1. Introducción estrategias que mejoren su porcentaje de utilización, posiblemente ofreciéndolo de forma compartida a los usuarios. 4. Interferencia entre aplicaciones: Es muy común que los usuarios deseen ser capaces de predecir el tiempo de ejecución de sus aplicaciones de modo que sea lo más determinista posible; en este sentido, en entornos de ejecución compartidos donde múltiples aplicaciones del propio o de múltiples usuarios hacen un uso compartido de los recursos, reducir la interferencia entre aplicaciones aislando recursos asignados a cada una es una característica deseable. Uno de los recursos de cómputo más ampliamente utilizados en los servicios de computación en la nube son los procesadores gráficos (GPUs). Durante las últimas dos décadas, la potencia de cómputo y el grado de paralelismo que una GPU de gama alta puede ofrecer ha crecido hasta resultar indispensables para obtener rendimiento en todo tipo de aplicaciones de propósito general. De hecho, a día de hoy esta capacidad de cómputo paralelo es tan elevada que muchas aplicaciones no son capaces de aprovechar todos los recursos de cómputo (núcleos de computación o ancho de banda a memoria) que ofrecen las GPUs de última generación. En respuesta a esto, una posibilidad radica en ofrecer los recursos de una o múltiples GPUs de modo compartido, siendo accesibles concurrentemente por parte de múltiples usuarios. Esta estrategia aumenta el grado de utilización de la(s) GPU(s), pero conlleva problemas de contención en el acceso a recursos compartidos, dependiendo de la naturaleza de las aplicaciones ejecutadas concurrentemente. Surge entonces un nuevo problema: sin soporte software/hardware por parte de los fabricantes, no existe una solución sencilla para ofrecer la GPU como un recurso de cómputo compartido (reduciendo así los costes de mantenimiento y adquisición y aumentando su utilización efectiva), evitando la interferencia entre aplicaciones concurrentes. Para resolver este problema, Nvidia ha desarrollado la tecnología MIG (Multi Instance GPU)1, la cual permite dividir una GPU en varias instancias completamente aisladas, cada una con sus propios recursos. De esta forma, los programas se ejecutan en paralelo en instancias separadas, lo que permite a los proveedores ofrecer a sus clientes un rendimiento predecible, que no se vea influenciado negativamente por los trabajos que puedan solicitar otros usuarios. Las instancias virtuales generadas no tienen por qué tener el mismo tamaño, sino que se puede dividir la GPU de forma asimétrica para soportar mejor cargas de trabajo de distinto tamaño y/o naturaleza. 1.2. Objetivos El objetivo de este trabajo es estudiar y evaluar el funcionamiento de la tecnología MIG sobre GPUs de última generación, y comparar su comportamiento y eficiencia con respecto a otras metodologías y tecnologías disponibles para compartir GPUs entre aplicaciones o usuarios. Para ello se analizarán las distintas configuraciones 1Esta tecnología sólo es compatible con algunas de las GPUs para datacenters de arquitectura Ampere y posteriores. 1.3. Estructura del documento 3 que existen para la GPU con la que se trabajará (Nvidia A30) frente a cargas de trabajo de distinta naturaleza, analizando tanto el rendimiento máximo obtenido como las potenciales interferencias entre ellas. Concretamente, este objetivo general se divide en un conjunto de objetivos específicos, que pueden resumirse como: 1. Estudiar el comportamiento de aplicaciones de distintas naturaleza, y como depende el rendimiento de cada una de los diferentes recursos disponibles en la GPU. 2. Analizar como se reparten los recursos de la GPU entre las aplicaciones anteriormente mencionadas, si se ejecutan de forma simultánea dentro de la misma GPU, y las pérdidas de rendimiento que resulten de dicha compartición. 3. Analizar de forma individual varias tecnologías que existen para mejorar la convivencia entre aplicaciones dentro de la GPU. 4. Comparar dichas tecnologías entre sí, analizando las ventajas e inconvenientes que ofrece cada una, y determinar en qué situaciones es preferible usa cada una. 1.3. Estructura del documento Primero, en el capítulo 2 se mencionan algunos conceptos teóricos fundamentales para este trabajo. Concretamente se hablará sobre la arquitectura de las GPUs, el modelo de programación CUDA, los problemas que surgen de la compartición e una GPU entre varios procesos y las tecnologías MIG y MPS. Posteriormente, en el Capítulo 3 se explica la metodología seguida durante toda la fase experimental. Se detallarán las cargas de trabajo escogidas, metodología y fases experimentales. A continuación, en el Capítulo 4 se analizaran los resultados obtenidos durante la fase experimental. Primero se introducirá la arquitectura objetivo, en la que se llevaron a cabo todos los experimentos. A continuación, se darán detalles sobre la metodología usada para lanzar los experimentos y se analizarán en profundidad los resultados obtenidos en cada una de las fases experimentales. Para concluir el capítulo, se incluye una sección final de conclusiones experimentales, en la que se analizarán de forma conjunta las conclusiones de todas las fases. Por último, el Capítulo 5 se listan las conclusiones generales observadas tras la conclusión del trabajo, así como posibles líneas de estudio que quedan pendientes para el futuro. Cap´ ıtulo 2 Marco teórico En este capítulo se realiza una breve descripción de los aspectos teóricos sobre las GPUs de Nvidia más relevantes para el trabajo desarrollado. 2.1. Arquitectura de las GPUs Antes de 2006, las GPUs presentaban una arquitectura estructurada en capas, cada una da las cuales correspondía a una de las etapas del pipeline de renderizado gráfico. Esto, además de ser poco flexible, generaba problemas si se produce un cuello de botella en alguna de las capas ya que, como realizaban funciones distintas, no se podía usar las otras capas para compensar. Además, impedía (o dificultaba) el uso de las GPUs para realizar operaciones fuera del ámbito del renderizado gráfico, limitando su flexibilidad pese al potencial de cómputo paralelo que presentaban. Fue en 2006, con la arquitectura Tesla, cuando Nvidia cambió de forma radical la arquitectura de sus GPUs. Desaparece la división en capas mencionada anteriormente, y surge por primera vez el concepto de Streaming Multiprocessor (SM). Debido a la gran flexibilidad que ofrece, este nuevo paradigma ha ido ganando popularidad y se ha ido mejorando y extendiendo hasta la actualidad, de tal forma que ahora las GPUs se utilizan para muchas otras aplicaciones, además de gráficos, que puedan beneficiarse del enorme nivel de paralelismo que ofrecen. En la actualidad, los núcleos de ejecución (cores) pasan de tener una función fija a ser de propósito general, completamente programables usando el modelo de programación CUDA. Estos cores se agrupan en los denominados SMs. Además, cada SM cuenta con otros recursos propios, como registros arquitectónicos, cores de propósito más especializado (por ejemplo, los núcleos tensoriales (Tensor Cores) que aparecen desde la arquitectura Volta), caché o planificadores, entre otros. A nivel software, los programas lanzados se dividen en bloques de hilos, que a su vez se dividen en fragmentos de 32 hilos (16 en arquitecturas anteriores) deno5 6Capítulo 2. Marco teórico Figura 2.1: Esquema del SM de la arquitectura Ampere. Fuente: [4] minados warps. Los bloques de distribuirán entre los SMs disponibles, de forma que todos los warps de un mismo bloque estén en el mismo SM. Al conjunto de todos los bloques relacionados con la misma tarea se le llama grid. Cada SM dispone de uno o más warp schedulers, dependiendo de la arquitectura (por ejemplo, Ampere tiene 4). Cada scheduler seleccionará en cada ciclo un warp distinto, de forma que cada uno de los hilos que forman el warp ejecute una de sus instrucciones. Como todos los hilos de un mismo warp comparten el mismo contador de programa, en caso de que alguno de ellos no tuviera que ejecutar esa instrucción se inhibirá las acciones que desencadene la ejecución de dicha instrucción. Cada warp scheduler tiene también asociada una memoria cache que pueden usar sus hilos. Cada SM dispone de un gran número de registros, que repartirá entre todos los hilos de los warps que tenga asociados. Además, todos los SMs disponen también de una memoria compartida de baja latencia, que pueden usar todos los hilos de un mismo bloque para comunicarse entre sí sin tener que acceder a la memoria principal, aumentando así de forma drámatica el rendimiento del programa paralelo. Por otro lado, la GPU dispone de una memoria global a la que tienen acceso todos los SMs, cuyo ancho de banda se reparte entre todos los SMs que la usen al mismo 2.2. Modelo de programación CUDA 7 tiempo. Esta memoria es la que se utiliza también para realizar las transferencias de datos entre la GPU y la memoria principal de la CPU. Aunque las tecnologías de memoria utilizadas en GPUs de última generación (DDR5 o HBM) exhiben un ancho de banda excelente, su uso todavía ralentiza la ejecución del programa paralelo, debido principalemnte a la cantidad de hilos/núcleos de ejecución disponibles. 2.2. Modelo de programación CUDA Para poder programar de forma sencilla esta nueva arquitectura de GPU multipropósito, Nvidia desarrolló también CUDA. Se trata de un nuevo modelo y entorno de programación que permite explotar las ventajas que ofrecen las nuevas GPU cambiando radicalmente el modelo de programación habitual. Nvidia CUDA toolkit es un paquete que ofrece numerosas herramientas para desarrollar software para estas GPUs. Por ejemplo, se incluye librerías de álgebra y aprendizaje automático, un compilador para CUDA C++ (nvcc) o herramientas para depuración y perfilado, entre otras características. Figura 2.2: Visualización de kernel para multiplicación de matrices. [6] CUDA C++ es una extensión de C++, que permite comunicarse y descargar trabajo en cualquiero dispositivo compatible con CUDA que se encuentre disponible. Para ello, permite definir funciones especiales, denominadas kernels, que se ejecutan de forma paralela en la GPU. Al invocar un kernel, el programador especifica el número instancias del kernel que se ejecutarán en paralelo configurando el número de bloques y el número de hilos por bloque que se generarán, normalmente dependiendo del tamaño de los datos con los que se vaya a operar. A cada hilo se le asignará un conjunto de variables locales (threadId yblockId), que el programador podrá usar cuando programe el kernel para diferenciar los datos con los que opere cada uno. Para facilitar la implementación de operaciones más complejas, se permite también realizar una división multidimensional del problema. En la figura 2.2 se representa de forma visual la división en bloques que resultaría de un kernel multidimensional. También se ofrecen funciones para comunicar y transferir datos entre la memoria de la CPU y la de la GPU. 8Capítulo 2. Marco teórico Figura 2.3: Distribución de hilos dentro de la GPU. Fuente: [6] El programador no necesita conocer el hardware en el que se ejecutará su código ni adaptarlo para que pueda lanzarse en varios modelos de GPUs, ya que toda la distribución de los hilos del kernel se realiza dinámicamente, en tiempo de ejecución. Cuando un proceso lanza un kernel, los bloques resultantes se reparten entre todos los SMs disponibles en la GPU, permitiendo que pueda usarse el mismo programa tanto en GPUs más sencillas como en otras de alto rendimiento, con muchos más SMs. 2.3. Compartición de GPU entre procesos Cuando solo hay un único proceso dentro de la GPU, todos sus bloques se pueden asignar a cualquier SM, y los warp schedulers se encargarán de ir alternando entre los hilos de los diferentes bloques. Sin embargo, cuando existen varios procesos usando la GPU de forma simultánea, la repartición de los recursos no es tan sencilla. Cada proceso reserva de forma separada sus propios recursos de almacenamiento y planificación, lo que supone una mayor ocupación de memoria y que cada SM tenga que realizar un cambio de contexto cada vez que ejecuta un warp de un proceso distinto, provocando una posible pérdida de rendimiento. Si un proceso no genera suficiente carga de trabajo como para llenar la GPU completa, la mayoría de los recursos de la GPU quedarán desaprovechados. Por eso, merece la pena explorar distintas tecnologías que nos permitan resolver el problema presentado en el párrafo anterior, y poder así lanzar varios procesos en la GPU de la forma más efectiva posible. 2.3.1. Nvidia MPS Nvidia Multi-Process-Service (MPS) es una alterativa a la API tradicional de 2.3. Compartición de GPU entre procesos 9 Figura 2.4: Esquema del funcionamiento de MPS Fuente: [5] CUDA, que permite mejorar el rendimiento obtenido cuando se ejecutan kernels de varios procesos (clientes) dentro de la misma GPU. Está formado por los siguientes tres componentes: 1. Demonio de control: encargado de encender y terminar el servidor, así como coordinar las conexiones entre los clientes y el servidor. 2. Runtime para clientes: integrado en la librería de drivers de CUDA, se encarga de coordinar los bloques de los distintos procesos dentro de la GPU. 3. Servidor: vía de comunicación con la GPU que comparten los distintos clientes. Para solucionar los problemas mencionados al final de la sección anterior el servidor reserva sus propios recursos de almacenamiento y planificación, los cuales serán compartidos por todos los clientes que le soliciten un trabajo. Eso permite resolver los problemas derivados de la compartición de la GPU entre múltiples procesos, de forma que kernels de distintos procesos puedan ejecutarse de forma concurrente. Como se comentó anteriormente, esto solo aporta un beneficio en el rendimiento total si estos kernels no ocupan por completo la GPU, ya que va a permitir que los recursos que queden libres durante la ejecución de un kernel puedan ser aprovechado por otro. Aunque queda fuera del alcance de este trabajo, MPS proporciona medidas de seguridad relacionadas con la protección de memoria y aislamiento de errores. Las 10 Capítulo 2. Marco teórico Figura 2.5: Device “1c.4g.20gb” sobre Nvidia A100. Fuente: [7] GPUs de la generación Volta y posteriores cuentan con funciones y protecciones más sofisticadas (véase [5] para más información). 2.3.2. Nvidia MIG MIG es una nueva tecnología de Nvidia, compatible con GPUs para centros de datos de generación Ampere y posterior [7], que permite dividir una GPU en hasta siete instancias aisladas entre sí (en el caso de la GPU Ampere A100, cuatro en el caso de la A30), de forma que cada una de ellas cuente con una fracción de los recursos de la GPU. Concretamente, MIG puede dividir recursos de cómputo, como SMs o decodificadores, así como bancos de cache, controladores y buses de memoria. En la figura 2.6 se muestra un esquema visual de esta tecnología. De este modo, los procesos de los distintos usuarios del sistema pueden lanzar trabajos a cualquiera de las instancias presentes, las cuales aparecen como una GPU cualquiera. La tecnología gira en torno a los denominados “slices”, que pueden ser de memoria o de SMs. Estos slices representan la fracción más pequeña en la que se puede dividir la memoria o los SMs de la GPU, respectivamente. Una partición (denominada “GPU instance” o GI) se forma combinando un conjunto de los slices de SMs con otro de los de memoria. Además, opcionalmente cada GI se puede subdividir a su vez en varias “Compute Instances” (CI), cada una de de las cuales cuenta con sus propios recursos de cómputo (SMs), pero comparte el resto de recursos del GI padre. Por defecto, cada GI tiene una única CI, que cuenta con todos los SMs de la GI a la que pertenece. Finalmente, un MIG device está formado por una única GPU instance y una o más Compute Instances. Para referirse al tamaño de una partición se usa una nomenclatura en concreto. Por ejemplo, en el caso de la Nvidia A100, el nombre de una GPU device que ocupe el tamaño completo de la GPU se denomina “7g.40gb”. En caso de que el partición esté formada por varias CIs, el número de slices se indica al principio del nombre. La figura 2.5 muestra un ejemplo visual de una partición “1c.4g.20gb” sobre la Nvidia A100. Toda la creación y manipulación se puede realizar utilizando la herramienta 2.3. Compartición de GPU entre procesos 11 nvidia-smi, una herramienta para la línea de comandos que se incluye con el propio driver de la GPU. Sin emgargo, para facilitar el trabajo, se ha utilizado la herramienta nvidia-mig-parted [1], que permite guardar múltiples configuraciones MIG en un fichero YAML y aplicarlas posteriormente de forma sencilla, aunque las mismas configuraciones podrían aplicarse también utilizando la herramienta nvidia smi. Figura 2.6: Compartición de GPU entre varios procesos sin utilizar la tecnología MIG (arriba) y utilizando la tecnología MIG (abajo). 18 Capítulo 3. Metodología # Función que procesa la salida de los tests de magma, # y devuelve una lista de puntos para dibujar las gráficas. def get_puntos(result: str)-> list[tuple[int,float]]: result =result.split("\n") # Quitar parentesis. lines: list[str]=[line.replace("(","").replace(")","")for line in result] # Dividir en columnas. lines =[[x for xin line.split(" ")if x!= ""]for line in lines] # Sacar indices de las columnas que nos interesan. ind_titulos =[x[0]for xin enumerate(result) if x[1].startswith("%")][-2] nombres_columnas =[x for xin lines[ind_titulos] if x!= "Gflop/s"][1:] ind_N =nombres_columnas.index('N') ind_CUBLAS =nombres_columnas.index('cuBLAS') # Quitar lineas que empiezan por %. lines: list[str]=[line for line in lines if len(line) >1and line[0]!= '%'] puntos =[(k, mean([float(cols[ind_CUBLAS]) for cols in list(g)])) for k,gin groupby(lines, lambda l: int(l[ind_N]))] return puntos # Punto de entrada al script. if __name__ == "__main__": mig_configs =sys.argv[1].split(",") comandos =(" ".join(sys.argv[2:])).split(",") if len(comandos) ==1and len(mig_configs) == 1: # 1 test en 1 configuracion de n devices. grafica_una_configuracion(mig_configs[0], comandos[0]) elif len(comandos) ==1and len(mig_configs) > 1: # 1 test en varias configuraciones de un solo device. grafica_varias_configuraciones(mig_configs, comandos[0]) elif len(comandos) >1and len(mig_configs) == 1: # n tests distintos en 1 configuracion de n devices. grafica_una_configuracion_varios_comandos(mig_configs[0], comandos) else: print("Número de tests y configuraciones incompatible.") Listing 5: Script de lanzamiento, parte 3. 3.3. Diseño de los experimentos 19 3.3.1. Ejecuciones aisladas En esta fase, se va a estudiar el comportamiento de las operaciones gemm y gemv en las distintas posibles particiones que soporta la Nvidia A30. Con ello, se pretende determinar cuál es el rendimiento de ambas operaciones cuando se ejecutan de forma aislada, dependiendo del número de recursos que dispongan. Se van a utilizar particiones que varíen el número de SMs y el ancho de banda asignada a cada una, con el objetivo de ver qué recursos afectan más a cada tipo de operación. Configuración SMs Memoria 4g.24gb 100 % 100 % 2c.4g.24gb 50 % 100 % 2g.12gb 50 % 50 % 1c.4g.24gb 25 % 100 % 1c.2g.12gb 25 % 50 % 1g.6gb 25 % 25 % Tabla 3.1: Diferentes configuraciones soportadas por Nvidia GPU A30 y su denominación. La información que se extraiga de esta fase será de gran utilidad en fases posteriores, ya que nos servirá para comparar y poder detectar futuras caídas de rendimiento debido a interferencias. 3.3.2. Ejecuciones combinadas En la segunda fase, se van a lanzar, dentro de una misma partición, diferentes combinaciones de aplicaciones de forma simultánea. Con ello se pretende observar como interfieren entre si aplicaciones concurrentes dentro de una GPU, sin que haya ningún tipo de medida para coordinarlas. Se lanzarán los siguientes experimentos: Configuración Lanzamientos 4g.24gb 4×Gemm 4×Gemv 2×Gemm +2×Gemv 2g.12gb 2×Gemm 2×Gemv Gemm +Gemv Tabla 3.2: Configuraciones experimentales para el estudio de ejecuciones combinadas. 20 Capítulo 3. Metodología Los resultados que se obtengan en esta fase podrán ser comparados con los de la fase anterior para detectar las interferencias que se produzcan, así como usarse en fases posteriores para observar cómo influye el uso de las tecnologías MIG y MPS. 3.3.3. Combinación de ejecuciones, usando MPS En esta sección se va a explorar la tecnología MPS, y ver como influye en el rendimiento de aplicaciones simultáneas. Para ello se van a lanzar varias combinaciones de ejecuciones sobre una misma partición, especificando en el comando de lanzamiento el directorio de la PIPE que usará el proceso para comunicarse con el MPS server. Concretamente, las pruebas que se lanzarán son las siguientes: Configuración Lanzamientos 4g.24gb 4×Gemm 4×Gemv 2×Gemm +2×Gemv 2g.12gb 2×Gemm 2×Gemv Gemm +Gemv Tabla 3.3: Configuraciones experimentales para el estudio de la tecnología MPS. Al obtener los resultados, estos se contrastarán con los de etapas anteriores para ver la mejora en el rendimiento que se puede conseguir usando esta tecnología. 3.3.4. Combinación de ejecuciones, usando MIG En esta etapa se va a analizar el aislamiento que proporciona MIG para aplicaciones que se ejecuten simultáneamente en particiones distintas. Al contrario que en fases anteriores, esta vez se van a generar más de una partición en cada experimento, de forma que cada una de las aplicaciones lanzadas va a ejecutarse en una partición distinta. Las configuraciones y tests que se usarán son los que aparecen a continuación: 3.3. Diseño de los experimentos 21 Configuración Lanzamientos 4x1g.6gb 4×Gemm 4×Gemv 2×Gemm +2×Gemv 2x2g.12gb 2×Gemm 2×Gemv Gemm +Gemv 2x1g.6gb 2×Gemm 2×Gemv Gemm +Gemv Tabla 3.4: Configuraciones experimentales para el estudio de la tecnología MIG. Cap´ ıtulo 4 Resultados experimentales 4.1. Descripción de la arquitectura objetivo Todos los experimentos de este trabajo se llevaron a cabo en ocejon, servidor de altas prestaciones del departamento DACYA cedido en exclusiva para desarrollar este trabajo. Se detallan a continuación algunas de sus especificaciones más relevantes: Procesador Intel Xeon Silver 4314 con 16 núcleos, funcionando a una frecuencia base de 2.4 GHz. GPU Nvidia A30, con un total de 24 GB de memoria HBM2e y 3584 CUDA cores y 224 Tensor Cores, repartidos entre 56 SMs. Las frecuencias de los SMs y la memoria son 1110 MHz y 1215 MHz, respectivamente. 64GB de memoria RAM DDR4. CUDA toolkit 12.0, con la versión del driver 525.85.12 oficial de Nvidia. Durante los primeros experimentos realizados, se observó como el rendimiento de la A30 caía de forma inesperada cuando la carga de trabajo se encontraba cerca de su máximo teórico. Un ejemplo de este fenómeno se encuentra en la la figura 4.1, donde se puede observar como el rendimiento, en lugar de quedarse estable, decae de forma gradual a partir de n= 6000. Tras investigar las posibles causas, se determinó que se debía a que la GPU reducía su frecuencia para cumplir con los límites de consumo que tenía configurados. Por este motivo, se decidió que, para todos los experimentos, se establecería la frecuencia de la GPU a 1110 MHz (340 MHz por debajo de la configuración por defecto). 23 24 Capítulo 4. Resultados experimentales Figura 4.1: Caída de rendimiento debido a límite de consumo. Al ser la Nvidia A30 de generación Ampere, MAGMA y CUBLAS usarán los tensor cores disponibles para acelerar aun más los cálculos. Esto no debería suponer un problema para realizar estos estudios, ya que la repartición de recursos por proceso se hace a nivel de SM. 4.2. Metodología experimental Todos los lanzamientos y gráficas de este trabajo se generaron usando los scripts de Python mencionados en el Capítulo 3. El script usará la herramienta mig-parted [1] para aplicar las configuraciones MIG que se especifiquen en los argumentos. Para que mig-parted pueda aplicar una configuración correctamente, esta se tiene que añadir a un fichero en formato YAML con una sintaxis específica documentada por la aplicación. A modo de ejemplo, se incluye al final de esta sección un fichero con dos configuraciones registradas. Una vez aplicadas las configuraciones, el script leerá la salida del comando “nvidia-smi -L” para obtener el ID de todas las particiones creadas, que usará posteriormente para lanzar los comandos indicados en un proceso distinto, estableciendo en cada la variable de entorno CUDA_VISIBLE_DEVICES a cada uno de los IDs obtenidos. Los tests de MAGMA generan una salida en forma de tabla cuyas filas se corresponden con los tamaños de problema que han ejecutado. Cuando todos los procesos 4.3. Ejecuciones aisladas 25 version: v1 mig-configs: 2c.4g.24gb: -devices: all mig-enabled: true mig-devices: 2c.4g.24gb: 1 dos_medios: -devices: all mig-enabled: true mig-devices: 2g.12gb: 2 Listing 6: Ejemplo de fichero YAML de configuración para la herramienta mig-parted [1]. terminen, el script generará las gráficas usando extrayendo de la salida de cada proceso los datos de la columna correspondiente al rendimiento para CUBLAS. 4.3. Ejecuciones aisladas Primero, se va a explorar el comportamiento que presentan las operaciones GEMM y GEMV en particiones de distinta topología, para ver qué rendimiento pueden alcanzar dependiendo de los recursos que tengan disponibles. 4.3.1. GEMM Lo primero que observamos, como se puede ver en la figura 4.2a, es que el rendimiento obtenido es directamente proporcional al tamaño de la partición utilizada (i.e., cada vez que se duplican los recursos de la partición, el rendimiento también se duplica). Esto nos dice que, al menos en ausencia de otras carga de trabajo simultáneas, los recursos que asigna MIG a cada una de las particiones es el que especifica la documentación, y la operación GEMM es capaz de aprovecharlos todos. Posteriormente se repitió el experimento anterior, pero manteniendo constante el número de SMs que podían usar las particiones y aumentando sólo el ancho de banda del que disponían. En este caso, se aprecia en la figura 4.2b que el rendimiento obtenido en los tres casos es el mismo (el mismo que se obtenía para la curva azul de la figura 4.2a). Esto se debe, como se mencionó anteriormente, a que GEMM se trata de una operación “compute-bound”, cuyo rendimiento depende de forma casi exclusiva del número de unidades de computo de las que disponga. 26 Capítulo 4. Resultados experimentales Finalmente, se dividió la GPU en instancias con el mismo ancho de banda de memoria, pero duplicando el número de SMs que tenían disponibles. Vemos que, al contrario que en la figura 4.2b, las curvas obtenidas en la figura 4.2c son prácticamente idénticas a las de la figura 4.2a. Se aprecia de nuevo la naturaleza “computebound” de la operación, ya que el rendimiento se ha duplicado manteniendo el ancho de memoria constante, pero aumentando el número de SMs. (a) Distinta configuración de memoria y número SMs (b) Distinta configuración de memoria, mismo número de SMs (c) Misma configuración de memoria, distinto número de SMs Figura 4.2: GEMM aislada, en distintos tipos de particiones. 4.3.2. GEMV Como se esperaba, vemos en la figura 4.3a que, al igual que con la GEMM, el rendimiento se duplica cuando se duplican todos los recursos de las particiones. Sin embargo, en la figura 4.3b aparece un resultado algo distinto al esperado. Como GEMV se trata de una operación “memory-bound”, se esperaba que el rendimiento se duplicara cuando se doblaba el ancho de banda disponible. Sin embargo, se observa como la curva verde y la naranja presentan el mismo rendimiento, a pesar 4.3. Ejecuciones aisladas 27 de que la segunda contara con el doble de ancho de banda que la primera. Además, la curva naranja de esta figura se estabiliza en torno a los 90 GLOPS, mientras que la de la figura 4.3a sobrepasa los 100 GFLOPS, a pesar de tener ambas asignadas el mismo ancho de banda. Las curvas de la figura 4.3c muestran una situación parecida. Vemos que la curva azul se estabiliza por debajo de los 100 GFLOPS respecto a los más de los de 200 que presenta la curva verde de la figura 4.3a, a pesar de que ambas cuentan con el mismo ancho de banda asociado. (a) Misma configuración de memoria y número SMs (b) Distinta configuración de memoria, mismo número de SMs (c) Misma configuración de memoria, distinto número de SMs Figura 4.3: GEMV aislada, en varias particiones 4.3.3. Conclusiones Durante esta primera fase experimental se ha estudiado como se comportan las operaciones GEMM y GEMMV dependiendo de los recursos que tengan disponibles. Concretamente, se ha comprobado la naturaleza “Compute bound” de las operaciones GEMM, ya que se ha visto que su rendimiento depende mucho del número de SMs que tenga disponibles, mientras que el ancho de banda de la memoria juega 34 Capítulo 4. Resultados experimentales 4.6.2. Dos cuartos de la GPU (2x1g.6gb) En este caso se lanzaron las operaciones sobre dos particiones 1g.6gb, cada una de las cuales se corresponde a un cuarto del total de los recursos de la GPU. De forma similar, los rendimientos que aparecen en las figuras 4.9a y 4.9b son los mismos que aparecían en las figuras 4.2 y 4.3, y la figura 4.9c tampoco presenta el problema de la bajada del rendimiento para la GEMV. (a) 2×Gemm (b) 2×Gemv (c) Gemm + Gemv Figura 4.9: Resultados de ejecución utilizando la tecnología MIG sobre una GPU configurada como 2×1g.6gb. 4.6.3. Cuatro cuartos de la GPU (4x1g.6gb) Por último, se lanzaron cuatro aplicaciones de forma concurrente sobre cuatro particiones 1g.6gb distintas, cada una de las cuales contaba con un cuarto de los recursos totales de la GPU. Los resultados (figura 4.10) en este caso son los mismos que los de las dos secciones anteriores, y no aparece ningún tipo de interferencia entre las cuatro particiones. 4.6. Ejecución concurrente con MIG 35 (a) 4×Gemm (b) 4×Gemv (c) 2×Gemm+2×Gemv Figura 4.10: Resultados de utilizar la tecnología MIG sobre una GPU configurada como 4×1g.6gb. 4.6.4. Conclusiones Se ha visto que el rendimiento de las aplicaciones que lanza una proceso en una partición no se ve afectado por otras aplicaciones en distintas particiones, independientemente del tipo de operación. Al contrario que en los resultados de fases anteriores, el rendimiento de las GEMV no se ha visto afectado por otras GEMM simultáneas, y los rendimientos han sido estables y predecibles, independientemente de la cantidad que hubiera al mismo tiempo y el tipo de partición. 36 Capítulo 4. Resultados experimentales 4.7. Conclusiones generales Las principales conclusiones a las que se ha llegado tras la realización de todos estos experimentos son las siguientes: Cuando varios procesos ejecutan aplicaciones de forma simultánea en la GPU, el rendimiento que se puede esperar de cada una no es predecible, y depende en gran medida de las otras. Este efecto es especialmente notable si una aplicación es más “memory-bound”, y se ejecuta al mismo tiempo que otras que son más “compute-bound”. Le tecnología MPS sólo permite obtener una mejora de rendimiento cuando todos los procesos hagan un uso parcial de la GPU, y las ventajas que ofrece se pierden cuando al menos uno de ellos no cumple esta condición. Por este motivo, MPS no permite ofrecer un rendimiento predecible y estable para los distintos procesos. Por último, hemos visto como MIG sí garantiza un aislamiento total entre las particiones, y por tanto permite ofrecer un rendimiento predecible y estable a distintos procesos siempre que haya, como máximo, un proceso usando cada partición al mismo tiempo. Como desventaja, al estar las particiones completamente aisladas, un proceso no puede usar los recursos de la GPU que estén libres fuera de su partición, por lo que a veces los rendimientos que se obtienen usando MIG pueden ser más bajos que los que se obtendrían usando MPS. Cap´ ıtulo 5 Conclusiones y Trabajo Futuro En este trabajo se han estudiado los efectos de contención e interferencia entre aplicaciones concurrentes ejecutando diferentes núcleos computacionales sobre una misma GPU. Para ello, se han escogido kernels caracterizados por realizar un uso intensivo de dos de los recursos compartidos a nivel de GPU: núcleos de computación (cores) y ancho de banda de memoria. Los kernels seleccionados son lo suficientemente característicos como para servir como referencia de cara al estudio de otro tipo de programas. Una vez conocidas las características de cada una de las operaciones a evaluar y su comportamiento de forma aislada, se procedió a estudiar varias alternativas para controlar la interacción entre operaciones de distintos procesos simultáneos dentro de la misma GPU. En primer lugar, se lanzaron a la GPU de forma concurrente varias instancias de estas aplicaciones, sin ningún tipo de tecnología para intermediar por el uso de recursos. Se vio como el rendimiento que se obtenía para cada una de las aplicaciones era mucho más impredecible que cuando se ejecutaban de manera individual, y en algunas ocasiones bajaba de forma drástica. En segundo lugar, se analizó la herramienta Nvidia Multi Process (MPS). Se concluyó que MPS aporta una mejora de rendimiento solo si cada uno de los procesos que usan la GPU no genera trabajo suficiente como para utilizar todos los recursos disponibles. En caso contrario, su utilidad se ve reducida. Además, también se observó como MPS no permite garantizar un rendimiento estable y predecible a cada uno de los procesos. Queda pendiente analizar más en profundidad esta herramienta, probando algunas opciones de configuración que no se han usado en este trabajo (por ejemplo, asignar un porcentaje de los recursos del servidor a un proceso). Por último, se estudió la tecnología MIG. Se observó como las particiones que se creaban estaban aisladas completamente del resto, de modo de no se produjeron interferencia entre las aplicaciones que se se ejecutaron en cada uno. Esto permite 37 38 Capítulo 5. Conclusiones y Trabajo Futuro garantizar un rendimiento estable y predecible para varios procesos, siempre que cada uno lance sus operaciones en una partición distinta. También se pudo observar que, en ocasiones, el rendimiento que se obtenía era menor que los que se obtenían con MPS, ya que el proceso de una partición no puede usar los recursos de otras particiones que se encuentren libres. Las conclusiones observadas pueden ser fácilmente aplicadas a otro tipo de aplicaciones, así como la metodología experimental utilizada. Además, se plantea como trabajo futuro la integración de este tipo de tecnologías de particionado sobre planificadores de tareas o trabajos reales, como Kubernetes. La combinación de MIG y MPS se plantea también como una línea de trabajo interesante, así como la evaluación de nuevas cargas de trabajo con distinto tipo de características. NOTA: todas las gráficas y código que se ha escrito o modificado en este trabajo se puede encontrar en el siguiente repositorio de Github: https://github.com/ jucm8/tfg-mig. Chapter 6 Introduction 6.1. Introduction Due to the great advances in science and engineering, together with the technological progress made in the last decades, it is increasingly common to find many computer applications of different nature that require great computational power. Machine learning algorithms, physics simulations, 3D rendering or even the latest video games require specialized and powerful hardware that most users don’t have available. This is one of the main reasons why the popularity of cloud computing platforms is raising lately, because they offer this computing capability remotely to users. The cloud provider’s resources are offered by demand and shared between all of their clients. However, users expect their computations to be able to exclusively use these resources, accessibility and performance wise. Therefore, four new distinct, but related, operational challenges arise in the field of cloud computing and the provision of shared computing resources: 1. Use times: In most cases, the use of shared resources by users is not uniform. Sometimes its resources are used intensively, and sometimes its resources remain idle and could be assigned to other users. 2. Applications of distinct nature: the nature of the scheduled applications can vary greatly, each one can have phases where a massive use of some or all of the available resources is made, and other lighter ones in which the full computational potential of the resources is not used (or is not required). 3. Acquisition and maintenance costs: The costs of servers (probably equipped with computational accelerators) is usually high, so it is advisable to implement strategies that improve its utilization rate in situations where it’s underutilized, possibly by offering it on a shared basis to users. 39 40 Chapter 6. Introduction 4. Interference between jobs: It is very common for users to want to be able to predict how much time their applications will take, in a way that is as deterministic as possible. In a context where computing resources are shared between multiple users , it makes sense to apply strategies to reduce interference between applications by isolating resources allocated to each one. One of the most widely used computational resources in cloud computing services are graphics processors (GPUs). Over the past two decades, the computational power and degree of parallelism that a high-end GPU provides has grown to be indispensable to achieve high performance in many different applications. In fact, today this parallel computing capability is so high that a lot of applications are not able to take advantage of all these resources. To address this issue, one possible solution is to offer the resources of one or multiple GPUs on a shared basis, accessible concurrently by multiple users. This strategy increases the utilization rate of the GPU(s), but brings new issues with the contention over access to shared resources. Thus, a new problem arises: without (software/hardware) support from manufacturers, there is no simple solution to offer the GPU as a shared compute resource (thus reducing maintenance and acquisition costs and increasing its effective utilization) without avoiding interference between concurrent applications. To solve this problem, Nvidia has developed the new MIG ("Multi Instance GPU") technology, which allows a GPU to be divided into several, completely isolated instances, each with its own resources. Concurrent programs can run in parallel, each one on a separate instance, allowing vendors to offer their customers predictable performance that is not negatively influenced by jobs that may be requested by other users. The GPU can be split asymmetrically to better support workloads of different size and/or nature, so not all partitions have to be of the same size. 6.2. Objectives The objective of this project is to study and evaluate Nvidia’s new MIG technology on last generation GPUs, and to compare its behavior and efficiency with respect to other existing technologies available for sharing GPUs between applications or users. For this purpose, we will analyze the different configurations available for the GPU we will be working with (Nvidia A30) against workloads of different nature, analyzing both the maximum performance obtained and the potential interferences between them. This main objective can be divided in four different smaller, more specific objectives: 6.3. Document structure 41 1. Study the behaviour of applications of different nature, and how their performance depend on the various kinds of resources available inside the GPU. 2. Analyze how resources are shared between concurrent applications inside the GPU, and the performance loss that ocurrs from this. 3. Individually study different technologies to mitigate the negative impacts of resource sharing inside the GPU. 4. Compare these technologies to each other, analyzing the pros and cons each one offers, and analyzing in which situations it is preferable to use each one. 6.3. Document structure Chapter 2 contains some theoretical concepts that are essential for this project. Specifically, it will discuss GPU architecture, the CUDA programming model, the problems that arise from sharing a GPU among several processes, and MIG and MPS technologies. Subsequently, the methodology followed during the whole experimental phase is explained in Chapter 3. The workloads chosen, methodology and the different experimental phases will be discussed. Afterwards, in Chapter 4 the results obtained in the experimental phase will be analyzed. First, the target architecture on which all experiments were carried out is introduced. The next section contains details about the methodology used to launch the experiments. Then, the results obtained in each of the experimental phases will be analyzed in depth. To conclude the chapter, a final section of experimental conclusions will be included, in which the conclusions of all the experimental phases will be analyzed together. Finally, Chapter 5 contains some general conclusions and possible lines of work that remain pending to study in the future. Chapter 7 Conclusions and future work This project has explored the effects of contention and interference between concurrent applications running different computational kernels on the same GPU. For this purpose, we have chosen kernels characterized by an intensive use of two of the different shared resources at the GPU: computational cores and memory bandwidth. The kernels selected are characteristic enough to serve as a reference for the study of other types of programs. Once the behaviour in isolation of each of the kernels was known, several alternative technologies to control the interaction between different simultaneous processes within the same GPU were studied. First, multiple instances of these applications were launched concurrently on the GPU, without any technology to intermediate resource usage. We observed that the performance obtained for each of the applications was much more unpredictable than when they were run isolated, and sometimes it dropped dramatically. Secondly, the Nvidia Multi Process Tool (MPS) was studied. It was concluded that MPS only provides a performance improvement if each one of the processes using the GPU does not generate enough work to use all the available resources. Otherwise, its benefits are very minimal. It was also observed that MPS does not guarantee stable and predictable performance for each one of the concurrent processes. It stays as future work to analyze this tool in more depth, testing some options MPS provides that have not been used in this project (for example, assigning a percentage of the resources to a process). Lastly, the MIG technology was studied. The created partitions were completely isolated from each other, and there was no interference between the applications running in each one. This allows to guarantee stable and predictable performance for several processes, as long as each one launches its operations in a different partition. It was also observed that sometimes, the performance obtained was lower than that obtained with MPS, since a process in one partition cannot use the resources of 43