Gestion des jobs

Introduction au gestionnaire de jobs

Notion de cluster

Un cluster est un ensemble de machines qui se compose d’une frontale, ou plusieurs frontales, et de noeuds de calcul. Une frontale est la machine sur laquelle l’utilisateur se connecte en ssh, tandis que les noeuds sont les machines sur lesquelles l’utilisateur fait tourner ses programmes.

Tous les programmes que l’utilisateur lance se font depuis une frontale en utilisant un gestionnaire de ressources chargé de trouver et d’allouer les ressources requises parmi les noeuds.

Le gestionnaire de ressources utilisé est OAR.

Notion de job

Un job est ce que l’utilisateur soumet au gestionnaire de ressources pour éxécuter un programme. Il est composé d’une description des ressources nécessaires à l’exécution du programme et les commandes permettant cette exécution, généralement fournies dans un script.

Parmi les ressources requises par le gestionnaire de ressources pour la soumission d’un job, on a le nombre de noeuds, de coeurs par noeud, et le temps de calcul maximal. Si l’utilisateur omet ces informations, le gestionnaire applique des valeurs par défaut. Les défauts sont 1 noeud, 1 coeur et 2h maximum.

Un job a un cycle de vie, il est :

  1. Soumis au gestionnaire
  2. En attente de ressources libres (Waiting)
  3. En exécution (Running)
  4. Terminé (Terminated)

Commandes OAR de gestion des jobs

Soumettre un job

La commande pour soumettre un job est oarsub. Cette commande a de nombreuses options que l’on peut trouver en utilisant l’option --help.

[cgirpi@froggy2 ~]$ oarsub --help
Usage: /usr/lib/oar/oarsub [options] [-I|-C|<script>]
Submit a job the OAR batch scheduler
Options are:
 -I, --interactive             Request an interactive job. Open a login shell
                               on the first node of the reservation instead of
                               running a script.
 -C, --connect=<job id>        Connect to a running job
 -l, --resource=<list>         Set the requested resources for the job.
                               The different parameters are resource properties
                               registered in OAR database, and `walltime' which
                               specifies the duration before the job must be
                               automatically terminated if still running.
                               Walltime format is [hour:mn:sec|hour:mn|hour].
                               Ex: host=4/cpu=1,walltime=2:00:00
     --array <number>          Specify an array job with 'number' subjobs
     --array-param-file <file> Specify an array job on which each subjob will
                               receive one line of the file as parameter
 -S, --scanscript              Batch mode only: asks oarsub to scan the given
                               script for OAR directives (#OAR -l ...)
 -q, --queue=<queue>           Set the queue to submit the job to
 -p, --property="<list>"       Add constraints to properties for the job.
                               (format is a WHERE clause from the SQL syntax)
 -r, --reservation=<date>      Request a job start time reservation,
                               instead of a submission. The date format is
                               "YYYY-MM-DD HH:MM:SS".
     --checkpoint=<delay>      Enable the checkpointing for the job. A signal
                               is sent DELAY seconds before the walltime on
                               the first processus of the job
     --signal=<#sig>           Specify the signal to use when checkpointing
                               Use signal numbers, default is 12 (SIGUSR2)
 -t, --type=<type>             Specify a specific type (deploy, besteffort,
                               cosystem, checkpoint, timesharing)
 -d, --directory=<dir>         Specify the directory where to launch the
                               command (default is current directory)
     --project=<txt>           Specify a name of a project the job belongs to
 -n, --name=<txt>              Specify an arbitrary name for the job
 -a, --anterior=<job id>       Anterior job that must be terminated to start
                               this new one
     --notify=<txt>            Specify a notification method
                               (mail or command to execute). Ex:
                                   --notify "mail:name@domain.com"
                                   --notify "exec:/path/to/script args"
     --resubmit=<job id>       Resubmit the given job as a new one
 -k, --use-job-key             Activate the job-key mechanism.
 -i, --import-job-key-from-file=<file>
                               Import the job-key to use from a files instead
                               of generating a new one.
     --import-job-key-inline=<txt>
                               Import the job-key to use inline instead of
                               generating a new one.
 -e  --export-job-key-to-file=<file>
                               Export the job key to a file. Warning: the
                               file will be overwritten if it already exists.
                               (the %jobid% pattern is automatically replaced)
 -O  --stdout=<file>           Specify the file that will store the standart
                               output stream of the job.
                               (the %jobid% pattern is automatically replaced)
 -E  --stderr=<file>           Specify the file that will store the standart
                               error stream of the job.
                               (the %jobid% pattern is automatically replaced)
     --hold                    Set the job state into Hold instead of Waiting,
                               so that it is not scheduled (you must run
                               "oarresume" to turn it into the Waiting state)
 -s, --stagein=<dir|tgz>       Set the stagein directory or archive
     --stagein-md5sum=<md5sum> Set the stagein file md5sum
 -D, --dumper                  Print result in DUMPER format
 -X, --xml                     Print result in XML format
 -Y, --yaml                    Print result in YAML format
 -J, --json                    Print result in JSON format
 -h, --help                    Print this help message
 -V, --version                 Print OAR version number

Soumission de base

La forme la plus basique d’utilisation est celle où on précise uniquement le projet et la commande à lancer : oarsub --project <your-project> <command>

Par exemple, ci-dessous un exemple de soumission de la commande /bin/hostname :

[cgirpi@froggy1 ~]$ oarsub --project cecipex /bin/hostname
[ADMISSION RULE] Set default walltime to 1800.
[ADMISSION RULE] Modify resource description with type constraints
[COMPUTE TYPE] Setting compute=YES
[ADMISSION RULE] Antifragmentation activated
[ADMISSION RULE] You requested 0 cores
[ADMISSION RULE] No antifrag for small jobs
OAR_JOB_ID=15576103

Chaque job est identifié de façon unique par son identifiant de job (OAR_JOB_ID). Dans l’exemple, cet identifiant a pour valeur 15576103.

Attention, la commande que vous passez en argument de oarsub, et que vous voulez exécuter sur le noeud, doit avoir les droits d’exécution. et être accessible depuis les noeuds. En particuier si le chemin d’accès n’est pas dans la variable d’environnement PATH, il faut alors passer en argument la commande avec son chemin complet.

Soumission avec demande explicite de ressources

Avec la soumission de commande précédente, nous n’avons demandé aucune ressource spécifique. Ainsi, en message de retour, le gestionnaire de ressources OAR nous a alloué le walltime par défaut (1800 secondes) et nous indique qu’aucun coeur de calcul n’a été demandé.

Walltime et fin de job Si votre job se termine normalement (ou plante !) avant le temps indiqué par le walltime, tout va bien, les ressources sont libérées aussitôt. En revanche, s’il est encore en cours d’exécution à la fin du walltime, il sera tué. Assurez-vous donc de spécifier un walltime suffisant pour qu’il puisse se terminer dans le temps imparti, mais pas trop grand afin qu’il ne patiente pas inutilement dans la file d’attente du gestionnaire de ressources.

Pour réservé des ressources explicitement, il faut utiliser l’option -l de la commande oarsub. Par exemple :

bouttier@froggy1 $ oarsub --project test -l /nodes=4/core=1,walltime=1:00:00 /bin/hostname
[ADMISSION RULE] Modify resource description with type constraints
[COMPUTE TYPE] Setting compute=YES
[ADMISSION RULE] Antifragmentation activated
[ADMISSION RULE] You requested 4 cores
[ADMISSION RULE] No antifrag for small jobs
OAR_JOB_ID=15676746

Avec cette commande, nous avons demandé 1 coeur sur 4 noeuds, soit un total de 4 coeurs, pour une durée maximale (walltime) d’une heure.

Comme nous l’avons vu auparavant, chaque job est identifié à l’aide d’un numéro unique pour chaque cluster contenu dans la variable d’environnement $OAR_JOB_ID, ici 15676746. Par défaut, comme le job s’exécute sur des ressources non accessibles directeemnt, nous n’avons pas accès aux sorties standard et erreur dans lesquelles nos commandes peuvent renvoyer des informations. En réalité, ces sorties sont recopiés dans deux fichiers propres à chaque job, nommés respectivement OAR.$OAR_JOB_ID.stdoutet OAR.$OAR_JOB_ID.stderr. Ces fichiers sont créés par OARla où vous avez soumis votre job.

Les mots-clés les plus couramment utilisés sont décrits dans ce tableau :

Mots-clésSignification
nodesNb de noeuds demandés
coreNb de coeurs demandés
cpuNb de cpu demandés
walltimeTemps maximal d’exécution demandé

Voici plusieurs exemples de réservations de ressources :

oarsub -l /nodes=10,walltime=00:05:00 --project test /bin/hostname

Ici, nous réservons 10 noeuds complets pour 5 minutes dee temps d’exécution maximal.

oarsub -l /core=54,walltime=00:00:30 --project test /bin/hostname

Dans ce cas, 54 coeurs sont réservés, que le gestionnaire va choisir en fonction des disponibilités de la machine (sur un nombre indéfini de noeuds au moment de la soumission), le tout pour 30 secondes de temps d’exécution.

oarsub -l /nodes=3/cpu=1, walltime=2:00:00 --project test /bin/hostname

Enfin, ici, nous demandons 3 noeuds avec 1 cpu sur chacun (les autres cpu de ces noeuds soeront donc dédiés à d’autres jobs), pour 2 heures de temps d’exécution maximal.

La mémoire vive La mémoire vive qui vous est allouée est celle correspondant aux coeurs que vous avez réservés. Ainsi, si vous réservez 1 noeud entier, vous avez accès à la totalité de la mémoire vive (RAM) du noeud. En revanche, si vous demandez n coeurs, vous aurez accès à `RAM_du_noeud*(n/nb_total_de_coeurs_sur_le_noeud)

Soumettre un job interactif

Une pratique courante pour bien appréhender la calcul sur un cluster est de soumettre un job interactif. En bref, voous demandez des ressources, et le gestionnaire de ressources va vous connecter sur l’une d’entre elle (un noeud sur lequel elle vous a alloué un coeur) à partir duquel vous pourrez lancer vos commandes/scripts/programmes en interactif. A la fin du walltime, votre session est automatiquement tuée. Si vous la quittez avant, le gestionnaire libérera vos ressources.

La soumission en interactif se fait à l’aide de l’option -I de la commande oarsub. Par exemple :

bouttier@froggy1 $ oarsub -I -l /nodes=1,walltime=1:00:00 --project admin
[ADMISSION RULE] Modify resource description with type constraints
[COMPUTE TYPE] Setting compute=YES
[ADMISSION RULE] Antifragmentation activated
[ADMISSION RULE] You requested 16 cores
[ADMISSION RULE] Disabling antifrag optimization as you are already using /node property
OAR_JOB_ID=15676747
Interactive mode : waiting...
Starting...

Connect to OAR job 15676747 via the node frog80

bouttier@frog80 $

Nous pouvons faire ici plusieurs remarques :

  • Nous avons lancé oarsubsur la frontale (froggy1 dans la premier prompt)
  • L’option -I a été bien rajoutée
  • Nous n’avons pas indiqué de commande à exécuter (absence de /bin/hostname)
  • Le gestionnaire de jobs nous a alloué 16 coeurs puisque nous avons demandé 1 noeud entier (qui comportent 16 coeurs sur le cluster froggy)
  • Une fois le job interactif lancé, nous sommes connecté à notre job via le noeud frog80

Nous voyons qu’ici, avec le deuxième prompt, nous sommes connecté sur le noeud frog80à partir duquel nous pourrons manipuler les fichiers, lancer des commandes, des scripts en interactif. Pour quitter le job, il suffit de quitter le noeud via la commande exit.

Soumettre un job à l’aide d’un script de soumission

La soumission interactive est utile pour prendre en main le cluster, faire des tests. En revanche, pour lancer automatiquement un ensemble de commande (préparation de fichier, préparation de l’environnement logiciel, exécution du programme principal, récupération des fichiers de sorties et nettoyage), il est très peu recommandé.

Dans ce cas d’utilisation, nous allons soumettre un job via un script de soumission. Ce script de soumission peut-être écrit dans différents langages interprétés, le plus souvent bashet python.

Le script de soumission va contenir l’ensemble des instructions dont vous avez besoins pour effectuer votre expérience ainsi que des directives OAR qui indiqueront aux gestionnnaires de ressources tout ce dont vous avez besoin. Ces directives sont signalées par la chaîne de caractères #OARen début d’une ligne. Attention, #OARn’est pas un commentaire de votre script de soumission.

Le script de soumission sera ensuite passé en paramètre à la commande oarsub à l’aide de l’option -S. Il faudra préalablement l’avoir rendu exécutable à l’aide de la commande chmod +x.

Comme mille mots valent bien une image, passons à un exemple concret. Voici un script de soumission complètement inutile mais qui illustrera tous les mécanismes que nous avons besoin de présenter ici. Nous l’appellerons donc logiquement dumb.sh dont voici le contenu :

#!/bin/bash

#OAR -n Hello_World
#OAR -l /nodes=2/core=1,walltime=00:01:30
#OAR --stdout hello_world.out
#OAR --stderr hello_world.err
#OAR --project test

cd /bettik/bouttier/
/bin/hostname >> dumb.txt

On peut distinguer deux grandes parties dans ce script :

  • Une partie dédiée aux directives qui seront lues par OAR, indiquées par #OAR
  • Les directives exécutées sur les ressources réservées sur le cluster.

Pour ces dernières, ce script, qui ne va fonctionner que sur les clusters lukeet dahu, va :

  • se déplacer dans le dossier /bettik/bouttier/
  • Écrire la sortie de la commande /bin/hostname dans le fichier dumb.txt. Pour qu’il fonctionne sur froggy, il faudrait travailler dans le dossier /scratchen lieu et place du dossier /bettik.

Pour les directives OAR,nous remarquons ici quelques options connues de oarsub. Regardons ligne par ligne ce que nous demandons au gestionnaire de ressources :

#OAR -n Hello_World

Ici, nous nommons notre job hello_world.

#OAR -l /core=1,walltime=00:01:30

Nous demandons 1 coeur pour 1 minutes 30 secondes maximum.

#OAR --stdout hello_world.out

Le fichier de sortie standard s’appellera hello_world.out.

#OAR --stderr hello_world.err

Le fichier d’erreur standard s’appellera hello_world.err.

#OAR --project test

Nous indiquons que nous appartenons au projet test.

En réalité, ces directives reprennent les options que nous passons en temps normal à la commande oarsub. Il est à noter que toutes les options décrites ici peuvent être utilisées en ligne de commande avec oarsub

Ici, les fichiers de sorties standard et erreur sont nommés indépendamment de l’identifiant de job. Cela peut être dangereux, parce que si soumettez plusieurs fois le script, cahque job écrira dans ce fichier et nous perdrons potentiellement les informations relatives à chaque job.

Avant de soumettre le script, il faut d’abord le rendre exécutable :

chmod +x dumb.sh

Maintenant, nous pouvons soumettre le script :

oarsub -S ./dumb.sh

Une fois les ressources demandées disponibles, la série de commandes décrite dans le script s’exécutera.

Suivre un job

Pour connaître l’état et les caractéristiques d’un job soumis, il faut utiliser la commande oarstat. Exécutée toute seule, cette commande renverra l’état des jobs soumis par l’ensemble des utilisateurs sur le cluster. Pour des raisons de lisibilités, nous allons la restreindre à un seul utilisateur à l’aide de l’option -usuivie du login :

bouttier@f-dahu:~$ oarstat -u bouttier
Job id    S User     Duration   System message
--------- - -------- ---------- ------------------------------------------------
4936641   W bouttier    0:00:00 R=1,W=0:1:30,J=B,N=Hello_World,P=admin,T=heterogeneous

Le résultat donne l’ensemble des jobs soumis par cet utilisateur. Nous voyons qu’il n’en a qu’un. Nous voyons son identifiant, son état (ici, W pour waiting, il est en attente de lancement), combien s’est écoulé depuis le début de son exécution (ici 0 puisqu’il est encore en attente) et ses caractéristiques (ressources demandées, walltime, nom, projet, type).

Pour connaître les informations détaillées d’un job, une fois muni de son identifiant, nous pouvons exécuter la commande suivante :

bouttier@f-dahu:~$ oarstat -f -j 4936641
Job_Id: 4936641
    job_array_id = 4936641
    job_array_index = 1
    name = Hello_World
    project = admin
    owner = bouttier
    state = Terminated
    wanted_resources = -l "{type = 'default'}/core=1,walltime=0:1:30"
    types = heterogeneous
    dependencies =
    assigned_resources = 1067
    assigned_hostnames = dahu66
    queue = default
    command = dumb.sh
    exit_code = 32512 (127,0,0)
    launchingDirectory = /home/bouttier
    stdout_file = hello_world.out
    stderr_file = hello_world.err
    jobType = PASSIVE
    properties = ((((hasgpu='NO') AND compute = 'YES') AND sequential='YES') AND desktop_computing = 'NO') AND drain='NO'
    reservation = None
    walltime = 0:1:30
    submissionTime = 2019-11-01 16:17:58
    startTime = 2019-11-01 16:18:09
    stopTime = 2019-11-01 16:18:11
    cpuset_name = bouttier_4936641
    initial_request = oarsub -S dumb.sh; #OAR -n Hello_Worl; #OAR -l /core=1,walltime=00:01:3; #OAR --stdout hello_world.ou; #OAR --stderr hello_world.er; #OAR --project admi
    message = R=1,W=0:1:30,J=B,N=Hello_World,P=admin,T=heterogeneous (Karma=0.000,quota_ok)
    scheduledStart = no prediction
    resubmit_job_id = 0
    events =
2019-11-01 16:18:12> SWITCH_INTO_TERMINATE_STATE:[bipbip 4936641] Ask to change the job state

Ici, la ligne state = Terminatednous indique qu’il est maintenant terminé.

Supprimer un job

Si vous avez lancé un job et que vous vous êtes apercu qu’il est inutile qu’il se poursuive (calcul inutile, erreur dans le script de soumission, etc.) vous pouvez supprimer votre soumission à l’aide de la commande oardel :

bouttier@f-dahu:~$ oarsub -S dumb.sh
[PARALLEL] Small jobs (< 32 cores) restricted to tagged nodes
[ADMISSION RULE] Modify resource description with type constraints
OAR_JOB_ID=4936645
bouttier@f-dahu:~$ oardel 4936645
Deleting the job = 4936645 ...REGISTERED.
The job(s) [ 4936645 ] will be deleted in the near future.

Le karma

Sur un cluster OAR, vous pouvez voir une valeur de karma lorsque vous soumettez un travail interactif, ou lorsque vous demandez le statut d’un job (oarstat -j $JOB_ID) ou lorsque vous vérifiez vos données comptables. Il s’agit d’une valeur utilisée pour assurer le partage équitable des ressources que nous utilisons sur chaque cluster de GRICAD. Le partage équitable signifie que le système essaie de permettre l’utilisation des ressources avec équité entre les utilisateurs. Plus votre karma est faible, plus vous avez de chances que vos travaux commencent avant ceux d’un utilisateur qui a une valeur karma plus élevée. Le karma est fonction du temps de calcul que vous avez demandé et effectivement consommé dans le passé (pendant une fenêtre coulissante, généralement une semaine ou deux selon la plateforme). Mais notez que le karma (et l’algorithme de partage équitable) n’est utilisé que lorsque le système est plein d’emplois. La plupart du temps, la programmation est de type FIFO avec remplissage.