
News
Contenuti per la community dell'HPC e gli appassionati di innovazione: tutorial, news e press release per utenti, ingegneri e amministratori
- Tutte le news
- Aerospace & Defence
- Artificial Intelligence
- Blog
- Cloud Platform
- HPC
- Kubernetes Cluster
- Press
- Progetti Europei
- Ultime news
- Varie E4
- Video
Come creare Job con Slurm ed esempi di automazione

Tra tutti i software comunemente presenti in un cluster HPC, il gestore delle risorse computazionali ha un ruolo di primaria importanza. Infatti, il suo compito è quello di armonizzare l’esecuzione dei Job di tutti gli utenti garantendo che ognuno abbia accesso alle risorse richieste. Questo compito è piuttosto arduo data la grande varietà delle richieste che possono essere effettuate e la complessità delle regole di gestione imposte dagli amministratori. Senza poi contare che ogni cluster HPC è di fatto una piccola opera d’arte creata dalla combinazione delle soluzioni hardware e software magistralmente (o magicamente) orchestrate tra loro per garantire il massimo delle performance e dell’affidabilità. Tutte queste complessità si riflettono nei gestori di risorse, rendendoli uno dei software più antipatici e difficili da usare… ma indispensabili per un proficuo svolgimento della routine quotidiana di ogni utente.
In questo articolo farò del mio meglio per riappacificare il rapporto tra gli utenti di cluster HPC e Slurm,[1] uno dei gestori di risorse open source più popolari a livello mondiale. Nello specifico, vi suggerirò alcune linee guida per la creazione e la gestione dei Job.
Realizzare un Job non-interattivo
All’interno di Slurm, così come per molti altri software di questa categoria, i Job possono essere suddivisi in due macro-gruppi: quelli interattivi e quelli non-interattivi. La differenza è alquanto ovvia, i primi necessitano che l’utente digiti ed esegua i comandi uno alla volta mentre i secondi sono totalmente automatizzati. Solitamente, gli amministratori raccomandano di usare quest’ultimi perché permettono un uso più efficiente delle risorse di calcolo. Tuttavia, raramente sono disponibili dei template per la redazione di “ricette” totalmente automatizzate e quindi devono essere realizzate a mano. Questo task può essere notevolmente semplificato facendo uso di un Job interattivo e di un editor di testo. Vediamo come.
Anzitutto, vi suggerisco di avviare uno di questi Job, usando il seguente comando:
srun --partition=<CODA> --nodes=<NUM SERVER> --ntasks=<NUM CORE> --mem=<MB RAM> --time=<HH:MM:SS> --pty /bin/bash
NB: le parti sottolineate devono essere sostituite con i valori specifici del cluster che state usando.
Eventualmente, potete aggiungere l’opzione --gres=gpu:<TIPO>:<NUM>
qualora il vostro Job necessiti di GPU.
Una volta che verrà visualizzato un prompt, il Job sarà attivo e potranno essere eseguiti i primi comandi come in un classico terminale Linux. Prima di procedere, tuttavia, vi consiglio di creare un nuovo file con il vostro editor di fiducia per cominciare a scrivere la vostra “ricetta” automatizzata. Questo file dovrà iniziare con le seguenti righe:
#!/bin/bash
#SBATCH --partition=<CODA>
#SBATCH --nodes=<NUM SERVER>
...
La prima di queste contiene l’interprete che Linux utilizzerà per eseguire le istruzioni riportate di seguito. Quindi segue la lista di tutte le opzioni che avete utilizzato per sottomettere il Job interattivo (con l’eccezione di --pty
) precedute da #SBATCH
. Questa sintassi permette a Slurm di riconfigurare i propri valori di default, evitandovi l’onere di riscriverle durante la sottomissione del Job non-interattivo.
Una volta concluso il preambolo della “ricetta”, potete procedere con l’esecuzione dei comandi all’interno del Job interattivo come riportato nella documentazione del vostro applicativo, avendo cura di riportarli all’interno del file di testo. Conclusa la trascrizione, il Job non-interattivo è pronto per essere eseguito tramite il comando sbatch
:
sbatch <FILE>
Potreste incontrare delle istruzioni che non possono essere automatizzate con il metodo precedente. Una di queste è la modifica dei file di input. Questo primo scoglio può essere superato tramite il seguente script:
mv <FILE> <FILE>.bk
head -n <NUM LINEE> <FILE>.bk >> <FILE>
cat >> <FILE> << EOF
<LINEA MODIFICATA>
<LINEA MODIFICATA>
...
EOF
tail -n <NUM LINEE> <FILE>.bk >> <FILE>
Nella prima riga il file da modificare viene rinominato in <FILE>.bk
, quindi il comando head
copia le prime righe (ovvero <NUM LINEE>
) dal file originale in un nuovo file (di nome <FILE>
). All’interno del comando cat
dovete inserire un blocco di testo contiguo che contiene tutte le righe già modificare. Infine, il comando tail
copia il numero di linee <NUM LINEE>
da <FILE>.bk
a <FILE>
partendo dal fondo a risalire.
Un altro caso in cui potreste trovare alcune difficoltà durante l’automazione del vostro Job riguarda i comandi che eseguono dei menù interattivi. Per ovviare a queste richieste, basta inserire tutte le risposte (una per riga) all’interno di un file (<INPUT FILE>
in questo esempio) e indicare quest’ultimo come input del comando originale, come riportato di seguito.
<CMD> < <INPUT_FILE>
Prima di chiudere l’editor di testo, vi consiglio di inserire nella vostra “ricetta” le variabili fornite da Slurm, soprattutto quando fate riferimento al numero di server, core, GPU e alla quantità di RAM. In questo modo, il vostro Job sarà in grado di adattarsi a tutte le combinazioni di risorse che userete in futuro. Queste variabili sono elencate all’interno delle guida on-line del comando sbatch
nella sezione “OUTPUT ENVIRONMENT VARIABLES”.[2]
Automazione dei workflow
La produzione di un dato scientificamente rilevante passa solitamente attraverso molti Job, più comunemente descritti come un workflow. Slurm offre molte strategie per l’automazione di questi protocolli permettendo all’utente di svincolare la produzione e la raffinazione di un dato dall’intervento umano. Di seguito vi elenco le tecniche a mio parere più gettonate.
- Job che sottomettono altri Job
Nella prima parte di questo articolo ho accennato al fatto che Slurm esegue i Job all’interno di un terminale Linux standard. Tra i suoi comandi troverete certamente anche sbatch
che vi permette di sottomettere un nuovo Job durante l’esecuzione di un altro.
Questa tecnica viene spesso utilizzata quando il proprio workflow prevede delle fasi di pre- e post-processing dei dati. Solitamente queste elaborazioni richiedono un numero di risorse molto inferiore rispetto al Job principale, quindi è opportuno rilasciare i core inutilizzati così che possano eseguire altri Job.
Prima dell’esecuzione del comando sbatch
, è buona regola inserire dei controlli (ad esempio con dei costrutti if
) che verifichino la bontà dei dati prodotti. Un esempio di controllo è la ricerca di una stringa di successo nei file di output, usando il comando grep
. Un’altra tecnica consiste nella verificare di una caratteristica intrinseca dei file prodotti, ad esempio che la loro dimensione sia superiore ad un valore di soglia. Un’ultima nota riguarda l’esecuzione del comando sleep 5s
dopo sbatch
. Questo consente a Slurm di completare la presa in carico il nuovo Job prima di eseguire le istruzioni successive.
- I Job eterogenei[3]
Questa feature permette di ripartire le risorse di calcolo di un Job in più sub-set. Lo use-case più classico riguarda l’esecuzione contemporanea di più operazioni di post-processing sugli stessi dati tramite risorse computazionali differenti.
Per realizzare un Job eterogeneo, è sufficiente separare i sub-set di risorse del Job eterogeneo con la riga #SBATCH hetjob
, come riportato di seguito:
#SBATCH --ntasks=8 --mem-per-cpu=8G
#SBATCH hetjob
#SBATCH --ntasks=1 --mem=16G --gres=gpu:v100:1
Durante l’esecuzione del Job i sub-set possono essere combinati oppure dedicati in modo esclusivo ad un singolo comando, usando l’opzione --het-group
di srun
.
srun --het-group=0,1 step-0.sh
srun --het-group=0 step-1a.sh : --het-group=1 step-1b.sh
srun --het-group=1 step-2.sh
In questo esempio, step-0.sh
utilizza entrambi i sub-set. step-1a.sh
e step-1b.sh
, invece, sono eseguiti contemporaneamente uno per sub-set. Infine, step-2.sh
utilizza solamente il secondo sub-set (ovvero quello con la GPU secondo lo schema precedente).
Il vantaggio di un Job eterogeneo rispetto a Job separati è l’immediata disponibilità delle risorse per tutti gli script sottomessi con srun
. Infatti, tutte le risorse richieste per un Job eterogeneo vengono allocate all’inizio della sua esecuzione e non verranno rilasciate fino al suo completamento, impedendo quindi ad altri Job di occuparle.
- I Job dipendenti[2]
In Slurm è possibile vincolare l’esecuzione di un Job sulla base dell’esito di un altro. Questa feature è stata implementata per gestire workflow altamente automatizzati che prevedono più sequenze operative da intraprendersi in base agli esiti degli step precedenti. Spesso, però, è utilizzata dagli utenti per limitare il numero di Job eseguiti contemporaneamente, preservando quindi una parte delle risorse di calcolo per task più urgenti.
Per sfruttare questa tecnica è necessario utilizzare l’opzione --dependency
di sbatch
. Questa opzione supporta le seguenti condizioni:
after:<JOBID>:<JOBID>:…
in cui il Job corrente verrà eseguito solamente quanto tutti quelli della lista sono già avviati oppure sono stati cancellati;afterany:<JOBID>:<JOBID>:…
dove il Job corrente verrà eseguito solamente dopo che tutti i Job della lista sono già terminati;afterok:<JOBID>:<JOBID>:…
ovvero il Job corrente verrà eseguito solamente se tutti i Job della lista sono già terminati con successo;afternotok:<JOBID>:<JOBID>:…
in cui il Job corrente verrà eseguito solamente se tutti i Job della lista sono già terminati con un fallimento;singleton
che viene utilizzato per eseguire un solo Job avente lo stesso nome e appartenente allo stesso utente.
Queste condizioni possono essere concatenate tra loro utilizzando “?
” quando è sufficiente soddisfarne una sola oppure “,
” quando devono avere un carattere cumulativo. Il valore di questa opzione può essere modificato in corso d’opera come mostrato nei seguenti esempi:
scontrol update jobid=<JOBID> dependency=afterok:<NUOVO JOBID>
scontrol update jobid=<JOBID> dependency=””
Nel primo caso il valore di dependency
viene sovrascritto con “afterok:<NUOVO JOBID>
”, mentre nel secondo caso esso viene completamente rimosso.
Durante l’implementazione questa feateure nel proprio workflow è necessario ricordare che la dipendenza tra i Job si basa solamente sul loro stato e non sulla qualità dei dati prodotti. Inoltre, non vi è garanzia che i Job che abbiano soddisfatto le proprie dipendenze vengano eseguiti immediatamente dal momento che devono comunque competere con gli altri Job del cluster per le risorse computazionali.
- Le allocazioni[4]
Quest’ultima feature consiste nel sottomettere un Job per “prenotare” delle risorse computazionali per un certo lasso di tempo così da evitare la competizione con gli altri Job del cluster. Solitamente le allocazioni vengono utilizzate per fare brevi test volti al debugging (di uno script per un Job non-interattivo o di un applicativo) oppure per verificare la bontà di un file di input prima di eseguire una simulazione più lunga.
Per creare un’allocazione è necessario utilizzare il comando salloc
come illustrato di seguito:
salloc --partition=<CODA> --nodes=<NUM SERVER> --ntasks=<NUM CORE> --mem=<MB RAM> --time=<HH:MM:SS> --begin=<HH:MM:SS> --no-shell &
Come si può notare, molte delle opzioni di questo comando sono simili a quelle di srun
e sbatch
. A queste deve essere aggiunta --no-shell
che evita di occupare l’intero Job con un terminale interattiva. Un’altra opzione che reputo molto utile in questo ambito è --begin
che indica il momento dopo il quale il Job potrà essere eseguito. Questo permettere di adeguare l’esecuzione del Job alle proprie disponibilità a calendario. Nel caso in cui il vostro tempo a disposizione fosse particolarmente contingentato, è possibile utilizzare l’opzione --deadline
per indicare un orario limite oltre il quale non è più necessario eseguire l’allocazione. Slurm provvederà automaticamente alla sua cancellazione dai Job in coda.
Una volta che il Job è in esecuzione, l’utente può richiedere le risorse “prenotate” utilizzando l’opzione --jobid
di srun
:
srun --nodes=<NUM SERVER> --ntasks=<NUM CORE> --mem=<MB RAM> --jobid=<JOBID_ALLOCAZIONE> test.sh
All’interno di un’allocazione possono essere eseguite anche più di uno step srun
alla volta, purché il numero totale delle risorse richieste non superi quelle “prenotate”.
È buona regola indicare un limite massimo di tempo per l’uso di un’allocazione in modo da non lasciare risorse computazionali inutilmente “prenotate” per lunghi periodi di tempo. Va inoltre considerato che un’allocazione deve comunque competere con gli altri Job del cluster per ottenere le risorse richieste quindi non è garantito che essa venga avviata all’orario indicato nell’opzione --begin
.
Conclusioni
Tra tutti i software presenti nei cluster HPC, Slurm e i gli altri gestori di risorse hanno quasi certamente il primato per essere i meno user-friendly. Tuttavia, spero che le informazioni che vi ho fornito in questo articolo possano aiutarvi ad alleggerire la carica di stress quotidiano causato da questa convivenza forzata… e perché no, incrementare l’efficienza dei vostri Job sfruttando al meglio tutti gli automatismi che vi ho illustrato. Detto ciò, non mi resta che augurarvi una più serena e proficua giornata!
Riferimenti
[1] hhttps://slurm.schedmd.com/overview.html
[2] https://slurm.schedmd.com/sbatch.html