La ejecución de trabajos se realiza mediante la herramienta SLURM, un workload manager y job scheduler que gestiona la ejecución de trabajos y recursos computacionales según el orden y prioridad. Gracias a SLURM, es posible una convivencia ordenada y justa entre múltiples usuarios sin interrumpirse entre ellos.
Las particiones son un conjunto de recursos agrupados para un determinado propósito. En el caso del Patagón, existen dos particiones
gpu
Para trabajos de GPU. Esta es la partición principal que caracteriza al Patagón. Puede consultar con el comando scontrol show partition gpu
.
cpu
Para trabajos de CPU secuenciales o paralelos. Esta partición existe para dar la posibilidad a investigaciones que por alguna razón aun no tienen programas que usan GPUs. Cabe mencionar que la cantidad de recursos computacionales de esta partición es mucho menor a la gpu
, ya que el Patagón esta pensado para GPU Computing. Puede consultar con el comando scontrol show partition cpu
.
Comencemos con algo simple, ejecutar el comando nvidia-smi
en el nodo de computo. Este comando lista las GPUs disponibles para utilizar.
➜ ~ srun -p gpu nvidia-smi -L
No devices found.
Como vemos, no existen GPUs disponibles debido a que Slurm asume 0 GPUs por defecto. Para solicitar GPUs, es necesario adicionar el parámetro --gres=gpu:A100:<num>
, donde <num>
es la cantidad de GPUs a solicitar. Por ejemplo, si queremos ejecutar nvidia-smi -L
con una GPU
➜ ~ srun -p gpu --gres=gpu:A100:1 nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-35a012ac-2b34-b68f-d922-24aa07af1be6)
El valor de <num>
define la cantidad de GPUs a reservar. Otro ejemplo, volvamos a ejecutar nvidia-smi -L
ahora pidiendo 4 GPUs
➜ ~ srun -p gpu --gres=gpu:A100:4 nvidia-smi -L
GPU 0: A100-SXM4-40GB (UUID: GPU-baa4736e-088f-77ce-0290-ba745327ca95)
GPU 1: A100-SXM4-40GB (UUID: GPU-d40a3b1b-006b-37de-8b72-669c59d14954)
GPU 2: A100-SXM4-40GB (UUID: GPU-35a012ac-2b34-b68f-d922-24aa07af1be6)
GPU 3: A100-SXM4-40GB (UUID: GPU-b75a4bf8-123b-a8c0-dc75-7709626ead20)
El maximo de GPUs en el patagón es actualmente 8 GPUs. Si se solicitan mas GPUs que la cantidad máxima, se retornara un error de recursos no satisfechos. Si se solicita un numero de GPUs entre 1-8 pero estos no se encuentran disponibles aun (otros usuarios usando GPUs), entonces el trabajo será encolado por SLURM y se ejecutará cuando sea su turno.
En el Patagón, las dependencias de librerías o software se satisface mediante contenedores. Es decir, al ejecutar un trabajo por SLURM, el usuario indica el contenedor que necesita para ejecutar el trabajo. Este contenedor se descarga automáticamente por el plugin pyxis para SLURM y la herramienta enroot para ejecutar contenedores. Así, el contenedor se transforma en el nuevo entorno del trabajo, pudiendo satisfacer todas las dependencias necesarias sin afectar a los otros usuarios ni a la configuración nativa del Patagón. Al finalizar la tarea, el contenedor se desmonta automáticamente del nodo de computo por defecto y se elimina a menos que el usuario indique que quiere conservarlo para futuro uso (y evitar descargarlo nuevamente).
Una razón importante por la que el Patagón maneja las dependencias con contenedores es porque así los nodos quedan libre de software instalado nativamente, disminuyendo las probabilidades de fallas a nivel software, incompatibilidad de versiones y tiempos mantención como también compilación.
Para poder entender mejor la función de los contenedores, ejecutemos nvcc --version
para consultar la versión del compilador de CUDA nvcc
.
➜ ~ srun -p gpu nvcc --version
slurmstepd: error: execve(): nvcc: No such file or directory
srun: error: nodeGPU01: task 0: Exited with exit code 2
Hemos tenido un error como resultado. Esto ocurre porque el nodo DGXA100 de cómputo carece de alguna versión particular de CUDA. Para lograr hacer funcionar este ejemplo, necesitamos indicar un contenedor que incluya CUDA al momento de ejecutar nuestra tarea, en este caso algo tan sencillo como nvcc --version
. Nvidia GPU Cloud (NGC) ofrece diversos contenedores para utilizar, incluyendo el contenedor de CUDA. En este caso, hemos escogido la versión 11.2.2 de CUDA:
➜ ~ srun --container-name=cuda-11.2.2 --container-image='nvcr.io/nvidia/cuda:11.2.2-devel-ubuntu20.04' nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Sun_Feb_14_21:12:58_PST_2021
Cuda compilation tools, release 11.2, V11.2.152
Build cuda_11.2.r11.2/compiler.29618528_0
Para lograr que pyxis/enroot puedan descargar y utilizar automáticamente contenedores de una URL especificada por el usuario, debe configurar sus credenciales.
Una vez que se ha asociado el contenedor a un nombre con --container-name=<nombre>
, luego puedes ejecutar solo utilizando --container-name=<nombre>
para referirte a tu contenedor.
➜ srun --container-name=cuda-11.2.2 nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Sun_Feb_14_21:12:58_PST_2021
Cuda compilation tools, release 11.2, V11.2.152
Build cuda_11.2.r11.2/compiler.29618528_0
Nota (Noviembre 2023): Debido a cambios recientes en pyxis
, para mantener la misma ubicacion dentro del job es necesario incluir --container-workdir=${PWD}
como opcion a srun
.
Por ejemplo, si el usuario es user
y esta actualmente ubicado en /home/user/
, entonces:
➜ ~ pwd
/home/user
➜ ~ srun --container-name=cuda-11.2.2 pwd
/
➜ ~ srun --container-workdir=${PWD} --container-name=cuda-11.2.2 pwd
/home/user
srun
(tiempo-real, anclado a la sesión)El comando srun
permite a los usuarios ejecutar trabajos para verlos en ejecución de forma directa e interactiva en el terminal. Este modo es síncrono con la sesión, es decir, el terminal queda anclado a la ejecución y progreso del trabajo, y si uno termina su sesión (se desconecta del Patagón), entonces el trabajo se pierde (a menos que este usando screen
o algo similar). El comando srun
sigue la estructura
srun --container-workdir=${PWD} <contenedor> <recursos> <tarea>
srun
Supongamos que hemos escrito un programa para GPU que multiplica dos matrices y ahora queremos ejecutarlo en el Patagón usando una GPU, entonces primero compilaríamos el programa
➜ srun --container-workdir=${PWD} --container-name=cuda-11.2.2 make
nvcc -O3 -arch=sm_80 -lnvidia-ml -Xcompiler -fopenmp main.cu -o prog
➜
Y luego podríamos ejecutar el programa
➜ srun --container-workdir=${PWD} --container-name=cuda-11.2.2 --gres=gpu:A100:1 ./prog 0 $((1024*30)) 1
GPU MATMUL
size: 30720 x 30720
mode 1
Exploring GPUs
Driver version: 450.102.04
NUM GPUS = 1
Listing devices:
GPU0 A100-SXM4-40GB, index=0, UUID=GPU-35a012ac-2b34-b68f-d922-24aa07af1be6 -> util = 0%
Choosing GPU 0
initializing A and B.......done
matmul shared mem..........done: time: 11.213796 secs
copying result to host.....done
verifying result...........done
➜
sbatch
(desacoplado de la sesión)El comando sbatch
permite ejecutar tareas por lotes sin la necesidad de mantener la sesión abierta, es decir el usuario puede desconectarse luego de haber lanzado su trabajo con sbatch
. Para utilizar sbatch
es necesario escribir un script, típicamente con extensión *.slurm
, en el cual se indicaran los recursos a solicitar, el contenedor, y la tarea en particular. Una tarea sbatch
puede contener múltiples llamadas a srun
en su script *.slurm
, y aun seguirá siendo considerada como una sola tarea. Esto ultimo es de gran utilidad cuando necesitamos construir un gran trabajo compuesto de trabajos menores. Por ejemplo, una tarea que conste de pre-procesamiento, procesamiento y post-procesamiento podría ser construida con tres llamadas a srun
dentro de un script *.slurm
.
sbatch
Supongamos que hemos escrito un programa para GPU como el producto de matrices. El siguiente script contiene el detalle de la ejecución para sbatch
.
#!/bin/bash
# IMPORTANT PARAMS
#SBATCH -p gpu # Submit to which partition
#SBATCH --gres=gpu:A100:1 # GPU resources, format TYPE:device:quantity
# OTHER PARAMS
#SBATCH -J TUT03-single-GPU # Name the job
#SBATCH -o TUT03-single-GPU-%j.out # Write the standard output to file named 'jMPItest-<job_number>.out'
#SBATCH -e TUT03-single-GPU-%j.err # Write the standard error to file named 'jMPItest-<job_number>.err'
# COMMANDS ON THE COMPUTE NODE
pwd # prints current working directory
date # prints the date and time
# compile the GPU program
srun --container-workdir=${PWD} --container-name=cuda-11.2.2 make
# run the GPU program multiple times
srun --container-workdir=${PWD} --container-name=cuda-11.2.2 ./prog 0 $((1024*30)) 1
Luego para ejecutar el trabajo, ocupamos el comando sbatch
pasando nuestro script como argumento.
➜ sbatch job.slurm
Submitted batch job 2986
➜
El trabajo genera dos archivos de salida que contienen el output estándar del programa en un archivo de extensión *.out
y el output de error en caso de alguna falla, en el archivo de extensión *.err
.
➜ ls
job.slurm main.cu Makefile prog TUT03-single-GPU-2986.err TUT03-single-GPU-2986.out
➜ cat TUT03-single-GPU-2986.out
/home/cnavarro/patagon-samples/01-custom-programs/TUT03-GPU-single
Mon 17 May 2021 09:58:39 PM -04
nvcc -O3 -arch=sm_80 -lnvidia-ml -Xcompiler -fopenmp main.cu -o prog
GPU MATMUL
size: 30720 x 30720
mode 1
Exploring GPUs
Driver version: 450.102.04
NUM GPUS = 1
Listing devices:
GPU0 A100-SXM4-40GB, index=0, UUID=GPU-35a012ac-2b34-b68f-d922-24aa07af1be6 -> util = 0%
Choosing GPU 0
initializing A and B.......done
matmul shared mem..........done: time: 11.215649 secs
copying result to host.....done
verifying result...........done
➜ cat TUT03-single-GPU-2986.err
➜