Aller au contenu

Gestion des signaux envoyés par Slurm

Il est possible de paramétrer Slurm pour envoyer un signal au calcul quelques secondes ou minutes avant la limite de temps (TimeLimit). Ce signal est interceptable et peut permettre, par exemple, d'envoyer l'ordre de génération d'un fichier de reprise ou de soumettre un nouveau calcul.

Les signaux sous Linux

A la base, les signaux sont utilisés par le noyau Linux pour avertir les processus d'évènements (instruction illégale, adressage mémoire invalide, etc.). Certains signaux sont interceptables par le processus destinataire afin d'exécuter une action associée. D'autres signaux tuent le processus destinataire.

Les signaux peuvent également être utilisés entre processus pour communiquer.

Exemple de signal classique : un CTRL + C au clavier sur un processus en tâche de fond lui envoie un signal SIGTERM.

Une série de signaux sont définie au niveau du système pour une utilisation par les utilisateurs. Ce sont les signaux SIGUSR1 et SIGUSR2.
La commande permettant d'envoyer un signal à un processus est la commande kill.

Gestion des signaux sous Slurm

Par défaut, quand la limite de temps d'un calcul est atteinte, Slurm envoie un signal SIGTERM à tous les processus pour les tuer et terminer le calcul. Les processus ont alors environ 30s pour se terminer. Au delà de ce temps, s'il reste des processus, ils reçoivent un signal SIGKILL. Le signal SIGTERM est un signal interceptable, contrairement au signal SIGKILL qui correspond à une mort assurée et immédiate.

En complément, il est possible de demander à Slurm d'envoyer un signal choisi, un certain temps avant d'atteindre la limite de temps. Le processus peut alors l'intercepter et effectuer des tâches de génération de fichiers de reprises, de nettoyage des données ou de re-soumission de calculs.

Exemple d'utilisation

Le script suivant est en plusieurs blocks :

  • bloc des commandes SLURM (lignes #SBATCH)
  • bloc de déclaration de la fonction et de l'association avec le signal
  • bloc du code avec un & sur la commande srun
  • bloc de fin du script avec un wait puis la recopie des fichiers
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash

#SBATCH --mem-per-cpu=3000
#SBATCH -n 1
#SBATCH -t 0:5:00
#SBATCH -p debug
# asks SLURM to send the SIGUSR1 signal 120 seconds before end of the time limit
#SBATCH --signal=B:SIGUSR1@120


## Handle function ##
# Function executed 120s before the end of the time limit
function sig_handler_USR1()
{
        echo "   function sig_handler_USR1 called"
        # do whatever cleanup you want here
           echo "   Signal trapped -  `date`"
           # Do what you want :
           #    save data ...
           #    cleanup ...
           #    requeue job ...
           #    send signal to MPI job ...
        exit 2
}

## Handle function association ##
# associate the function "sig_handler_USR1" with the USR1 signal
trap 'sig_handler_USR1' SIGUSR1


## Job script ##
cd $LOCAL_WORK_DIR
srun sleep 40000 &


# Let's wait for signals or end of all background commands
wait

# This is the place to move your data files to your home-dir as a normal job
mkdir $SLURM_SUBMIT_DIR/$SLURM_JOB_ID
mv *.log *.dat $SLURM_SUBMIT_DIR/$SLURM_JOB_ID

exit 0

Informations avancées

Paramètre --signal

Format : --signal=[B:]signal[@durée]

  • Si aucune durée n'est indiquée, un signal sera envoyé 60s avant la fin de la limite de temps.
  • Si le "B" n'est pas spécifié, alors le signal est envoyé à tous les processus SAUF au script de lancement. S'il est spécifié, le signal est envoyé au script de lancement uniquement.
  • Les signaux peuvent être spécifiés par leur numéro ou leur nom (ex : 10 ou SIGUSR1). Pour connaître la liste des signaux disponibles sur Myria, à partir d'une frontale, tapez la commande man 7 signal.

Vous pouvez préférer que le signal soit émis vers votre code C ou Fortran afin de lui faire effectuer une action précise (ex : génération d'un fichier de reprise) plutôt que par le script de soumission.

Commande trap

La commande trap permet d'associer une commande ou une fonction à un signal : en cas de réception de ce signal par le script de soumission, son exécution est stoppée pour exécuter la commande ou fonction associée.
Dans l'exemple ci-dessus, la commande trap 'sig_handler_USR1' SIGUSR1 définie l'exécution de la fonction sig_handler_USR1 en cas de réception du signal SIGUSR1 par le script de soumission.

Le nom du signal peut être modifié ou spécifié par une valeur numérique (ex : SIGUSR1 correspond aux signaux 10, 30 et 16).
La fonction peut être remplacée par une commande.

Il est possible de déclarer plusieurs interceptions de signaux différents dans un même script en rajoutant d'autres lignes trap.

Commande wait

La fin d'un script de soumission déclenche la fin du calcul et l'envoie de signaux SIGKILL vers ceux-ci.

La commande wait, comme son nom l'indique, attend que les processus fils (commande(s) srun ... &) soient terminées pour continuer d'exécuter les lignes suivantes.

Si les commandes srun ne sont pas exécutées en tâches de fond, le script bash ne sera pas en mesure d'intercepter les signaux.

Si le calcul contient plusieurs steps (commandes srun) à tourner successivement, il faut alterner des commandes srun ... & et wait afin d'attendre le fin de la commande précédente.

Signal SIGTERM

Comme indiqué plus haut, Slurm envoie un signal SIGTERM quand la limite de temps est atteinte. Il est tout à fait possible de rajouter une interception de ce signal également. Dans ce cas, il suffit de rajouter une ligne trap sur le signal et de l'associer à une fonction.

Si vous avez également utilisé l'option --signal, à la fin de la fonction associée, repassez en mode wait pour attendre la fin du calcul, car si le script de soumission se termine, cela tue ses fils (commandes srun). Cela correspond à remplacer la commande exit 2 de l'exemple par la commande wait

Commande scancel

La commande scancel a un comportement similaire à la commande kill : elle ne "tue" pas, elle envoie un signal à un calcul...

Le signal envoyé par défaut est une succession de 3 signaux : SIGCONT puis SIGTERM et environ 30s plus tard SIGKILL.

Il est possible d'envoyer un autre signal via la commande scancel, en utilisant le paramètre --signal. Afin que le signal soit envoyé uniquement au script de soumission, il faut rajouter l'option -b ou --batch.

exemple : scancel --batch --signal=SIGUSR1 num_job

Code de sortie

Si vous définissez un code de sortie différent dans la fonction sig_handler_USR1 (exemple : exit 2), du code de sortie et fin de script (exemple : exit 0), vous conserverez une trace du mode de sortie de votre calcul :

  • 0 → fin de script normale,
  • 2 → fin de script normale grâce au signal 120s avant la limite de temps

Pour retrouver les codes de sortie d'un précédent calcul, utilisez la commande sacct -j job_id. La colonne "ExitCode" utilise le format Code_d_erreur:Signal_reçu. Le script de soumission correspond à la ligne "batch".

Références


Dernière mise à jour: 16 septembre 2020 17:49:56