Das Queueing-System

Programme auf Soroban werden in der Regel nicht interaktiv gestartet, sondern als Job an ein sog. queueing system geschickt. Das eingesetzte System heißt Slurm (Simple Linux Utility for Resource Management). Das Queueing-System ist so konfiguriert, dass versucht wird dafür zu sorgen, dass die Ressourcen unter den Nutzern gerecht aufgeteilt werden. Damit werden Jobs von Nutzern, die in der jüngeren Vergangenheit nicht sehr viel CPU-Zeit verbraucht haben, tendenziell vor denen von Nutzern, die aktiver waren, starten. Dieser Ansatz wird fairshare scheduling genannt.

Grundlegende Befehle

Die wichtigsten Kommandos sind:
sbatch einen Job-Skript abschicken z.B. sbatch myscript.sh
scancel einen Job löschen z.B. scancel 123
sinfo verfügbare Partitions und Knoten anzeigen z.B. sinfo -l
squeue / smap Jobs im Queue anzeigen z.B. squeue -u myusername
Mehr Informationen finden Sie bei den entsprechenden man pages, z.B. man sbatch. Beachten Sie, dass ein Job-Skript muss ausführbar sein - dies kann mit chmod u+x myscript.sh erreicht werden.

Batch-Skript-Beispiele

Allgemeine Bemerkungen

Gearbeitet sollte generell im Dateisystem scratch. Nur die Ergebnisse, die nach Beendigung des Jobs sollte auf dem Dateisystem home erzeugt oder dorthin kopiert werden. Weitere Information zu den Dateisystemen stehen hier.

Zeilen, die mit #SBATCH anfangen enthalten die Steuerinformationen für das Queuing-System. Aus Sicht der Shell handelt es sich nur um Kommentare, die ignoriert werden. Sie können daher auch beliebige andere Shellsprachen (csh, ksh, Python. Perl, ...) verwenden, solange die Syntax #SBATCH als Kommentar zulässig ist.

Einfacher serieller Job

Hier ist ein Beispiel für einen einzelnen seriellen Job. Der angegebene job name erscheint in dem Feld NAME der Ausgabe von squeue. Eine Email wird an die angegebene Adresse geschickt, wenn der Job zu Ende geht.

#!/bin/bash

#SBATCH --mail-user=username@zedat.fu-berlin.de # replace with your own address
#SBATCH --job-name=my_serial_job                # replace the name 
#SBATCH --mail-type=end
#SBATCH --mem=2048                              # replace with amount suitable for your job
#SBATCH --time=08:00:00                         # replace with amount suitable for your job

cd /scratch/username                            # replace with your own directory
serial_prog > serial.out                        # replace with your own program

Die Option --mem spezifiziert die maximal benötigte Speichermenge in Megabytes. Dieser sollte immer angegeben werden, da der Default-Wert lediglich 1 MB beträgt, was für viele Jobs nicht ausreichend sein wird.

Die Option --time legt die maximale _wall-clock_-Zeit fest, die vom Job benötigt wird. Falls dieser Wert nicht angegeben wird, gilt der Default-Wert der Partition und der Job wird nicht von Backfilling profitieren können.

Einfacher MPI-paralleler Job

Hier ist ein Beispiel für einen MPI-parallelen Job. Die Anzahl der Knoten, auf denen der Job laufen soll, muss angegeben werden. Darüber hinaus muss das Module für die MPI-Implementierung geladen werden, die zum Compilieren des Programms verwendet wurde.

#!/bin/bash

#SBATCH --mail-user=username@zedat.fu-berlin.de # replace with your own address
#SBATCH --job-name=my_parallel_job              # replace name
#SBATCH --mail-type=end
#SBATCH --ntasks=32                             # replace with amount suitable for your job
#SBATCH --mem-per-cpu=4096                      # replace with amount suitable for your job
#SBATCH --time=08:00:00                         # replace with amount suitable for your job

module load gcc openmpi/gcc                     # replace with module suitable for your job

cd /scratch/username                                  # replace with your directory
mpirun -np $SLURM_NTASKS parallel_prog > parallel.out # replace with your program

Die Speicheranforderungen werden normalerweise via --mem-per-cpu angegeben. Es ist aber auch möglich, den benötigen Speicher mit der Option --mem zu spezifizieren. Diese bestimmt die maximal benötigte Speichermenge pro Knoten in MB. Der Speicher sollte immer angegeben werden, da sonst, wie oben beschrieben, der Default-Wert zum tragen kommt. Die Variable $SLURM_NTASKS enthält automatisch den Wert, der durch --ntasks spezifiziert wurde.

Einfacher SMP-paralleler Job

Hier ist ein Beispiel für einen einfachen SMP-parallelen Job. Die Anzahl der Tasks für den Job muss angegeben werden.

#!/bin/bash

#SBATCH --mail-user=username@zedat.fu-berlin.de # replace with your address
#SBATCH --job-name=my_smp_parallel_job          # replace name
#SBATCH --mail-type=end
#SBATCH --ntasks=8                              # replace with amount suitable for your job
#SBATCH --nodes=1-1
#SBATCH --mem-per-cpu=4096                      # replace with amount suitable for your job
#SBATCH --time=08:00:00                         # replace with amount suitable for your job

cd /scratch/dummyuser                           # replace with your directory
smp_prog > parallel.out                         # replace with your program

Man beachte, dass die Anzahl der erforderlichen Knoten explizit mit --nodes=1-1 auf eins gesetzt wird. Sonst könnten sich die dem Job zugewiesen Kerne auch auf mehreren Knoten befinden und stünden damit den Job nicht zur Verfügung.

Job-Array

Für eine große Zahl von Jobs, die durch eine einzelne ganze Zahl parametrisiert werden können, kann man ein Job-Array verwenden:

#!/bin/bash

#SBATCH --mail-user=username@zedat.fu-berlin.de # replace with your own address
#SBATCH --job-name=my_array_job                 # replace the name 
#SBATCH --mail-type=end
#SBATCH --mem=2048                              # replace with amount suitable for your job
#SBATCH --time=08:00:00                         # replace with amount suitable for your job

cd /scratch/username                            # replace with your own directory
my_prog ${SLURM_ARRAY_TASK_ID} > my_prog.out    # replace with your own program

Ein Job-Array wird folgendermaßen abgeschickt:

sbatch --array=1-20 my_script.sh

Für jeden Wert, der durch die Option --array spezifiziert wird, wird die Variable ${SLURM_ARRAY_TASK_ID} im Skript durch diesen Wert ersetzt. Die maximale Array-Größe ist 3001.

Mehrteiliger serieller Job

Manchmal besteht ein Job aus mehreren Schritten, die als Kette hintereinander ausgeführt werden müssen. Folgender Perl-Skript kann für diesen Fall verwendet werden.

#!/usr/bin/perl

use strict;
use warnings;

my $script_file = '~/chain/script.sh';           # Define Slurm script to be
my $log_file    = '~/chain/out.log';             # run and common output file

my @parameter_sets = ("first $log_file",         # Define parameters set to
                      "second $log_file ",       # be passed for each step
                      "third $log_file");

my $job_id   = -1;                               # Initialize job ID variable

# Main loop over parameter sets
#
for (my $i = 0; $i < scalar(@parameter_sets); $i++) {

    my $cmd = 'sbatch';                          # Construct call to sbatch
    if ($job_id > 0) {                           # and add dependency
        $cmd .= " --dependency=afterOK:$job_id";
    }
    $cmd .= " $script_file $parameter_sets[$i] $i 2>&1";

    my $output = `$cmd`;                         # Submit job and abort if no
    ($output =~ /^Submitted batch job (\d+)/)    # job ID is returned
      or die "Error executing $cmd";

    $job_id = $1;
}

Obiges Perl-Skript wird interaktiv ausgeführt und erzeugt Aufträge, die an das Batch-System geschickt werden und von ihm dann abgearbeitet werden.

Speicher

Wie oben erwähnt, muss die Speichermenge, die ein Job erfordert, mittels der Option --mem-per-cpu oder --mem (Speicher pro Knoten) angegeben werden. Der Gesamtspeicher ist in der Tabelle unten aufgelistet:

Knoten # Speicher
node003-node042 40 24 GB
node001-node002, node043-node100 60 48 GB
node101-node112 12 96 GB

Allerdings haben die Knoten keine Festplatten, so dass das Betriebssystem vollständig im Speicher gehalten werden muss. Damit ist der Speicher, der den Nutzern tatsächlich zur Verfügung steht, weniger. Dieser Wert wird als RealMemory vom Befehl scontrol shown node <node name> angegeben, z.B.

$ scontrol show node node003
NodeName=node003 Arch=x86_64 CoresPerSocket=6
   CPUAlloc=7 CPUErr=0 CPUTot=12 Features=(null)
   Gres=(null)
   OS=Linux RealMemory=18000 Sockets=2
   State=MIXED ThreadsPerCore=1 TmpDisk=0 Weight=1
   BootTime=2013-07-19T03:21:29 SlurmdStartTime=2013-07-19T03:39:31
   Reason=(null)
$ scontrol show node node101
NodeName=node101 Arch=x86_64 CoresPerSocket=6
   CPUAlloc=11 CPUErr=0 CPUTot=12 Features=bigmem
   Gres=(null)
   OS=Linux RealMemory=90000 Sockets=2
   State=MIXED ThreadsPerCore=1 TmpDisk=0 Weight=2
   BootTime=2013-06-28T04:47:24 SlurmdStartTime=2013-06-28T04:57:41
   Reason=(null)

Partitionen

Der Cluster besteht wird in mehrere sogenannte Partitionen aufgeteilt. Eine Partition bezeichnet eine Gruppe von Knoten, die aufgrund ihrer Hardware unterschieden werden. Die auf soroban verfügbaren Partitionen können mit dem Befehl sinfo aufgelistet werden.

Die Partition kann im Batch-Skript mit folgender Zeile angegeben werden:

#SBATCH --partition=gpu

Quality of Service

Eine Dienstqualität - quality of service oder QOS - ist ein Satz von Parametern, die mit einem Job assoziiert sind. Die QOS, die verfügbar sind, sowie die Eigenschaften, die sie definieren, können mit dem Befehl sqos angesehen werden.

Ein QOS kann die Priorität eines Jobs erhöhen, dies wird aber durch eine Verringerung der maximalen Laufzeit des Jobs ausgeglichen. Darüber hinaus kann nur eine begrenzte Zahl von Jobs pro Nutzerin oder Nutzer mit einem gegeben QOS abgeschickt werden bzw. kann damit laufen.

Mit folgendem im Batch-Script kann der QOS festgelegt werden:

#SBATCH --qos=medium

Damit kann z.B. ein Test-Job in der Partition 'main' mit der QOS 'short' gestartet werden, der sich über viele Knoten erstreckt. Achtung: Eine Einschränkung, wie TimeLimit, die von der QOS festgelegt wird, wird gegenüber der gleichen, von der Partition festgelegten Einschränkung Vorrang haben.

Interaktive Jobs

Es ist möglich, innerhalb des Queuing-Systems interaktiv zu arbeiten, in dem man den Befehl srun verwendet, z.B.

$ srun --ntasks=1 --time=00:30:00 --mem=1000 bash

Ein konsolbasierte MATLAB-Sitzung kann mit folgenden Befelen gestartet werden:

$ module add matlab
$ srun --licenses=matlab_MATLAB --partition=interactive --qos=short --reservation=licenses_matlab --mem=4000 --pty matlab -nodesktop -nosplash

Für graphische Anwendungen muss die Option --x11 verwendet werden. Man kann z.B. einen interaktiven Job, der die graphische Oberfläche von MATLAB benutzt, mit folgenden Befehlen starten:

$ srun --partition=interactive --qos=short --reservation=licenses_matlab --licenses=matlab_MATLAB --ntasks=1 --cpus-per-task=1 --time=00:30:00 --mem=4000 --pty --x11 bash
$ module add matlab
$ matlab

Um mehrere Programme parallel laufen zu lassen, muss man zuerst die Ressourcen mit dem Befehl salloc reservieren, z.B.

$ salloc --partition=interactive --qos=short --ntasks=4 --nodes=1-1 --time=00:30:00 --mem=4000

Danach können beispielsweise zwei Jobs, job01.sh und job02.sh, die einen beziehungsweise drei Kerne benötigen, auf folgender Weise gestartet werden:

$ srun --partition=interactive --qos=short --ntasks=1 job01.sh && srun --ntasks=3 job02.sh