Fondamenti di scheduler

Ultimo aggiornamento il 2025-08-04 | Modifica questa pagina

Panoramica

Domande

  • Cos’è uno scheduler e perché un cluster ne ha bisogno?
  • Come si lancia un programma da eseguire su un nodo di calcolo del cluster?
  • Come posso catturare l’output di un programma eseguito su un nodo del cluster?

Obiettivi

  • Invia un semplice script al cluster.
  • Monitorare l’esecuzione dei lavori utilizzando gli strumenti della riga di comando.
  • Ispezionare i file di output e di errore dei lavori.
  • Trovare il posto giusto per mettere grandi insiemi di dati sul cluster.

Programmatore di lavoro


Un sistema HPC può avere migliaia di nodi e migliaia di utenti. Come si decide chi riceve cosa e quando? Come facciamo a garantire che un task venga eseguito con le risorse di cui ha bisogno? Questo lavoro è gestito da uno speciale software chiamato scheduler. In un sistema HPC, lo scheduler gestisce i lavori da eseguire dove e quando.

L’illustrazione seguente paragona i compiti di uno schedulatore di lavori a quelli di un cameriere in un ristorante. Se vi è capitato di dover aspettare un po’ in coda per entrare in un ristorante famoso, allora potete capire perché a volte i vostri lavori non partono immediatamente come nel vostro portatile.

Confronta un job scheduler con un cameriere in un ristorante

Lo scheduler utilizzato in questa lezione è Slurm. Sebbene Slurm non sia utilizzato ovunque, l’esecuzione dei lavori è abbastanza simile indipendentemente dal software utilizzato. La sintassi esatta può cambiare, ma i concetti rimangono gli stessi.

Esecuzione di un lavoro batch


L’uso più semplice dello scheduler è quello di eseguire un comando in modo non interattivo. Qualsiasi comando (o serie di comandi) che si desidera eseguire sul cluster è chiamato lavoro e il processo di utilizzo dello schedulatore per eseguire il lavoro è chiamato invio di lavori in batch.

In questo caso, il lavoro da eseguire è uno script di shell, ovvero un file di testo contenente un elenco di comandi UNIX da eseguire in modo sequenziale. Il nostro script di shell sarà composto da tre parti:

  • Alla prima riga, aggiungere #!/bin/bash. L’opzione #! (pronunciata “hash-bang” o “shebang”) indica al computer quale programma deve elaborare il contenuto di questo file. In questo caso, gli stiamo dicendo che i comandi che seguono sono scritti per la shell a riga di comando (con cui abbiamo fatto tutto finora).
  • in qualsiasi punto sotto la prima riga, aggiungeremo un comando echo con un saluto amichevole. Una volta eseguito, lo script di shell stamperà nel terminale qualsiasi cosa venga dopo echo.
    • echo -n stamperà tutto ciò che segue, senza terminare la riga stampando il carattere di nuova riga.
  • Nell’ultima riga, invocheremo il comando hostname, che stamperà il nome della macchina su cui viene eseguito lo script.

BASH

[yourUsername@login1 ~] nano example-job.sh

BASH

#!/bin/bash

echo -n "This script is running on "
hostname

Creare il nostro lavoro di prova

Eseguire lo script. Viene eseguito sul cluster o solo sul nostro nodo di accesso?

BASH

[yourUsername@login1 ~] bash example-job.sh

OUTPUT

This script is running on login1

Questo script è stato eseguito sul nodo di login, ma vogliamo sfruttare i nodi di calcolo: abbiamo bisogno che lo scheduler metta in coda example-job.sh per eseguirlo su un nodo di calcolo.

Per inviare questo task allo scheduler, si usa il comando sbatch. Questo crea un lavoro che eseguirà il script quando verrà spedito a un nodo di calcolo che il sistema di accodamento ha identificato come disponibile per eseguire il lavoro.

BASH

[yourUsername@login1 ~] sbatch  example-job.sh

OUTPUT

Submitted batch job 7

E questo è tutto ciò che dobbiamo fare per inviare un lavoro. Il nostro lavoro è finito: ora lo scheduler prende il sopravvento e cerca di eseguire il lavoro per noi. Mentre il lavoro è in attesa di essere eseguito, viene inserito in un elenco di lavori chiamato queue. Per verificare lo stato del nostro lavoro, controlliamo la coda usando il comando squeue -u yourUsername.

BASH

[yourUsername@login1 ~] squeue -u yourUsername

OUTPUT

JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
    9 cpubase_b example-   user01  R       0:05      1 node1

Possiamo vedere tutti i dettagli del nostro lavoro, soprattutto che è nello stato R o RUNNING. A volte i nostri lavori potrebbero dover aspettare in coda (PENDING) o avere un errore (E).

Dov’è l’output?

Nel nodo di accesso, questo script stampava l’output nel terminale, ma ora, quando squeue mostra che il lavoro è terminato, non viene stampato nulla nel terminale.

L’output del lavoro del cluster viene solitamente reindirizzato a un file nella directory da cui è stato lanciato. Usare ls per trovare e cat per leggere il file.

Personalizzazione di un lavoro


Il lavoro appena eseguito ha utilizzato tutte le opzioni predefinite dello schedulatore. In uno scenario reale, probabilmente non è quello che vogliamo. Le opzioni predefinite rappresentano un minimo ragionevole. È probabile che avremo bisogno di più core, più memoria, più tempo e altre considerazioni speciali. Per avere accesso a queste risorse, dobbiamo personalizzare il nostro script di lavoro.

I commenti negli script di shell UNIX (indicati con #) sono generalmente ignorati, ma ci sono delle eccezioni. Per esempio, il commento speciale #! all’inizio degli script specifica quale programma deve essere usato per eseguirli (di solito si vede #!/usr/bin/env bash). Anche gli schedulatori, come Slurm, hanno un commento speciale usato per indicare opzioni specifiche dello schedulatore. Sebbene questi commenti differiscano da schedulatore a schedulatore, il commento speciale di Slurm è #SBATCH. Tutto ciò che segue il commento #SBATCH viene interpretato come un’istruzione per lo schedulatore.

Illustriamo questo esempio. Per impostazione predefinita, il nome di un lavoro è il nome dello script, ma l’opzione -J può essere usata per cambiare il nome di un lavoro. Aggiungere un’opzione allo script:

BASH

[yourUsername@login1 ~] cat example-job.sh

BASH

#!/bin/bash
#SBATCH -J hello-world

echo -n "This script is running on "
hostname

Inviare il lavoro e monitorarne lo stato:

BASH

[yourUsername@login1 ~] sbatch  example-job.sh
[yourUsername@login1 ~] squeue -u yourUsername

OUTPUT

JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
   10 cpubase_b hello-wo   user01  R       0:02      1 node1

Fantastico, abbiamo cambiato con successo il nome del nostro lavoro!

Richieste di risorse

Che dire di cambiamenti più importanti, come il numero di core e di memoria per i nostri lavori? Una cosa assolutamente fondamentale quando si lavora su un sistema HPC è specificare le risorse necessarie per eseguire un lavoro. Questo permette allo scheduler di trovare il momento e il posto giusto per programmare il nostro lavoro. Se non si specificano i requisiti (ad esempio la quantità di tempo necessaria), è probabile che si rimanga bloccati con le risorse predefinite del sito, il che probabilmente non è ciò che si desidera.

Le seguenti sono diverse richieste di risorse chiave:

  • --ntasks=<ntasks> o -n <ntasks>: Di quanti core di CPU ha bisogno il vostro lavoro, in totale?

  • --time <days-hours:minutes:seconds> o -t <days-hours:minutes:seconds>: Quanto tempo reale (walltime) impiegherà il lavoro per essere eseguito? La parte <days> può essere omessa.

  • --mem=<megabytes>: Di quanta memoria su un nodo ha bisogno il lavoro in megabyte? Si possono anche specificare i gigabyte aggiungendo una piccola “g” dopo (esempio: --mem=5g)

  • --nodes=<nnodes> o -N <nnodes>: Su quante macchine separate deve essere eseguito il lavoro? Si noti che se si imposta ntasks su un numero superiore a quello che può offrire una sola macchina, Slurm imposterà automaticamente questo valore.

Si noti che il solo fatto di richiedere queste risorse non rende il lavoro più veloce, né significa necessariamente che si consumeranno tutte queste risorse. Significa solo che vengono messe a disposizione. Il lavoro può finire per utilizzare meno memoria, meno tempo o meno nodi di quelli richiesti, ma verrà comunque eseguito.

È meglio che le richieste riflettano accuratamente i requisiti del lavoro. In una puntata successiva di questa lezione parleremo di come assicurarsi di utilizzare le risorse in modo efficace.

Invio di richieste di risorse

Modificare il nostro script hostname in modo che venga eseguito per un minuto, quindi inviare un lavoro per esso sul cluster.

BASH

[yourUsername@login1 ~] cat example-job.sh

BASH

#!/bin/bash
#SBATCH -t 00:01 # timeout in HH:MM

echo -n "This script is running on "
sleep 20 # time in seconds
hostname

BASH

[yourUsername@login1 ~] sbatch  example-job.sh

Perché il tempo di esecuzione Slurm e il tempo sleep non sono identici?

Le richieste di risorse sono in genere vincolanti. Se si superano, il lavoro viene eliminato. Utilizziamo il tempo di parete come esempio. Richiederemo 1 minuto di tempo di parete e cercheremo di eseguire un lavoro per due minuti.

BASH

[yourUsername@login1 ~] cat example-job.sh

BASH

#!/bin/bash
#SBATCH -J long_job
#SBATCH -t 00:01 # timeout in HH:MM

echo "This script is running on ... "
sleep 240 # time in seconds
hostname

Inviare il lavoro e attendere che finisca. Una volta terminato, controllare il file di log.

BASH

[yourUsername@login1 ~] sbatch  example-job.sh
[yourUsername@login1 ~] squeue -u yourUsername

BASH

[yourUsername@login1 ~] cat slurm-12.out

OUTPUT

This script is running on ...
slurmstepd: error: *** JOB 12 ON node1 CANCELLED AT 2021-02-19T13:55:57
DUE TO TIME LIMIT ***

Il nostro lavoro è stato annullato per aver superato la quantità di risorse richieste. Anche se questo sembra un problema, in realtà si tratta di una caratteristica. Il rispetto rigoroso delle richieste di risorse consente allo scheduler di trovare il miglior posto possibile per i lavori. Ancora più importante, garantisce che un altro utente non possa utilizzare più risorse di quelle che gli sono state assegnate. Se un altro utente sbaglia e tenta accidentalmente di usare tutti i core o la memoria di un nodo, Slurm limiterà il suo lavoro alle risorse richieste o lo ucciderà del tutto. Gli altri lavori sul nodo non ne risentiranno. Ciò significa che un utente non può rovinare l’esperienza degli altri: gli unici lavori interessati da un errore di programmazione saranno i propri.

Annullamento di un lavoro


A volte capita di commettere un errore e di dover cancellare un lavoro. Questo può essere fatto con il comando scancel. Inviamo un lavoro e poi annulliamolo usando il suo numero di lavoro (ricordate di cambiare il tempo di esecuzione in modo che funzioni abbastanza a lungo da permettervi di annullarlo prima che venga ucciso).

BASH

[yourUsername@login1 ~] sbatch  example-job.sh
[yourUsername@login1 ~] squeue -u yourUsername

OUTPUT

Submitted batch job 13

JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
   13 cpubase_b long_job   user01  R       0:02      1 node1

Ora annullate il lavoro con il suo numero (stampato nel terminale). Un ritorno pulito del prompt dei comandi indica che la richiesta di annullamento del lavoro è andata a buon fine.

BASH

[yourUsername@login1 ~] scancel 38759
# It might take a minute for the job to disappear from the queue...
[yourUsername@login1 ~] squeue -u yourUsername

OUTPUT

JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)

Annullamento di lavori multipli

È anche possibile cancellare tutti i lavori in una volta sola usando l’opzione -u. In questo modo si cancellano tutti i lavori di un utente specifico (in questo caso, l’utente stesso). Si noti che è possibile cancellare solo i propri lavori.

Provare a inviare più lavori e poi annullarli tutti.

Per prima cosa, inviare un trio di lavori:

BASH

[yourUsername@login1 ~] sbatch  example-job.sh
[yourUsername@login1 ~] sbatch  example-job.sh
[yourUsername@login1 ~] sbatch  example-job.sh

Poi, annullarli tutti:

BASH

[yourUsername@login1 ~] scancel -u yourUsername

Altri tipi di lavoro


Finora ci siamo concentrati sull’esecuzione di lavori in modalità batch. Slurm offre anche la possibilità di avviare una sessione interattiva.

Molto spesso ci sono compiti che devono essere eseguiti in modo interattivo. Creare un intero script di lavoro potrebbe essere eccessivo, ma la quantità di risorse richieste è troppo elevata per essere gestita da un nodo di login. Un buon esempio potrebbe essere la creazione di un indice del genoma per l’allineamento con uno strumento come HISAT2. Fortunatamente, è possibile eseguire questo tipo di compiti una tantum con srun.

srun esegue un singolo comando sul cluster e poi esce. Dimostriamo questo eseguendo il comando hostname con srun. (È possibile annullare un lavoro srun con Ctrl-c)

BASH

[yourUsername@login1 ~] srun hostname

OUTPUT

smnode1

srun accetta tutte le stesse opzioni di sbatch. Tuttavia, invece di specificarle in uno script, queste opzioni vengono specificate sulla riga di comando quando si avvia un lavoro. Per inviare un lavoro che utilizza 2 CPU, ad esempio, si può usare il seguente comando:

BASH

[yourUsername@login1 ~] srun -n 2 echo "This job will use 2 CPUs."

OUTPUT

This job will use 2 CPUs.
This job will use 2 CPUs.

In genere, l’ambiente di shell risultante sarà lo stesso di quello di sbatch.

Lavori interattivi

A volte si ha bisogno di molte risorse per l’uso interattivo. Forse è la prima volta che si esegue un’analisi o si sta cercando di eseguire il debug di qualcosa che è andato storto con un lavoro precedente. Fortunatamente, Slurm semplifica l’avvio di un lavoro interattivo con srun:

BASH

[yourUsername@login1 ~] srun --pty bash

Dovrebbe apparire un prompt di bash. Si noti che il prompt probabilmente cambierà per riflettere la nuova posizione, in questo caso il nodo di calcolo su cui si è effettuato l’accesso. Si può anche verificare con hostname.

Creazione della grafica remota

Per vedere l’output grafico dei lavori, è necessario utilizzare l’inoltro X11. Per connettersi con questa funzione abilitata, usare l’opzione -Y quando si effettua il login con il comando ssh, ad esempio, ssh -Y yourUsername@cluster.hpc-carpentry.org.

Per dimostrare cosa succede quando si crea una finestra grafica sul nodo remoto, usare il comando xeyes. Dovrebbe apparire un paio di occhi relativamente adorabili (premere Ctrl-C per fermarsi). Se si utilizza un Mac, è necessario aver installato XQuartz (e riavviato il computer) perché questo funzioni.

Se nel cluster è installato il plugin slurm-spank-x11, si può garantire l’inoltro X11 nei lavori interattivi usando l’opzione --x11 per srun con il comando srun --x11 --pty bash.

Al termine del lavoro interattivo, digitare exit per uscire dalla sessione.

Punti Chiave

  • Lo scheduler gestisce la condivisione delle risorse di calcolo tra gli utenti.
  • Un lavoro è solo uno script di shell.
  • Richiedere poco più risorse di quelle necessarie.