ARREGLOS DE TRABAJOS
Los arreglos de trabajos permiten enviar muchas tareas que difieren en un solo parámetro (por ejemplo el fichero de entrada, el directorio que contiene los datos, entre otros), de forma más eficiente que enviando las tareas individualmente. Se conocen también como array job, job array y array task.
Especificación
Existen diferentes formas de especificar los arreglos:
#SBATCH --array=0-31 # - intervalo
#SBATCH --array=1,3,5,7 # , valores individuales
#SBATCH --array=1-7:2 # : salto
El número de tareas ejecutándose al mismo tiempo se puede especificar con el signo %.
#SBATCH --array=1-31%5 # 5 tareas ejecutándose del arreglo 1-31.
Es importante especificar el número de tareas ejecutándose a valores no más de 5 o 6, para no ocupar todos los nodos con un solo array job.
JOB ID y Variables de ambiente
Además de la variable SLURM_JOB_ID que se crea para cada trabajo, con los arreglos se crean otras variables de ambiente:
SLURM_ARRAY_JOB_ID se dará al primer job ID del arreglo. SLURM_ARRAY_TASK_ID se dará al valor del índice del job array. SLURM_ARRAY_TASK_COUNT se dará al número de las tareas en el arreglo. SLURM_ARRAY_TASK_MAX se dará al mayor valor del valor del índice del arreglo. SLURM_ARRAY_TASK_MIN se dará al menor valor del valor del índice del arreglo.
Por ejemplo, si se envía un --array1-3 y Slurm responde:
Submitted batch job 36
entonces se tiene:
SLURM_JOB_ID=36 SLURM_ARRAY_JOB_ID=36 SLURM_ARRAY_TASK_ID=1 SLURM_ARRAY_TASK_COUNT=3 SLURM_ARRAY_TASK_MAX=3 SLURM_ARRAY_TASK_MIN=1 SLURM_JOB_ID=37 SLURM_ARRAY_JOB_ID=36 SLURM_ARRAY_TASK_ID=2 SLURM_ARRAY_TASK_COUNT=3 SLURM_ARRAY_TASK_MAX=3 SLURM_ARRAY_TASK_MIN=1 SLURM_JOB_ID=38 SLURM_ARRAY_JOB_ID=36 SLURM_ARRAY_TASK_ID=3 SLURM_ARRAY_TASK_COUNT=3 SLURM_ARRAY_TASK_MAX=3 SLURM_ARRAY_TASK_MIN=1
Todas estas variables se pueden utilizar en los scripts de envío, pero las más usadas son SLURM_JOB_ID y SLURM_ARRAY_JOB_ID.
Nombres de ficheros
Para especificar los nombres de ficheros de stdin, stdout y sterr, se sustituyen %A por SLURM_ARRAY_JOB_ID y %a por SLURM_ARRAY_TASK_ID. Por ejemplo:
#SBATCH --output=array_%A_%a.out #SBATCH --error=array_%A_%a.err
Especificar correo
Por defecto Slurm envía correos cuando el trabajo termina, comienza o falla (END, BEGIN, FAIL). En el caso de los arreglos de trabajo, el correo se refiere al job array y no a las tareas. En caso que se desee el envío del correo por las tareas añada: ARRAY_TASKS.
Se debe tener cuidado al usar ARRAY_TASKS por el número de correos que pueda generar.
Ejemplos
Caso 1. 1000 trabajos similares con los mismos recursos, pero con ficheros de entrada diferentes
Ficheros de entrada: fichero-1, fichero-2, …, fichero-1000
#SBATCH --array=1-1000%5 # 1000 trabajos ejecutándose 5 cada vez #SBATCH --output=array_%A_%a.out #SBATCH --error=array_%A_%a.err ./programa < fichero-$SLURM_ARRAY_TASK_ID
Caso 2. El caso anterior pero con ficheros en diferentes directorios
Directorios: directorio1/, directorio2/, … con fichero-1, fichero-2, … en cada directorio respectivamente.
Crear el fichero lista_directorios.txt con los nombres de los directorios en columna.
Es importante notar que los nombres de los directorios pueden no tener una raíz única, no ser iguales e incluso no tener números consecutivos, sino números en cualquier orden.
#SBATCH --array=1-1000%5 # 1000 jobs ejecutándose 5 cada vez #SBATCH --output=array_%A_%a.out #SBATCH --error=array_%A_%a.err # Define la variable DIR usando sed y la lista_directorios.txt DIR=$(sed -n "${SLURM_ARRAY_TASK_ID}p" lista_directorios.txt) # Cambia al directorio DIR cd $DIR # Ejecuta el programa ./programa < fichero-$SLURM_ARRAY_TASK_ID
Otra forma más sencilla de hacer este caso es de la siguiente forma:
- Crear un directorio con fichero-1, fichero-2, …
- Utilizar las siguientes directivas en el script de envío:
#SBATCH --array=1-1000%5 # 1000 jobs ejecutándose 5 cada vez #SBATCH --output=array_%A_%a.out # STDOUT #SBATCH --error=array_%A_%a.err # STDERR # Cambia al directorio del id de la tarea cd $SLURM_ARRAY_TASK_ID # Ejecuta el programa ./programa < fichero-$SLURM_ARRAY_TASK_ID
En esta última forma se utiliza la variable $SLURM_ARRAY_TASK_ID, que almacena el id de la tarea del arreglo.
Caso 3. El caso 2 pero con 5000 trabajos en vez de 1000
Es poco eficiente ejecutar 5000 trabajos en un nodo, por lo que es mejor hacer ciclos con 1000 en un nodo. De esta forma, se tendrán 5 trabajos haciendo cada uno ciclos de 1000.
Directorios: directorio1/, directorio2/, … con fichero-1, fichero-2, …
Crear el fichero lista_directorios.txt con los nombres de los directorios en columna.
En el siguiente script se combina el array task con ciclos de bash para procesar varias ejecuciones cortas.
#SBATCH --array=1-5 #SBATCH --output=array_%A_%a.out #SBATCH --error=array_%A_%a.err # Número de ejecuciones que cada tarea de Slurm debe hacer NUMLINES=1000 # Calcula valores iniciales y finales de esta tarea basados en el task id y el número de ejecuciones STOP=$((SLURM_ARRAY_TASK_ID*NUMLINES)) START="$(($STOP - $(($NUMLINES - 1))))" # Ejecuta un ciclo de bash para esta tarea for (( N = $START; N <= $STOP; N++ )) do DIR=$(sed -n "${SLURM_ARRAY_TASK_ID}p" lista_directorios.txt) cd $DIR endo # Ejecuta el programa ./programa < fichero-$SLURM_ARRAY_TASK_ID
Caso 4. Diferentes opciones para un programa
Es posible pasar diferentes opciones a un programa usando el array task id.
Se escribe un fichero file.txt que contenga en cada línea los argumentos ARG1, ARG2, …
El siguiente es un ejemplo de programa Python al que se le pasan diferentes opciones:
#SBATCH --array=0-4 #SBATCH --output=array_%A_%a.out #SBATCH --error=array_%A_%a.err case $SLURM_ARRAY_TASK_ID in 0) ARGS="-i foo.txt -o foo.out" ;; 1) ARGS="-i bar.txt -o bar.out" ;; 2) ARGS="-i ich.txt -o ich.txt" ;; 3) ARGS="-i pin.txt -o pin.txt" ;; 4) ARGS="-i lsin.txt -o lsin.txt" ;; esac python program.py $ARGS > output-$SLURM_ARRAY_TASK_ID.txt
Notas importantes
Para que los programas escritos en Python y R puedan leer el array task id es necesario cargar los módulos correspondientes.
Python:
import sys jobid = sys.getenv(´SLURM_ARRAY_TASK_ID´)
R:
task_id <- Sys.getenv(¨SLURM_ARRAY_TASK_ID¨)