Le gestionnaire de batch Slurm permet aux utilisateurs d’associer aux jobs des champs optionnels au format texte, tel que le nom du job ou un commentaire. Ces champs ne sont pas directement utilisés par Slurm, leur valeur n’a pas d’influence sur son comportement. Ils sont librement disponible pour stocker des données qui sont liées aux jobs, en les manipulant à travers les commandes standards de Slurm. Ces champs peuvent par exemple se réveler utiles pour différencier, filtrer, classifier ou annoter des jobs.

Nous allons voir dans ce post une méthode pour utiliser le champ de commentaire pour associer des metadonnées structurées aux jobs et enrichir les rapports d’accounting avec des informations personnalisées.

Le commentaire peut être défini à la soumission des jobs avec l’argument --comment:

$ sbatch --comment hello --wrap "sleep 60"
Submitted batch job 943

Il est alors visible avec la commande scontrol show job $ID :

$ scontrol show job 943
JobId=943 JobName=wrap
   Comment=hello

Il est également possible de définir le commentaire pendant l’exécution du job avec la commande scontrol update job $ID.

Par défaut, le commentaire est mémorisé par Slurm tant que le job est en file du scheduler (en attente, bloqué ou en cours d’exécution). Une fois le job terminé, le commentaire est perdu. Il est cependant possible de configurer Slurm pour enregistrer le commentaire dans la base de donnée d’accounting SlurmDBD, en activant ce paramètre dans le fichier de configuration slurm.conf:

AccountingStoreFlags = job_comment

Les commentaires des jobs deviennent alors persistants après la fin des jobs et ils peuvent être récupérés avec la commande d’accounting Slurm standard sacct.

Le champ de commentaire peut stocker un texte, sans contrainte particulière sur son format. Ce texte peut notamment être une représentation sérialisée d’une structure de données, tel que JSON.

Voici un exemple de script de batch shell simpliste comment.sh qui positionne un commentaire un tableau associatif une clé mesh et une valeur entière aléatoire à la fin de son exécution :

#!/bin/sh

# compute stuff here

MESH=$(shuf -i 0-1000 -n 1)
scontrol update job $SLURM_JOB_ID comment="{\"mesh\": ${MESH}}"

En soumettant par exemple deux jobs avec ce script de batch :

$ sbatch comment.sh
Submitted batch job 894
$ sbatch comment.sh
Submitted batch job 895

Il est ensuite possible d’extraire cette métadonnée de l’accounting, en couplant la sortie de la commande sacct à l’utilitaire jq :

$ sacct --json | jq '.jobs | map({id: .job_id, user: .user, cores: .required.CPUs, meta: .comment.job|fromjson })'
[
  {
    "id": 894,
    "user": "remi",
    "cores": 1,
    "meta": {
      "mesh": 760
    }
  },1
  {
    "id": 895,
    "user": "remi",
    "cores": 1,
    "meta": {
      "mesh": 720
    }
  }
]

Voici un exemple plus avancé de script Python comment.py qui met à jour le commentaire en fin d’exécution avec un tableau associatif de 3 clés et des valeurs de types différents :

 1#!/usr/bin/python3
 2import signal
 3import time
 4import atexit
 5import sys
 6import os
 7import subprocess
 8import random
 9import json
10
11def save_metadata():
12    """Save computation metadata in Slurm job's comment."""
13    job_id = os.getenv('SLURM_JOB_ID')
14    metadata = {
15        'mesh': random.randrange(0, 1000),
16        'complexity': random.random(),
17        'tag': random.choice(['choose', 'among', 'three']),
18    }
19    cmd = ['scontrol', 'update', 'job', job_id, f"comment={json.dumps(metadata)}"]
20    print(f"Saving metadata in Slurm job {job_id} comment field")
21    subprocess.run(cmd)
22
23
24def handle_timeout(signum, frame):
25    """Signal handler which stops the computation."""
26    signame = signal.Signals(signum).name
27    print(f"Signal {signame} ({signum}) received due to job timeout, saving "
28           "metadata and exiting properly")
29    sys.exit(0)
30
31
32def main():
33    # Bind SIGUSR1 sent by Slurm to notify of approaching job's timelimit
34    signal.signal(signal.SIGUSR1, handle_timeout)
35    # Register save_metadata() function to run just before exiting the program
36    atexit.register(save_metadata)
37
38    # Start fake computation for 5 minutes
39    print("Starting computation")
40    time.sleep(300.)  # simulating long interruptible computation
41
42
43if name == '__main__':
44    main()

Le script enregistre la fonction save_metadata() (l11) avec le module atexit (l36) pour gérer correctement les cas d’erreur et les interruptions de l’exécution par Slurm, par exemple en cas d’atteinte de la limite de temps ou de préemption.

Ce script a une durée d’exécution approximative de 5 minutes. Il est soumis à Slurm une première fois avec une limite à 10 minutes pour lui laisser le temps de se terminer normalement, et une deuxième fois avec une limite à 3 minutes en demandant à Slurm d’envoyer un signal SIGUSR1 60 secondes avant sa terminaison :

$ sbatch --time 10 --wrap "srun python3 -u comment.py"
Submitted batch job 10773
$ sbatch --time 3 --signal USR1@60 --wrap "srun python3 -u comment.py"
Submitted batch job 10774

Voici les sorties des jobs obtenues dans les deux cas :

$ cat slurm-10773.out
Starting computation
Saving metadata in Slurm job 10773 comment field
$ cat slurm-10774.out
Starting computation
Signal SIGUSR1 (10) received due to job timeout, saving metadata and exiting properly
Saving metadata in Slurm job 10774 comment field

Dans le cas où le job se termine normalement, la fonction save_metadata() est exécutée en fin de job. Dans le cas où le job doit se terminer à cause de sa limite, le script reçoit le signal SIGUSR1, exécute le handler handle_timeout() qui provoque l’arrêt du script, ce qui déclenche l’exécution de la fonction save_metadata().

Nous pouvons ensuite bien extraire ces métadonnées fictives de la base d’accouting Slurm :

$ sacct --json | jq '.jobs | map({id: .job_id, user: .user, cores: .required.CPUs, meta: .comment.job|fromjson })'
[
  {
    "id": 10773,
    "user": "remi",
    "cores": 1,
    "meta": {
      "mesh": 376,
      "complexity": 0.2924316126744422,
      "tag": "among"
    }
  },
  {
    "id": 10774,
    "user": "remi",
    "cores": 1,
    "meta": {
      "mesh": 157,
      "complexity": 0.7724739043178511,
      "tag": "three"
    }
  }
]

Cette fonctionnalité peut se révéler intéressante pour associer diverses metadonnées aux jobs Slurm, notamment pour générer des indicateurs et des métriques supplémentaires et personnalisées dans les rapports d’accounting des calculateurs.