Sperli: Ränge, die einander Nachrichten schicken

Sperli (Simple Parallel Execution over Remote Links Interface) ist die Cluster-Schicht von Hilde: ein Job aus n Rängen, jeder ein Prozess auf einem gelisteten Host, die Nachrichten mit einem Tag senden und empfangen. Sie hat die Semantik des Nachrichtenaustauschs (Rang, Größe, Senden und Empfangen mit Tag) und nichts von der Schnittstelle von MPI. Die Bytes auf der Leitung stehen in das Sperli-Protokoll; die Abweisungen sind die Codes H1601 bis H1625 aus die Fehlercodes. Diese Seite beschreibt Punkt-zu-Punkt-Nachrichten, die Kollektive, die Checkpoints und den Launcher; die C-Bibliothek folgt auf die Checkpoints.

Sicherheit

Sicherheit ist keine Option und hat keinen Schalter.

hilde run

hilde run -n 3 --hosts hosts.txt ./app arguments

hilde run führt hilde-launcher aus, das make neben hilde baut. Das Programm ist der Pfad einer ausführbaren Datei, die auf jedem Host dieselbe ist. Die Optionen:

OptionBedeutung
-n Ndie Zahl der Ränge, 1 bis 4096; erforderlich
--hosts DATEIdie Hostliste; erforderlich
--deny-hosts DATEINamen, die außer denen von SPERLI_REFUSED_HOSTS und den reservierten abgewiesen werden, einer je Zeile
--checkpoint-dir VERZ, --checkpoint-every SEKUNDEN, --restart-max K, --resume JOB--checkpoint-dir und --restart-max lassen den Launcher einen gescheiterten Job neu starten; die anderen beiden werden gelesen und behalten

Eine Hostliste hat einen Host je Zeile und einen optionalen Port: node1, node2 47001. Eine Zeile, die mit # beginnt, ist ein Kommentar. Rang i läuft auf Zeile i; es muss mindestens N Zeilen geben. Ein Rang auf localhost oder einer Adresse von 127. wird direkt gestartet, bekommt einen freien Port und hört an der Loopback-Adresse seiner Zeile (127.0.0.1 für localhost); jeder andere Rang wird über ssh an Port 62222 gestartet (ssh -p 62222 -o BatchMode=yes host programm argumente, jedes Wort in Anführung) und hört am Port seiner Zeile oder an 47000 und seinem Rang. Die Ausgabe der Ränge wird, Rang für Rang, gezeigt, wenn sie beendet sind: [rank 1] Text. Der Exit-Status ist 0, wenn jeder Rang mit 0 endete.

hilde run [--modules=d:d] DATEI.hiq argumente ist kein Job: es baut das Modul und führt sein main auf diesem Rechner aus; Module, die sich seit einem früheren Bau nicht geändert haben, kommen aus dem Cache übersetzter Module. Erkannt wird es an der Endung .hiq; die Wörter nach der Datei gehören dem Programm.

Ein Rang

Ein Rang liest seinen Job aus der ersten Zeile seiner Standardeingabe und tritt bei:

let line: String := readLine(&!input);
case readJobText(asSpan(&line)) of
    when Right(right as job: Job) do
        case init(job) of
            when Right(right as opened: Comm) do
                var comm: Comm := opened;
                let sent: Int32 := send(&!comm, 1, 7, message);
                case recv(&!comm, 1, 7) of
                    when Right(right as text: String) do
                        destroyString(text);
                    when Left(left as code: Int32) do
                        skip;
                end case;
                finish(comm);
            when Left(left as code: Int32) do
                skip;
        end case;
    when Left(left as code: Int32) do
        skip;
end case;

Kollektive

let code: Int32 := barrier(&!comm);
case allreduce(&!comm, int64Type(), sumReduction(), numbers) of
    when Right(right as total: String) do
        destroyString(total);
    when Left(left as code: Int32) do
        skip;
end case;
AufrufErgebnis
barrier(comm)0, wenn jeder Rang ihn aufgerufen hat
bcast(comm, root, data)die Daten von root auf jedem Rang
reduce(comm, root, type, operation, data)die Reduktion über alle Ränge bei root; sonst die leere Zeichenkette
allreduce(comm, type, operation, data)die Reduktion auf jedem Rang
gather(comm, root, data)die Blöcke aller Ränge in Rangfolge bei root; sonst die leere Zeichenkette
scatter(comm, root, data)Block i der Daten von root auf Rang i

Checkpoints

useCheckpoints(&!comm, "ckpt");
let code: Int32 := checkpoint(&!comm, &state);
case resume(&!comm) of
    when Right(right as back: String) do
        destroyString(back);
    when Left(left as code: Int32) do
        skip;
end case;

Die C-Bibliothek

libsperli ist die C-Schnittstelle von Sperli, für ein Programm, das nicht in Hilde geschrieben ist, etwa das Go-Paket. Sie ist eine statische Bibliothek und ein Header je Ziel:

sh scripts/libsperli/build.sh

schreibt libsperli/c/<ziel>/libsperli.a und libsperli/c/<ziel>/sperli.h, mit <ziel> einem von linux, openbsd, freebsd und darwin, dem System, auf dem das Skript läuft. Ein Programm bindet die Bibliothek mit -lpthread -ltls -lcrypto und nimmt sperli.h ein, der den vollen Text jeder Funktion enthält.

FunktionAufruf
sperli_inittritt dem Job bei, den eine Beschreibung nennt; gibt das Handle
sperli_rank, sperli_sizeder eigene Rang, die Zahl der Ränge
sperli_send, sperli_recveine Nachricht an einen Rang oder von ihm mit einem Tag
sperli_barrier, sperli_bcast, sperli_reduce, sperli_allreduce, sperli_gather, sperli_scatterdie Kollektive
sperli_resultkopiert die Daten heraus, die ein Aufruf behalten hat
sperli_checkpoint_directory, sperli_checkpoint, sperli_resumedie Checkpoints
sperli_finishverlässt den Job
sperli_describeein Satz zu einem Code
CodeNameBedeutung
-1SPERLI_E_NULL_POINTERein Zeiger ist NULL, wo Bytes oder ein Ergebnis gebraucht werden
-2SPERLI_E_BAD_LENGTHeine Länge ist null, wo Daten gebraucht werden, oder über ihrer Grenze
-3SPERLI_E_BAD_RANKein Rang liegt nicht im Job oder ist der eigene, wo ein Gegenüber gebraucht wird
-4SPERLI_E_BAD_TAGein Tag ist größer als 2147483647
-5SPERLI_E_BAD_HANDLEdas Handle ist nicht die lebende Sitzung
-6SPERLI_E_NOT_READYdie Sitzung hält keine Comm
-7SPERLI_E_BAD_TYPEein Elementtyp ist größer als 6
-8SPERLI_E_BAD_OPERATIONeine Reduktion ist 0 oder größer als 10
-9SPERLI_E_BUFFER_TOO_SMALLder Puffer ist kürzer als das Ergebnis; das Ergebnis bleibt erhalten
-10SPERLI_E_NO_RESULTes gibt kein Ergebnis zu holen
-11SPERLI_E_RESULT_PENDINGein früheres Ergebnis wurde nicht geholt
-12SPERLI_E_BUSYein anderer Aufruf läuft
-13SPERLI_E_ALREADY_INITIALISEDder Prozess hält schon eine Sitzung
-14SPERLI_E_BAD_PATHein Pfad enthält ein Nullbyte
-15SPERLI_E_BAD_COUNTdie Daten sind keine ganze Zahl von Elementen oder Blöcken
-16SPERLI_E_INTERNALder Kern antwortete mit einem Code, der keiner dieser ist

Gemischte Jobs, das Summenbeispiel und der Benchmark

Ein Job kann Hilde-Ränge und Ränge des Go-Pakets (sperli, das libsperli benutzt) mischen; Leitung, Zertifikate und Token sind dieselben. Die Programme und Skripte:

PfadWas es ist
examples/sperli-sumdie Summe einer Tabelle mit 3.000.000 Zeilen über die Ränge eines Jobs; Zeile i enthaelt i + 1, die Summe ist also 4500001500000
examples/sperli-benchLatenz und Bandbreite zwischen zwei Rängen: ping, echo, stream und sink
libsperli/test/mixeddie Hilfen der Tests: die Beschreibungen eines Jobs und ein Rang 0, der auf eine gewählte Art falsch ist
scripts/sperli/mixed-test.shdie gemischten Tests
scripts/sperli/bench.shder Benchmark
PaarUmlauf, MittelBandbreite
Hilde und Hilde68 us90,1 MB/s
Hilde (Rang 0) und Go381 us4,3 MB/s
Go und Go547 us4,3 MB/s

Dateien

Ein Rang schreibt seine CA, sein Zertifikat und seinen Schlüssel in ein Verzeichnis sperli-<job>-<rang> des Arbeitsverzeichnisses, nur für seinen Benutzer lesbar, und entfernt sie, wenn er dem Job beigetreten oder daran gescheitert ist. Er braucht ein Arbeitsverzeichnis, in das er schreiben darf.