scieee AI-readable full text Open interactive document viewer

Un gestor de GPUs remotas para clusters HPC

Iserte, Sergio

Abstract

SLURM es un gestor de recursos para clusters que permite compartir una serie de recursos heterogéneos entre los trabajos en ejecución. Sin embargo, SLURM no está diseñado para compartir recursos como los procesadores gráficos (GPUs). De hecho, aunque SLURM admita plug-ins de recursos genéricos para poder manejar GPUs, éstas sólo pueden ser accedidas de forma exclusiva por un trabajo en ejecución del nodo que las hospeda. Esto es un serio inconveniente para las tecnologias de virtualización de GPUs remotas, cuya misión es proporcionar al usuario un acceso completamente transparente a todas las GPUs del cluster, independientemente de la ubicación concreta, tanto del trabajo como de la GPU. En este trabajo presentamos un nuevo tipo de dispositivo en SLURM, “rgpu”, para conseguir que una aplicación desde su nodo acceda a cualquier GPU del cluster haciendo uso de la tecnología de virtualización de GPUs remotas, rCUDA. Además, con este nuevo mecanismo de planificación, un trabajo puede utilizar tantas GPUs como existan en el cluster, siempre y cuando estén disponibles. Finalmente, presentamos los resultados de varias simulaciones que muestran los beneficios de este nuevo enfoque, en términos del incremento de la flexibilidad de planificación de trabajos.

Full text

DEPARTAMENT D’ENGINYERIA I CI` ENCIA DELS COMPUTADORS UNIVERSITAT JAUME I SIU043 Trabajo Final de M´ aster M´ ASTER EN SISTEMAS INTELIGENTES Curso 2013 / 2014 Memoria T´ ecnica del Proyecto Un gestor de GPUs remotas para clusters HPC Proyecto presentado por el alumno: Sergio Iserte Agut Dirigido por Rafael Mayo Gual Castell´ on, a 29 de Julio de 2014 Resumen SLURM es un gestor de recursos para clusters que permite compartir una serie de recursos heterog´ eneos entre los trabajos en ejecuci´ on. Sin embargo, SLURM no est´ a dise˜ nado para compartir recursos como los procesadores gr´ aficos (GPUs). De hecho, aunque SLURM admita plug-ins de recursos gen´ ericos para poder manejar GPUs, ´ estas s´ olo pueden ser accedidas de forma exclusiva por un trabajo en ejecuci´ on del nodo que las hospeda. Esto es un serio inconveniente para las tecnolog´ ıas de virtualizaci´ on de GPUs remotas, cuya misi´ on es proporcionar al usuario un acceso completamente transparente a todas las GPUs del cluster, independientemente de la ubicaci´ on concreta, tanto del trabajo como de la GPU. En este trabajo presentamos un nuevo tipo de dispositivo en SLURM, “rgpu”, para conseguir que una aplicaci´ on desde su nodo acceda a cualquier GPU del cluster haciendo uso de la tecnolog´ ıa de virtualizaci´ on de GPUs remotas, rCUDA. Adem´ as, con este nuevo mecanismo de planificaci´ on, un trabajo puede utilizar tantas GPUs como existan en el cluster, siempre y cuando est´ en disponibles. Finalmente, presentamos los resultados de varias simulaciones que muestran los beneficios de este nuevo enfoque, en t´ erminos del incremento de la flexibilidad de planificaci´ on de trabajos. Palabras clave SLURM, gestor de recursos, virtualizaci´ on GPU, rCUDA Agradecimientos Por un lado quiero dar las gracias a todos los componentes del grupo de investigaci´ on HPC&A de la UJI, en especial a los miembros del Crazy Hector’s Lab, por la armon´ ıa y el buen ambiente de trabajo que generan. Tambi´ en, agradecer a los miembros del grupo GAP de la UPV por la ayuda prestada para el desarrollo del proyecto y por haberme dejado utilizar su infraestructura para realizar los experimentos. Por otro lado, no podr´ ıa dejar de agradecer el apoyo de mi familia, haciendo una menci´ on especial a mi abuelo Joaqu´ ın, mis padres Javier y Dina, mi hermano Jorge y por supuesto, mi querida Ana. ´ Indice general I Memoria T´ ecnica del Proyecto 9 1. Introducci´ on 11 1.1. Motivaci´ on .................................... 11 1.2. Objetivos ..................................... 13 1.3. Metodolog´ ıa .................................... 13 1.4. Organizaci´ on de la memoria ........................... 13 2. Descripci´ on del proyecto 15 2.1. Introducci´ on te´ orica ............................... 15 2.1.1. RPC .................................... 15 2.1.2. Gestor de recursos ............................ 15 2.1.3. SLURM .................................. 16 2.1.4. GPU .................................... 16 2.1.5. CUDA ................................... 16 2.1.6. rCUDA ................................... 16 2.2. Estimaci´ on de recursos .............................. 17 2.3. Planificaci´ on temporal .............................. 17 2.3.1. Identificaci´ on de tareas ......................... 17 2.3.2. Estimaci´ on de la duraci´ on de las tareas ................. 18 2.4. Requisitos del proyecto .............................. 18 6´ INDICE GENERAL 3. Descripci´ on de SLURM 21 3.1. Introducci´ on ................................... 21 3.2. Arquitectura .................................... 22 3.2.1. Demonio central slurmctld ........................ 24 3.2.2. Demonios locales slurmd ......................... 24 3.2.3. Demonio de la base de datos slurmdbd ................. 25 3.3. Servicios y Operaciones ............................. 25 3.3.1. Comandos de usuario .......................... 25 3.3.2. Plug-ins .................................. 26 3.3.3. Capa de Comunicaci´ on .......................... 27 3.3.4. Seguridad ................................. 27 3.3.5. Inicio de los trabajos ........................... 28 3.3.5.1. Modo Interactivo ........................ 28 3.3.5.2. Modo Lote ........................... 30 3.3.5.3. Modo Reserva ......................... 30 4. Descripci´ on de rCUDA 33 4.1. Introducci´ on ................................... 33 4.2. Arquitectura .................................... 33 5. Integraci´ on de la virtualizaci´ on de GPUs con rCUDA en SLURM 37 5.1. Introducci´ on ................................... 37 5.2. Cambios en SLURM ................................ 38 5.2.1. Configuraci´ on ............................... 38 5.2.2. Estructura de los paquetes RPC ..................... 38 5.2.3. Ficheros comunes ............................. 39 5.2.3.1. Paquetes RPC .......................... 39 5.2.3.2. M´ odulo GRes (Generic Resources)............... 39 5.2.3.3. Variables de entorno ...................... 40 5.2.4. Demonio controlador slurmctld ..................... 40 5.2.4.1. Configuraci´ on ......................... 40 5.2.4.2. Comunicaci´ on ......................... 40 5.2.4.3. Trabajo ............................. 41 5.2.4.4. Etapa de trabajo ........................ 41 5.2.5. Plug-ins .................................. 41 5.3. C´ omo utilizar la nueva funcionalidad de SLURM ................ 42 5.4. Utilizando SLURM con GPUs virtualizadas ................... 43 SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut ´ INDICE GENERAL 7 6. Evaluaci´ on de prestaciones 45 6.1. Aplicaciones .................................... 45 6.1.1. GPU-BLAST ................................ 45 6.1.2. LAMMPS ................................. 45 6.1.3. MCUDA-MEME .............................. 46 6.1.4. GROMACS ................................ 46 6.2. Cargas de trabajos ................................ 46 6.3. Experimentaci´ on ................................. 47 6.4. Resultados ..................................... 49 7. Conclusiones 53 Bibliograf´ ıa 55 II Documentos Anexos 59 A. Ficheros de configuraci´ on de SLURM 61 A.1. slurm.conf ..................................... 61 A.2. gres.conf ...................................... 62 A.3. slurmdbd.conf ................................... 62 B. Scripts auxiliares 65 B.1. GPU-Blast ..................................... 65 B.2. LAMMPS ..................................... 65 B.3. MCUDA-MEME CUDA .............................. 66 B.4. MCUDA-MEME rCUDA .............................. 66 B.5. GROMACS .................................... 66 B.6. genera carga.py .................................. 67 C. SLURM for rCUDA User’s Guide 69 C.1. Introduction .................................... 69 C.2. Configuration ................................... 69 C.2.1. Applying the patch and installation ................... 69 C.2.2. Controller node environment variables ................. 70 C.2.3. Configuration files ............................ 70 C.2.3.1. slurm.conf ........................... 70 C.2.3.2. gres.conf ............................ 71 C.3. How to use modified SLURM .......................... 71 C.3.1. Submision options ............................ 72 C.3.1.1. Using sbatch .......................... 72 C.3.2. Submision examples ........................... 73 C.4. Further Information ............................... 73 D. Cambios realizados en los ficheros de SLURM 75 Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 14 1.4. Organizaci´ on de la memoria SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Cap´ ıtulo 2 Descripci´ on del proyecto En este cap´ ıtulo se va a explicar el desarrollo completo del proyecto. Se parte de una serie de definiciones de los conceptos b´ asicos relacionados. Se sigue con la estimaci´ on temporal y de costes de las tareas que lo componen. Se termina con la explicaci´ on de la ejecuci´ on completa del proyecto junto con los resultados. Tambi´ en se realiza una comparativa de los resultados generados en el proyecto con los requisitos iniciales, para comprobar su grado de cumplimiento. 2.1. Introducci´ on te´ orica En este apartado se explican los t´ erminos b´ asicos y fundamentales para familiarizarse con las herramientas y sistemas con los que se trabaja en el proyecto y cuyo uso va a ser continuo a lo largo de la memoria. De este modo, se facilitar´ a la compresi´ on de las explicaciones que se encuentran a lo largo de este documento. 2.1.1. RPC El Remote Procedure Call (RPC) (del ingl´ es, Llamada a Procedimiento Remoto) es un protocolo que permite a un programa de ordenador ejecutar c´ odigo en otra m´ aquina remota sin tener que preocuparse por las comunicaciones entre ambos. El protocolo es un gran avance sobre los sockets usados hasta el momento. De esta manera el programador no ten´ ıa que estar pendiente de las comunicaciones, estando ´ estas encapsuladas dentro de las RPC. Las RPC son muy utilizadas dentro del paradigma cliente-servidor. Siendo el cliente el que inicia el proceso solicitando al servidor que ejecute cierto procedimiento o funci´ on y enviando ´ este de vuelta el resultado de dicha operaci´ on al cliente [?]. 2.1.2. Gestor de recursos Un gestor de recursos es una herramienta capaz de asignar los recursos disponibles dentro de un sistema, siguiendo unas directrices, a las aplicaciones que requieren el uso de esos recursos. 16 2.1. Introducci´ on te´ orica 2.1.3. SLURM SLURM es un sistema de gesti´ on de recursos y de planificaci´ on de trabajos opensource, tolerante a fallos y escalable para todo tipo de clusters. SLURM incluye gesti´ on de trabajos, gesti´ on de particiones y control sobre el estado de las m´ aquinas que forman el cluster. Adem´ as proporciona tres servicios clave: Reserva recursos de forma exclusiva o no para los usuarios durante un tiempo determinado, permitiendo a ´ estos utilizar dichos recursos. Ofrece un entorno para el lanzamiento y monitorizaci´ on de los trabajos que se encuentran en el sistema. Dispone de un arbitraje para el manejo de la cola de tareas dependiendo de los recursos requeridos por los trabajos y aquellos disponibles. 2.1.4. GPU La GPU es un coprocesador dedicado al procesamiento de gr´ aficos u operaciones de coma flotante, para aligerar la carga de trabajo de la CPU en ciertas aplicaciones. Para el prop´ osito de este proyecto se utilizan las GPUs para aprovechar la gran potencia de c´ alculo que ofrecen. El uso de GPUs para hacer c´ alculos de aplicaciones no relacionadas con los gr´ aficos, se denomina GPUGPU, GPU de prop´ osito general. 2.1.5. CUDA CUDA son las siglas de Compute Unified Device Architecture (Arquitectura Unificada de Dispositivos de C´ omputo) que hace referencia tanto a un compilador como a un conjunto de herramientas de desarrollo creadas por nVidia que permiten a los programadores usar una variaci´ on del lenguaje de programaci´ on C para codificar algoritmos en GPU de nVidia. CUDA intenta explotar las ventajas de las GPU frente a las CPU de prop´ osito general utilizando el paralelismo que ofrecen sus m´ ultiples n´ ucleos, que permiten el lanzamiento de un alt´ ısimo n´ umero de hilos simult´ aneos. Por ello, si una aplicaci´ on est´ a dise˜ nada utilizando numerosos hilos que realizan tareas independientes (que es lo que hacen las GPU al procesar gr´ aficos, su tarea natural), una GPU podr´ a ofrecer un gran rendimiento en campos que podr´ ıan ir desde la biolog´ ıa computacional a la criptograf´ ıa por ejemplo [?]. 2.1.6. rCUDA rCUDA es una herramienta de virtualizaci´ on de GPUs remotas que ofrece pleno soporte con CUDA, lo que significa que las aplicaciones originales no deben ser modificadas. rCUDA implementa todas las funciones del CUDA Runtime API, excepto las relacionadas con gr´ aficos. Incluye comunicaciones altamente optimizadas sobre TCP e InfiniBand, adem´ as de tener capacidad para trabajar como multi-hilo y multi-nodo. rCUDA se puede utilizar en las mismas plataformas Linux que CUDA, proporcionando tambi´ en soporte para arquitecturas x86 y ARM. SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 2. Descripci´ on del proyecto 17 2.2. Estimaci´ on de recursos Un cluster de 9 nodos de los cuales 8 se configuraron como nodos de c´ omputo, mientras que el otro fue el front-end. Cada nodo ven´ ıa equipado con una placa base Supermicro 1027GF-TRF, dos procesadores Intel Xeon E5-2620 (Ivy Bridge) hexacore a 2.1 GHz y 32 Gbytes de memoria SRAM DDR3 a 1.6 GHz. Adem´ as cada uno de ellos cont´ o con un acelerador NVIDIA Tesla K20 GPU conectado a la placa base a trav´ es de un PCIe 2.0 x16. La comunicaci´ on entre los nodos se hizo con un conmutador Mellanox SX6025 (InfiniBand FDR-compatible), ya que cada nodo ten´ ıa instalada una tarjeta de red Mellanox ConnectX-3 VPI single-port (InfiniBand FDR-compatible). El ancho de banda te´ orico de la configuraci´ on de la red era de 56 Gbytes/s. El sistema operativo instalado en cada nodo fue un CentOS 6.4; la red de comunicaciones ejecut´ o el controlador Mellanox OFED 2.1-1.0.0; y las GPUs utilizaron CUDA 5.5 y el controlador NVIDIA 331.62; la versi´ on del virtualizaci´ on de GPUs remotas rCUDA utilizada fue la 4.1. Una estaci´ on de trabajo con conexi´ on a Internet para poder conectarse remotamente al frontend del cluster. 2.3. Planificaci´ on temporal En esta secci´ on del cap´ ıtulo se identifican las tareas a llevar a cabo en el desarrollo del proyecto y su duraci´ on. 2.3.1. Identificaci´ on de tareas A continuaci´ on se describe cada una de las tareas identificadas: 1: Estudiar la estructura de rCUDA An´ alisis a fondo del funcionamiento de rCUDA. 2: Codificaci´ on de la nueva l´ ogica de SLURM Durante esta tarea se desarrollar´ a todo el c´ odigo necesario para la integraci´ on de rCUDA en SLURM. El desarrollo implica tanto modificaciones en el c´ odigo fuente de SLURM, como creaci´ on de plug-ins y nuevas funciones. 3: Realizaci´ on de pruebas Esta actividad consiste en llevar a cabo todo tipo de pruebas y buscar posibles errores de la aplicaci´ on. En caso de encontrar errores se deber´ an solucionar y volver a repetir el proceso hasta que la aplicaci´ on funcione perfectamente. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 18 2.4. Requisitos del proyecto 1 Estudiar la estructura de rCUDA 15 2 Codificaci´ on de la nueva l´ ogica de SLURM 205 3 Realizaci´ on de pruebas 45 4 Redacci´ on del manual de uso 5 5 Redacci´ on de la memoria 20 6 Preparaci´ on de la presentaci´ on 9 7 Presentaci´ on del proyecto 1 Cuadro 2.1: Duraci´ on estimada de las tareas 4: Redacci´ on del manual de uso El manual de usuario es el documento de ayuda destinado al usuario. En esta tarea se redactar´ a el documento que contendr´ a los pasos a seguir para utilizar la nueva versi´ on de SLURM. 5: Redacci´ on de la memoria Durante esta tarea se redactar´ a la memoria del proyecto. En ella se detallar´ an: los objetivos, los detalles de implementaci´ on, la documentaci´ on, etc. 6: Preparaci´ on de la presentaci´ on En esta tarea se preparar´ a el ´ ındice y las transparencias para la presentaci´ on del proyecto. Tambi´ en se preparar´ a un ejemplo del funcionamiento y llevar´ an a cabo los ensayos de la exposici´ on oral. 7: Presentaci´ on del proyecto En esta ´ ultima actividad se realizar´ a la presentaci´ on del proyecto ante el tribunal. En la presentaci´ on se dar´ a a conocer los principales resultados del proyecto desarrollado. 2.3.2. Estimaci´ on de la duraci´ on de las tareas La estimaci´ on de la duraci´ on de las actividades se ha realizado en base a experiencias previas en otros proyectos. En la tabla 2.1 se pueden ver las duraciones previstas para cada tarea identificada. 2.4. Requisitos del proyecto Esta secci´ on define los requisitos necesarios para que el proyecto se considere satisfactoriamente finalizado. SLURM contar´ a con un nuevo recurso para denominar las GPUs remotas (rGPUs). el funcionamiento de SLURM no se ver´ a alterado, tan s´ olo ampliado. SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 2. Descripci´ on del proyecto 19 no se permitir´ a el uso simult´ aneo de los recursos gen´ ericos GPU (local) y rGPU (remota). SLURM deber´ a poder asignar GPUs remotas a los trabajos que necesiten GPU para su ejecuci´ on. rCUDA deber´ a ejecutar la aplicaci´ on en las rGPUs que SLURM le ha asignado. SLURM deber´ a tener una pol´ ıtica de selecci´ on de rGPUs (plug-in) que: •se base en la pol´ ıtica de selecci´ on de recursos consumibles select/cons res. •tenga en cuenta el n´ umero de rGPUs y cantidad de memoria solicitada por el trabajo. •seleccione rGPUs de una lista ordenada que contenga todas las rGPUs de la partici´ on. •priorice la selecci´ on de rGPUs locales, es decir, de nodos asignados al trabajo. SLURM deber´ a escribir el resultado de la planificaci´ on de rGPUs en variables de entorno para la configuraci´ on de rCUDA. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster Cap´ ıtulo 3 Descripci´ on de SLURM Este cap´ ıtulo describe la herramienta de gesti´ on de recursos y planificaci´ on de trabajos para clusters Linux. Tras una introducci´ on, se analiza a fondo la arquitectura y los servicios que ofrece SLURM. 3.1. Introducci´ on SLURM es una herramienta para Linux de c´ odigo abierto, tolerante a fallos y altamente escalable para clusters Linux de todos los tama˜ nos. El dise˜ no resultante SLURM ofrece estas caracter´ ısticas: Simplicidad: es suficientemente simple de usar para un usuario que tenga inter´ es. C´ odigo abierto: est´ a disponible para todo el p´ ublico de forma gratuita y se distribuye con licencia GNU. Portabilidad: se ha escrito en lenguaje C y utiliza el motor de configuraci´ on GNU autoconf. Aunque inicialmente estaba dirigido a sistemas Linux, en la actualidad puede ser ejecutado en otros sistemas operativos basados en UNIX. Adem´ as el mecanismo de plug-ins que tiene SLURM permite configurarlo y ejecutarlo en diferente tipo de arquitecturas. Independencia de interconexi´ on: admite varios protocolos de comunicaci´ on y tiene en cuenta diferentes topolog´ ıas de red. Escalabilidad: el dise˜ no permite ejecutar SLURM en cluster con miles de nodos, demostrando su alto rendimiento. Tolerancia a fallos: puede manejar diversos tipos de fallo sin necesidad de cancelar la carga de trabajos. Los recursos reservados para un trabajo en un nodo que haya sufrido alg´ un problema, ser´ an gestionados de modo que el trabajo disfrutar´ a de los recursos en otro lugar. Seguridad: cuenta con diferentes tipos de encriptado para la autenticaci´ on de los usuarios en el sistema. 22 3.2. Arquitectura Amigable con el administrador de sistemas: utiliza una configuraci´ on simple y mayormente centralizada, que se puede modificar en tiempo de ejecuci´ on sin que la carga de trabajos se vea afectada. Como cualquier gestor de cargas de trabajos en clusters, SLURM tiene tres funcionalidades principales: Permite a los usuarios la reserva de recursos, en modo exclusivo y/o compartido, durante un tiempo determinado. Ofrece un entorno para el inicio, ejecuci´ on y monitorizaci´ on de trabajos en un conjunto de nodos. Arbitra el uso de los recursos mediante la gesti´ on de una cola de trabajos pendientes. Opcionalmente, SLURM dispone de plug-ins con los que ampliar su funcionalidad y/o modificar su comportamiento. 3.2. Arquitectura Por un lado, SLURM ejecuta en el nodo de gesti´ on un demonio central slurmctld para monitorizar recursos y trabajos. Tambi´ en pueden haber demonios de respaldo que hagan el trabajo del controlador principal, en el caso de que este falle. Por el otro, cada servidor de c´ omputo (nodo) ejecuta un demonio slurmd. Se puede decir que el demonio est´ a a la espera de trabajos, cuando un trabajo llega, lo ejecuta y devuelve el estado. Acto seguido, se queda de nuevo esperando m´ as trabajo. Estos demonios en los nodos de c´ omputo proveen al sistema un modo de tolerancia a fallos basado en las comunicaciones jer´ arquicas. Finalmente, existe un demonio (aunque su uso es opcional) slurmdbd que se utiliza para guardar la informaci´ on de registro de los eventos que suceden en el sistema, en una base de datos. La comunicaci´ on entre los demonios (ver secciones 3.2.1,3.2.2 y3.2.3) y la interacci´ on con el usuario (ver secci´ on 3.3.1), se produce siguiendo el esquema de la figura 3.1. As´ ı pues, las entidades controladas por los demonios de SLURM son: recursos computacionales, particiones (agrupaciones l´ ogicas de nodos), trabajos y etapas (conjuntos de tareas dentro de un trabajo). Por lo tanto, a un trabajo se le asigna un conjunto de recursos de un partici´ on concreta. Una vez reservado los recursos, el usuario puede lanzar trabajos paralelos en forma de etapas de trabajo. Por lo que una sola etapa de trabajo puede utilizar todos los nodos, pero tambi´ en varias etapas de un trabajo pueden utilizar parcialmente los recursos reservados para el trabajo. Por ejemplo: en la parte izquierda de la Figura 3.2 vemos como los 5 nodos asignados a un trabajo son utilizado por la misma etapa de trabajo. Al contrario, en la derecha el trabajo crea una tarea que utilizar´ a dos nodos de una reserva de 4 nodos. Este comportamiento vendr´ a dado por la propia naturaleza del trabajo y la aplicaci´ on que ejecute ´ este. Es decir, el primer ejemplo corresponde a un trabajo en el que se crean procesos en todos los nodos reservados, mientras que en el segundo caso un trabajo a reservado nodos que la tarea que se encarga de la ejecuci´ on no va a utilizar. SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 3. Descripci´ on de SLURM 23 Figura 3.1: Componentes de SLURM Figura 3.2: Entidades de SLURM Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 30 3.3. Servicios y Operaciones Figura 3.5: Inicio de un trabajo interactivo 3.3.5.2. Modo Lote La figura 3.6 muestra el proceso que se sigue para iniciar un trabajo en modo lote, o lo que es lo mismo, un trabajo encolado. Una vez un trabajo en modo lote (batch) es enviado a la cola, srun env´ ıa a slurmctld una petici´ on para ejecutar un trabajo en modo lote, que contiene la localizaci´ on de la entrada y salida del trabajo a procesar, el directorio actual, el entorno y los recursos necesarios. slurmctld encola la petici´ on en su cola de prioridad ordenada. Una vez los recursos est´ en disponibles y la prioridad es la debida, slurmctld reserva los recursos para el trabajo y contacta con el primer nodo de la lista de reservados, para pedirle que inicie el trabajo del usuario. En este caso, el trabajo puede contener una llamada asrun o un script con m´ ultiples invocaciones a srun. El demonio slurmd del nodo remoto responde al controlador iniciando: el trabajo (job), la tarea (step) y el script del usuario. Los procesos srun ejecutados desde el script tendr´ an acceso a los recursos reservados y podr´ an iniciar los job step en los nodos que dispongan. Terminada la ejecuci´ on job step, el proceso srun, invocado desde el script, notifica aslurmctld y termina. El script continua su ejecuci´ on que puede contener m´ as job step. Cuando la ejecuci´ on del script se completa, el hilo de la tarea que ejecutaba el script recoge el estado de la salida del programa y env´ ıa a slurmctld, un mensaje informando de esta salida. slurmctld se percata de que el trabajo a sido completado y env´ ıa a todos los demonios locales involucrados una petici´ on para ejecutar el ep´ ılogo. Hecho esto, el controlador libera los recursos reservados. 3.3.5.3. Modo Reserva En este modo, los usuarios esperan reservar recursos para un trabajo y de forma interactiva ejecutar job step en esa reserva. El proceso de inicio de trabajos en este modo (alloc) est´ a representado en la figura 3.7. SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 3. Descripci´ on de SLURM 31 Figura 3.6: Inicio de un trabajo encolado El proceso srun env´ ıa una petici´ on de recursos, a la cual el controlador slurmctld responder´ a, si es posible, con una lista de nodos seleccionados, un identificador de trabajo, etc. El proceso srun abre una nueva shell en el terminal del usuario, que permitir´ a a ´ este acceder a los recursos reservados. srun esperar´ a a que el usuario salga de la shell antes de considerar el trabajo completado. Desde la nueva shell se puede lanzar job step, ya que ´ esta es el propio trabajo. El usuario mediante estos job step podr´ a solicitar recursos, siempre y cuando el trabajo los tenga asignados. Cuando se ejecuta un srun desde la nueva shell,´ este lee el entorno y las opciones que el usuario ha dado al trabajo, entonces notifica al controlador que se ha iniciado un nuevo job step dentro del trabajo. slurmctld registra el job step y responde a srun con la credencial del trabajo. A partir de aqu´ ı, srun inicia los trabajos con el mismo m´ etodo que se ha visto en modo interactivo (secci´ on: 3.3.5.1). Finalmente, cuando el usuario sale del shell, el proceso srun original recibe el estado de salida, notifica a slurmctld y termina. Como en los otros casos, el controlador ejecutar´ a el ep´ ılogo en los nodos reservados y los liberar´ a. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 32 3.3. Servicios y Operaciones Figura 3.7: Inicio de un trabajo en modo reserva SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Cap´ ıtulo 4 Descripci´ on de rCUDA Este cap´ ıtulo describe la herramienta de virtualizaci´ on de GPUs rCUDA. Tras una introducci´ on, se analiza a fondo la arquitectura y los servicios que ofrece rCUDA. 4.1. Introducci´ on rCUDA ofrece acceso transparente a cualquier GPU instalada en un cluster, independientemente del nodo donde se est´ e ejecutando la aplicaci´ on que solicita servicios GPGPU. Por tanto, rCUDA es realmente ´ util en los siguientes escenarios: i) en un cluster equipado con rCUDA se puede reducir el n´ umero total de GPUs del sistema, aumentando el ratio de utilizaci´ on de los aceleradores hardware; ii) rCUDA tambi´ en puede ser aprovechado para acelerar significativamente la computaci´ on de datos paralelos en un cluster convencional, a˜ nadiendo al sistema un n´ umero reducido de aceleradores, menor que el n´ umero total de nodos; iii) rCUDA aumenta el n´ umero de GPUs accesibles por una aplicaci´ on, que pasa de tener tan s´ olo las GPUs locales, a disponer de todas las disponibles en el cluster. En resumen, son muchos los casos en los que sacrificando un poco de tiempo de ejecuci´ on podemos obtener ahorros considerables en energ´ ıa, mantenimiento, espacio y refrigeraci´ on. 4.2. Arquitectura El entorno rCUDA est´ a divido en dos grandes m´ odulos cliente y servidor, como se describe en la Figura 4.1: La parte del cliente consiste en una colecci´ on de funciones envoltorio, las cuales reemplazan a NVIDIA CUDA Runtime (proporcionado por NVIDIA como una biblioteca compartida) en el nodo cliente (nodo sin GPU). La biblioteca cliente se encarga de enviar las funciones CUDA al servidor y recuperar el resultado. Este mecanismo hace creer a la aplicaci´ on que tiene acceso directo a la GPU f´ ısica. 34 4.2. Arquitectura Aplicación CUDA GPU CLIENTE SERVIDOR Biblioteca rCUDA Demonio rCUDA ComunicacionesComunicaciones Red GPU Figura 4.1: Esquema general de la arquitectura de rCUDA. La parte del servidor se ejecuta en cada nodo con al menos una GPU. El servidor recibe, interpreta y ejecuta la llamada a la API reenviada por el cliente. Se utiliza un proceso diferente para procesar cada ejecuci´ on remota sobre un contexto de GPU independiente, lo que permite la multiplexaci´ on de GPUs. Como puede verse en la Figura 4.1, rCUDA responde a una arquitectura distribuida cliente-servidor. Los clientes hacen uso de la biblioteca de funciones envoltorio que realizan las llamadas a CUDA runtime API. As´ ı pues, los clientes obtienen acceso a los dispositivos virtualizados, mientras que los nodos que hospedan los dispositivos f´ ısicos ejecutan los demonios que procesan las peticiones a CUDA. Ya que los clientes y servidores se comunican a trav´ es de la red, se hace uso de un protocolo personalizado de comunicaciones de alto rendimiento, para optimizar la transferencia de datos en la red. Lado del Cliente: la biblioteca envoltorio CUDA runtime API se instala en un nodo sin GPU que necesite la capacidad de procesar c´ odigo para GPU. Este cliente intercepta, procesa y reenv´ ıa las llamadas al servidor. Una vez la biblioteca de funciones envoltorio se carga din´ amicamente, autom´ aticamente se establece la conexi´ on con el servidor (o servidores) especificado en la, correspondiente variable, de entorno. Cuando la biblioteca se descarga, la conexi´ on se cierra autom´ aticamente y los recursos son liberados. ´ esto evita la necesidad de extender el CUDA runtime API original, con funciones explicitas de inicializaci´ on y destrucci´ on. Para cada llamada CUDA se produce esta secuencia de tareas: (1) comprobaciones locales (depende de cada funci´ on); (2) mapeados opcionales, p.e., para asignar identificadores a los punteros o localmente almacenar informaci´ on que se recuperar´ a m´ as tarde; (3) empaquetar los argumentos junto con un identificador de funci´ on; (4) enviar la petici´ on de ejecuci´ on al servidor; (5) en funciones s´ ıncronas, esperar a la respuesta del servidor. Lado del servidor: el demonio servidor, localizado en los nodos que ofrecen servicios de aceleraci´ on, se encarga de recibir, interpretar y ejecutar las llamadas a CUDA. Por cada ejecuci´ on remota se crea un nuevo proceso (usando pre-fork para un mayor rendimiento) que ejecuta todas las peticiones de una sola aplicaci´ on remota, en un contexto de GPU independiente. Por tanto, la multiplexaci´ on de la GPU se consigue generando un proceso diferente en el servidor por cada ejecuci´ on remota sobre un nuevo contexto de GPU. Esto tambi´ en asegura que el servidor sobreviva a una excepci´ on en la que el proceso sea abortado (p.e., ante una llamada CUDA inapropiada). Este dise˜ no permite que en un cluster HPC donde los trabajos son planificados y asignados a diferentes procesadores de prop´ osito general (CPUs), todas las GPUs pueden ser SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 4. Descripci´ on de rCUDA 35 compartidas, de forma segura, por distintos trabajos. Las aplicaciones pueden ser ejecutadas concurrentemente siempre y cuando haya suficiente memoria en el dispositivo y es el driver del dispositivo quien controlar´ a la ejecuci´ on concurrente de aplicaciones en diferentes contextos activos, usando su propio planificador. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 36 4.2. Arquitectura SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Cap´ ıtulo 5 Integraci´ on de la virtualizaci´ on de GPUs con rCUDA en SLURM Este cap´ ıtulo describe el trabajo realizado en cuanto a desarrollo y modificaciones de la versi´ on original de SLURM, para soportar la virtualizaci´ on de GPUs mediante rCUDA. El c´ odigo fuente de SLURM est´ a organizado de forma de ´ arbol de directorios. Cada directorio contiene los ficheros relativos a una parte diferenciada del funcionamiento de SLURM. Para cada uno de estos ficheros se describen los cambios aplicados. Aparte de las modificaciones, tambi´ en se han a˜ nadido nuevos plug-ins, que no dejan de ser nuevos directorios a˜ nadidos al ´ arbol. 5.1. Introducci´ on Las modificaciones llevadas a cabo para conseguir la funcionalidad esperada, fueron las siguientes: 1. Se han a˜ nadido nuevas estructuras de datos a SLURM para poder trabajar con la informaci´ on de las GPUS, requerida por los trabajos, particiones y nodos. 2. Se ha modificado el m´ odulo GRes (Generic Resources), que es el encargado de gestionar los recursos gen´ ericos de los nodos, en este caso las GPUs. Se ha a˜ nadido a este m´ odulo la l´ ogica necesaria para que todas las GPUs del cluster sean accesibles desde cualquier nodo, lo que implica que se puedan compartir entre los nodos. 3. Se han implementado dos nuevos plug-ins. El primero de ellos “gres/rgpu”, declara un nuevo recurso gen´ erico en el sistema, la GPU remota. El segundo “select/cons rgpu” es responsable de seleccionar los recursos, en especial las rGPU. El c´ odigo de este plug-in de selecci´ on de recursos est´ a basado en el ya existente “select/cons res”, por lo que se puede esperar un comportamiento similar entre ambos. 4. En los paquetes RPC, usados en las comunicaciones entre los demonios, se han a˜ nadido nuevos campos con informaci´ on de rGPU. 5. Finalmente, se ha a˜ nadido el c´ odigo necesario para escribir las variables de entorno que leer´ a rCUDA: 38 5.2. Cambios en SLURM RCUDA DEVICE COUNT, da a conocer el n´ umero de dispositivos que necesita este trabajo. RCUDA DEVICE X, indica la IP del nodo donde la rGPU est´ a instalada. Tras estos cambios, el usuario puede enviar trabajos a la cola de tres modos diferentes: Original (SLURM): El comportamiento de SLURM es el correspondiente a la versi´ on 2.6.2. Exclusivo (rCUDAex): SLURM desacopla las GPUs de los nodos, aunque ´ estas s´ olo pueden ser usadas por un trabajo a la vez. Compartido (rCUDAco): Igual que el modo exclusivo, pero los trabajos pueden compartir las GPUs. 5.2. Cambios en SLURM A continuaci´ on se explican los cambios en el c´ odigo que se llevaron a cabo. Adem´ as, en el Anexo Dse puede ver el resultado de la ejecuci´ on del comando diff aplicado a la versi´ on original y la versi´ on modificada. 5.2.1. Configuraci´ on Para la configuraci´ on de la instalaci´ on se a˜ nadieron todos los plug-ins creados al fichero ./configure.ac. A˜ nadir estos plug-ins a la configuraci´ on global, permite que se generen autom´ aticamente sus Makefile.  src/plugins/select/cons rgpu/M a k e f i l e src/plugins/g r e s /rgpu/M a k e f i l e  5.2.2. Estructura de los paquetes RPC La comunicaci´ on entre procesos SLURM se lleva a cabo intercambiando paquetes RPC. Para poder transmitir la informaci´ on referente a las rGPUS, se modificaron las estructuras de datos para que albergaran esta informaci´ on. Esta informaci´ on se debe transmitir entre: procesos de env´ ıo de trabajos a la cola (srun,sbatch ysalloc), demonio controlador, demonios locales y procesos encargados de las etapas de los trabajos. Por tanto, se han a˜ nadido nuevos campos de estructuras de datos intercambiadas entre los procedimientos de env´ ıos de trabajos, reservas de recursos o creaci´ on de etapas de trabajos. A las estructuras afectadas se les ha a˜ nadido estos campos:  u i n t 3 2 t nrgpu ;/* cantidad de rgpus asignadas */ char *rgpulist;/* lista de rgpus asignadas */  SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 5. Integraci´ on de la virtualizaci´ on de GPUs con rCUDA en SLURM 39 5.2.3. Ficheros comunes En el directorio./src/common se encuentra el c´ odigo com´ un que ejecutan todos los procesos SLURM. 5.2.3.1. Paquetes RPC Los paquetes RPC enviados entre procesos pasan por una fase de empaquetado, al ser enviados, y una fase de desempaquetado, al ser recibidos. Como se han a˜ nadido nuevos campos a las estructuras de datos de los paquetes, tambi´ en se tienen que adaptar las funciones encargadas de estos procedimientos para que empaqueten y desempaqueten los nuevos campos referentes a las rGPUs. La informaci´ on de las rGPUs viaja de unos procesos a otros, concretamente, entre el proceso que env´ ıa el trabajo a la cola y el demonio controlador; y a la hora de distribuir tareas sobre los nodos. Ejemplos de empaquetado y desempaquetado:  packstr(msg-> rgpu list ,buffer); safe unpackstr xmalloc(& tmp ptr -> rgpu list , & uint32 tmp ,buffer);  5.2.3.2. M´ odulo GRes (Generic Resources) El m´ odulo GRes de SLURM se encarga de gestionar los recursos gen´ ericos como las GPUs. Como se ha explicado anteriormente, este m´ odulo es incapaz de compartir recursos entre trabajos, ni entre nodos. Por lo tanto, cualquier operaci´ on que involucre a alg´ un recurso gen´ erico, pasar´ a por este c´ odigo. La idea general para conseguir que este m´ odulo se comportara como se esperaba fue: 1. Llamar a la funci´ on que reserva rGPUs, desde la pol´ ıtica de selecci´ on (se explica m´ as adelante). 2. Recorrer las rGPUs del nodo afectado. 3. Comprobar que la rGPU tenga suficiente memoria libre. 4. Actualizar los registros del trabajo con el identificador de la rGPU, actualizar los registros de la rGPU con el identificador del trabajo. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 46 6.2. Cargas de trabajos 6.1.3. MCUDA-MEME Versi´ on del algoritmo de descubrimiento de motivos MEME (versi´ on 4.4.0), que combina CUDA, MPI y OpenMP para el procesamiento en paralelo. Con caracter´ ısticas similares a LAMMPS, MCUDA-MEME es multi-hilo y multi-proceso, pero debido a su implementaci´ on necesitar´ a una GPU por cada proceso. La versi´ on de MPI utilizada es MVAPICH2 que nos permitir´ a utilizar la red InfiniBand. 3 6.1.4. GROMACS Simulador de din´ amica molecular que procesa ecuaciones Newtonianas de movimiento de cientos de millones de part´ ıculas. Su principal uso es en mol´ eculas bioqu´ ımicas, como las prote´ ınas, l´ ıpidos y ´ acidos nucleicos los cuales tienen muchas interacciones complicadas. La versi´ on que hemos utilizado (4.6.5) utiliza procesos MPI y hilos OpenMP para paralelizar sus c´ alculos. La aplicaci´ on est´ a preparada para obtener unos resultados similares para un mismo n´ umero de cores sin importar la distribuci´ on procesos/hilos. GROMACS es la ´ unica aplicaci´ on utilizada que no precisa de GPUs para su ejecuci´ on. 4 Todas las aplicaciones que realizan c´ alculo en GPUs se encuentran en el cat´ alogo de aplicaciones de NVIDIA. 5. 6.2. Cargas de trabajos La combinaci´ on de rCUDA y SLURM permite que las GPUs sean compartidas por varios trabajos. Para ello, es necesario indicar la m´ axima cantidad de memoria requerida por cada trabajo. Debido a que el controlador de la GPU est´ a cargado en memoria de la GPU, no toda la memoria de ´ esta estar´ a disponible para nuestros trabajos. Lo mismo pasa con el demonio de rCUDA que tambi´ en se encuentra cargado. Es m´ as, por cada proceso que sea gestionado por rCUDA, se necesitar´ a un demonio independiente. A lo que hay que sumar siempre un demonio rCUDA ocioso (cargado en memoria de GPU) a la espera de trabajo. Por lo tanto, el valor a calcular se corresponde a la memoria del propio trabajo, a la memoria del controlador de la GPU y a la memoria del demonio de rCUDA. As´ ı pues, la cantidad m´ axima de memoria vendr´ a dada por la expresi´ on: AppM axM em +NV IDIA Controlador + (rCUDAd ·(hilos + 1)). Hemos generado tres cargas de diferente duraci´ on te´ orica. Estas cargas se han generado aleatoriamente, pero son reproducibles si se mantiene la semilla de las funciones que calculan n´ umeros aleatorios. El generador de cargas de trabajo recibe el tiempo te´ orico que deber´ ıa durar la ejecuci´ on, por lo que va a˜ nadiendo nuevos trabajos aleatorios que se encargan de una de las cuatro aplicaciones. Elegir una aplicaci´ on para a˜ nadir a la carga, es un proceso aleatorio donde la probabilidad de cada una de ser elegida es de un 25 %. El c´ odigo encargado de generar las cargas de trabajos se puede ver en B.6. Destacar que el 3https://sites.google.com/site/yongchaosoftware/mcuda-meme 4http://www.gromacs.org 5http://www.nvidia.com/object/gpu-applications.html SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 6. Evaluaci´ on de prestaciones 47 tiempo te´ orico deber´ ıa ser similar a la duraci´ on de la ejecuci´ on secuencial de los trabajos. En nuestro caso, los trabajos se solapan por lo que el tiempo de ejecuci´ on es mucho menor (como se ver´ a en la siguiente secci´ on). La tabla 6.1 muestra los tiempos de ejecuci´ on de cada aplicaci´ on y este es el tiempo que utiliza el script para a˜ nadir trabajos a la carga, mientras la suma del tiempo de los trabajos no supere el tiempo te´ orico dado. En los Anexos B.1,B.2,B.3,B.4 yB.5 se encuentran los scripts que se ejecutan con el comando de SLURM salloc. Cuadro 6.1: M´ aximo rendimiento de las aplicaciones Aplicaci´ on Configuraci´ on Tiempo de ejecuci´ on (s) GPU-Blast 1 proceso con 6 hilos 21 LAMMPS 5 procesos mono-hilo en 5 nodos diferentes 15 MCUDA-MEME 4 procesos mono-hilo en 4 nodos diferentes 165 GROMACS 2 procesos, con 12 hilos cada uno, en 2 nodos 167 La tabla 6.2 contiene la descripci´ on detallada, para cada duraci´ on, de la cantidad de instancias de cada aplicaci´ on. El orden de los trabajos es independiente del tipo de carga, por lo que las modificaciones en la configuraci´ on de los trabajos no supone una llegada de trabajos a la cola distinta. En resumen, tenemos 4 escenarios con 6 cargas cada uno. Adem´ as, esas cargas se dividen en 2 grupos dependiendo si requieren GPUs o rGPUs. Ambos grupos cuentan con las 3 duraciones te´ oricas de carga. Cuadro 6.2: Descripci´ on de las cargas de trabajos Aplicaci´ on Carga 2 horas 4 horas 8 horas GPU-Blast 12 43 81 LAMMPS 18 47 90 MCUDA-MEME 18 36 77 GROMACS 23 42 79 Total 71 168 327 6.3. Experimentaci´ on Para esta fase del proyecto hay que aclarar c´ omo fue configurado SLURM. Para poder permitir adelantamientos entre trabajos se utiliz´ o la pol´ ıtica de planificaci´ on backfill, que permite el adelantamiento de trabajos. Adem´ as, la selecci´ on de recursos consumibles fue realizada por la pol´ ıtica cons rgpu que es la ´ unica que permite el uso de GPUs remotas. Utiliza la implementaci´ on MVAPICH2 de MPI, especialmente preparada para la tecnolog´ ıa InfiniBand. Y para enviar trabajos a la cola escogimos el comando salloc para Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 48 6.3. Experimentaci´ on trabajos multi-proceso, ya que srun necesita que la aplicaci´ on est´ e enlazada a la implementaci´ on de la biblioteca PMI de SLURM. En los experimentos llevados a cabo se pueden distinguir f´ acilmente tres prop´ ositos: 1. Conseguir el mayor rendimiento posible. A partir de los datos extra´ ıdos de un an´ alisis de escalabilidad, hemos obtenido para cada aplicaci´ on su ´ optima configuraci´ on de ejecuci´ on en nuestro cluster. Esta an´ alisis med´ ıa tiempos de ejecuci´ on de las aplicaciones con diferente configuraci´ on de n´ umero de procesos e hilos, siempre cuando fuera posible. Aunque nuestro cluster estuviera equipado con 8 GPUs, restringimos a 4 el uso de GPUs para MCUDA-MEME, ya que nuestro objetivo era reducir el n´ umero de GPUs en el cluster (hasta 4 unidades) manteniendo el n´ umero de nodos de c´ omputo. Por el contrario, LAMMPS se configura con 5 GPUs debido a su implementaci´ on. La tabla 6.3 resume la mejor configuraci´ on para ambos modos de ejecuci´ on. Es importante matizar que la b´ usqueda del m´ aximo rendimiento es perfectamente entendible cuando hayan pocos trabajos a ejecutar. Sin embargo, nuestras cargas contienen un considerable n´ umero de trabajos, por lo que esta configuraci´ on ser´ a propensa a desperdiciar recursos, ya que muchos trabajos esperar´ an a que se liberen el resto de recursos. 2. Aumentar la productividad global. Para este prop´ osito se han a˜ nadido varios grados de libertad que evitan que cada proceso se ejecute en un nodo diferente. Aunque sabemos que esta configuraci´ on no va a mapear de manera ´ optima los recursos a los trabajos, pero si que se reducir´ a el tiempo de inactividad de muchos recursos. La tabla 6.4 refleja como aplicaciones tales como GPU-Blast y LAMMPS, no fuerzan a sus procesos a ejecutarse en diferentes nodos (se ha eliminado el argumento -N). Sin embargo, tambi´ en se aprecia que las configuraciones de MCUDA-MEME y GROMACS permanecen sin cambios. La explicaci´ on para MCUDA-MEME es que la aplicaci´ on necesita 4 GPUs (uno por proceso); LAMMPS es capaz de usar la misma GPU para diferentes procesos, mientras que MCUDA-MEME no es capaz. GROMACS experimenta un aumento dram´ atico en el tiempo de ejecuci´ on si dos o m´ as instancias comparten un nodo, debido a que los hilos se mapean a los mismos cores en todas las instancias. Por este motivo, decidimos dar a cada instancia acceso exclusivo a dos nodos. Tras estos cambios se observ´ o un sustancial aumento en la productividad de trabajos por minuto. 3. Nuestro plan era reducir progresivamente el n´ umero de GPUs en el nodo, desde 8 hasta 6 y 4. As´ ı pues, se modific´ o la orden de lanzamiento de LAMMPS para que casara con la nueva “plataforma”. Esto supuso cambiar a -n5 -c1 --gres=rgpu:4:3275M la orden de LAMMPS, porque ya no hab´ ıan 5 GPUs en el cluster. Finalmente, a la hora de enviar tan gran r´ afaga de trabajos en un tiempo tan reducido, experimentamos que el controlador de SLURM se saturaba. Para paliar este imprevisto se a˜ nadi´ o un retraso entre cada env´ ıo. Este retraso aumenta a medida que los trabajos son encolados partiendo desde un valor cercano al cero. SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 6. Evaluaci´ on de prestaciones 49 Cuadro 6.3: Par´ ametros de lanzamiento para obtener el m´ aximo rendimiento individual Aplicaci´ on Lanzamiento con CUDA Lanzamiento con rCUDA GPU-Blast -N1 -n1 -c6 –gres=gpu:1 -N1 -n1 -c6 –gres=rgpu:1:1686M LAMMPS -N5 -n5 -c1 –gres=gpu:1 -N5 -n5 -c1 –gres=rgpu:5:3275M MCUDA-MEME -N4 -n4 -c1 –gres=gpu:1 -n4 -c1 –gres=rgpu:4:163M GROMACS -N2 -n2 -c12 -N2 -n2 -c12 Cuadro 6.4: Par´ ametros de lanzamiento para obtener la m´ axima productividad global Aplicaci´ on Lanzamiento con CUDA Lanzamiento con rCUDA GPU-Blast -n1 -c6 –gres=gpu:1 -n1 -c6 –gres=rgpu:1:1686M LAMMPS -n5 -c1 –gres=gpu:1 -n5 -c1 –gres=rgpu:5:3275M MCUDA-MEME -N4 -n4 -c1 –gres=gpu:1 -n4 -c1 –gres=rgpu:4:163M GROMACS -N2 -n2 -c12 -N2 -n2 -c12 6.4. Resultados Esta secci´ on contiene una serie de gr´ aficas que muestran el comportamiento de los resultados obtenidos en cuanto a tiempo de ejecuci´ on y productividad del sistema (trabajos por minuto). Las Figuras 6.1 y6.2 sirven para aclarar lo explicado anteriormente respecto a las configuraciones de lanzamiento de trabajos. La primera de ellas muestra que buscar el m´ aximo rendimiento por aplicaci´ on (ver Tabla 6.3) genera tiempos similares entre los modos de GPUs y rGPUs. Aunque trabajando en el modo rCUDA se comparten GPUs, las restricciones de utilizar cierto n´ umero de nodos provoca una sobrecarga que retrasa el avance global. Por ejemplo, la ejecuci´ on en paralelo de 12 instancias (12 son los cores de cada nodo) en los mismos 4 nodos implica un tiempo de 1.884 segundos. Por el contrario, la ejecuci´ on en serie necesita 165 segundos ×12 instancias = 1.980, tiempo bastante similar al de la ejecuci´ on en paralelo. En la siguiente Figura se aprecia que evitando que cada proceso se ejecute en un nodo diferente (ver Tabla 6.4) se consiga reducir el tiempo de ejecuci´ on y aumentar la productividad. Compar´ andolas, se ve que no s´ olo se obtienen mejores resultados utilizando GPUs locales con CUDA, si no que la ganancia utilizando rCUDA es muy destacable. A simple vista, en las Figuras 6.2,6.3 y6.4 podemos apreciar que rCUDA reduce el tiempo de ejecuci´ on, en varios casos en un factor mayor de 2×, esto est´ a bien reflejado en los resultados en el cluster de 4 GPUs. Aun m´ as destacable es el hecho de que rCUDA mantenga el ´ ındice de productividad independientemente del n´ umero de GPUs, al contrario de lo que sucede al utilizar CUDA. Eliminar GPUs de varios nodos supone un efecto muy negativo para CUDA, tal y como se muestra en las gr´ aficas. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 50 6.4. Resultados Figura 6.1: Ejecuci´ on en plataforma con 8 GPUs. Lanzamiento configurado para obtener el m´ aximo rendimiento. Figura 6.2: Ejecuci´ on en plataforma con 8 GPUs SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut 6. Evaluaci´ on de prestaciones 51 Figura 6.3: Ejecuci´ on en plataforma con 6 GPUs Figura 6.4: Ejecuci´ on en plataforma con 4 GPUs Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 52 6.4. Resultados SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Cap´ ıtulo 7 Conclusiones En este proyecto hemos integrado la gesti´ on de GPUs remotas en el planificador de trabajos SLURM. Con estas modificaciones y utilizando un virtualizador de GPUs remotas como rCUDA, las GPUs en un cluster son virtualmente separadas del nodo donde est´ an f´ ısicamente instaladas. As´ ı pues, los trabajos ejecut´ andose en un nodo pueden utilizar GPUs de otros nodos. Hemos a˜ nadido a SLURM la definici´ on de un nuevo recursos gen´ erico SLURM y par´ ametros para que el planificador pueda administrar las RGPUs. Adem´ as, hemos realizado diversas modificaciones para aumentar la funcionalidad en varios comandos de SLURM. Tambi´ en hemos llevado a cabo una extensa evaluaci´ on de prestaciones de la nueva funcionalidad en un cluster real. Con este prop´ osito hemos definido una colecci´ on de cargas de trabajos sint´ eticas para demostrar tanto la funcionalidad como el aumento de rendimiento que se obtiene. Pudiendo as´ ı reducir el n´ umero de recursos f´ ısicos del cluster sin afectar al resultado. Actualmente, la versi´ on de SLURM-rCUDA adopta decisiones de planificaci´ on que involucran a las GPUs dependiendo de su memoria. En un futuro, tenemos planeado implementar otros algoritmos de planificaci´ on que aparte de tener en cuenta la memoria de la GPU, tenga tambi´ en en cuenta: la carga computacional, la energ´ ıa consumida o la distancia de red entre nodos. 54 SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Bibliograf´ ıa [1] SLURM website, http://www.schedmd.com [2] Andy B. Yoo, Morris A. Jette, Mark Grondona, “SLURM: Simple Linux Utility for Resource Management”, in Job Scheduling Strategies for Parallel Processing, L. Rudolph and U. Schwiegelshohn, Editors. 2003, SpringerVerlag. p. 44-60. [3] Quadrics Resource Management System http://www.quadrics.com/website/pdf/rms.pdf [4] Distributed Production Control System http://www.llnl.gov/icc/lc/dpcs overview.html [5] Beowulf Distributed Process Space http://brpoc.sourceforge.net [6] Y. Georgiou, “Resource and Job Management in High Performance Computing”, PhD Thesis, Joseph Fourier University, France, 2010. [7] Seren Soner, Can ¨ Ozturan. Integer Programming Based Heterogeneous CPU-GPU Cluster Scheduler for SLURM Resource Manager. [8] Seren Soner, Can Ozturan, Itir Karaca. Extending SLURM with Support for GPU Ranges. [9] Gerald Sabin P. Sadayappan. On Enhancing the Reliability of Job Schedulers. [10] Susanne M. Balle and Dan Palermo. Enhancing an Open Source Resource Manager with Multi-Core/Multi-threaded Support. [11] Jiadong Wu, Weiming Shi, and Bo Hong. Dynamic Kernel/Device Mapping Strategies for GPU-assisted HPC Systems. [12] C. Reano, R. Mayo, E.S. Quintana-Orti F. Silla, J. Duato A.J. Pena. Influence of InfiniBand FDR on the Performance of Remote GPU Virtualization, IEEE Cluster, 2013. [13] Antonio J. Pe˜ na et al. An efficient implementation of GPU virtualization in high performance clusters, in Euro-Par Workshops, 2009. [14] Antonio J. Pe˜ na et al. Performance of CUDA virtualized remote GPUs in high performance clusters, in ICPP, 2011. [15] S. Barrachina, M. Castillo, F. D. Igual, R. Mayo, E. S. Quintana-Orti and G. QuintanaOrti. Exploiting the capabilities of modern GPUs for dense matrix computations, Concurr. Comput. : Pract. Exper., vol. 21, no. 18, pp. 24572477, 2009. 62 A.2. gres.conf #AccountingStorageType = accounting_storage / none AccountingStoreJobComment=YES AccountingStorageHost=virtualgap AccountingStoragePort=6819 AccountingStorageUser=slurm JobCompHost=l o c a l h o s t #JobCompPass = qwerty JobCompUser=slurm JobCompPort=3306 JobCompType=jobcomp /mysql #JobCompType = jobcomp / none FastSchedule=1 CryptoType=crypto/munge SlurmctldDebug=1 SlurmctldLogFile=/ nfs/gap/slurm /var /s l u r m c t l d .log SlurmdDebug=1 SlurmdLogFile=/ nfs/gap/slurm /var /slurmd. %n.log NodeName=mlxc2i1 NodeHostname=mlxc2 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxf2i1 NodeHostname=mlxf2 CPUs=12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxc3i1 NodeHostname=mlxc3 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxc6i1 NodeHostname=mlxc6 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxc7i1 NodeHostname=mlxc7 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxc8i1 NodeHostname=mlxc8 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxc10i1 NodeHostname=mlxc10 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 NodeName=mlxc11i1 NodeHostname=mlxc11 CPUs =12 S o c k e t s =2 C o r e s P e r S o c k e t =6 ThreadsPerCore=1 RealMemory=32072 TmpDisk=29528 State=UNKNOWN Gres =gpu :1 , rgpu:1 PartitionName=main Nodes=mlxf2i1 ,mlxc2i1 ,mlxc3i1 ,mlxc6i1 ,mlxc7i1 ,mlxc8i1 ,mlxc10i1 , mlxc11i1 D e f a u l t =YES MaxTime=INFINITE S t a t e =UP  A.2. gres.conf  Name=gpu F i l e =/ dev /n v i d i a 0 Name=rgpu F i l e =/ dev /n v i d i a 0 Cuda =3.5 Mem=4726M  A.3. slurmdbd.conf  ArchiveEvents=y es ArchiveJobs=y es A r c h i v e S t e p s =no ArchiveSuspend=no AuthType =auth /munge SlurmUser=slurm DbdHost=virtualgap DbdPort =6819 DebugLevel =1 PurgeEventAfter=1 months SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut A. Ficheros de configuraci´ on de SLURM 63 PurgeJobAfter=1 months P u r g e S t e p A f t e r =1 months PurgeSuspendAfter=1 months StorageHost=virtualgap StoragePort=3306 StoragePass=qwerty StorageType=accounting storage/mysql StorageUser=slurm  Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 64 A.3. slurmdbd.conf SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Ap´ endice B Scripts auxiliares En este documento se encuentran todos los scripts de apoyo que se han implementado durante el desarrollo del proyecto. B.1. GPU-Blast  #!/ bin / bash set -e i f [$# -ne 2 ]; then echo " error USAGE : ./ script . sh ’job id ’ ’mem rgpu ’" e x i t 1 f i f i l e =" $1_$2 . job " touch $ f i l e chmod 774 $ f i l e i f [$2 -eq -1 ]; then printenv |egrep -i’ CUDA_VISIBLE_DEVICES | SLURM_NODELIST | JOB_ID ’ >$ f i l e e l s e printenv |egrep -i’RCUDA_|JOB_ID’ >$ f i l e f i path home =/ nfs/gap/s i s e r t e /gpu-blast executions path app =/ nfs/APPS/APPS/GPU-BLAST/1.1 ncbi -blast -2.2.26 $path app /bin /blastp -db $path home/sorted env nr -query $path app /TESTS/queries/ SequenceLength 00003000.t x t -num threads 6 -gpu t  B.2. LAMMPS  #!/ bin / bash set -e i f [$# -ne 2 ]; then echo " error USAGE : ./ script . sh ’job id ’ ’mem rgpu ’" e x i t 1 f i f i l e =" $1_$2 . job " touch $ f i l e chmod 774 $ f i l e i f [$2 -eq -1 ]; then 66 B.3. MCUDA-MEME CUDA printenv |egrep -i’ CUDA_VISIBLE_DEVICES | SLURM_NODELIST | JOB_ID ’ >$ f i l e e l s e printenv |egrep -i’RCUDA_|JOB_ID’ >$ f i l e f i path home =/ nfs/gap/s i s e r t e /lammps executions path app =/ nfs/APPS/APPS/LAMMPS/lammps-1 Feb14/mvapich2 +CUDA55/b in path mpiru n =/ nfs/LIBS /LIBS /MVAPICH2/2.0b/bin /mpirun p a t h t e s t =/ nfs/gap/s i s e r t e /lammps55 executions/input lammps $path mpirun -np $SLURM NPROCS -h o s t s $SLURM JOB NODELIST $pat h a pp /lmp g ++ - va r x 4 - var y 4 - va r z 8 - s f cuda <$path test/my in .l j  B.3. MCUDA-MEME CUDA  #!/ bin / bash set -e i f [$# -ne 2 ]; then echo " error USAGE : ./ script . sh ’job id ’ ’mem rgpu ’" e x i t 1 f i f i l e =" $1_$2 . job " touch $ f i l e chmod 774 $ f i l e printenv |egrep -i’ CUDA_VISIBLE_DEVICES | SLURM_NODELIST | JOB_ID ’ >$ f i l e ./ c r e a t e n o d e l i s t f i l e n o r e p e a t i n g $SLURM JOB NODELIST $SLURM JOBID /nfs/LIBS /LIBS /MVAPICH2/2.0b/b in /mpirun rsh -ssh -e x p o r t -np $SLURM NNODES - h o s t f i l e machines$SLURM JOBID MV2 SMP USE LIMIC2=1 MV2 IBA HCA=mlx4 0 MV2 NUM PORTS=1 MV2 SHOW ENV INFO=2 ./mcuda-meme nrsf testcases/n r s f 5 0 0 .f a s t a -dna -mod oops -maxsize 500000 -num threads 1  B.4. MCUDA-MEME rCUDA  #!/ bin / bash set -e i f [$# -ne 2 ]; then echo " error USAGE : ./ script . sh ’job id ’ ’mem rgpu ’" e x i t 1 f i f i l e =" $1_$2 . job " touch $ f i l e chmod 774 $ f i l e printenv |egrep -i’RCUDA_|JOB_ID’ >$ f i l e ./ c r e a t e n o d e l i s t f i l e $SLURM JOB NODELIST $SLURM JOBID $SLURM NPROCS /nfs/LIBS /LIBS /MVAPICH2/2.0b/b in /mpirun rsh -ssh -e x p o r t -np $SLURM NPROCS - h o s t f i l e machines$SLURM JOBID MV2 SMP USE LIMIC2=1 MV2 IBA HCA=mlx4 0 MV2 NUM PORTS=1 MV2 SHOW ENV INFO=2 ./mcuda-meme nrsf testcases/n r s f 5 0 0 .f a s t a -dna -mod oops -maxsize 500000 -num threads 1  B.5. GROMACS SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut B. Scripts auxiliares 67  #!/ bin / bash set -e i f [$# -ne 2 ]; then echo " error USAGE : ./ script . sh ’job id ’ ’mem ’" e x i t 1 f i f i l e =" $1_$2 . job " touch $ f i l e chmod 774 $ f i l e APPS PATH=/ nfs/APPS/APPS LIBS PATH =/ nfs/LIBS /LIBS GROMACS MPI PATH=$APPS PATH/GROMACS/4.6.5/MPI/mvapich2 GROMACS MPI BIN=$GROMACS MPI PATH/b in GROMACS MPI LIB=$GROMACS MPI PATH/lib GROMACS MPI INC=$GROMACS MPI PATH/include MVAPICH2 PATH=$LIBS PATH/MVAPICH2/2.0b MVAPICH2 BIN=$MVAPICH2 PATH/bi n MVAPICH2 LIB=$MVAPICH2 PATH/lib MVAPICH2 INC=$MVAPICH2 PATH/include FFTW SINGLE PATH=$LIBS PATH/FFTW/3.3.3/SINGLE FFTW SINGLE LIB=$FFTW SINGLE PATH/lib FFTW DOUBLE PATH=$LIBS PATH/FFTW/3.3.3/DOUBLE FFTW DOUBLE LIB=$FFTW DOUBLE PATH/lib e x p o r t LD LIBRARY PATH =$GROMACS MPI LIB:$MVAPICH2 LIB:$FFTW SINGLE LIB: $FFTW DOUBLE LIB:$LD LIBRARY PATH e x p o r t PATH=$GROMACS MPI BIN:$MVAPICH2 BIN:$PATH e x p o r t OMP NUM THREADS=$SLURM CPUS PER TASK ./ c r e a t e n o d e l i s t f i l e $SLURM JOB NODELIST $SLURM JOBID $SLURM NPROCS cat machines$SLURM JOBID mpirun rsh -ssh -e x p o r t -np $SLURM NPROCS -h os tfile machines$SLURM JOBID MV2 SMP USE LIMIC2=1 MV2 IBA HCA=mlx4 0 MV2 NUM PORTS=1 MV2 SHOW ENV INFO=2 $GROMACS MPI PATH/b in /mdrun mpi -pin on -pinoffset 0 - n s t e p s 100000 -s/nfs/gap /s i s e r t e /gromacs executions/b p t i .t p r  B.6. genera carga.py  #coding: latin1 imp ort random ,sys ,os random.seed (2) c l a s s App: de f i n i t (self ,id ,orden ,ruta ,memoria,duracion): s e l f .nameID =id #nombre i d e n t i f i c a d o r de l t i p o de app s e l f .orden =orden #comando slurm de e n v ˜ A o de t r a b a j o s e l f .r u t a =r u t a #r u ta d el s c r i p t a e j e c u t a r s e l f .memoria =memoria #memoria de GPU n e c e s a r i a (en MB) s e l f .duracion =duracion #du raci on de l a e j e c u c i o n (en segundos), c a l c u l a d a a p r i o r i de f s t r (s e l f ): return " %s - %d" % ( s e l f .nameID,s e l f .duracion) def inicializa apps shared() : apps = [] cont apps =dict() app =App(" GPUBlast " ," srun -n1 -c6 -- rcuda - mode = shar -- rcuda - distribution = global --gres = rgpu :1:1686 M" ," gpublast . sh" , 1686 , 21) apps .append (app) cont apps[app.nameID]=0 Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 68 B.6. genera carga.py app =App(" mCUDA - MEME " ," salloc -n4 -c1 -- rcuda - mode= shar -- rcuda - distribution = global --gres = rgpu :4:163 M" ,"./ mcudameme_rcuda .sh", 163 , 165) apps .append (app) cont apps[app.nameID]=0 app =App(" LAMMPS " ," salloc - n4 -c1 --rcuda - mode = shar --rcuda - distribution = global --gres = rgpu :4:3275 M" ,"./ lammps .sh ", 3275 , 15) apps .append (app) cont apps[app.nameID]=0 app =App("GROMACS"," salloc -N2 -n2 -c12 "," ./ gromacs . sh ", 0, 167) apps .append (app) cont apps[app.nameID]=0 return (apps ,cont apps) de f i n i c i a l i z a a p p s o r i g i n a l (): apps = [] cont apps =dict() app =App(" GPUBlast " ,"srun -N1 -n1 -c6 -- gres = gpu :1"," gpublast . sh ", -1, 21) apps .append (app) cont apps[app.nameID]=0 app =App(" mCUDA - MEME " ," salloc -N4 -n4 -c1 -- gres = gpu :1 ","./ mcudameme_cuda.sh", -1, 165) apps .append (app) cont apps[app.nameID]=0 app =App(" LAMMPS " ," salloc -N4 -n4 -c1 --gres = gpu :1 ","./ lammps . sh ", -1, 15) apps .append (app) cont apps[app.nameID]=0 app =App("GROMACS"," salloc -N2 -n2 -c12 "," ./ gromacs . sh ", 0, 167) apps .append (app) cont apps[app.nameID]=0 return (apps ,cont apps) i f name == " __main__ ": i f len(s y s .ar gv ) == 2: tiempo =int(s y s .a rgv [1]) * 60 e l s e : print " Error - USAGE : python carga_heter . py ’ minutes ’" s y s .e x i t (1) cadena ="_ %i_rcuda_v2 " % ( tiempo /60) (apps,c o n t a p p s ) = inicializa apps shared() #( apps ,c o n t a p p s ) = i n i c i a l i z a a p p s o r i g i n a l () cargash1 =open(" carga %s. sh " %cadena ,"w") t i m e s l e e p =100000 cronometro=0 njob =0 jobList = [] while cronometro <tiempo : i d j o b =random.randint(0, len(apps ) -1) jobList.append (i d j o b ) app =apps [i d j o b ] idapp =app.nameID comando =" %s %s %i %i &\ nusleep %i\n" % ( app.orden ,app.ru ta ,njob ,app.memoria,t i m e s l e e p ) cargash1.write(comando) cronometro += apps [i d j o b ]. duracion njob += 1 c o n t a p p s [idapp] += 1 i f (njob % 10) == 0: t i m e s l e e p += 250000 cargash1.c l o s e ()  SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut Ap´ endice C SLURM for rCUDA User’s Guide C.1. Introduction On the one hand, SLURM is a resource manager tool that dispatches jobs to resources according to the specified policies and constrained by a specific criteria. It is an opensource resource manager designed for Linux clusters of all sizes. However, SLURM does not allow to share generic resources, such as GPUs, among nodes as it does with CPUs. On the other hand, the rCUDA framework enables the concurrent usage of CUDAcompatible devices remotely. To enable a remote GPU-based acceleration, this framework creates virtual CUDA-compatible devices on those machines without a local GPU. These virtual devices represent physical GPUs located in remote hosts offering GPGPU services. In order to use rCUDA framework on clusters where SLURM is installed, a code modification over the original SLURM sources has to be done. In this document, the steps to install and run the modified SLURM are explained. C.2. Configuration This software is a patch to modify automatically the original SLURM (2.6.2 version) code. Once modified, a new installation of SLURM is required. Now, SLURM is going to be able to share GPU (referred to as rgpu) among nodes. C.2.1. Applying the patch and installation The steps to change the original code are: 1. Download SLURM-2.6.2 from SLURM website 2. Move the patch into SLURM folder 3. Execute patch command: patch -p1 -i rCUDA.patch 4. Install SLURM 70 C.2. Configuration C.2.2. Controller node environment variables Set the “RCUDAPROTO” environment variable to IB if an InfiniBand network connection is used (TCP by default). Set the “RCUDAPATH” environment variable according to the rCUDA client side middleware location (“$HOME/rCUDA/framework/rCUDAl” by default). Set the “CUDAPATH” environment variable according to the CUDA location (“/usr/ local/cuda/lib64” by default). C.2.3. Configuration files C.2.3.1. slurm.conf This file has to be the same (or with the same content) in all nodes where SLURM is running (controller node included). There is a set of parameters that the user has to change manually. This parameters are used to notice the controller that a remote GPU (rgpu) can be shared by the nodes. SelectType=select/cons_rgpu SelectTypeParameters=(CR_CORE | CR_CPU | CR_SOCKET | ...) GresTypes=rgpu,gpu Moreover, the user is entitled to alter the default behaviour by adding in the configuration the next fields: RcudaModeDefault=(exclusive | shared) RcudaDistDefault=(global | node) RgpuMinMemory=256 Being the mode by default exclusive (what means that only one job at once can be run in a RGPU), the user can change it, and set the mode shared (the RGPU can host jobs while it has enough memory). The distribution by default is global, so the amount of requested RGPUs is the total amount. If the distribution used is node, the total amount of RGPUs will be given by the amount of requested RGPUs and the amount of requested nodes (both numbers are involved in a multiplication in order to obtain the total amount of RGPUs). The field RgpuMinMemory indicates the minimun quantity of MB used by a job in the GPUs, if its quantity has not been declared in the submision (by default: 512). In this excerpt, the quantity is set as 256 MB. It is important to be aware that this field only allows integers and the units can not be included. Finally, in the nodes description the user has to add this resource (rgpu) in each node where one or more GPUs are located. SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut C. SLURM for rCUDA User’s Guide 71 NodeName=n15 NodeAddr=n15 CPUs=2 Sockets=1 CoresPerSocket=2 ThreadsPerCore=1 RealMemory=2005 Gres=rgpu:1,gpu:1 NodeName=n16 NodeAddr=n16 CPUs=8 Sockets=1 CoresPerSocket=4 ThreadsPerCore=2 RealMemory=7682 Gres=rgpu:4,gpu:4 NodeName=n17 NodeAddr=n17 CPUs=8 Sockets=1 CoresPerSocket=4 ThreadsPerCore=2 RealMemory=7682 In this sample nodes n15 and n16 have 1 and four GPUs and n17 does not have any GPU. C.2.3.2. gres.conf This file must exist in each node where a generic resource is installed. Using the previous sample, this is the gres.conf file content used in n16: Name=rgpu File=/dev/nvidia0 Cuda=2.1 Mem=1535m Name=rgpu File=/dev/nvidia1 Cuda=1.3 Mem=131072K Name=rgpu File=/dev/nvidia2 Cuda=3.0 Mem=2048M Name=rgpu File=/dev/nvidia3 Cuda=3.5 Mem=5g Name=gpu File=/dev/nvidia0 Name=gpu File=/dev/nvidia1 Name=gpu File=/dev/nvidia2 Name=gpu File=/dev/nvidia3 As can be seen in this example, apart from the path of the device, for each rgpu, the user has to add the GPU Compute Capability (referred to as Cuda) and the Memory (referred to as Mem) parameters. Using one line per device. The Cuda field expects two integers separated by a dot, which refer to the major and minor version. While the Mem field expects and integer and the units (see the example above). C.3. How to use modified SLURM Once the patch is applied and SLURM is installed and configured, the user is going to work in a standard SLURM version with new features. Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 78 +e n v v a r p r o t o =getenv(" RCUDAPROTO "); +envvar rcuda =getenv(" RCUDAPATH "); + +i f (envvar rcuda == NULL) +x s t r c a t (envvar rcuda ," rCUDA / framework / rCUDAl "); +i f (envvar library == NULL) +xstrfmtcat(s t r ," %s/ %s:",envvar home ,envvar rcuda); +e l s e +xstrfmtcat(s t r ," %s/ %s: %s:" ,envvar home ,envvar rcuda , envvar library); +// if ( envvar_proto == NULL ) +// env_array_overwrite_fmt ( dest , " RCUDAPROTO ", " %s", " TCP ") ; + +t m p s t r =xstrdup(batch -> r g p u l i s t ); +tok =s t r t o k (tmp str ,","); +while (tok != NULL) { +sprintf(aux ," RCUDA_DEVICE_ %i",rgpuCount); +e n v a r r a y o v e r w r i t e f m t (dest ,aux ," %s",tok ); +rgpuCount++; +tok =s t r t o k (NULL,","); + } +e n v a r r a y o v e r w r i t e f m t (dest ," RCUDA_DEVICE_COUNT "," %i",rgpuCount ); + } e l s e { +/* WRITING CUDA PATH IN LD_LIBRARY_PATH */ +char *envvar cuda; +envvar cuda =getenv(" CUDAPATH "); + +i f (envvar cuda == NULL) +x s t r c a t (envvar cuda ,"/ usr / local / cuda/ lib64 :/ usr / local / cuda/lib "); + +i f (envvar library == NULL) +xstrfmtcat(s t r ," %s",envvar cuda); +e l s e +xstrfmtcat(s t r ," %s: %s",env var cuda ,envvar library); + } +e n v a r r a y o v e r w r i t e f m t (dest ," LD_LIBRARY_PATH "," %s",str); +x f r e e (str); + /* There is no explicit node count in the batch structure , * so we need to calculate the node count . */ for (i= 0; i<batch -> num cpu groups;i++) { @@ -1235 ,11 +1339 ,61 @@ u i n t 3 2 t n ode cnt =step -> s t e p l a y o u t -> nod e c nt ; u i n t 3 2 t c l u s t e r f l a g s =slurmdb setup cluster flags() ; +char *envvar library , * envvar home ; +char *str =xstrdup(""); +envvar home =getenv(" HOME "); + tpn =u i n t 1 6 a r r a y t o s t r (step -> s t e p l a y o u t -> node cnt , step -> s t e p l a y o u t -> t a s k s ); e n v a r r a y o v e r w r i t e f m t (dest ,"SLURM_STEP_ID"," %u",step -> job step id); e n v a r r a y o v e r w r i t e f m t (dest ,"SLURM_STEP_NODELIST", " %s",step -> s t e p l a y o u t -> node list); + +envvar library =getenv(" LD_LIBRARY_PATH "); + +i f (step -> s t e p l a y o u t -> r g p u l i s t != NULL){ +/* WRITING RCUDA ENVIRONMENT VARIABLES */ +int rgpuCount=0; +char *tok , * e n v v a r pr o t o , * tmp str , * envvar rcuda; +char aux [2048]; + +e n v v a r p r o t o =getenv(" RCUDAPROTO "); +envvar rcuda =getenv(" RCUDAPATH "); + +i f (envvar rcuda == NULL) SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 79 +x s t r c a t (envvar rcuda ," rCUDA / framework / rCUDAl "); +i f (envvar library == NULL) +xstrfmtcat(s t r ," %s/ %s:",envvar home ,envvar rcuda); +e l s e +xstrfmtcat(s t r ," %s/ %s: %s:" ,envvar home ,envvar rcuda , envvar library); +i f (e n v v a r p r o t o == NULL) +e n v a r r a y o v e r w r i t e f m t (dest ," RCUDAPROTO "," %s" ," TCP"); + +t m p s t r =xstrdup(step -> s t e p l a y o u t -> r g p u l i s t ); +tok =s t r t o k (tmp str ,","); +while (tok != NULL) { +sprintf(aux ," RCUDA_DEVICE_ %i",rgpuCount); +e n v a r r a y o v e r w r i t e f m t (dest ,aux ," %s",tok ); +rgpuCount++; +tok =s t r t o k (NULL,","); + } +e n v a r r a y o v e r w r i t e f m t (dest ," RCUDA_DEVICE_COUNT "," %i",rgpuCount ); + } e l s e { +/* WRITING CUDA PATH IN LD_LIBRARY_PATH */ +char *envvar cuda; +envvar cuda =getenv(" CUDAPATH "); + +i f (envvar cuda == NULL) +x s t r c a t (envvar cuda ,"/ usr / local / cuda/ lib64 :/ usr / local / cuda/lib "); + +i f (envvar library == NULL) +xstrfmtcat(s t r ," %s",envvar cuda); +e l s e +xstrfmtcat(s t r ," %s: %s",env var cuda ,envvar library); + } +e n v a r r a y o v e r w r i t e f m t (dest ," LD_LIBRARY_PATH "," %s",str); +x f r e e (str); + i f (c l u s t e r f l a g s &CLUSTER FLAG BG) { char geo char[HIGHEST DIMENSIONS+1]; --- slurm -2.6.2/ src/common/g r e s .c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/common/g r e s .c2014 -07 -17 17:12:40.908858623 +0200 @@ -83 ,6 +83 ,7 @@ #include " src / common / xmalloc .h" #include " src / common / xstring .h" #include " src / common / read_config .h" +# include " job_resources .h" #d e f i n e GRES MAGIC 0x438a34d4 @@ -635 ,6 +636 ,8 @@ {" Count ",S P STRING}, /* Number of Gres available */ {"CPUs " ,S P STRING}, /* CPUs to bind to Gres resource */ {"File ",S P STRING}, /* Path to Gres device */ + {"Cuda",S P STRING}, + {"Mem" ,S P STRING}, {NULL} }; int i; @@ -695 ,8 +698 ,6 @@ }e l s e i f (p-> count == 0) p-> count = 1; -s p h a s h t b l d e s t r o y (t b l ); - for (i=0; i<g r e s c o n t e x t c n t ;i++) { i f (strcasecmp(value ,gres context[i]. gres name ) == 0) break; @@ -706 ,6 +707 ,49 @@ destroy gres slurmd conf(p); Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 80 return 0; } + +i f (gres context[i]. plugin id==1970300786) { +/* Parsering Cuda Capability Version and GPU Memory */ +i f (s p get string(& tmp str ," Cuda ",t b l )) { +char *tok =NULL; +int ver1 ,ver2 ; +tok =s t r t o k (tmp str ,"."); +ver1 =atoi(t ok ); +i f (ver1 <1) +fatal(" Invalid gres data for %s, Cuda Major not allowed , Cuda Capabily= %s",p->name,t m p s t r ); +tok =s t r t o k (NULL,""); +ver2 =atoi(t ok ); +i f (ver2 <0) +fatal(" Invalid gres data for %s, Cuda Minor not allowed , Cuda Capabily= %s",p->name,t m p s t r ); +x f r e e (t m p s t r ); +p-> cc version =ver1 * 1000 + ver2 * 10; + } e l s e +fatal(" Invalid gres data for %s, Cuda Capability does not specified in gres.conf ",p->name); + +i f (s p get string(& tmp str ," Mem" ,t b l )) { +tmp long =strtol(tmp str , & last , 10) ; +i f (( tmp long ==LONG MIN)||( tmp long==LONG MAX)) { +fatal(" Invalid gres data for %s, Count= %s" ,p->name , +t m p s t r ); + } +i f (( l a s t [0]== ’k’) ||( l a s t [0]== ’K’)) +tmp long *= 1024; +e l s e i f (( l a s t [0]== ’m’) ||( l a s t [0]== ’M ’)) +tmp long *= (1024*1024) ; +e l s e i f (( l a s t [0]== ’g’) ||( l a s t [0]== ’G ’)) +tmp long *= (1024*1024*1024); +e l s e {// if ( last [0] != ’\0 ’) { +fatal(" Invalid gres data for %s, Mem= %s",p->name, +t m p s t r ); + } +p->mem =tmp long; +x f r e e (t m p s t r ); + } e l s e +fatal(" Invalid gres data for %s, RGPU Memory does not specified in gres.conf ",p->name); + } + +s p h a s h t b l d e s t r o y (t b l ); + p-> plugin id =gres context[i]. plugin id; *dest = ( void *)p; return 1; @@ -903 ,6 +947 ,10 @@ pack32(gres slurmd conf -> cpu cnt ,buffer); pack8(gres slurmd conf -> h a s f i l e ,buffer); pack32(gres slurmd conf -> plugin id ,buffer); +i f (gres slurmd conf -> plugin id==1970300786) { +pack32(gres slurmd conf -> cc version ,buffer); +pack64(gres slurmd conf ->mem,buffer); + } packstr(gres slurmd conf -> cpus ,buffer); packstr(gres slurmd conf ->name,buffer); } @@ -921 ,7 +969 ,8 @@ extern i n t gres plugin node config unpack(Buf b u f f e r ,char *node name ) { int i,j,r c ; -u i n t 3 2 t count ,cpu cnt ,magic ,plugin id ,utmp32; +u i n t 6 4 t mem; SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 81 +u i n t 3 2 t count ,cpu cnt ,magic ,plugin id ,utmp32,c c v e r ; u i n t 1 6 t r e c c n t ,v e r s i o n ; u i n t 8 t h a s f i l e ; char *tmp cpus , *tmp name; @@ -948 ,6 +997 ,10 @@ sa f e u n pa c k 32 (& cpu cnt ,buffer); safe unpack8(& h a s f i l e ,buffer); sa f e u n pa c k 32 (& plugin id ,buffer); +i f (plugin id==1970300786) { +sa f e u n pa c k 32 (& c c v e r ,buffer); +sa f e u n pa c k 64 (&mem,buffer); + } safe unpackstr xmalloc(& tmp cpus , &utmp32,buffer); safe unpackstr xmalloc(& tmp name , &utmp32,buffer); @@ -998 ,6 +1051 ,10 @@ tmp cpus =NULL;/* Nothing left to xfree */ p->name =tmp name;/* We need to preserve for accounting ! */ p-> plugin id =plugin id; +i f (plugin id==1970300786) { +p-> cc version =c c v e r ; +p->mem =mem; + } list append(g r e s c o n f l i s t ,p); } slurm mutex unlock(& gres context lock); @@ -1033 ,6 +1090 ,13 @@ x f r e e (gres node ptr -> topo gres bitmap); x f r e e (gres node ptr -> t o p o g r e s c n t a l l o c ); x f r e e (gres node ptr -> topo gres cnt avail); +// debug (" RCUDA freeing cc_version , mem_rgpu_avail , mem_rgpu_alloc ..."); +i f (gres node ptr -> cc version) +x f r e e (gres node ptr -> cc version); +i f (gres node ptr -> mem rgpu avail) +x f r e e (gres node ptr -> mem rgpu avail); +i f (gres node ptr -> mem rgpu alloc) +x f r e e (gres node ptr -> mem rgpu alloc); x f r e e (gres node ptr); x f r e e (g r e s p t r ); } @@ -1448 ,6 +1512 ,58 @@ return r c ; } +/* Built the rgpu list of the node */ +extern i n t rgpu node config validate(g r e s s t a t e t *g r e s p t r ) +{ +int i,r c =SLURM SUCCESS; +boo l cc =true ,a l l o c =true ,avail=t r u e ; +g r e s n o d e s t a t e t *gres data; +ListIterator iter; +g r e s s l u r m d c o n f t *gres slurmd conf; + +gres data = ( g r e s n o d e s t a t e t *) g r e s p t r -> gres data; + +// debug ("\ n ") ; +// debug2 (" RCUDA %s( %s, %d) - - gres_data -> gres_cnt_found : %i", __FILE__ , __func__ , __LINE__ , gres_data -> gres_cnt_found ); +i f (! g r e s d a t a -> cc version) { +cc =false; +g r e s d a t a -> cc version =xrealloc(g r e s d a t a -> cc version ,g r e s d a t a -> g r e s c n t f o u n d *s i z e o f (u i n t 3 2 t )); +i f (g r e s d a t a -> cc version == NULL) +fatal(" xrealloc : malloc failure - gres_data -> cc_version "); + } +i f (! g r e s d a t a -> mem rgpu alloc) { +a l l o c =false; +g r e s d a t a -> mem rgpu alloc =xrealloc(g r e s d a t a -> mem rgpu alloc , g r e s d a t a -> g r e s c n t f o u n d *sizeof(u i n t 6 4 t )); +i f (g r e s d a t a -> mem rgpu alloc == NULL) Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 82 +fatal(" xrealloc : malloc failure - gres_data -> mem_rgpu_alloc "); + } +i f (! g r e s d a t a -> mem rgpu avail) { +avail =false; +g r e s d a t a -> mem rgpu avail =xrealloc(g r e s d a t a -> mem rgpu avail , g r e s d a t a -> g r e s c n t f o u n d *sizeof(u i n t 6 4 t )); +i f (g r e s d a t a -> mem rgpu avail == NULL) +fatal(" xrealloc : malloc failure - gres_data -> mem_rgpu_avail "); + } +i t e r =list iterator create(gres conf list); +i f (i t e r ==NULL) +fatal(" list_iterator_create : malloc failure "); +i= 0; +while (( gres slurmd conf = ( g r e s s l u r m d c o n f t *) l i s t n e x t (i t e r ))) { +i f (gres slurmd conf -> plugin id!=1970300786) +continue; +i f (! cc ) +g r e s d a t a -> cc version[i] = gres slurmd conf -> cc version; +i f (! a l l o c ) +g r e s d a t a -> mem rgpu alloc[i] = 0LLU; +i f (! avail) +g r e s d a t a -> mem rgpu avail[i] = gres slurmd conf ->mem; +// debug ("\ tRCUDA %s( %s, %d) - - gres_data -> mem_rgpu_alloc [ %i]: %lu ", __FILE__ , __func__ , __LINE__ , i, gres_data -> mem_rgpu_alloc [i]) ; +i++; + } +// debug ("\ n ") ; +l i s t i t e r a t o r d e s t r o y (i t e r ); +return r c ; +} + /* * Validate a node ’s configuration and put a gres record onto a list * Called immediately after gres_plugin_node_config_unpack () . @@ -1467 ,7 +1583 ,7 @@ uint16_t fast_schedule , char ** reason_down ) { - int i , rc , rc2 ; + int i , rc , rc2 , rc3 ; ListIterator gres_iter ; gres_state_t * gres_ptr ; @@ -1493 ,6 +1609 ,10 @@ rc2 = _node_config_validate ( node_name , orig_config , new_config , gres_ptr , fast_schedule , reason_down , & gres_context [i]) ; + if ( gres_context [i]. plugin_id ==1970300786) { + rc3 = _rgpu_node_config_validate ( gres_ptr ); + rc2 = MAX ( rc2 , rc3 ) ; + } rc = MAX ( rc , rc2 ) ; } slurm_mutex_unlock (& gres_context_lock ); @@ -1751 ,6 +1871 ,72 @@ new_gres->gres_cnt_alloc = gres_ptr->gres_cnt_alloc; if ( gres_ptr - > gres_bit_alloc ) new_gres -> gres_bit_alloc = bit_copy (gres_ptr -> gres_bit_alloc ); + + if ( gres_ptr -> topo_cnt == 0) + return new_gres ; + + new_gres -> topo_cnt = gres_ptr -> topo_cnt ; + new_gres -> topo_cpus_bitmap = xmalloc ( gres_ptr -> topo_cnt * + sizeof ( bitstr_t *) ); + new_gres -> topo_gres_bitmap = xmalloc ( gres_ptr -> topo_cnt * + sizeof ( bitstr_t *) ); + new_gres -> topo_gres_cnt_alloc = xmalloc ( gres_ptr -> topo_cnt * SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 83 + sizeof ( uint32_t )); + new_gres -> topo_gres_cnt_avail = xmalloc ( gres_ptr -> topo_cnt * + sizeof ( uint32_t )); + for ( i =0; i < gres_ptr - > topo_cnt ; i ++) { + new_gres -> topo_cpus_bitmap [i] = + bit_copy ( gres_ptr -> topo_cpus_bitmap [i]); + new_gres -> topo_gres_bitmap [i] = + bit_copy ( gres_ptr -> topo_gres_bitmap [i]); + new_gres -> topo_gres_cnt_alloc [i] = + gres_ptr -> topo_gres_cnt_alloc [i ]; + new_gres -> topo_gres_cnt_avail [i] = + gres_ptr -> topo_gres_cnt_avail [i ]; + } + return new_gres ; +} + + static void * _rgpu_node_state_dup (void * gres_data ) +{ + int i; + gres_node_state_t * gres_ptr = ( gres_node_state_t *) gres_data ; + gres_node_state_t * new_gres ; + + if ( gres_ptr == NULL ) + return NULL ; + + if ( gres_ptr -> mem_rgpu_avail == NULL ) + return NULL ; + + new_gres = xmalloc ( sizeof ( gres_node_state_t )); + new_gres -> gres_cnt_found = gres_ptr -> gres_cnt_found ; + new_gres -> gres_cnt_config = gres_ptr -> gres_cnt_config ; + new_gres -> gres_cnt_avail = gres_ptr -> gres_cnt_avail ; + new_gres -> gres_cnt_alloc = gres_ptr -> gres_cnt_alloc ; + if ( gres_ptr -> gres_bit_alloc ) + new_gres -> gres_bit_alloc = bit_copy (gres_ptr -> gres_bit_alloc ); + // debug ("\ n ") ; + // debug2 (" RCUDA %s( %s, %d) - - gres_ptr -> gres_cnt_avail: %i", __FILE__ , __func__ , __LINE__ , gres_ptr -> gres_cnt_avail ); + if ( gres_ptr -> gres_cnt_avail > 0) { + xassert ( gres_ptr - > mem_rgpu_avail ); + xassert ( gres_ptr - > mem_rgpu_alloc ); + xassert ( gres_ptr - > cc_version ) ; + + new_gres -> cc_version = xmalloc ( gres_ptr -> gres_cnt_avail * sizeof ( uint32_t)); + new_gres -> mem_rgpu_alloc = xmalloc ( gres_ptr -> gres_cnt_avail * sizeof ( uint64_t)); + new_gres -> mem_rgpu_avail = xmalloc ( gres_ptr -> gres_cnt_avail * sizeof ( uint64_t)); + for (i = 0; i < gres_ptr -> gres_cnt_avail ; i ++) { + // debug ("\ tRCUDA %s( %s, %d) - - dup before : i= %i gres_ptr -> mem_rgpu_alloc [i]= %lu new_gres -> mem_rgpu_alloc [i]= % lu ", __FILE__ , __func__ , __LINE__ , i, gres_ptr -> mem_rgpu_alloc [i], new_gres -> mem_rgpu_alloc [i ]); + // debug ("\ tRCUDA %s( %s, %d) - - dup before : i= %i gres_ptr -> mem_rgpu_alloc [i]= %lu gres_ptr -> mem_rgpu_avail [i]= % lu gres_ptr -> cc_version [i]= % lu \n", __FILE__ , __func__ , __LINE__ , i, gres_ptr -> mem_rgpu_alloc [i], gres_ptr -> mem_rgpu_avail [i], gres_ptr -> cc_version [i]); + new_gres -> cc_version [i] = gres_ptr -> cc_version [i]; + new_gres -> mem_rgpu_alloc [i] = gres_ptr -> mem_rgpu_alloc [i ]; + new_gres -> mem_rgpu_avail [i] = gres_ptr -> mem_rgpu_avail [i ]; + // debug ("\ tRCUDA %s( %s, %d) - - dub after : i= %i gres_ptr -> mem_rgpu_alloc [i]= %lu new_gres -> mem_rgpu_alloc [i]= % lu ", __FILE__ , __func__ , __LINE__ , i, gres_ptr -> mem_rgpu_alloc [i], new_gres -> mem_rgpu_alloc [i ]); + + } + } + // debug ("\ n ") ; if ( gres_ptr - > topo_cnt == 0) return new_gres ; Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 84 @@ -1803 ,7 +1989 ,10 @@ for ( i =0; i < g res_context_cnt ; i ++) { if ( gres_ptr - > plugin_id != gres_context [i]. plugin_id ) continue; - gres_data = _node_state_dup ( gres_ptr - > gres_data ); + if ( gres_ptr -> plugin_id ==1970300786) + gres_data = _rgpu_node_state_dup ( gres_ptr -> gres_data); + else + gres_data = _node_state_dup (gres_ptr -> gres_data ); if ( gres_data ) { new_gres = xmalloc ( sizeof ( gres_state_t )); new_gres -> plugin_id = gres_ptr -> plugin_id ; @@ -1819 ,7 +2008 ,7 @@ } list_iterator_destroy ( gres_iter ); slurm_mutex_unlock (& gres_context_lock ); - + return new_list ; } @@ -3755 ,6 +3944 ,11 @@ rc2 = ESLURM_INVALID_GRES; continue; } + if ( list_count ( job_gres_list ) ==0) { + info (" step %u. %u has gres spec , job has not null but none ", + job_id , step_id ); + continue; + } /* Now make sure the step ’s request isn ’t too big for * the job ’s gres allocation */ job gres iter =list iterator create(j o b g r e s l i s t ); @@ -4820 ,3 +5014 ,1196 @@ } slurm mutex unlock(& gres context lock); } + +/* **************************** RCUDA ***************************************** */ + +static int validate rgpu data(char *tok ,u i n t 6 4 t *res){ +char *la st n u m =NULL; +u i n t 6 4 t cn t =strtol(tok , & last num , 10) ; +i f (s t r l e n (l a st num ) >1) +return SLURM ERROR; +e l s e i f (l a st num [0]== ’ \0 ’) + ; +e l s e i f (( las t n u m [0]== ’k ’)||( la s t n um [0]== ’K’)) +cnt *= 1024; +e l s e i f (( las t n u m [0]== ’m ’)||( la s t n um [0]== ’M’)) +cnt *= (1024*1024) ; +e l s e i f (( las t n u m [0]== ’g ’)||( la s t n um [0]== ’G’)) +cnt *= (1024*1024*1024); +e l s e +return SLURM ERROR; +i f (cnt <0) +return SLURM ERROR; + * res = ( u i n t 6 4 t )cnt; +return SLURM SUCCESS; +} + +static int validate compute capability(char *tok ,int tok size ,u i n t 3 2 t *res){ + +char l a s t ,next last; +char *minor v , *aux; +int major ,minor; +u i n t 3 2 t v e r s i o n = 0; + SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 85 +i f (tok size < 5){ +e r r o r (" _validate_compute_capability : some character missing ( detected only %i in %s)",tok size ,tok ); +return SLURM ERROR; + } +l a s t =tok [tok size -1]; +next last =t ok [tok size -2]; +i f (( l a s t == ’c’ || l a s t == ’C ’) && ( next last == ’c’ || next last == ’C’)) { +// cutting the string after testing that it is a correct request +tok [tok size -2] = ’\0 ’; +// major = strtok_r (tok , "." , & minor ); +major =strtol(tok , & minor v , 10) ; +minor =strtol(m inor v +s i z e o f (char ), &aux , 10) ; +v e r s i o n =major *1000 + minor*10; + } e l s e +return SLURM ERROR; + + * res =v e r s i o n ; +return SLURM SUCCESS; +} + +/* + * The same function as _job_config_validate () , but with the capability + * of processing rgpu jobs . This function is supossed to parser the + * quantity of rgpus and the memory requested , besides the usual + * gres parsering carried out by _job_config_validate () + */ +static int job config validate 2(char *co n f i g ,u i n t 3 2 t *g r e s c n t , +slurm gres context t *context ptr , +u i n t 6 4 t *mem cnt,u i n t 3 2 t *com cap ) +{ +char *la st n u m =NULL, * l a s t =NULL, * tmp str , * to k ; +int n t ok s ,rc ,s i z e ; +u i n t 3 2 t cc = 0; +u i n t 6 4 t cnt ,cnt mem = 0; +char *toks[3]; +char end; + +i f (! strcmp(c o n f i g ,context ptr -> gres name )) { +cnt = 1; + } e l s e i f (! strncmp(c o n f i g ,context ptr -> gres name colon , +context ptr -> g r e s n a m e c o l o n l e n )) { +i f (context ptr -> plugin id==1970300786) { +t m p s t r =xstrdup(config); +tok =strtok r(tmp str ,":", & l a s t ); +// tok == rgpu +tok =strtok r(NULL,":", & l a s t ); +n toks=0; +while(t ok ) { +toks[n t o k s ++] = xstrdup(tok ); +tok =strtok r(NULL,":", & l a s t ); + } + +i f (n toks > 3) +return SLURM ERROR; + +i f (n toks > 1){ +// strtol ( toks [ n_toks -1] , & last_num , 10) ; +s i z e =s t r l e n (toks[n t o ks -1]); +end =toks[n to ks -1][ s i z e -1]; +// testing the last character of the last tok +i f (( end == ’c’)||( end == ’C’)){ +// the tok is likely to be the compute capability +r c =validate compute capability(toks[ n t ok s -1] , s i z e , & cc ); +i f (r c == SLURM ERROR) +return SLURM ERROR; +i f (n toks == 3) { Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 86 +r c =validate rgpu data(toks[1] , & cnt mem); +i f (r c == SLURM ERROR) +return SLURM ERROR; + + } + } e l s e { +i f (n toks == 2){ +// if the ending is not "c", it should be the memory tok +r c =validate rgpu data(toks[1] , & cnt mem); +i f (r c == SLURM ERROR) +return SLURM ERROR; + + } e l s e +return SLURM ERROR; + } + } +r c =validate rgpu data(toks[0] , & cnt); +i f (r c == SLURM ERROR) +return SLURM ERROR; + }// rgpu plugin +e l s e {// normal plugin +config += context ptr -> g r e s n a m e c o l o n l e n ; +cnt =strtol(c o n f i g , & last num , 10) ; +i f (la s t n um [0]== ’\0 ’) + ; +e l s e i f (( las t n u m [0]== ’k ’)||( la s t n um [0]== ’K’)) +cnt *= 1024; +e l s e i f (( las t n u m [0]== ’m ’)||( la s t n um [0]== ’M’)) +cnt *= (1024*1024) ; +e l s e i f (( las t n u m [0]== ’g ’)||( la s t n um [0]== ’G’)) +cnt *= (1024*1024*1024); +e l s e +return SLURM ERROR; +i f (cnt <0) +return SLURM ERROR; + } + } e l s e +return SLURM ERROR; + + * g r e s c n t = ( u i n t 3 2 t )cnt; + *mem cnt = ( u i n t 6 4 t )cnt mem; + * com cap = ( u i n t 3 2 t )cc ; +return SLURM SUCCESS; +} + +/* + * The same function as _job_state_validate () , but with the capability + * of parsering the memory required . + */ +static int j o b s t a t e v a l i d a t e 2 (char *c o n f i g ,void ** g r e s d a t a , +slurm gres context t *context ptr) +{ +int r c ; +u i n t 3 2 t g r e s c n t ,com cap ; +u i n t 6 4 t mem cnt; + + +r c =job config validate 2(c o n f i g , & g r e s c n t ,context ptr , &mem cnt, & com cap ); +i f (( r c ==SLURM SUCCESS) && ( g r e s c n t >0) ) { +g r e s j o b s t a t e t *g r e s p t r ; +g r e s p t r =x ma ll oc (sizeof(g r e s j o b s t a t e t )); +g r e s p t r -> g r e s c n t a l l o c =g r e s c n t ; + +g r e s p t r -> rgpu cnt mem =mem cnt; + * gres data =g r e s p t r ; + } e l s e SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 87 + * gres data =NULL; +return r c ; +} + +/* + * The same function as gres_plugin_job_state_validate () , but isolating + * the rgpu processing , which will be carried out in + * gres_rgpu_job_state_validate(). + * Given a job ’s requested gres configuration , validate it and build + * a gres list and special strings for the rgpu management . + * IN req_config - job request ’s gres input string + * OUT gres_list - List of Gres records for this job to track usage + * OUT rgpu_req - job request of rgpus , string + * OUT new_req - job request of gres ( no rgpu ), string + * RET SLURM_SUCCESS or ESLURM_INVALID_GRES + */ +extern i n t gres plugin job state validate 2(char *req config ,L i s t *g r e s l i s t , +char ** rgpu req ,char ** new req ) +{ +char *tmp str , * tok , * l a s t =NULL; +int i,rc ,rc2; +g r e s s t a t e t *g r e s p t r ; +void *j o b g r e s d a t a ; + +i f (( req config==NULL) ||( req config[0]== ’ \0 ’)) { + * g r e s l i s t =NULL; +return SLURM SUCCESS; + } + +i f (( r c =gres plugin init() )!=SLURM SUCCESS) +return r c ; + +slurm mutex lock(& gres context lock); +t m p s t r =xstrdup(req config); +tok =strtok r(tmp str ,",", & l a s t ); +while (tok &&( r c ==SLURM SUCCESS)) { +rc2 =SLURM ERROR; +for (i= 0; i<g r e s c o n t e x t c n t ;i++) { +rc2 =j o b s t a t e v a l i d a t e 2 (tok , & j o b g r e s d a t a , + & gres context[i]) ; +i f (( rc2!=SLURM SUCCESS) ||( j o b g r e s d a t a ==NULL)) +continue; +i f (gres context[i]. plugin id==1970300786) { + * r g p u r e q =xstrdup(t ok ); +debug3(" sched : job_create : gres %s found for this job" , * r g p u r e q ); +break; + } +i f (* g r e s l i s t ==NULL) { + * g r e s l i s t =l i s t c r e a t e (gres job list delete); +i f (* g r e s l i s t ==NULL) +fatal(" list_create malloc failure "); + } +// rewrite string req_config +i f (!* new req ) + * new req =xmalloc (2048); +e l s e { +x s t r c a t (* new req ,","); + } +xstrfmtcat(* new req ," %s" ,tok ); +// +g r e s p t r =x ma ll oc (s i z e o f (g r e s s t a t e t )); +g r e s p t r -> plugin id =gres context[i]. plugin id; +g r e s p t r -> gres data =j o b g r e s d a t a ; +list append(* g r e s l i s t ,g r e s p t r ); +break;/* processed it */ + } +i f (rc2!=SLURM SUCCESS) { +i n f o (" Invalid gres job specification %s" ,tok ); +r c =ESLURM INVALID GRES; Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 94 +job gres ptr -> rgpu mem alloc[n o d e o f f s e t ][ i] = job mem req; +// xassert ( node_gres_ptr -> mem_rgpu_alloc [i] > 0) ; +/* + debug (" RCUDA_ALLOC (2/2) %i ( %s) Node: %s GPU: %i Mem_Job : %lu " + " Mem_Free : %lu Mem_Alloc : %lu Mem_total : %lu Position_array:%p Position_array[i]:%p", + job_id , str_time , node_name , i, job_mem_req , + node_gres_ptr -> mem_rgpu_avail [i] - node_gres_ptr -> mem_rgpu_alloc[i], + node_gres_ptr -> mem_rgpu_alloc [i], node_gres_ptr -> mem_rgpu_avail[i], + ( void *) ( node_gres_ptr -> mem_rgpu_alloc ), + ( void *) (& node_gres_ptr -> mem_rgpu_alloc [i ]) ); + */ +/* if rgpu is full , set the bit */ +i f (node gres ptr -> mem rgpu alloc[i] == node gres ptr -> mem rgpu avail[i]){ +node gres ptr -> g r e s c n t a l l o c ++; +b i t s e t (node gres ptr -> gres bit alloc ,i); + } +/* set the bit in the job ’s bitmap */ +b i t s e t (job gres ptr -> g r e s b i t a l l o c [n o d e o f f s e t ], i); + * rgpus remaining -= 1; + } + } +return SLURM SUCCESS; +} + +/* + * Allocate rgpus to a job and update node and job rgpus information + * IN job_gres_status - information about the rgpus of the job + * IN node_gres_list - node ’s rgpu list built by + * gres_plugin_node_config_validate() -> + * _rgpu_node_config_validate() + * IN node_offset - zero - origin index to the node of interest + * IN job_id - job ’s ID ( for logging ) + * IN node_name - name of the node ( for logging ) + * IN / OUT rgpus_remaining - number of RGPUs that still have not + * been allocated + * IN node_cnt - total number of nodes originally + * allocated to the job + * RET SLURM_SUCCESS or error code + */ +extern i n t g r e s r g p u j o b a l l o c (s t r u c t j o b r e s o u r c e s *job ,L i s t n o d e g r e s l i s t , +int node offset ,u i n t 3 2 t j o b i d ,char *node name , +u i n t 3 2 t *rgpus remaining) +{ +int i,rc ,rc2; +L i s t I t e r a t o r n o d e g r e s i t e r ; +g r e s s t a t e t *job gres ptr , * n o d e g r e s p t r ; +job gres ptr = ( g r e s s t a t e t *) job -> r g p u j o b s t a t e ; +u i n t 3 2 t n ode cnt =b i t s e t c o u n t (job -> rgp u node bi tm ap ); + +b ool p l u g i n f o u n d =false; + +i f (job gres ptr==NULL) +return SLURM SUCCESS; +i f (n o d e g r e s l i s t ==NULL) { +e r r o r (" gres_job_alloc : job %u has gres specification while " +" node %s has none ",j o b i d ,node name); +return SLURM ERROR; + } + +r c =gres plugin init(); + +slurm mutex lock(& gres context lock); SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 95 + +i f (job gres ptr -> plugin id==1970300786) { +p l u g i n f o u n d =t r u e ; + } e l s e +e r r o r (" gres_rgpu_job_alloc : no rgpu plugin configured " +"for data type %u for job %u and node %s" , +job gres ptr -> plugin id ,j o b i d ,node name); + +for (i= 0; i<g r e s c o n t e x t c n t ;i++) { +i f (j o b g r e s p t r -> plugin id== +gres context[i]. plugin id) +break; + } +i f (i>= g r e s c o n t e x t c n t ) { +e r r o r (" gres_rgpu_job_alloc : no plugin configured " +"for data type %u for job %u and node %s", +job gres ptr -> plugin id ,j o b i d ,node name); +/* A likely sign that GresPlugins has changed */ + } + +node gres iter =list iterator create(n o d e g r e s l i s t ); +while (( node gres ptr = ( g r e s s t a t e t *) +l i s t n e x t (node gres iter))) { +i f (j o b g r e s p t r -> plugin id== node gres ptr -> plugin id) +break; + } +l i s t i t e r a t o r d e s t r o y (node gres iter); +i f (n o d e g r e s p t r ==NULL) { +e r r o r (" gres_rgpu_job_alloc : job %u allocated gres/ %s " +"on node %s lacking that gres ", +j o b i d ,gres context[i]. gres name ,node name); + } +rc2 =rgpu job alloc(job ,job gres ptr -> g r e s d a t a , +node gres ptr -> g r e s d a t a ,node cnt , +node offset ,j o b i d ,node name ,rgpus remaining); +i f (rc2!=SLURM SUCCESS) +r c =rc2; + +slurm mutex unlock(& gres context lock); + +return r c ; +} + +/* Deallocate every single rgpu allocated in this node by this job */ +static int rgpu job dealloc(void *j o b g r e s d a t a ,void *n o d e g r e s d a t a , +int node offset ,u i n t 3 2 t j o b i d ,char *node name ) +{ +// debug2 (" RCUDA_DEALLOC job: %i ( pid: %d - thread: %u): %s( %s, %d)", job_id , getpid () , ( unsigned int) pthread_self () , __FILE__ , __func__ , __LINE__ ); +int i,len ,len2 ,g r e s c n t ; +g r e s j o b s t a t e t *job gres ptr = ( g r e s j o b s t a t e t *) j o b g r e s d a t a ; +g r e s n o d e s t a t e t *n o d e g r e s p t r = ( g r e s n o d e s t a t e t *) n o d e g r e s d a t a ; + +char *gres name ="rgpu"; +/* calcular fecha actual + struct tm * tm ; + time_t t; + char str_time [100]; + */ + +/* + * Validate data structures . Either job_gres_data -> node_cnt and + * job_gres_data - > gres_bit_alloc are both set or both zero / NULL . + */ +xassert(node offset >=0); +xassert(job gres ptr); +xassert(node gres ptr); +i f (job gres ptr -> node cnt <= n o d e o f f s e t ) { +e r r o r (" gres/ %s: job %u dealloc of node %s bad node_offset %d " +" count is %u" ,gres name ,j o b i d ,node name ,node offset , Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 96 +job gres ptr -> nod e c nt ); +return SLURM ERROR; + } + +i f (node gres ptr -> g r e s b i t a l l o c && j o b g r e s p t r -> g r e s b i t a l l o c && +job gres ptr -> g r e s b i t a l l o c [n o d e o f f s e t ]) { +len =b i t s i z e (job gres ptr -> g r e s b i t a l l o c [n o d e o f f s e t ]); +len2 =b i t s i z e (node gres ptr -> g r e s b i t a l l o c ); +i f (len2 != len) { +e r r o r (" gres/ %s: job %u and node %s bitmap sizes differ " +"( %d != %d)",gres name ,j o b i d ,node name ,len , len2 ); +len =MIN(len ,len 2 ); + } + +for (i= 0; i<len;i++) { +i f (! b i t t e s t (j o b g r e s p t r -> g r e s b i t a l l o c [n o d e o f f s e t ], i) ) +continue; +/* + t = time ( NULL ) ; + tm = localtime (&t); + strftime ( str_time , sizeof ( str_time ), " %H: %M: %S", tm ); + debug (" len2= %i, len= %i, found= %i , i= %i, node_offset = %i", len2 , len , node_gres_ptr -> gres_cnt_found , i , node_offset ); + */ +debug(" RCUDA_DEALLOC %i - Node( %i): %s GPU: %i Mem_Job: %lu " +" Mem_Alloc: %lu Mem_total: %lu", +j o b i d ,node offset ,node name ,i, +job gres ptr -> rgpu mem alloc[n o d e o f f s e t ][ i], +node gres ptr -> mem rgpu alloc[i], +node gres ptr -> mem rgpu avail[i]) ; +/* debug (" mem_rgpu_free: %lu , ( avail: %lu - alloc: %lu)", node_gres_ptr -> mem_rgpu_avail [i] - node_gres_ptr -> mem_rgpu_alloc [i], node_gres_ptr -> mem_rgpu_avail [i], node_gres_ptr -> mem_rgpu_alloc [i ]) ; + */ + +// xassert ( node_gres_ptr -> mem_rgpu_alloc ); +// xassert ( node_gres_ptr -> mem_rgpu_alloc [i] > 0) ; +node gres ptr -> mem rgpu alloc[i] -= job gres ptr -> rgpu mem alloc[n o d e o f f s e t ][ i]; +/* + debug (" RCUDA_DEALLOC (2/2) %i ( %s) Node: %s GPU: %i Mem_Job: % lu " + " Mem_Free : %lu Mem_Alloc : %lu Mem_total : %lu Position_array:%p Position_array[i]:%p", + job_id , str_time , node_name , i, + job_gres_ptr -> rgpu_mem_alloc [ node_offset ][ i], + node_gres_ptr -> mem_rgpu_avail [i] - node_gres_ptr -> mem_rgpu_alloc[i], + node_gres_ptr -> mem_rgpu_alloc [i], node_gres_ptr -> mem_rgpu_avail[i], + ( void *) ( node_gres_ptr -> mem_rgpu_alloc ), + ( void *) (& node_gres_ptr -> mem_rgpu_alloc [i ]) ); + */ +i f (node gres ptr -> mem rgpu alloc[i]==0) { +b i t c l e a r (node gres ptr -> gres bit alloc ,i); +node gres ptr -> gres cnt alloc - -; + } e l s e i f (node gres ptr -> mem rgpu alloc[i] <0) +e r r o r (" gres/ %s: job %u dealloc node %s gres " +" count underflow ",gres name ,j o b i d ,node name ); + } + } e l s e { +node gres ptr -> g r e s c n t a l l o c = 0; +e r r o r (" gres/ %s: job %u node %s gres count underflow" , +gres name ,j o b i d ,node name ); + } + +i f (job gres ptr -> g r e s b i t a l l o c && +job gres ptr -> g r e s b i t a l l o c [n o d e o f f s e t ]&& SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 97 +node gres ptr -> topo gres bitmap&& +node gres ptr -> t o p o g r e s c n t a l l o c ) { +for (i= 0; i<node gres ptr -> topo cnt;i++) { + +g r e s c n t =bit overlap(job gres ptr -> +g r e s b i t a l l o c [n o d e o f f s e t ], +node gres ptr -> +topo gres bitmap[i]); +node gres ptr -> t o p o g r e s c n t a l l o c [i] -= g r e s c n t ; + } + } +return SLURM SUCCESS; +} + +/* + * Deallocate rgpus from a job and update node and job rgpus information + * IN job_gres_status - information about the rgpus of the job + * IN node_gres_list - node ’s rgpu list built by + * gres_plugin_node_config_validate() -> + * _rgpu_node_config_validate () + * IN node_offset - zero - origin index to the node of interest + * IN job_id - job ’s ID ( for logging ) + * IN node_name - name of the node ( for logging ) + * RET SLURM_SUCCESS or error code + */ +extern i n t gres rgpu job dealloc(void *job gres status ,L i s t n o d e g r e s l i s t , +int node offset ,u i n t 3 2 t j o b i d ,char *node name ) +{ +int i,rc ,rc2; +L i s t I t e r a t o r n o d e g r e s i t e r ; +g r e s s t a t e t *job gres ptr , * n o d e g r e s p t r ; +char *gres name ="rgpu"; +job gres ptr = ( g r e s s t a t e t *) j o b g r e s s t a t u s ; + +i f (j o b g r e s s t a t u s ==NULL) { +return SLURM SUCCESS; + } +i f (n o d e g r e s l i s t ==NULL) { +e r r o r (" gres_job_dealloc : job %u has gres specification while " +" node %s has none ",j o b i d ,node name); +return SLURM ERROR; + } + +r c =gres plugin init(); + +slurm mutex lock(& gres context lock); +i f (job gres ptr -> plugin id!=1970300786) { +e r r o r (" gres_rgpu_job_dealloc : no plugin configured " +"for data type %u for job %u and node %s", +job gres ptr -> plugin id ,j o b i d ,node name); + } + +for (i= 0; i<g r e s c o n t e x t c n t ;i++) { +i f (j o b g r e s p t r -> plugin id== +gres context[i]. plugin id) +break; + } +i f (i>= g r e s c o n t e x t c n t ) { +e r r o r (" gres_plugin_job_dealloc : no plugin configured " +"for data type %u for job %u and node %s", +job gres ptr -> plugin id ,j o b i d ,node name); +/* A likely sign that GresPlugins has changed */ +gres name ="UNKNOWN"; + } +node gres iter =list iterator create(n o d e g r e s l i s t ); +while (( node gres ptr = ( g r e s s t a t e t *) +l i s t n e x t (node gres iter))) { +i f (j o b g r e s p t r -> plugin id== node gres ptr -> plugin id) +break; Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 98 + } +l i s t i t e r a t o r d e s t r o y (node gres iter); +i f (n o d e g r e s p t r ==NULL) { +e r r o r (" gres_rgpu_job_dealloc : node %s lacks gres/ %s " +"for job %u",node name ,gres name ,j o b i d ); + } + +rc2 =rgpu job dealloc(job gres ptr -> g r e s d a t a , +node gres ptr -> g r e s d a t a ,node offset ,j o b i d ,node name ); + +i f (rc2!=SLURM SUCCESS) +r c =rc2; + +slurm mutex unlock(& gres context lock); +return r c ; +} + +/* + * The same function as _step_state_validate () , but with the capability + * of parsering the memory required . Similar to the process of the + * job_state_validate () . + */ +static int s t e p s t a t e v a l i d a t e 2 (char *c o n f i g ,void ** g r e s d a t a , +slurm gres context t *context ptr) +{ +int r c ; +u i n t 3 2 t g r e s c n t ,com cap ; +u i n t 6 4 t mem cnt; + +r c =job config validate 2(c o n f i g , & g r e s c n t ,context ptr , &mem cnt, & com cap ); +i f (( r c ==SLURM SUCCESS) && ( g r e s c n t >0) ) { +g r e s s t e p s t a t e t *g r e s p t r ; +g r e s p t r =x ma ll oc (sizeof(g r e s s t e p s t a t e t )); +g r e s p t r -> g r e s c n t a l l o c =g r e s c n t ; +g r e s p t r -> rgpu cnt mem =mem cnt; +g r e s p t r -> com cap =com cap ; + * gres data =g r e s p t r ; + } e l s e + * gres data =NULL; + +return r c ; +} + +/* + * The same function as gres_plugin_step_state_validate () , but isolating + * the rgpu processing , which will be carried out in + * gres_rgpu_step_state_validate(). + * Given a step ’s requested gres configuration , validate it and build + * a gres list and special strings for the rgpu management . + * This is a very similar method to the job_state_validate () , and the + * global idea is the same , but this is used for the steps of the job. + * IN req_config - step request ’s gres input string + * OUT step_gres_list - List of Gres records for this step to track usage + * IN job_gres_list - List of Gres records for this job + * IN job_id , step_id - ID of the step being allocated . + * RET SLURM_SUCCESS or ESLURM_INVALID_GRES + */ +extern i n t +gres plugin step state validate 2(char *req config , +L i s t *s t e p g r e s l i s t ,L i s t j o b g r e s l i s t , u i n t 3 2 t j o b i d , +u i n t 3 2 t s t e p i d ,char ** rgpu req ,char ** new req ) +{ +char *tmp str , * tok , * l a s t =NULL; +int i,rc ,rc2 ,rc3; +g r e s s t a t e t *step gres ptr , * job gres ptr; +void *step gres data , * j o b g r e s d a t a ; +L i s t I t e r a t o r j o b g r e s i t e r ; SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 99 + + * s t e p g r e s l i s t =NULL; +i f (( req config==NULL) ||( req config[0]== ’ \0 ’)) +return SLURM SUCCESS; + +i f (( r c =gres plugin init() )!=SLURM SUCCESS) +return r c ; + +slurm mutex lock(& gres context lock); +t m p s t r =xstrdup(req config); +tok =strtok r(tmp str ,",", & l a s t ); +while (tok &&( r c ==SLURM SUCCESS)) { +rc2 =SLURM ERROR; +for (i= 0; i<g r e s c o n t e x t c n t ;i++) { +rc2 =s t e p s t a t e v a l i d a t e 2 (tok , & step gres data , + & gres context[i]) ; +i f (( rc2!=SLURM SUCCESS) ||( s t e p g r e s d a t a ==NULL)) +continue; +i f (gres context[i]. plugin id==1970300786) { + * r g p u r e q =xstrdup(t ok ); +break; + } +i f (j o b g r e s l i s t ==NULL) { +i n f o (" step %u. %u has gres spec , job has none", +j o b i d ,s t e p i d ); +rc2 =ESLURM INVALID GRES; +continue; + } + +/* Now make sure the step ’s request isn ’t too big for + * the job ’s gres allocation */ +job gres iter =list iterator create(j o b g r e s l i s t ); +i f (job gres iter==NULL) +fatal(" list_iterator_create : malloc failure "); +while (( job gres ptr = ( g r e s s t a t e t *) +l i s t n e x t (job gres iter))) { +i f (job gres ptr -> plugin id== +gres context[i]. plugin id) +break; + } +l i s t i t e r a t o r d e s t r o y (job gres iter); +i f (job gres ptr==NULL) { +i n f o (" Step %u. %u gres request not in job " +" alloc %s",j o b i d ,s t e p i d ,t ok ); +r c =ESLURM INVALID GRES; +step state delete(s t e p g r e s d a t a ); +break; + } + +j o b g r e s d a t a =job gres ptr -> gres data; +rc3 =step test(step gres data ,j o b g r e s d a t a ,NO VAL, +true ,gres context[i]. gres name , +j o b i d ,s t e p i d ); +i f (rc3==0) { +i n f o (" Step %u. %u gres higher than in job " +" allocation %s",j o b i d ,s t e p i d ,to k ); +r c =ESLURM INVALID GRES; +step state delete(s t e p g r e s d a t a ); +break; + } + +i f (* s t e p g r e s l i s t ==NULL) { + * s t e p g r e s l i s t =l i s t c r e a t e ( +gres step list delete); +i f (* s t e p g r e s l i s t ==NULL) +fatal(" list_create malloc failure "); + } +// rewrite string req_config +i f (!* new req ) + * new req =xmalloc (2048); Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 100 +e l s e { +x s t r c a t (* new req ,","); + } +xstrfmtcat(* new req ," %s" ,tok ); +// +step gres ptr =xmalloc (sizeof(g r e s s t a t e t )); +step gres ptr -> plugin id =gres context[i]. plugin id; +step gres ptr -> gres data =s t e p g r e s d a t a ; +list append(* s t e p g r e s l i s t ,step gres ptr); +break;/* processed it */ + } +i f (rc2!=SLURM SUCCESS) { +i n f o (" Invalid gres step %u. %u specification %s" , +j o b i d ,s t e p i d ,t ok ); +r c =ESLURM INVALID GRES; +break; + } +tok =strtok r(NULL,",", & l a s t ); + } +slurm mutex unlock(& gres context lock); + +x f r e e (t m p s t r ); + +return r c ; +} + +/* + * Given a step ’s requested rgpus configuration , validate it and build + * a gres record . Quite similar to the original function + * gres_plugin_step_state_validate(), but only for the + * gres plugin gres / rgpu . + * OUT rgpu_gres - gres_state_t record for the rgpus of this step + * IN req_config - job request ’s gres input string + * IN job_rgpu - number of rgpu required by the step + * IN job_memrgpu - quantity of memory required by the step + * RET SLURM_SUCCESS or ESLURM_INVALID_GRES + */ +extern i n t +g r e s r g p u s t e p s t a t e v a l i d a t e (char *req config ,void ** r g p u g r e s , +u i n t 3 2 t j ob rgp u ,u i n t 6 4 t job memrgpu) +{ +char *t m p s t r ; +int i,rc ,rc2 =SLURM SUCCESS; +g r e s s t a t e t *step gres ptr; +void *s t e p g r e s d a t a ; +g r e s s t e p s t a t e t *aux; + +i f (( req config==NULL) ||( req config[0]== ’ \0 ’)) +return SLURM SUCCESS; + +i f (( r c =gres plugin init() )!=SLURM SUCCESS) +return r c ; + +slurm mutex lock(& gres context lock); +t m p s t r =xstrdup(req config); +for (i= 0; i<g r e s c o n t e x t c n t ;i++) { +rc2 =s t e p s t a t e v a l i d a t e 2 (tmp str , & step gres data , + & gres context[i]); +i f (( rc2!=SLURM SUCCESS) ||( s t e p g r e s d a t a ==NULL)) +continue; +i f (gres context[i]. plugin id==1970300786) { +aux = ( g r e s s t e p s t a t e t *) s t e p g r e s d a t a ; +i f (aux -> gres cnt alloc >j o b r g p u ) { +i n f o (" Invalid number of rgpus step specification"); +step state delete(s t e p g r e s d a t a ); +rc2 =ESLURM INVALID GRES; +break; + } e l s e i f (aux -> rgpu cnt mem >job memrgpu) { +i n f o (" Invalid quantity of memory of rgpu step specification "); SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 101 +step state delete(s t e p g r e s d a t a ); +rc2 =ESLURM INVALID GRES; +break; + } +// new in version issue016 , which allow to request x rgpus in y nodes (x*y rgpus) +aux -> g r e s c n t a l l o c =j o b r g p u ; +// +step gres ptr =xmalloc (sizeof(g r e s s t a t e t )); +step gres ptr -> plugin id =gres context[i]. plugin id; +step gres ptr -> gres data =s t e p g r e s d a t a ; + * r g p u g r e s =step gres ptr; +break;/* processed it */ + } + } +i f (rc2!=SLURM SUCCESS) { +// info (" Invalid gres step %u. %u specification %s", +// job_id , step_id , tok ) ; +r c =ESLURM INVALID GRES; + } +slurm mutex unlock(& gres context lock); +x f r e e (t m p s t r ); + +return r c ; +} + +/* + * Allocate resource rgpu to a step and update job and step + * rgpu information . + * IN step_rgpu_bitstr - step ’s rgpu record built by gres_rgpu_step_state_validate () + * IN job_rgpu_bitstr - job ’s rgpu record built by gres_rgpu_job_state_validate () + * IN job_id , step_id - ID of the step being allocated . + * OUT output - string with the rgpus allocated . + * RET SLURM_SUCCESS or error code + */ +extern i n t gres rgpu step alloc(void *st e p rg p u ,b i t s t r t *s t e p r g p u b i t s t r , +b i t s t r t *j o b r g p u b i t s t r ,char *rgpu list ,u i n t 3 2 t jo b i d , +u i n t 3 2 t s t e p i d ,char ** output) +{ +char *tmp str , * tok , * d e v l i s t ; +g r e s s t a t e t *step gres ptr; +g r e s s t e p s t a t e t *s t e p g r e s d a t a ; +int rem ai nin g ; +int i b i t ,i first ,i l a s t ; + +step gres ptr = ( g r e s s t a t e t *) s t e p r g p u ; +s t e p g r e s d a t a =step gres ptr -> gres data; + +/* Such as SALLOC works , the bits will be allocated if they are free. Anyway , + * if the number of requested bits is higher than the free bits , they will + * be selected again , no matter if they are already allocated . */ +i f i r s t = 0; +i l a s t =b i t s i z e (j o b r g p u b i t s t r ); +remaining =step gres data -> g r e s c n t a l l o c ; + +for (i b i t =i f i r s t ; ( i b i t <i l a s t ) && ( remaining >0); i b i t ++) { +i f (b i t t e s t (j o b r g p u b i t s t r ,i b i t )) +continue; +b i t s e t (j o b r g p u b i t s t r ,i b i t ); +b i t s e t (s t e p r g p u b i t s t r ,i b i t ); +rem ai nin g -= 1; + } +i f (remaining >0) { +for (i b i t =i f i r s t ; ( i b i t <i l a s t ) && ( remaining >0); i b i t ++) { +i f (b i t t e s t (s t e p r g p u b i t s t r ,i b i t )) +continue; +b i t s e t (j o b r g p u b i t s t r ,i b i t ); Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 102 +b i t s e t (s t e p r g p u b i t s t r ,i b i t ); +remaining -= 1; + } + } +i f (remaining >0) +e r r o r (" gres_rgpu_step_alloc : remaining: %d > 0 in job: %u step : %u" ,remaining ,j o b i d ,s t e p i d ); + +d e v l i s t =NULL; +t m p s t r =xstrdup(r g p u l i s t ); + +tok =s t r t o k (tmp str ,","); +for (i b i t = 0; ( i b i t <b i t s i z e (job rgpu bitstr)) && ( tok !=NULL); i b i t ++) { +i f (b i t t e s t (s t e p r g p u b i t s t r ,i b i t )) { +i f (! d e v l i s t ) +d e v l i s t =xmalloc (2048); +e l s e +x s t r c a t (d e v l i s t ," ,"); +x s t r c a t (d e v l i s t ,t ok ); + } +tok =s t r t o k (NULL,","); + } +x s t r c a t (d e v l i s t ," \0"); + * output =xstrdup(d e v l i s t ); +x f r e e (d e v l i s t ); +x f r e e (t m p s t r ); + +return SLURM SUCCESS; +} --- slurm -2.6.2/ src/common/g r e s .h2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/common/g r e s .h2014 -06 -25 09:59:56.033663932 +0200 @@ -53 ,6 +53 ,13 @@ GRES VAL TYPE ALLOC = 3 }; +/* gpu scheduling data */ +s t r u c t g pu d ata { +u i n t 3 2 t weight ;/* weight of the scheduling */ +u i n t 3 2 t n ode id ;/* node hosting the gpu */ +u i n t 3 2 t gp u i d ;/* id of the gpu in this node */ +}; + /* Gres state information gathered by slurmd daemon */ type def s t r u c t gres slurmd conf { /* Count of gres available in this configuration record */ @@ -71 ,6 +78 ,10 @@ /* Gres ID number */ u i n t 3 2 t p l u g i n i d ; + +/* rgpu specifications */ +u i n t 6 4 t mem; +u i n t 3 2 t c c v e r s i o n ; }g r e s s l u r m d c o n f t ; /* Current gres state information managed by slurmctld daemon */ @@ -95 ,6 +106 ,11 @@ b i t s t r t ** topo gres bitmap; u i n t 3 2 t *t o p o g r e s c n t a l l o c ; u i n t 3 2 t *topo gres cnt avail; + +/* Specific information ( if gres . conf contains RGPU resources ) */ +u i n t 6 4 t *mem rgpu alloc;/* memory allocated in each gpu */ +u i n t 6 4 t *mem rgpu avail;/* memory of each gpu */ +u i n t 3 2 t *cc version;/* version of each gpu */ }gres node state t; /* Gres job state as used by slurmctld daemon */ @@ -111 ,6 +127 ,16 @@ SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 103 *g r e s b i t s t e p a l l o c i s a s u b s e t of g r e s b i t a l l o c */ b i t s t r t ** g r e s b i t s t e p a l l o c ; u i n t 3 2 t *gres cnt step alloc; + +/* Quantity of memory requiered in every single rgpu */ +u i n t 6 4 t rgpu cnt mem; +/* For each rgpu in each node , this matrix will + * save the quantity of memory allocated by this + * job in each rgpu of the partition */ +u i n t 6 4 t ** rgpu mem alloc; +/* Minimum version of compute capability of the rgpus required . + * This value is got by : major * 1000 + minor * 10 */ +u i n t 3 2 t com cap ; }g r e s j o b s t a t e t ; /* Gres job step state as used by slurmctld daemon */ @@ -127 ,6 +153 ,9 @@ u i n t 3 2 t n ode cnt ; b i t s t r t *node in use; b i t s t r t ** g r e s b i t a l l o c ; + +u i n t 6 4 t rgpu cnt mem; +u i n t 3 2 t com cap ; }g r e s s t e p s t a t e t ; /* @@ -619 ,4 +648 ,64 @@ */ extern u i n t 3 2 t g r e s g e t v a l u e b y t y p e (L i s t j o b g r e s l i s t ,char *gres name ); + +/*************************** RCUDA ********************************************/ + + +extern i n t gres plugin job state validate 2(char *req config ,L i s t *g r e s l i s t , char ** rgpu req ,char ** new req ); + +extern i n t gres rgpu job state validate(char *req config ,void ** g r e s r g p u ); + +extern L i s t weight my gpus (int node id ,L i s t g r e s l i s t ,u i n t 6 4 t job mem); + +extern i n t g r e s r g p u j o b a l l o c i d (s t r u c t j o b r e s o u r c e s *job ,L i s t n o d e g r e s l i s t , +int node offset ,u i n t 3 2 t j o b i d ,char *node name , +u i n t 3 2 t *rg pus r e mai n in g ,u i n t 3 2 t gpu id ); +/* + * Allocate rgpus to a job and update node and job rgpus information + * IN job_gres_status - information about the rgpus of the job + * IN node_gres_list - node ’s gres_list built by + * gres_plugin_node_config_validate() + * IN node_offset - zero - origin index to the node of interest + * IN job_id - job ’s ID ( for logging ) + * IN node_name - name of the node ( for logging ) + * IN / OUT rgpus_remaining - number of RGPUs that haven ’t still been + * allocated + * IN node_cnt - total number of nodes originally allocated + * to the job + * RET SLURM_SUCCESS or error code + */ +extern i n t g r e s r g p u j o b a l l o c (s t r u c t j o b r e s o u r c e s *job ,L i s t n o d e g r e s l i s t , +int node offset ,u i n t 3 2 t j o b i d ,char *node name , +u i n t 3 2 t *rgpus remaining); +/* + * Deallocate rgpus to a job and update node and job rgpus information + * IN job_gres_status - information about the rgpus of the job + * IN node_gres_list - node ’s gres_list built by + * gres_plugin_node_config_validate() + * IN node_offset - zero - origin index to the node of interest + * IN job_id - job ’s ID ( for logging ) + * IN node_name - name of the node ( for logging ) + * RET SLURM_SUCCESS or error code Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 110 + launch_msg_ptr -> rgpu_list = xstrdup ( job_ptr -> rgpu_list ); /* FIXME : for some reason these CPU arrays total all the CPUs * actually allocated , rather than totaling up to the requested * CPU count for the allocation . --- slurm -2.6.2/ src/ slurmctld/ read_config .c 2013 -09 -10 23:44:33.000000000 +0200 +++ slurm - rcuda/ src / slurmctld / read_config .c 2014 -02 -26 20:07:21.153103612 +0100 @@ -238 ,6 +238 ,63 @@ # endif } + typedef struct gres_state { + uint32_t plugin_id ; + void * gres_data ; +} gres_state_t; + + static void _count_rgpus ( void ) +{ + struct part_record * part_ptr ; + struct node_record * node_ptr ; + ListIterator part_iterator; + int i , total_rgpus ; + ListIterator node_gres_iter ; + gres_state_t *node_gres_ptr; + + /* scan partition table and identify nodes in each */ +p a r t i t e r a t o r =list iterator create(p a r t l i s t ); +while (( part ptr = ( s t r u c t part record *) l i s t n e x t (p a r t i t e r a t o r ))) { +FREE NULL BITMAP(part ptr -> node bitmap ); + +i f (( part ptr -> nodes == NULL) || ( part ptr -> nodes[0] == ’\0 ’)) { +/* Partitions need a bitmap , even if empty */ +part ptr -> node bitmap =bit alloc(node record count); +continue; + } + +i f (node name2bitmap (part ptr -> nodes,f a l s e , + & part ptr -> node bitmap )) { +fatal(" Invalid node names in partition %s" , +part ptr ->name); + } + +total rgpus = 0; +for (i=0; i<node record count;i++) { +i f (b i t t e s t (part ptr -> node bitmap ,i) == 0) +continue; +n o d e p t r = & node record table ptr[i]; +i f (node ptr -> g r e s l i s t !=NULL) { +// counting the amount of rgpus per partition +node gres iter =list iterator create(node ptr -> g r e s l i s t ); +while (( n o d e g r e s p t r = ( g r e s s t a t e t *) +l i s t n e x t (node gres iter))) { +g r e s n o d e s t a t e t *g r e s p u n t e r o = ( g r e s n o d e s t a t e t *) +node gres ptr -> gres data; +i f (node gres ptr -> plugin id==1970300786) { +// debug3 (" read_config : rgpu: %i found in this node " , gres_puntero -> gres_cnt_avail ); +total rgpus += gres puntero -> g r e s c n t a v a i l ; + } + } +l i s t i t e r a t o r d e s t r o y (node gres iter); + } + } +part ptr -> total rgpus =total rgpus; +i n f o (" read_config : total rgpu in the partition( %s): %i",part ptr -> name,part ptr -> total rgpus); + } SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 111 +l i s t i t e r a t o r d e s t r o y (p a r t i t e r a t o r ); +return; +} /* * _build_bitmaps_pre_select - recover some state for jobs and nodes prior to @@ -272 ,7 +329 ,7 @@ continue; node_ptr = & node_record_table_ptr [i]; part_ptr -> total_nodes ++; - if (slurmctld_conf.fast_schedule) + if (slurmctld_conf.fast_schedule) part_ptr -> total_cpus += node_ptr -> config_ptr -> cpus ; else @@ -752 ,7 +809 ,7 @@ /* initialization */ START TIMER; - + i f (reconfig) { /* in order to re - use job state information , * update nodes_completing string (based on node bitmaps ) */ @@ -892 ,8 +949 ,9 @@ } x f r e e (s t a t e s a v e d i r ); g r e s r e c o n f i g (reconfig); +c o u n t r g p u s (); reset job bitmaps(); /* must follow select_g_job_init () */ - + (void )sync nodes to jobs() ; (void )sync job files(); p u r g e o l d n o d e s t a t e (o l d n o d e t a b l e p t r ,old node record count); --- slurm -2.6.2/ src/s l u r m c t l d /s l u r m c t l d .h2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s l u r m c t l d /s l u r m c t l d .h2014 -02 -26 20:07:21.153103612 +0100 @@ -327 ,7 +327 ,11 @@ u i n t 1 6 t s t a t e u p ;/* See PARTITION_ * states in slurm .h */ u i n t 3 2 t t o t a l n o d e s ;/* total number of nodes in the partition */ u i n t 3 2 t t o t a l c p u s ;/* total number of cpus in the partition */ + +u i n t 3 2 t t o t a l r g p u s ;/* total number of shared gpus in the partition */ + u i n t 1 6 t c r t y p e ;/* Custom CR values for partition (if supported by select plugin ) */ + }; extern L i s t p a r t l i s t ;/* list of part_record entries */ @@ -636 ,6 +640 ,22 @@ u i n t 3 2 t w a i t 4 s w i t c h ;/* Maximum time to wait for minimum switches */ boo l b e s t s w i t c h ;/* true = min number of switches met */ time t wait4switch start;/* Time started waiting for switch */ + +/* RCUDA SPECIFIC */ +u i n t 1 6 t r g p u e n a b l e ;/* specify if mode rgpus is enabled . + * 0 rgpu NOT enabled , + * 1 rgpu enabled and the job has not been queued , + * 2 rgpu enabled and the job has been queued */ +char *r g p u l i s t ;/* string with the information of the selected + * rgpus . The string is composed by pairs of + * numbers which indicate the node and de rgpu + * in the node . For example : " name :0 , name :1". */ +b i t s t r t *r g p u a l l o c l i s t ;/* bitstr of the rgpu list , where each bit is a rgpu */ +void *g r e s r g p u ;/* gres_state_t of the rgpus requestes */ +char *gres rgpu str;/* String with the rgpu requested */ +u i n t 1 6 t rcuda mode ;/* 0 for default , 1 for " exclusive ", 2 for " shared Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 112 " mode */ +u i n t 1 6 t r c u d a d i s t ;/* 0 for default , 1 for " global ", 2 for "node" distribution */ +u i n t 3 2 t rgpu min mem ;/* MB */ }; /* Job dependency specification , used in " depend_list " within job_record */ @@ -704 ,6 +724 ,10 @@ switch jobinfo t *s w i t c h j o b ;/* switch context , opaque */ t i m e t t i m e l a s t a c t i v e ;/* time step was last found on node */ t i m e t t o t s u s t i m e ;/* total time in suspended state */ + +b i t s t r t *r g p u l i s t s t e p ; +void *g r e s r g p u ;/* gres_state_t of the rgpus requestes */ +char *gres rgpu str;/* String with the rgpu requested */ }; extern L i s t j o b l i s t ;/* list of job_record entries */ --- slurm -2.6.2/ src/s l u r m c t l d /srun comm.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s l u r m c t l d /srun comm.c2014 -01 -20 11:46:56.828646810 +0100 @@ -93 ,6 +93 ,7 @@ msg arg =x ma ll oc (sizeof(resource allocation response msg t)); msg arg -> j o b i d =j o b p t r -> j o b i d ; msg arg -> node list =xstrdup(j o b p t r -> nodes); +msg arg -> r g p u l i s t =xstrdup(j o b p t r -> r g p u l i s t ); msg arg -> a l i a s l i s t =xstrdup(j o b p t r -> a l i a s l i s t ); msg arg -> num cpu groups =j o b r e s r c s p t r -> cpu array cnt; msg arg -> cpus per node =xmalloc(sizeof(u i n t 1 6 t ) * --- slurm -2.6.2/ src/s l u r m c t l d /step mgr.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s l u r m c t l d /step mgr.c2014 -01 -20 11:46:56.844646815 +0100 @@ -181 ,6 +181 ,7 @@ s t e p p t r -> time limit =INFINITE; s t e p p t r -> jobacct =jobacctinfo create(NULL); s t e p p t r -> requid = -1; +s t e p p t r -> r g p u l i s t s t e p =bit alloc(j o b p t r -> job resrcs -> rgpus); (void )list append (j o b p t r -> s t e p l i s t ,s t e p p t r ); return s t e p p t r ; @@ -257 ,6 +258 ,9 @@ *the switch g job step complete() must be c a l l e d upon co mp l et i on *and not upon r e c o r d p u rg in g .P r e s e n t l y both ev en t s oc cu r *simultaneously. */ +s t r u c t j o b r e c o r d *j o b p t r =s t e p p t r -> j o b p t r ; +int i first ,i l a s t ,i b i t ; + i f (s t e p p t r -> s w i t c h j o b ) { switch g job step complete(s t e p p t r -> s w i t c h j o b , s t e p p t r -> s t e p l a y o u t -> node list); @@ -265 ,6 +269 ,16 @@ r e s v p o r t f r e e (s t e p p t r ); checkpoint free jobinfo (s t e p p t r -> check job); +i f (s t e p p t r -> gres rgpu str) { +i f i r s t = 0; +i l a s t =b i t s i z e (j o b p t r -> r g p u a l l o c l i s t ); +for (i b i t =i f i r s t ; ( i b i t <i l a s t ); i b i t ++) +i f (b i t t e s t (s t e p p t r -> r g p u l i s t s t e p ,i b i t )) +b i t c l e a r (j o b p t r -> rgpu alloc list ,i b i t ); + } +FREE NULL BITMAP(s t e p p t r -> r g p u l i s t s t e p ); +x f r e e (s t e p p t r -> gres rgpu str); + x f r e e (s t e p p t r -> ho s t ); x f r e e (s t e p p t r ->name); slurm step layout destroy(s t e p p t r -> step layout); @@ -1763 ,6 +1777 ,13 @@ } gres plugin step state log(s t e p p t r -> g r e s l i s t ,j o b p t r -> j o b i d , s t e p p t r -> s t e p i d ); + SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 113 +i f (s t e p p t r -> gres rgpu str) { +gres rgpu step alloc(s t e p p t r -> gr e s r g p u ,s t e p p t r -> r g p u l i s t s t e p , +j o b p t r -> rgpu alloc list , +j o b p t r -> rgpu list ,j o b p t r -> j o b i d ,s t e p p t r -> s t e p i d , + & s t e p p t r -> s t e p l a y o u t -> r g p u l i s t ); + } } /* Dump a job step ’s CPU binding information . @@ -2080 ,13 +2101 ,30 @@ xfree ( step_specs ->gres ); else if ( step_specs - > gres == NULL ) step_specs -> gres = xstrdup ( job_ptr -> gres ) ; - i = gres_plugin_step_state_validate ( step_specs -> gres , & step_gres_list , + + /* This function creates the gres structure of the steps . + * The rgpu steps are not created here , but they are + * created in step_alloc_rgpu () . + */ +char *r g p u r e q =NULL, * new req =NULL; +void *r g p u g r e s =NULL; +i=gres plugin step state validate 2(s t e p s p e c s -> gres , & s t e p g r e s l i s t , j o b p t r -> g r e s l i s t ,j o b p t r -> j o b i d , -NO VAL); +NO VAL, & rgpu req , & new req ); + i f (i!= SLURM SUCCESS) { i f (s t e p g r e s l i s t ) l i s t d e s t r o y (s t e p g r e s l i s t ); return i; + } e l s e { +i f (r g p u r e q ) { +x f r e e (s t e p s p e c s -> g r e s ); +s t e p s p e c s -> g r e s =new req ; +i=g r e s r g p u s t e p s t a t e v a l i d a t e (rgpu req , & r g p u gr es , +j o b p t r -> job resrcs -> rgpus ,j o b p t r -> job resrcs -> memrgpu); +i f (i!=SLURM SUCCESS) +return i; + } } j o b p t r -> t i m e l a s t a c t i v e =now; @@ -2181 ,6 +2219 ,8 @@ break; } +s t e p p t r -> gres rgpu str =r g p u r e q ; +s t e p p t r -> g r e s r g p u =r g p u g r e s ; s t e p p t r -> g r e s =s t e p s p e c s -> g r e s ; s t e p s p e c s -> g r e s =NULL; s t e p p t r -> g r e s l i s t =s t e p g r e s l i s t ; --- slurm -2.6.2/ src/s l u r m c t l d /job scheduler.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s l u r m c t l d /job scheduler.c2014 -07 -17 17:19:12.576857646 +0200 @@ -1189 ,6 +1189 ,7 @@ launch msg ptr -> ntasks =j o b p t r -> details -> num tasks; launch msg ptr -> a l i a s l i s t =xstrdup(j o b p t r -> a l i a s l i s t ); launch msg ptr -> nodes =xstrdup(j o b p t r -> nodes); +launch msg ptr -> r g p u l i s t =xstrdup(j o b p t r -> r g p u l i s t ); launch msg ptr -> overcommit =j o b p t r -> details -> overcommit; launch msg ptr ->open mode =j o b p t r -> details ->open mode; launch msg ptr -> acctg freq =xstrdup(j o b p t r -> details -> acctg freq); --- slurm -2.6.2/ src/s run /libsrun/allocate.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s run /libsrun/allocate.c2014 -02 -26 20:07:21.153103612 +0100 @@ -770 ,6 +770 ,8 @@ j-> s p a n k j o b e n v s i z e =opt.s p a n k j o b e n v s i z e ; } +j-> rcuda mode =opt.rcuda mode; +j-> rcuda dist =opt.rcuda dist; Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 114 return (j); } --- slurm -2.6.2/ src/s run /libsrun/opt.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s run /libsrun/opt.c2014 -02 -26 20:07:21.153103612 +0100 @@ -192 ,6 +192 ,9 @@ #d e f i n e LONG OPT LAUNCH CMD 0x156 #d e f i n e LONG OPT PROFILE 0x157 +# d e f i n e LONG OPT RCUDA MODE 0x160 +# define LONG OPT RCUDA DISTRIBUTION 0x161 + extern char ** e n v i r o n ; /* ---- global variables , defined in opt . h ----*/ @@ -917 ,6 +920 ,8 @@ {"uid ",required argument , 0, LONG OPT UID}, {" usage ",no argument , 0, LONG OPT USAGE}, {" wckey ",required argument , 0, LONG OPT WCKEY}, + {"rcuda - mode",required argument , 0, LONG OPT RCUDA MODE}, + {"rcuda-distribution",required argument , 0, LONG OPT RCUDA DISTRIBUTION}, {NULL, 0, 0, 0} }; char *opt string ="+A: B:c:C:d:D:e: Eg : hHi :I:: jJ :kK :: lL :m :n:N:" @@ -937 ,10 +942 ,11 @@ e l s e e r r o r (" opt. progname is already set ."); optind = 0; + while(( o p t c h a r =getopt long(argc ,argv ,o p t s t r i n g , optz , & o p t i o n i n d e x )) != -1) { switch (o p t c h a r ) { - + case (int)’?’: fprintf(stderr , "Try \" srun -- help \" for more information \n"); @@ -1561 ,6 +1567 ,28 @@ x f r e e (opt.g r e s ); opt.g r e s =xstrdup(optarg); break; +case LONG OPT RCUDA MODE: +opt.rcuda mode = 0; +i f (strcasecmp(optarg ," shar ") == 0 || strcasecmp(optarg ," shared") == 0) +opt.rcuda mode = 2; +e l s e i f (strcasecmp(optarg ," excl") == 0 || strcasecmp( optarg ," exclusive ") == 0) +opt.rcuda mode = 1; +e l s e { +i n f o (" Invalid rCUDA mode : %s ( exclusive , shared )", optarg); +e x i t (error exit); + } +break; +case LONG OPT RCUDA DISTRIBUTION: +opt.rcuda dist = 0; +i f (strcasecmp(optarg ," node ") == 0) +opt.rcuda dist = 2; +e l s e i f (strcasecmp(optarg ,"global") == 0) +opt.rcuda dist = 1; +e l s e { +e r r o r (" Invalid rCUDA distribution : %s ( global , node )",optarg); +e x i t (error exit); + } +break; case LONG OPT ALPS: verbose(" Not running ALPS. -- alps option ignored ."); SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 115 break; @@ -1593 ,7 +1621 ,7 @@ char ** r e s t =NULL; set options(argc ,argv ); - + i f (( opt.pn min memory > -1) && ( opt.mem per cpu > -1)) { i f (opt.pn min memory <opt.mem per cpu) { i n f o (" mem < mem -per - cpu - resizing mem to be equal " --- slurm -2.6.2/ src/s run /libsrun/opt.h2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s run /libsrun/opt.h2014 -04 -15 15:55:29.712364799 +0200 @@ -235 ,6 +235 ,11 @@ int req switch;/* Minimum number of switches */ int w a i t 4 s w i t c h ;/* Maximum time to wait for minimum switches */ boo l u se r m an a ge d i o ;/* 0 for " normal" IO , 1 for " user manged " IO */ + +/* RCUDA SPECIFIC */ +u i n t 1 6 t rcuda mode ;/* 0 for default , 1 for " exclusive ", 2 for " shared " mode */ +u i n t 1 6 t r c u d a d i s t ;/* 0 for default , 1 for " global ", 2 for "node " distribution */ +/******************/ }o p t t ; extern o p t t opt ; --- slurm -2.6.2/ src/s run /libsrun/srun job.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s run /libsrun/srun job.c2014 -01 -20 11:46:57.232646809 +0100 @@ -96 ,6 +96 ,7 @@ u i n t 3 2 t num cpu groups ; dynamic plugin data t *select jobinfo; uint32 t stepid; +char *rgpulist; }allocation info t; static int shepard fd = -1; @@ -195 ,6 +196 ,7 @@ ai -> stepid =NO VAL; ai -> alias list =resp -> a l i a s l i s t ; ai -> nodelist =opt.alloc nodelist; +ai -> rgpulist =resp -> r g p u l i s t ; hl =hostlist create(ai -> nodelist); hostlist uniq(hl ); a l l o c c o u n t =h o s t l i s t c o u n t (h l ); @@ -397 ,10 +399 ,12 @@ i-> cpus per node =resp -> cpus per node; i-> c p u c o u n t r e p s =resp -> c p u c o u n t r e p s ; i-> select jobinfo =select g select jobinfo copy(resp -> select jobinfo); - +i-> rgpulist =xstrdup(resp -> r g p u l i s t ); + job =job create structure(i); x f r e e (i-> nodelist); +x f r e e (i-> rgpulist); x f r e e (i); return (job); --- slurm -2.6.2/ src/s a l l o c /opt.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s a l l o c /opt.c2014 -04 -15 15:55:29.076364805 +0200 @@ -167 ,6 +167 ,9 @@ #define LONG OPT REQ SWITCH 0x143 #d e f i n e LONG OPT PROFILE 0x144 +# d e f i n e LONG OPT RCUDA MODE 0x160 +# define LONG OPT RCUDA DISTRIBUTION 0x161 + /* ---- global variables , defined in opt . h ----*/ o p t t opt ; int error exit = 1; Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 116 @@ -688 ,6 +691 ,8 @@ {" wait - all - nodes " ,required argument , 0, LONG OPT WAIT ALL NODES}, {" wckey ",required argument , 0, LONG OPT WCKEY}, {" switches ",required argument , 0, LONG OPT REQ SWITCH}, + {"rcuda - mode",required argument , 0, LONG OPT RCUDA MODE}, + {"rcuda-distribution",required argument , 0, LONG OPT RCUDA DISTRIBUTION}, {NULL, 0, 0, 0} }; char *opt string = @@ -1159 ,6 +1164 ,28 @@ x f r e e (opt.g r e s ); opt.g r e s =xstrdup(optarg); break; +case LONG OPT RCUDA MODE: +opt.rcuda mode = 0; +i f (strcasecmp(optarg ," shar ") == 0 || strcasecmp(optarg ," shared") == 0) +opt.rcuda mode = 2; +e l s e i f (strcasecmp(optarg ," excl") == 0 || strcasecmp( optarg ," exclusive ") == 0) +opt.rcuda mode = 1; +e l s e { +i n f o (" Invalid rCUDA mode : %s ( exclusive , shared )", optarg); +e x i t (error exit); + } +break; +case LONG OPT RCUDA DISTRIBUTION: +opt.rcuda dist = 0; +i f (strcasecmp(optarg ," node ") == 0) +opt.rcuda dist = 2; +e l s e i f (strcasecmp(optarg ,"global") == 0) +opt.rcuda dist = 1; +e l s e { +e r r o r (" Invalid rCUDA distribution : %s ( global , node )",optarg); +e x i t (error exit); + } +break; case LONG OPT WAIT ALL NODES: opt.w a i t a l l n o d e s =strtol(optarg ,NULL, 10) ; break; --- slurm -2.6.2/ src/s a l l o c /opt.h2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s a l l o c /opt.h2014 -04 -15 15:55:29.192364802 +0200 @@ -162 ,6 +162 ,10 @@ char ** spank job env;/* SPANK controlled environment for job * Prolog and Epilog */ int s p a n k j o b e n v s i z e ;/* size of spank_job_env */ + +/* RCUDA SPECIFIC */ +u i n t 1 6 t rcuda mode ;/* 0 for default , 1 for " exclusive ", 2 for " shared " mode */ +u i n t 1 6 t r c u d a d i s t ;/* 0 for default , 1 for " global ", 2 for "node " distribution */ }o p t t ; extern o p t t opt ; --- slurm -2.6.2/ src/s a l l o c /s a l l o c .c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/s a l l o c /s a l l o c .c2014 -04 -15 15:55:29.412364802 +0200 @@ -748 ,7 +748 ,10 @@ desc -> spank job env =opt.spank job env; desc -> s p a n k j o b e n v s i z e =opt.s p a n k j o b e n v s i z e ; } - + +desc -> rcuda mode =opt.rcuda mode; +desc -> rcuda dist =opt.rcuda dist; + return 0; SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 117 } --- slurm -2.6.2/ src/sbatch/opt.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/sbatch/opt.c2014 -04 -15 15:55:29.504364803 +0200 @@ -176 ,6 +176 ,9 @@ #d e f i n e LONG OPT PROFILE 0x154 #d e f i n e LONG OPT IGNORE PBS 0x155 +# d e f i n e LONG OPT RCUDA MODE 0x160 +# define LONG OPT RCUDA DISTRIBUTION 0x161 + /* ---- global variables , defined in opt . h ----*/ o p t t opt ; int error exit = 1; @@ -729 ,6 +732 ,8 @@ {"wrap ",required argument , 0, LONG OPT WRAP}, {" switches ",required argument , 0, LONG OPT REQ SWITCH}, {"ignore -pbs ",no argument , 0, LONG OPT IGNORE PBS}, + {"rcuda - mode",required argument , 0, LONG OPT RCUDA MODE}, + {"rcuda - distribution " ,required argument , 0, LONG OPT RCUDA DISTRIBUTION}, {NULL, 0, 0, 0} }; @@ -1624 ,6 +1629 ,28 @@ x f r e e (opt.g r e s ); opt.g r e s =xstrdup(optarg); break; +case LONG OPT RCUDA MODE: +opt.rcuda mode = 0; +i f (strcasecmp(optarg ," shar ") == 0 || strcasecmp(optarg ," shared") == 0) +opt.rcuda mode = 2; +e l s e i f (strcasecmp(optarg ," excl") == 0 || strcasecmp( optarg ," exclusive ") == 0) +opt.rcuda mode = 1; +e l s e { +i n f o (" Invalid rCUDA mode : %s ( exclusive , shared )", optarg); +e x i t (error exit); + } +break; +case LONG OPT RCUDA DISTRIBUTION: +opt.rcuda dist = 0; +i f (strcasecmp(optarg ," node ") == 0) +opt.rcuda dist = 2; +e l s e i f (strcasecmp(optarg ,"global") == 0) +opt.rcuda dist = 1; +e l s e { +e r r o r (" Invalid rCUDA distribution : %s ( global , node )",optarg); +e x i t (error exit); + } +break; case LONG OPT WAIT ALL NODES: opt.w a i t a l l n o d e s =strtol(optarg ,NULL, 10) ; break; --- slurm -2.6.2/ src/sbatch/opt.h2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/sbatch/opt.h2014 -04 -15 15:55:29.648364803 +0200 @@ -177 ,6 +177 ,11 @@ char ** spank job env;/* SPANK controlled environment for job * Prolog and Epilog */ int s p a n k j o b e n v s i z e ;/* size of spank_job_env */ + +/* RCUDA SPECIFIC */ +u i n t 1 6 t rcuda mode ;/* 0 for default , 1 for " exclusive ", 2 for " shared " mode */ +u i n t 1 6 t r c u d a d i s t ;/* 0 for default , 1 for " global ", 2 for "node " distribution */ +/******************/ Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 118 }o p t t ; extern o p t t opt ; --- slurm -2.6.2/ src/sbatch/sbatch.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/sbatch/sbatch.c2014 -07 -17 16:47:00.660862465 +0200 @@ -461 ,6 +461 ,8 @@ i f (opt.w a i t 4 s w i t c h >= 0) desc -> w a i t 4 s w i t c h =opt.w a i t 4 s w i t c h ; +desc -> rcuda mode =opt.rcuda mode; +desc -> rcuda dist =opt.rcuda dist; return 0; } --- slurm -2.6.2/ src/squeue /print.c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/squeue /print.c2014 -06 -26 11:37:17.929433883 +0200 @@ -782 ,6 +781 ,18 @@ i f (s u f f i x ) p r i n t f (" %s",s u f f i x ); return SLURM SUCCESS; +} + +int p r i n t j o b r g p u l i s t (j o b i n f o t *job ,int width ,boo l r i g h t , +char *s u f f i x ) +{ +i f (job == NULL)/* Print the Header instead */ +p r i n t s t r (" RGPULIST ",width ,right ,false); +e l s e +p r i n t s t r (job -> rgpu list ,width ,right ,false); +i f (s u f f i x ) +p r i n t f (" %s",s u f f i x ); +return SLURM SUCCESS; } int print job node inx(j o b i n f o t *job ,int width ,boo l r i g h t ,char *s u f f i x ) --- slurm -2.6.2/ src/squeue /print.h2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/squeue /print.h2014 -06 -26 11:37:17.929433883 +0200 @@ -98 ,6 +98 ,8 @@ job format add function(list ,wid ,right ,prefix ,p r i n t j o b r e a s o n ) #define job format add reason list(list ,wid ,right ,p r e f i x ) \ job format add function(list ,wid ,right ,prefix ,print job reason list) +# d e f i n e j o b f o r m a t a d d r g p u l i s t (list ,wid ,right ,prefix) \ +job format add function(list ,wid ,right ,prefix ,p r i n t j o b r g p u l i s t ) #d e f i n e j ob f orm at a dd n am e (list ,wid ,right ,s u f f i x ) \ job format add function(list ,wid ,right ,suffix ,p r i n t j o b n a m e ) #define job format add licenses(list ,wid ,right ,s u f f i x ) \ @@ -205 ,6 +207 ,8 @@ char *s u f f i x ); int print job reason list(j o b i n f o t *job ,int width ,bool right justify , char *s u f f i x ); +int p r i n t j o b r g p u l i s t (j o b i n f o t *job ,int width ,bool right justify , +char *s u f f i x ); int p r i n t j o b n a m e (j o b i n f o t *job ,int width ,bool right justify , char *s u f f i x ); int print job licenses(j o b i n f o t *job ,int width ,bool right justify , --- slurm -2.6.2/ src/squeue /o p t s .c2013 -09 -10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/squeue /o p t s .c2014 -06 -26 11:37:17.929433883 +0200 @@ -783 ,6 +783 ,11 @@ field size , right justify , s u f f i x ); +e l s e i f (field[0] == ’Z ’) +j o b f o r m a t a d d r g p u l i s t (params.format list , +field size , +right justify , +s u f f i x ); e l s e { p r e f i x =xstrdup(" %"); x s t r c a t (prefix ,token);  SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 119  --- slurm -2.6.2/ src/plugins/select/c o n s r e s /s e l e c t c o n s r e s .c2013-09-10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/plugins/s e l e c t /cons rgpu/select cons rgpu.c2014-06-25 09:01:28.341672679 +0200 @@ -124 ,8 +124 ,6 @@ int s w i t c h r e c o r d c n t a t t r i b u t e (( weak import)); b i t s t r t *a v a i l n o d e b i t m a p a t t r i b u t e (( weak import)); b i t s t r t *i d l e n o d e b i t m a p a t t r i b u t e (( weak import)); -u i n t 1 6 t *cr no de n u m c o r es a t t r i b u t e (( weak import)); -u i n t 3 2 t *c r n o d e c o r e s o f f s e t a t t r i b u t e (( weak import)); #e l s e s l u r m c t l c o n f t s l u r m c t l d c o n f ; s t r u c t no d e rec o r d *node record table ptr; @@ -137 ,8 +135 ,6 @@ int switch record cnt; b i t s t r t *avail node bitmap; b i t s t r t *i d l e n o d e b i t m a p ; -u i n t 1 6 t *cr no de n u m c o r es ; -u i n t 3 2 t *cr node cores offset; #e n d i f /* @@ -169 ,9 +165 ,9 @@ * as 100 or 1000. Various SLURM versions will likely require a certain * minimum version for their plugins as the node selection API matures. */ -const char plugin name [] = " Consumable Resources ( CR ) Node Selection plugin "; -const char p l u g i n t y p e [] = " select / cons_res "; -const u i n t 3 2 t p l u g i n i d = 101; +const char plugin name [] = " Consumable Resources RGPU Node Selection plugin " ; +const char p l u g i n t y p e [] = " select / cons_rgpu "; +const u i n t 3 2 t p l u g i n i d = 150; const u i n t 3 2 t p l u g i n v e r s i o n = 100; const u i n t 3 2 t p s t a t e v e r s i o n = 7; /* version control on saved state */ @@ -180 ,6 +176 ,8 @@ uint32 t select debug flags; u i n t 1 6 t s e l e c t f a s t s c h e d u l e ; +u i n t 1 6 t *cr n o d e num c o r e s =NULL; +u i n t 3 2 t *cr node cores offset =NULL; s t r u c t part res record *s e l e c t p a r t r e c o r d =NULL; s t r u c t n o d e r e s r e c o r d *select node record =NULL; s t r u c t node use record *select node usage =NULL; @@ -192 ,9 +190 ,13 @@ s t r u c t s e l e c t n o d e i n f o { u i n t 1 6 t magic ;/* magic number */ u i n t 1 6 t a l l o c c p u s ; -u i n t 3 2 t alloc memor y ; }; +type def s t r u c t gres state { +u i n t 3 2 t p l u g i n i d ; +void *gres data; +} g r e s s t a t e t ; + extern select nodeinfo t *select p select nodeinfo alloc(void ); extern i n t select p select nodeinfo free(select nodeinfo t *node i nf o ); @@ -210 ,8 +212 ,7 @@ static int run now(s t r u c t j o b r e c o r d *j o b p t r ,b i t s t r t *bitmap , u i n t 3 2 t min nodes ,u i n t 3 2 t max nodes , u i n t 3 2 t re q nodes ,u i n t 1 6 t jo b n od e re q , -List preemptee candidates ,L i s t *p r e e m p t e e j o b l i s t , -b i t s t r t *e x c c o r e b i t m a p ); +List preemptee candidates ,L i s t *preemptee job list); static int sort usable nodes dec(s t r u c t j o b r e c o r d *j ob a , s t r u c t j o b r e c o r d *j o b b ); static int test only(s t r u c t j o b r e c o r d *j o b p t r ,b i t s t r t *bitmap , @@ -220 ,10 +221 ,10 @@ Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 126 @@ -1558 ,6 +1680 ,8 @@ } j o b i t e r a t o r =list iterator create(preemptee candidates); +i f (j o b i t e r a t o r ==NULL) +fatal(" memory allocation failure "); while (( tmp job ptr = ( s t r u c t j o b r e c o r d *) l i s t n e x t (j o b i t e r a t o r ))) { i f (! IS JOB RUNNING(tmp job ptr) && @@ -1575 ,10 +1699 ,9 @@ r c =c r j o b t e s t (j o b p t r ,bitmap ,min nodes , max nodes ,req node s , SELECT MODE WILL RUN , -tmp c r ty p e ,job node req , +cr type ,j o b n o d e r e q , select node cnt , -future part ,f u t u r e u s a g e , -e x c c o r e b i t m a p ); +future part ,future usage); t m p j o b p t r -> details -> usable nodes = 0; /* * If successful , set the last job ’s usable count to a @@ -1622 ,9 +1745 ,13 @@ * actually used */ i f (* preemptee job list == NULL) { *preemptee job list =l i s t c r e a t e (NULL); +i f (* preemptee job list==NULL) +fatal(" list_create malloc failure "); } preemptee iterator =list iterator create( preemptee candidates); +i f (preemptee iterator==NULL) +fatal(" memory allocation failure "); while (( tmp job ptr = ( s t r u c t j o b r e c o r d *) l i s t n e x t (preemptee iterator))) { mode =slurm job preempt mode(tmp job ptr); @@ -1660 ,8 +1787 ,7 @@ static int will run test(s t r u c t j o b r e c o r d *j o b p t r ,b i t s t r t *bitmap , u i n t 3 2 t min nodes ,u i n t 3 2 t max nodes , u i n t 3 2 t re q nodes ,u i n t 1 6 t jo b n od e re q , -List preemptee candidates ,L i s t *p r e e m p t e e j o b l i s t , -b i t s t r t *e x c c o r e b i t m a p ) +List preemptee candidates ,L i s t *preemptee job list) { s t r u c t part res record *f u t u r e p a r t ; s t r u c t node use record *future usage; @@ -1671 ,27 +1797 ,16 @@ b i t s t r t *orig map; int action ,r c =SLURM ERROR; t i m e t now =time (NULL); -u i n t 1 6 t t m p c r t y p e =c r t y p e ; orig map =bit copy(bitmap); - -i f (j o b p t r -> part ptr -> c r t y p e ) { -i f ((( c r t y p e &CR SOCKET) || ( c r t y p e &CR CORE)) && - ( c r t y p e &CR ALLOCATE FULL SOCKET)) { -t m p c r t y p e &= ~(CR SOCKET|CR CORE); -t m p c r t y p e |= j o b p t r -> part ptr -> c r t y p e ; - } e l s e { -i n f o (" cons_res: Can ’t use Partition SelectType unless " -" using CR_Socket or CR_Core and " -"CR_ALLOCATE_FULL_SOCKET"); - } - } +i f (! orig map) +fatal(" bit_copy : malloc failure "); /* Try to run with currently available nodes */ r c =c r j o b t e s t (j o b p t r ,bitmap ,min nodes ,max nodes ,req n ode s , SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 127 -SELECT MODE WILL RUN ,t m p c r ty p e ,j o b n o d e r e q , +SELECT MODE WILL RUN ,cr type ,job node req , select node cnt ,s e l e c t p a r t r e c o r d , -select node usage ,e x c c o r e b i t m a p ); +select node usage); i f (r c == SLURM SUCCESS) { FREE NULL BITMAP(orig map); j o b p t r -> start time =time (NULL); @@ -1717 ,6 +1832 ,8 @@ i f (! c r j o b l i s t ) fatal(" list_create : memory allocation error "); j o b i t e r a t o r =list iterator create(j o b l i s t ); +i f (j o b i t e r a t o r ==NULL) +fatal(" memory allocation failure "); while (( tmp job ptr = ( s t r u c t j o b r e c o r d *) l i s t n e x t (j o b i t e r a t o r ))) { i f (! IS JOB RUNNING(tmp job ptr) && !IS JOB SUSPENDED(tmp job ptr)) @@ -1745 ,15 +1862 ,11 @@ i f (preemptee candidates) { b i t o r (bitmap ,orig map); r c =c r j o b t e s t (j o b p t r ,bitmap ,min nodes ,max nodes , -req nod es ,SELECT MODE WILL RUN ,t m p cr ty p e , +req nodes ,SELECT MODE WILL RUN ,cr type , job node req ,select node cnt ,future part , -f u t u r e u s a g e ,e x c c o r e b i t m a p ); -i f (r c == SLURM SUCCESS) { -/* Actual start time will actual ly be later than " now ", - * but return " now " for backfill scheduler to - * initiate preemption . */ -j o b p t r -> start time =now; - } +future usage); +i f (r c ==SLURM SUCCESS) +j o b p t r -> start time =now+1; } /* Remove the running jobs one at a time from exp_node_cr and try @@ -1761 ,6 +1874 ,8 @@ if ( rc != SLURM_SUCCESS ) { list_sort ( cr_job_list , _cr_job_list_sort ); job_iterator = list_iterator_create ( cr_job_list ); + if ( job_iterator == NULL ) + fatal (" memory allocation failure ") ; while (( tmp_job_ptr = list_next ( job_iterator ))) { int ovrlap ; bit_or ( bitmap , orig_map ) ; @@ -1767 ,16 +1882 ,16 @@ ovrlap = bit_overlap ( bitmap , tmp_job_ptr -> node_bitmap ); if ( ovrlap == 0) /* job has no usable nodes */ continue;/* skip it */ -debug2(" cons_res: _will_run_test , job %u: overlap= %d", +debug2(" cons_rgpu : _will_run_test , job %u: overlap= %d", t m p j o b p t r -> j o b i d ,ovrlap); +// debug (" RCUDA job: %i %s( %s, %d) llamando a rm_job_from_res () " , job_ptr -> job_id , __FILE__ , __func__ , __LINE_ _ ); r m j o b f r o m r e s (future part ,f u t u r e u s a g e , t m p j o b p t r , 0) ; r c =c r j o b t e s t (j o b p t r ,bitmap ,min nodes , max nodes ,req node s , -SELECT MODE WILL RUN ,t m p c r ty p e , +SELECT MODE WILL RUN ,cr type , j o b n o d e r e q ,select node cnt , -future part ,f u t u r e u s a g e , -e x c c o r e b i t m a p ); +future part ,future usage); i f (r c == SLURM SUCCESS) { i f (t m p j o b p t r -> end time <= now) j o b p t r -> start time =now + 1; @@ -1796 ,8 +1911 ,12 @@ *in s e l e c t e d plu gin ,but by Moab or something e l s e . */ Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 128 i f (* preemptee job list == NULL) { *preemptee job list =l i s t c r e a t e (NULL); +i f (* preemptee job list==NULL) +fatal(" list_create malloc failure "); } preemptee iterator =list iterator create(preemptee candidates); +i f (preemptee iterator==NULL) +fatal(" memory allocation failure "); while (( tmp job ptr = ( s t r u c t j o b r e c o r d *) l i s t n e x t (preemptee iterator))) { i f (bit overlap(bitmap , @@ -1836 ,7 +1955 ,8 @@ select node usage =NULL; destroy part data(s e l e c t p a r t r e c o r d ); s e l e c t p a r t r e c o r d =NULL; -c r f i n i g l o b a l c o r e d a t a () ; +x f r e e (c r n o d e n u m c o r e s ); +x f r e e (cr node cores offset); i f (c r t y p e ) verbose(" %s shutting down ... ",plugin name ); @@ -1914 ,7 +2034 ,7 @@ /* initial global core data structures */ select state initializing =t r u e ; select fast schedule =slurm get fast schedule(); -cr init global core data(node ptr ,node cnt ,select fast schedule); +i n i t g l o b a l c o r e d a t a (node ptr ,nod e c nt ); destroy node data(select node usage ,select node record); s e l e c t n o d e c n t =n o de cnt ; @@ -1929 ,7 +2049 ,6 @@ s t r u c t config record *config ptr; config ptr =n o d e p t r [i]. config ptr; select node record[i]. cpus =c o n f i g p t r -> cpus ; -select node record[i]. board s =c o n f i g p t r -> boa rds ; select node record[i]. sockets =c o n f i g p t r -> sockets; select node record[i]. cores =c o n f i g p t r -> cores; select node record[i]. vpus =c o n f i g p t r -> t h r e a d s ; @@ -1937 ,7 +2056 ,6 @@ real memory ; }e l s e { select node record[i]. cpus =n o d e p t r [i]. cpus ; -select node record[i]. board s =n o d e p t r [i]. boa rds ; select node record[i]. sockets =n o d e p t r [i]. sockets; select node record[i]. cores =n o d e p t r [i]. cores; select node record[i]. vpus =n o d e p t r [i]. t h r e a d s ; @@ -1997 ,16 +2115 ,14 @@ u i n t 3 2 t min nodes ,u i n t 3 2 t max nodes , u i n t 3 2 t re q nodes ,u i n t 1 6 t mode, List preemptee candidates , -L i s t *p r e e m p t e e j o b l i s t , -b i t s t r t *e x c c o r e b i t m a p ) +L i s t *preemptee job list) { int r c =EINVAL; u i n t 1 6 t j o b n o d e r e q ; -static boo l de bug c pu b in d =f a l s e ,debug check =false; +boo l de bug c pu b in d =f a l s e ,debug check =false; xassert(bitmap); -debug2(" select_p_job_test for job %u",j o b p t r -> j o b i d ); i f (! debug check) { debug check =t r u e ; i f (slurm get debug flags() & DEBUG FLAG CPU BIND) @@ -2031 ,16 +2147 ,14 @@ i f (mode == SELECT MODE WILL RUN) { r c =will run test(j o b p t r ,bitmap ,min nodes ,max nodes , req nodes ,job node req , -preemptee candidates ,p r e e m p t e e j o b l i s t , SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 129 -e x c c o r e b i t m a p ); +preemptee candidates ,preemptee job list); }e l s e i f (mode == SELECT MODE TEST ONLY) { r c =test only(j o b p t r ,bitmap ,min nodes ,max nodes , req nod es ,j o b n o d e r e q ); }e l s e i f (mode == SELECT MODE RUN NOW) { r c =run now (j o b p t r ,bitmap ,min nodes ,max nodes , req nod es ,j o b n o d e r e q , -preemptee candidates ,p r e e m p t e e j o b l i s t , -e x c c o r e b i t m a p ); +preemptee candidates ,preemptee job list); }e l s e fatal(" select_p_job_test : Mode %d is invalid ",mode); @@ -2048 ,8 +2162 ,8 @@ i f (j o b p t r -> job resrcs) log job resources(j o b p t r -> j o b i d ,j o b p t r -> job resrcs); e l s e { -i n f o ("no job_resources info for job %u rc= %d", -j o b p t r -> j o b i d ,r c ); +i n f o ("no job_resources info for job %u" , +j o b p t r -> j o b i d ); } }e l s e i f (d ebug cp u bi nd && j o b p t r -> job resrcs) { log job resources(j o b p t r -> j o b i d ,j o b p t r -> job resrcs); @@ -2184 ,12 +2298 ,7 @@ Buf b u f f e r , u i n t 1 6 t p r o t o c o l v e r s i o n ) { -i f (protocol version >= SLURM 2 6 PROTOCOL VERSION) { -pack16(nodeinfo -> alloc cpus ,buffer); -pack32(nodeinfo -> alloc memory ,buffer); - } e l s e { pack16(nodeinfo -> alloc cpus ,buffer); - } return SLURM SUCCESS; } @@ -2203 ,12 +2312 ,7 @@ n o d e i n f o p t r =select p select nodeinfo alloc(); *no d ei n fo =n o d e i n f o p t r ; -i f (protocol version >= SLURM 2 6 PROTOCOL VERSION) { -sa f e u n pa c k 16 (& nodeinfo ptr -> alloc cpus ,buffer); -sa f e u n pa c k 32 (& nodeinfo ptr -> alloc memory ,buffer); - } e l s e { sa f e u n pa c k 16 (& nodeinfo ptr -> alloc cpus ,buffer); - } return SLURM SUCCESS; @@ -2247 ,13 +2351 ,14 @@ { s t r u c t part res record *p p t r ; s t r u c t no d e rec o r d *n o d e p t r =NULL; -int i=0, n=0, start ,end; -u i n t 1 6 t tmp,tmp 16 = 0, tm p p art ; +int i= 0, n= 0, c,start ,end; +u i n t 1 6 t tmp,tmp 16 = 0; static t i m e t l a s t s e t a l l = 0; u i n t 3 2 t n ode t hr ea ds ,node cpus; +select nodeinfo t *n o de i nf o =NULL; /* only set this once when the last_node_update is newer than - * the last time we set things up . */ +the l a s t time we s e t t h i n g s up. */ i f (l a s t s e t a l l && ( l a s t n o d e u p d a t e <l a s t s e t a l l )) { debug2("Node select info for set all hasn’t " " changed since %ld ", @@ -2262 ,12 +2367 ,14 @@ Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 130 } l a s t s e t a l l =l a s t n o d e u p d a t e ; -for (n= 0, n o d e p t r =node record table ptr; -n<s e l e c t n o d e c n t ;n++ , n o d e p t r ++) { -select nodeinfo t *n o de i nf o =NULL; -/* We have to use the ’_g_ ’ here to make sure we get the - * correct data to work on. i.e. cray calls this plugin - * from within select / cray which has it ’s own struct . */ +for (n= 0; n<s e l e c t n o d e c n t ;n++) { +n o d e p t r = &( node record table ptr[n]); + +/* We have to use the ’_g_ ’ here to make sure we get + the correct data to work on. i.e. cray calls this + plugin from within select / cray which has it ’s own + struct . + */ s e l e c t g s e l e c t n o d e i n f o g e t (node ptr -> select nodeinfo , SELECT NODEDATA PTR, 0, (void *)& n ode i nf o ); @@ -2290 ,16 +2397 ,20 @@ for (p p t r =s e l e c t p a r t r e c o r d ;p p t r ;p p t r =p pt r -> ne xt ) { i f (! p pt r ->row) continue; -tm p p art = 0; for (i= 0; i<p p t r ->num rows;i++) { i f (! p pt r ->row[i]. row bitmap ) continue; -tmp =b i t s e t c o u n t r a n g e (p ptr ->row[i]. row bitmap , -start ,end); -/* Report row with largest CPU count */ -tm p p art =MAX(tmp,t m p p ar t ); +tmp = 0; +for (c=start;c<end;c++) { +i f (b i t t e s t (p pt r ->row[i]. row bitmap , +c)) +tmp++; + } +/* get the row with the largest cpu + count on it. */ +i f (tmp>tmp 16) +tmp 16 =tmp; } -tmp 16 += tmp par t ;/* Add CPU counts all parts */ } /* The minimum allocatable unit may a core , so scale @@ -2308 ,12 +2419 ,6 @@ tmp_16 *= node_threads ; nodeinfo -> alloc_cpus = tmp_16 ; - if ( select_node_record ) { - nodeinfo -> alloc_memory = - select_node_usage [n ]. alloc_memory ; - } else { - nodeinfo -> alloc_memory = 0; - } } return SLURM_SUCCESS ; @@ -2341 ,7 +2446 ,6 @@ { int rc = SLURM_SUCCESS ; uint16_t * uint16 = ( uint16_t *) data ; - uint32_t * uint32 = ( uint32_t *) data ; char ** tmp_char = ( char **) data ; select_nodeinfo_t **select_nodeinfo = (select_nodeinfo_t **) data; @@ -2372 ,9 +2476 ,6 @@ case SELECT_NODEDATA_EXTRA_INFO: SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 131 * tmp_char = NULL ; break ; - case SELECT_NODEDATA_MEM_ALLOC: - * uint32 = nodeinfo -> alloc_memory ; - break ; default : error (" Unsupported option %d for get_nodeinfo ." , dinfo ); rc = SLURM_ERROR; @@ -2528 ,6 +2629 ,8 @@ /* reload job data */ j o b i t e r a t o r =list iterator create(j o b l i s t ); +i f (j o b i t e r a t o r ==NULL) +fatal(" memory allocation failure "); while (( j o b p t r = ( s t r u c t j o b r e c o r d *) l i s t n e x t (j o b i t e r a t o r ))) { i f (IS JOB RUNNING(j o b p t r )) { /* add the job */ @@ -2543 ,221 +2646 ,6 @@ return SLURM SUCCESS; } /* * select _p_resv_test - Identify the nodes which " best " satisfy a reservation * request . " best " is defined as either single set of consecutive nodes @@ -2765 ,60 +2653 ,35 @@ * OR the fewest number of consecutive node sets * IN avail_bitmap - nodes available for the reservation * IN node_cnt - count of required nodes - * IN core_bitmap - cores which can not be used for this reservation - * OUT avail_bitmap - nodes allocated for the reservation - * OUT core_bitmap - cores which allocated to this reservation * RET - nodes selected for use by the reservation */ -extern b i t s t r t *s e l e c t p r e s v t e s t (b i t s t r t *avail bitmap ,u i n t 3 2 t node cnt , -u i n t 3 2 t *c o r e c n t ,b i t s t r t ** core bitmap) +extern b i t s t r t *s e l e c t p r e s v t e s t (b i t s t r t *avail bitmap ,u i n t 3 2 t n ode c nt ) { b i t s t r t ** switches bitmap;/* nodes on this switch */ -b i t s t r t ** s w i t c h e s c o r e b i t m a p ;/* cores on this switch */ int *s w i t c h e s c p u c n t ;/* total CPUs on switch */ int *switches node cnt;/* total nodes on switch */ int *switches required;/* set if has required node */ b i t s t r t *a v a i l n o d e s b i t m a p =NULL;/* nodes on any switch */ -b i t s t r t *sp avail bitmap; -int rem nodes ,r e m cor e s = 0; /* remaining resources desired */ +int rem nodes;/* remaining resources desired */ int i,j; int b e s t f i t i n x ,first ,l a s t ; int best fit nodes; int best fit location = 0, best fit sufficient; bool sufficient; -int c o r e s p e r n o d e ; xassert(avail bitmap); - -/* When reservation includes a nodelist we use sequential_pick code */ -i f (! switch record cnt || ! switch record table || ! n ode c n t ) { -return sequential pick(avail bitmap ,node cnt ,c o r e c n t , -core bitmap); - } +i f (! switch record cnt|| ! switch record table) +return b i t p i c k c n t (avail bitmap ,no d e cnt ); /* Use topology state information */ i f (b i t s e t c o u n t (avail bitmap) < n o de cn t ) return a v a i l n o d e s b i t m a p ; - -i f (c o r e c n t && (* core bitmap == NULL)) - * core bitmap =make core bitmap filtered(avail bitmap , 0); Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 132 - rem nodes =n o de cn t ; -/* Assuming symmetric cluster */ -i f (c o r e c n t ) { -re m c o r e s =c o r e c n t [0]; -c o r e s p e r n o d e =c o r e c n t [0] / MAX(node cnt , 1); - } e l s e i f (cr n o de nu m c o r e s ) -c o r e s p e r n o d e =cr no d e n u m c o r e s [0]; -e l s e -c o r e s p e r n o d e = 1; - /* Construct a set of switch array entries , * use the same indexes as switch_record_table in slurmctld */ switches bitmap =xmal lo c (sizeof(b i t s t r t *) * switch record cnt); -s w i t c h e s c o r e b i t m a p =x ma ll oc (s i z e o f (b i t s t r t *) * switch record cnt); s w i t c h e s c p u c n t =xmalloc (sizeof(int) * switch record cnt); switches node cnt =xma ll oc (sizeof(int) * switch record cnt); switches required =xma ll oc (sizeof(int) * switch record cnt); @@ -2822 ,45 +2685 ,11 @@ s w i t c h e s c p u c n t =xmalloc (sizeof(int) * switch record cnt); switches node cnt =xma ll oc (sizeof(int) * switch record cnt); switches required =xma ll oc (sizeof(int) * switch record cnt); - for (i=0; i<switch record cnt;i++) { -char str[100]; switches bitmap[i] = bit copy(switch record table[i]. node bitmap ); b i t a n d (switches bitmap[i], avail bitmap); switches node cnt[i] = bit set count(switches bitmap[i]) ; } #i f SELECT DEBUG @@ -2881 ,8 +2710 ,7 @@ /* Determine lowest level switch satifying request with best fit */ b e s t f i t i n x = -1; for (j=0; j<switch record cnt;j++) { -i f (( switches node cnt[j] < rem nodes) || - ( c o r e c n t && ( s w i t c h e s c p u c n t [j] < c o r e c n t [0]) )) +i f (switches node cnt[j]< rem nodes) continue; i f (( b e s t f i t i n x == -1) || (switch record table[j]. level < @@ -2890 ,7 +2718 ,6 @@ (( switch record table[j]. level == switch record table[b e s t f i t i n x ]. level) && (switches node cnt[j] < switches node cnt[b e s t f i t i n x ]))) -/* We should use core count by switch here as well */ b e s t f i t i n x =j; } i f (b e s t f i t i n x == -1) { @@ -2911 ,17 +2738 ,11 @@ /* Select resources from these leafs on a best - fit basis */ a v a i l n o d e s b i t m a p =bit alloc(node record count); while (rem nodes > 0) { -int avail cores in node; best fit nodes =best fit sufficient = 0; for (j=0; j<switch record cnt;j++) { i f (switches node cnt[j] == 0) continue; -i f (c o r e c n t ) { -sufficient = - ( switches node cnt[j] >= rem nodes) && - ( s w i t c h e s c p u c n t [j] >= c o r e c n t [0]); - } e l s e -sufficient =switches node cnt[j] >= rem nodes; +sufficient = ( switches node cnt[j] >= rem nodes); /* If first possibility OR */ /* first set large enough for request OR */ /* tightest fit ( less resource waste ) OR */ SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut D. Cambios realizados en los ficheros de SLURM 133 @@ -2943 ,9 +2764 ,8 @@ first =b i t f f s (switches bitmap[best fit location]) ; l a s t =b i t f l s (switches bitmap[best fit location]); for (i=first; (( i<= l a s t ) && ( first >=0) ); i++) { -i f (! b i t t e s t (switches bitmap[best fit location], i)){ +i f (! b i t t e s t (switches bitmap[best fit location], i)) continue; - } b i t c l e a r (switches bitmap[best fit location], i); switches node cnt[best fit location]--; @@ -2956 ,26 +2776 ,7 @@ continue; } b i t s e t (a v a i l n o d e s b i t m a p ,i); -i f (c o r e c n t ) -re m c o r e s -= c o r e s p e r n o d e ; i f (--rem nodes <= 0) break; } @@ -2984 ,93 +2785 ,13 @@ i f (rem nodes > 0) /* insufficient resources */ FREE NULL BITMAP(a v a i l n o d e s b i t m a p ); -f i n i :fo r (i=0; i<switch record cnt;i++) { +f i n i :fo r (i= 0; i<switch record cnt;i++) FREE NULL BITMAP(switches bitmap[i]); -FREE NULL BITMAP(s w i t c h e s c o r e b i t m a p [i]); - } - x f r e e (switches bitmap); -x f r e e (s w i t c h e s c o r e b i t m a p ); x f r e e (s w i t c h e s c p u c n t ); x f r e e (switches node cnt); x f r e e (switches required); return a v a i l n o d e s b i t m a p ; }   --- slurm -2.6.2/ src/plugins/select/c o n s r e s /s e l e c t c o n s r e s .h2013-09-10 23:44:33.000000000 +0200 +++ slurm -rcuda/src/plugins/s e l e c t /cons rgpu/select cons rgpu.h2014-01-20 11:46:55.880646814 +0100 +# i f n d e f CONS RGPU H +# d e f i n e CONS RGPU H #include <fcntl.h> #include <stdio.h> @@ -85 ,7 +85 ,6 @@ s t r u c t n o d e r e s r e c o r d { s t r u c t no d e rec o r d *n o d e p t r ;/* ptr to the actual node */ u i n t 1 6 t cpus ;/* count of processors configured */ -u i n t 1 6 t bo ards ;/* count of boards configured */ u i n t 1 6 t s o c k e t s ;/* count of sockets configured */ u i n t 1 6 t c o r e s ;/* count of cores configured */ u i n t 1 6 t vpus ;/* count of virtual cpus ( hyperthreads ) @@ -112 ,4 +111 ,4 @@ extern void cr_sort_part_rows ( struct part_res_record * p_ptr ) ; extern uint32_t cr_get_coremap_offset ( uint32_t node_index ); +# endif /* ! _CONS_RGPU_H */  Sergio Iserte Agut SIU043 - Trabajo Final de M´ aster 134 SIU043 - Trabajo Final de M´ aster Sergio Iserte Agut