⏲️ Slurm signals

⏲️ Slurm signals#

Una situación común es que un job se quede sin tiempo y SLURM lo cancele abruptamente, sin oportunidad de guardar el estado o escribir algun mensaje.

Para evitar este corte repentino, SLURM permite configurar el envío automático de señales a los procesos antes de que se cumpla el tiempo límite. Esta funcionalidad se puede aprovechar para implementar un graceful shutdown: una finalización controlada del trabajo que permita, por ejemplo, guardar el progreso, generar un checkpoint, copiar archivos del scratch al home, etc.

A continuación un ejemplo de juguete para ser adaptado.

Programa de ejemplo#

Primero necesitamos un programa que haga cómputo. Para simplificar el ejemplo, vamos a usar el siguiente script que simula hacer cálculos por 200 segundos.

work.sh#
 1#!/bin/bash
 2
 3function sig_handler() {
 4         echo "$(date +"%H:%M:%S"): pid=$$: Executable interrupted, task=$SLURM_PROCID"
 5         exit 2
 6}
 7
 8trap 'sig_handler' SIGTERM
 9
10echo $(date +"%H:%M:%S"): pid=$$: BEGIN form $(hostname)
11sleep 200 &
12wait
13echo $(date +"%H:%M:%S"): pid=$$: END form $(hostname)

La función sig_handler simplemente imprime un log si el proceso es cancelado.

Script de submit#

El script va a llamar a nuestro programa, cuando éste termine, llama a la función save_results que simula guardar el resultado.

  • SBATCH --time: 10 minutos de límite, y el signal se lanza a los pocos segundos (a los 5 segundos, pero en la práctica no es exacto)

  • SBATCH --signal: Configura la señal que enviará SLURM:

    • SIGTERM: Signal Terminate, solicita amablemente al proceso que termine.

    • @595: Cuantos segundos antes del límite se tiene que enviar la señal (9m55s).

    • B:: Si agregamos esto, la señal va al script. Sin esto, la señal va directamente al programa (ejecutado con srun).

  • srun es bloqueante, por lo que cuando todas las tasks terminen o se cancelen, se va a llamar a save_results.

job.sh#
 1#!/bin/bash
 2#SBATCH --partition=short
 3#SBATCH --nodes=2
 4#SBATCH --ntasks-per-node=1
 5## Format: days-hours:minutes
 6#SBATCH --time=0-0:10
 7## Format: sig_num@time-in-seconds
 8#SBATCH --signal=SIGTERM@595
 9
10. /etc/profile
11
12function save_results {
13	echo $(date +"%H:%M:%S"): Saving results
14
15    for i in {0..100..10}
16    do
17        echo $(date +"%H:%M:%S"): Saving progress $i%...;
18        sleep 10;
19    done
20
21    echo $(date +"%H:%M:%S"): Results saved
22}
23
24echo $(date +"%H:%M:%S"): Calling srun from $(hostname)
25
26srun work.sh
27save_results
28
29echo $(date +"%H:%M:%S"): End of script

Ejemplo de salida#

  • Podemos ver que el srun se ejecuta en el primer nodo.

  • work.sh atrapa la señal e imprime su log.

  • El exit code 2 confirma que el job terminó por la signal.

  • El «proceso de guardado» corre por 100 segundos.

slurm.out#
12:37:02: Calling srun from ivb14.ivb.ccad.unc.edu.ar
12:37:02: pid=713874: BEGIN form ivb14.ivb.ccad.unc.edu.ar
12:37:02: pid=351777: BEGIN form ivb15.ivb.ccad.unc.edu.ar
slurmstepd: error: *** STEP 1052540.0 ON ivb14 CANCELLED AT 2024-06-04T12:37:04 ***
12:37:04: pid=713874: Executable interrupted, task=0
12:37:04: pid=351777: Executable interrupted, task=1
srun: error: ivb14: task 0: Exited with exit code 2
srun: error: ivb15: task 1: Exited with exit code 2
12:37:05: Saving results
12:37:05: Saving progress 0%...
12:37:15: Saving progress 10%...
12:37:25: Saving progress 20%...
12:37:35: Saving progress 30%...
12:37:45: Saving progress 40%...
12:37:55: Saving progress 50%...
12:38:05: Saving progress 60%...
12:38:15: Saving progress 70%...
12:38:25: Saving progress 80%...
12:38:35: Saving progress 90%...
12:38:45: Saving progress 100%...
12:38:55: Results saved
12:38:55: End of script

Si el programa terminal antes, el output tiene la siguiente pinta:

slurm.out#
13:10:44: Calling srun from rome52.rome.ccad.unc.edu.ar
13:10:44: pid=1880296: BEGIN form rome52.rome.ccad.unc.edu.ar
13:10:45: pid=1880296: END
13:10:46: pid=1433777: BEGIN form rome53.rome.ccad.unc.edu.ar
13:10:47: pid=1433777: END
13:10:47: Saving results
13:10:47: Saving progress 0%...
13:10:57: Saving progress 10%...
13:11:07: Saving progress 20%...
13:11:17: Saving progress 30%...
13:11:27: Saving progress 40%...
13:11:37: Saving progress 50%...
13:11:47: Saving progress 60%...
13:11:57: Saving progress 70%...
13:12:07: Saving progress 80%...
13:12:17: Saving progress 90%...
13:12:27: Saving progress 100%...
13:12:37: Results saved
13:12:37: End of script