Batch-System Torque
Einstellen (submit) von Jobs
Schnellstart: Hallo Welt
Vorweg ein Beispiel für ein einfaches Job-Skript job.sh auf einem Knoten, mit eMail-Benachrichtigung an eine fiktive Adresse:
#!/bin/bash #PBS -m abe #PBS -q c8 #PBS -l nodes=1:ppn=8 #PBS -M name@example.com #PBS -l walltime=00:00:30 # Finde temporäres Verzeichnis $TMPDIR. source /G/home/rrz/lib/modules.sh module load rrz/tmpdir echo "Meine Job ID: $PBS_JOBID" echo "Mein Verzeichnis: $TMPDIR" cd "$TMPDIR" echo "Hallo Welt!" > hallo.txt echo "Ich habe diese Knoten/CPUs reserviert:" > knoten.txt cat "$PBS_NODEFILE" >> knoten.txt # Sichere Ergebnis ins globale Scratch. outdir=$(/G/home/rrz/bin/rrz-globalscratch)/hallo mkdir $outdir cp hallo.txt knoten.txt $outdir
Mit dem Shell-Kommando
qsub job.sh
wird dieses Skript in der Queue c8 (ein Knoten mit 8 Prozessoren und 16 GiB RAM) eingestellt und kommt zur Ausführung, wenn passende Ressourcen frei sind. Bitte beachten Sie die Hinweise zu den verschiedenen Dateisystemen, insbesondere zum temporären Arbeitsverzeichnis ($TMPDIR).
Will man einen Job wieder löschen, bevor er durchgeführt wurde, geht das mit dem Kommando qdel.
Einleitung
Der Cluster besteht aus Knoten (Nodes) identischer Bauart bei unterschiedlicher Speicherausstattung. Wir unterscheiden anhand des Merkmals Speicher zwei Typen c von d. Typ c (node1 - node70) sind mit 16GB RAM (2GB pro Core) und Typ d (node71 - node84) mit 32GB RAM ausgestattet (4GB pro Core).
Queues
Es stehen - folgt man dem obigen Klassifizierungsmerkmal - zwei Typen von Queues, Typ c und d, zur Verfügung. Neben diesen führen wir noch Test-Queues, bei denen die Speicherzusammensetzung zunächst keine Relevanz hat.
Die konkrete Bezeichnung einer Queue setzt sich zusammen aus Typ + Anzahl an Tasks. Tasks sind meist gleichbedeutend mit Cores. Ein Knoten besitzt insgesamt 8 Cores. Ein simples Beispiel: 1x 16GB Node entspricht der Queue c8. Die Queue d32 dagegen, belegt ganze 4 Knoten mit 32GB Speicher mit jeweils 8 Tasks / Cores pro Node. Es folgt eine Auflistung sämtlicher Queues mit dem Befehl qstat:
rz9a024@hpclogin:~> qstat -q server: master Queue Memory CPU Time Walltime Node Run Que Lm State ---------------- ------ -------- -------- ---- --- --- -- ----- c1 -- -- 336:00:0 1 0 0 16 E R c8 -- -- 72:00:00 1 0 0 16 E R d8 -- -- 72:00:00 1 3 0 8 E R c16 -- -- 120:00:0 2 1 0 10 E R c32 -- -- 48:00:00 4 0 0 10 E R d16 -- -- 72:00:00 2 0 0 7 E R d32 -- -- 48:00:00 4 0 0 3 E R test -- -- 02:00:00 4 0 0 16 E R batch -- -- -- -- 0 0 -- D S d8_long -- -- 192:00:0 1 4 0 4 E R atk -- -- 72:00:00 2 1 0 1 E R c64 -- -- 72:00:00 8 0 0 1 E R test8_short -- -- 00:12:00 1 0 0 4 E R ----- ----- 9 0 rz9a024@hpclogin:~>
Ein weiteres wichtiges Merkmal der Queues ist, neben der Taskanzahl und der Speicherbelegung pro Knoten, die maximale mögliche Laufzeit (=Walltime) der Jobs. Diese ist aus der obigen Tabelle für die aufgeführten Queues ersichtlich.
Weitere detailierte Informationen einer Queue erfragt man mit dem Befehl: qsub -Q [Queue] -f.
Hier ein Beispiel:
1 rz9a024@hpclogin:~> qstat -Q c8 -f 2 Queue: c8 3 queue_type = Execution 4 max_queuable = 30 5 total_jobs = 0 6 state_count = Transit:0 Queued:0 Held:0 Waiting:0 Running:0 Exiting:0 7 max_running = 16 8 resources_max.ncpus = 8 9 resources_max.nodect = 1 10 resources_max.walltime = 72:00:00 11 resources_min.ncpus = 4 12 resources_min.nodect = 1 13 mtime = 1243586154 14 resources_assigned.ncpus = 0 15 resources_assigned.nodect = 0 16 max_user_run = 8 17 enabled = True 18 started = True
Zeile 3 zeigt an, dass es sich um eine "ausführende" Queue zu Berechnungs- bzw. Test-Zwecken (execution) handelt. Zeile 4 gibt die Zahl max. einzustellender Jobs in die Warteliste an. Zeile 5 zeigt die Anzahl aktuell laufender Jobs. Zeile 7 zeigt die maximale Zahl simultan lauffähiger Jobs, Zeile 16 maximale Jobs pro Benutzer. Zeile 9 zeigt die max. Anzahl anforderbarer Nodes an, Zeile 8, die anforderbaren CPUs/Cores, Zeile 10 die Walltime im Format HH:MM:SS, Zeile 11-12 das Minimum der Ressourcen aus Zeile 8, 9. Zeile 14,15 zeigt die Zahl der von Jobs benutzten CPUs/Cores bzw. Nodes.
Weitere Informationen erhalten sie mit dem Befehl: man qstat
Job-Submission
Jobs werden mit dem Befehl qsub an das Batch-System übergeben. Die allgemeine Syntax für den Befehl lautet: qsub -qQUEUE BATCHFILE -lnodes=NNodes:ppn=NCPUs:feature (mem16 für c-Knoten oder mem32 für d-Knoten). Das Batch-File ist ein Textfile, das eine Beschreibung des auszuführenden Jobs liefert:
1 #!/bin/bash 2 3 #PBS -l nodes=2:ppn=8:mem16 4 #PBS -m abe 5 #PBS -M user.nachname@domain.com 6 7 EXEC="/opt/intel/impi/3.2.1/test/test_openmpi1.3.1" 8 MPIRUN="/opt/openmpi/1.3.1/intel/bin/mpirun" 9 10 export LD_LIBRARY_PATH="/opt/openmpi/1.3.1/intel/lib/" 11 source /opt/intel/Compiler/11.0/081/bin/iccvars.sh intel64 12 13 $MPIRUN --mca mpi_paffinity_alone 1 $EXEC
Zeile 1 dient der Beschreibung des Text-Files. In Zeile 3 werden Ressourcen für den Job angefordert: nodes=AnzahlNodes:ppn=ProzessorenproNode. In Zeile 4-5 wird das Batch-System angewiesen, bei Beginn, Beendingung oder Abbruch der Berechnung eine Nachricht (Email) an den angegebenen Empfänger zu versenden. Zeile 7 definiert das Executable, welches als Argument in Zeile 13 dem auszuführenden Befehl (üblicherweise mpirun) übergeben wird. In Zeile 10-11 werden zusätzliche Umgebungsvariablen definiert, die bei Laufzeit benötigt werden.
Zusatz: An Stelle des in Zeile 13 ausgeführten Executable könnte prinzipiell jeder beliebige Befehl (auch non-MPI-Programme oder in Ausnahmefällen sogar ein Skript) stehen. Zum besseren Verständnis sei vermerkt, dass der Befehl mpirun dabei insgesamt soviele Prozesse wie mit der Ressourcen-Angabe definiert worden sind erzeugt und jeweils das Executable einmal pro Thread ausführt. Ein Nutzen von MPI liegt hier neben anderen in der Realisierung des Datenaustauschs auch über die Knotengrenze hinweg. Als technische Basis dient hier der dem Transfer zugrunde gelegte und sehr kurze Latenzzeiten ermöglichende Infiniband-Stack (OFED).
Sie submittieren diesen Job mit: qsub -qc16 BATCHFILE.
Um flexibler bei Berechnungen zu sein, ist es auch möglich ein rudimentäres Batch-File zu halten, wobei dann Ressourcen und zusätzliche Paramter an den Befehl qsub übergeben werden müssen. Mit der Option -l können dafür Ressourcen speziell für den Job angefordert werden, z.B.: qsub -qc16 -lnodes=2:ppn=8:mem16. Die nächste Abbildung zeigt so ein Batch-File:
1 #!/bin/bash 2 3 #PBS -V 4 5 EXEC="/opt/intel/impi/3.2.1/test/test_openmpi1.3.1" 6 MPIRUN="/opt/openmpi/1.3.1/intel/bin/mpirun" 7 8 export LD_LIBRARY_PATH="/opt/openmpi/1.3.1/intel/lib/" 9 source /opt/intel/Compiler/11.0/081/bin/iccvars.sh intel64 10 11 $MPIRUN --mca mpi_paffinity_alone 1 $EXEC
Auch die Mailbenachrichtigung kann per Kommando eingeschaltet werden: qsub -qc16 -lnodes=2:ppn=8:mem16 -m abe -M empfänger@domain.com BATCHFILE
Hier geht's zur Gesamtübersicht vorhandener MPI-Implementationen.
weitere Themen
Debugging von Batchfiles
Die Batchfiles sind eigentlich Shell-Skripte, die mit zusätzlichen Steuerkommandos an PBS übergeben werden. Mit etwas Umsicht bezüglich fehlender Umgebungsvariablen vom Batch-System kann man die Skripte interaktiv testen. Dazu kann man interaktiv einen Knoten reservieren und dort das Script direkt in der Linux-Konsole ausführen. Da die Wartezeit auf eine solche interaktive Reservierung variabel ist, bietet sich aber nach einfachsten lokalen Tests auf dem Login-Knoten das Einstellen von Test-Jobs mit reduzierter Problemgröße ins Batch-System an. Anhand der produzierten Log-Dateien lassen sich Fehler auch diagnostizieren.
Job-Handling
Löschen/Abbrechen eines Jobs geschieht mit dem Befehl qdel (siehe Manpage dazu). Das Verhalten des Schedulers in Bezug auf den Job kann mit checkjob erfragt werden.
Job-Ausgaben / Logging
Sämtliche Outputs eines Jobs werden bei dessen Laufzeit in die Datei BATCHFILENAME.oJOBID bzw. Errors auch nach BATCHFILENAME.eJOBID geschrieben; das heißt in das Verzeichnis, von dem aus man den Job (mit dem Befehl "qsub") submitiert hat. Das ist meistens jedoch: /G/home/USER/. Hier ein simples Beispiel: Heißt das Batchfile z.B. "batch.test" und qsub bzw. qstat geben als JobID "8300" aus, dann finden sich die Ausgaben in batch.test.8300o bzw. die Errors in batch.test.8300e. Man kann sich komfortabel über "cat *JOBID* | less" (für JOBID die Jobnummer einsetzen!) den gesamten Log ausgeben lassen.
Job-Arrays
Job-Arrays ermöglichen es dem Benutzer, multibel Jobs abzuschicken, bei denen sich das Job-File selbst gar nicht oder nur geringfügig ändert. Man denke bei geringfügigen Änderungen beispielsweise an die Setzung neuer Parameter. Die allgemeine Syntax hierzu lautet: qsub -t[a..n(a)]{ ,[b..n(b)] ... } -q[Queue] [Jobfile]. Mit dem Schalter -t werden die Intervalle an den Befehl qsub übergeben. Beispielsweise:
qsub -t 0-4 -q test8_short testfile
Auch folgendes Kommando ist zulässig:
qsub -t 1-20,30-40,45-50 -q test8_short testfile
Job-Arrays benutzen daher auch eine besondere Art der Namenszuweisung (s. 1.Spalte, u.):
rz9a024@hpclogin:~> qstat Job id Name User Time Use S Queue ------------------------- ---------------- --------------- -------- - ----- 2491-0.master test.sh-0 rz9a024 0 Q test8_short 2491-1.master test.sh-1 rz9a024 0 Q test8_short 2491-2.master test.sh-2 rz9a024 0 Q test8_short 2491-3.master test.sh-3 rz9a024 0 Q test8_short 2491-4.master test.sh-4 rz9a024 0 Q test8_short rz9a024@hpclogin:~>
Die so erzeugten Jobs 2491-* des qsub-Befehls (hier der ersten Zeile; s.o.) werden in Form eines Arrays behandelt. An die identische Array-Jobnummer (Prefix vor '-') wird jeweils ein Suffix zur Bezeichnung der (Sub-)Jobs innherhalb des Arrays angehängt. Zusätzlich steht nun innerhalb eines ausgeführten Batch-Skripts die Variable $PBS_ARRAYID zur Verfügung. Variieren kann man daher den Job mit folgender simplen Abfrage-Technik:
#!/bin/bash #PBS -V ... ... while : do [ $PBS_ARRAYID -eq 0 ] && { echo "won't execute!"; break; } [ $PBS_ARRAYID -eq 1 ] && { echo "this won't execute, too!"; break; } [ $PBS_ARRAYID -eq 3 ] && { echo "execute with different parameters!"; $MPIRUN -n 8 --mca mpi_paffinity_alone 1 $EXEC $EXTRA_ARGs break; } # all others $MPIRUN -n 8 --mca mpi_paffinity_alone 1 $EXEC break done ...
Serielle und non-MPI - Jobs (z.B. R)
Für serielle und non-MPI Berechnungen steht ihnen die Queue c1zur Verfügung. Beispiel:
cat BATCHFILE | qsub -qc1 -l ncpus=1
oder auch:
cat BATCHFILE | qsub -qc1 -l ncpus=1 -t0,1,2,3
... um z.B. gleichzeitig 4 Instanzen des Programms auf jeweils einem Core laufen zu lassen (Stichwort: Job-Arrays, s.o.).