Forschungsprojekte wie Seti@home haben es vorgemacht: Das freie Framework Boinc tranchiert aufwändige Rechenaufgaben zu handlichen Arbeitspaketen, passend für viele einzelne Computer. Dieser Artikel zeigt, wie man eine verteilte Anwendung für Boinc selbst schreibt.
Komplexe Berechnungen oder Simulationen verlangen große Rechnerleistung. Mit dem Framework Boinc lassen sich vorhandene Computer-Ressourcen mit vergleichsweise geringem Aufwand in ein leistungsfähiges Clustersystem verwandeln. Hinter der Abkürzung Boinc verbirgt sich die Berkeley Open Infrastructure for Network Computing [1].
Dabei handelt es sich um eine Sammlung kleinerer Anwendungen, die zusammen eine Kommunikationsinfrastruktur bereitstellen, die einzelne Rechner zu Clustern nach den Prinzipien des Public Resource Computing (PRC) zusammenschaltet (Abbildung 1). Die bekannteste Boinc-Anwendung stammt von dem Projekt Seti@home [2], das außerirdische Radiosignale auswertet und das freie Framework seit 2004 einsetzt.

Abbildung 1: Client- und Serverkomponenten: Kommunikationsinfrastruktur und Anwendungen innerhalb des Boinc-Framework.
Nach dem Motto “Teile und herrsche” verteilt Boinc die Lösung einer komplexen Aufgabe, etwa die Bearbeitung von Filmsequenzen, auf viele Rechner. Einzige Voraussetzung: Das Problem ist in voneinander unabhängige Arbeitspakete, die so genannten Workunits, aufteilbar. Die Ablaufsteuerung und Verteilung der Arbeitspakete übernehmen die Softwarekomponenten von Boinc.
Manager und Client
Es gibt Komponenten für die Server- und für die Client-Seite. Die Client-Seite installiert mit dem Boinc-Manager automatisch auch den Boinc-Client. Der Manager ist ein erweitertes grafisches Dashboard (Abbildung 2). Über diese Oberfläche konfiguriert der Anwender, an welchen Rechenprojekten er teilnehmen möchte. Daneben kann er hier Ressourcen-Einstellungen vornehmen, die Bearbeitung eines Projekts unterbrechen oder wieder aufnehmen sowie den Fortschritt der Verarbeitung ablesen.

Abbildung 2: Der Boinc-Manager zeigt den Bearbeitungsstand aller Workunits und erlaubt es dem Anwender, Jobs zu pausieren oder abzubrechen.
Der Client ist das Herzstück eines Boinc-Projekts. Er verwaltet die eigentlichen Berechnungsroutinen. Der Boinc-Client ist eine Terminalanwendung und für die Kommunikation mit einem Boinc-Projektserver zuständig. Er lädt die für das ausgewählte Projekt anstehenden Arbeitspakete sowie das auszuführende Programm per HTTP vom Server herunter. Nach der Bearbeitung der Workunits schickt der teilnehmende Computer die Ergebnisse per HTTP wieder an den Boinc-Server zurück.
Die Server-Seite besteht aus den Komponenten Feeder, Transitioner, Validator, Assimilator, File Deleter und kleineren Applikationen, die Einträge in einer Datenbank periodisch aktualisieren. Mit Hilfe dieser Komponenten überprüft das System die Rechenergebnisse und führt sie zusammen.
Das Rückgrat der Infrastruktur bildet eine MySQL-Datenbank. Diese speichert die gesamten Informationen über die im Cluster registrierten Computer und Anwender, die verfügbaren Projekte, den Berechnungsstand einer Aufgabe und eventuell die Ergebnisse.
Bunnys bearbeiten
Dieser Artikel beschreibt eine Anwendung, die das Prinzip von Boinc exemplarisch vorführt. Sie modifiziert eine Filmsequenz durch Effekte. Als Beispiel kommt dazu der Animationsfilm “Big Buck Bunny” [3] zur Verwendung, der unter einer Creative-Commons-Lizenz verfügbar ist (Abbildung 3).

Abbildung 3: Ein Bild aus der Original-Filmsequenz (oben links) und die von der Beispielanwendung modifizierten Versionen: Kantendetektion (oben rechts), Ölgemälde (unten links) und Negativbild (unten rechts).
Zunächst teilen Skripte die gesamte Filmsequenz in kleine Teilsequenzen auf. Jeder Clientrechner lädt sich eine oder mehrere Teilsequenzen herunter und modifiziert diese mit verschiedenen Algorithmen der Bildverarbeitung. Am Ende führt ein Skript auf dem Server die Teilsequenzen wieder zu einem Film zusammen.
Programmierung in C++
Das Programm für die Bildbearbeitung ist in C++ geschrieben, wofür das Boinc-Framework ein umfangreiches API bereithält. Um eigene Anwendungen für die Schnittstelle zu schreiben, muss der Entwickler die Boinc-Quellen selbst übersetzen. Informationen dazu finden sich im Kasten “Installation”.
Installation
Die Serverkomponenten und Entwicklungsbibliotheken für Boinc stehen – im Gegensatz zu Boinc-Client und -Manager – nicht als binäre Pakete zur Verfügung. Wer ein eigenes Boinc-Projekt aufsetzt, muss diese Komponenten also selbst aus dem Quelltext übersetzen. Wie das funktioniert, beschreibt die Boinc-Dokumentation unter [8].
Einfacher ist es, die Beispielanwendung zu diesem Artikel von [9] herunterzuladen. Dieses Paket enthält Skripte, die die Boinc-Quellen aus dem Web holen, das hier vorgestellte Beispiel kompilieren und eine Filmsequenz auf einem lokalen oder weltweiten Cluster bearbeiten. Es lässt sich grundsätzlich jedes Video verwenden. Aus Lizenzgründen hat sich die Redaktion für den Creative-Commons-Film “Big Buck Bunny” entschieden.
Zu den Installationsvoraussetzungen gehört der Apache-2.x-Webserver mit SSL-Modul und PHP-5-Unterstützung. Außerdem ist eine MySQL-Datenbank erforderlich, mindestens in Version 4.0.9. Alle weiteren Abhängigkeiten listet eine eigene Seite im Boinc-Wiki auf [10].
Nach dem Entpacken des Archivs liegen einige Dateien und Verzeichnisse vor. Die Datei »README.DEUTSCH« begleitet den Anwender Schritt für Schritt, vom Aufsetzen des Boinc-Servers über das Anlegen eines neuen Projekts bis zum Erstellen der Arbeitspakete.
Das Boinc-API unterstützt den Programmierer bei Projekten für einzelne oder mehrere (Multicore-)Prozessoren. Ab Revision 22674 ermöglicht Boinc darüber hinaus die Programmierung von Nvidia- und ATI-Grafikprozessoren (GPU). Nvidia-Prozessoren lassen sich mit Open CL [4] oder CUDA [5], ATI-Prozessoren nur mit Open CL programmieren.
Für alle Funktionen des Boinc-API gilt prinzipiell, dass Funktionsaufrufe die nicht »0« (»BOINC_SUCCESS« ) zurückgeben, einen Fehler erzeugt haben. In der aktuellen Version gibt es 135 Fehlernummern (-235 bis -100). Das Client-API funktioniert unter Linux, Mac OS X und Windows. Der Boinc-Server dagegen wird offiziell nur unter Linux unterstützt.
Lediglich eine Handvoll Funktionen ist notwendig, um ein eigenes Boinc-Projekt zu erstellen. Vor der ersten Verwendung ist es erforderlich, das Boinc-Framework zu initialisieren. Hierzu stehen zwei Funktionen zur Verfügung:
int boinc_init(); int boinc_init_options(BOINC_OPTIONS* opt);
Die erste Initialisierungsfunktion ist die am meisten genutzte und kommt auch für das Beispiel in diesem Artikel zum Einsatz. Mit der zweiten Funktion (und der Möglichkeit der Übergabe eines Zeigers auf eine Struktur) lässt sich das Laufzeitverhalten beeinflussen. Climateprediction.net beispielsweise bedient sich dieser Variante. In diesem Projekt benötigen die Workunits mehrere Tage bis Wochen (im hier beschriebenen Beispiel nur Minuten). Daher bekommt der Projektserver in einem definierten Intervall ein Lebenszeichen übermittelt, sodass er das Arbeitspaket nicht als verloren oder abgebrochen verzeichnet.
Wenn bei der Ausführung ein abrupter Fehler auftritt, lässt sich das Programm mit zwei Funktionen beenden:
int boinc_finish(int status); int boinc_temporary_exit(int delay);
Den Parameter »status« sollte der Programmierer mit Bedacht wählen: Ein Wert gleich 0 bedeutet, dass alle Anweisungen ohne Fehler abgearbeitet wurden. Bei einem anderen Wert wird das Arbeitspaket verworfen und dieser Vorgang bei der nächsten Kommunikation dem Projektserver gemeldet. Der Projektserver entscheidet, ob er das Arbeitspaket erneut an denselben oder an einen anderen Client zur Bearbeitung schickt oder komplett verwirft.
Atempause
Die zweite Funktion ist für Projekte mit GPU-Nutzung interessant. Berechnungen auf einer GPU verwenden den Speicher auf der Grafikkarte. Dabei kann es vorkommen, dass dieser Speicher zum gewünschten Zeitpunkt kurzfristig nicht reservierbar ist. In den meisten Fällen handelt es sich hierbei allerdings nur um ein temporäres Problem. Der Parameter »delay« erlaubt es daher dem Entwickler, ein Warte-Intervall anzugeben, nach dem die Software erneut versucht das Projekt zu starten.
Der Entwickler eines Boinc-Projekts hat hinsichtlich der Datensatzformate in den Workunits völlig freie Hand. Er legt das Format selbst fest, ist aber auch für das korrekte Erzeugen und Auslesen dieser Datensätze verantwortlich. Dabei kann es sich zum Beispiel um reinen Text oder binäre Daten handeln. Eine Workunit wird in einem so genannten Slot (Abbildung 4) ausgeführt.
Schablonen für Ein- und Ausgabe
Die gelben Elemente in Abbildung 4 muss der Entwickler selbst erstellen. In der Regel braucht er die Eingabe- und Ausgabeschablonen nur einmal zu schreiben und kann sie für künftige Workunits derselben Applikation wiederverwenden. Eine Modifikation ist meist nur nötig, wenn Eingabedateien hinzukommen oder entfernt werden.

Abbildung 4: Ein- und Ausgabeschablonen erzeugen eindeutige Namen für die zu verarbeitenden Dateien.
Die Eingabeschablone (Input Template) enthält zwei Dateibeschreibungen für die logischen Namen der Eingabedateien. »file_number« 0 definiert den Dateinamen »lmboinc.xml« , 1 beschreibt den Dateinamen »archive_in.zip« . Diese Dateien machen eine Workunit aus.
Die Ausgabeschablone (Result Template) beschreibt das Verhalten im Umgang mit Berechnungsergebnissen:
- »<OUTFILE_0/>, <generated_locally/>« beschreibt einen generierten Namen, den das Boinc-Framework definiert und der eindeutig ist, sodass sich das Ergebnis ohne Konflikte an den Boinc-Server übertragen lässt, »generated_locally« beschreibt eine neu erstellte Datei auf Seiten des Boinc-Clients.
- »<upload_when_present/>« bewirkt, dass die Datei zum Projekt hochgeladen wird, wenn das entsprechende Arbeitspaket abgearbeitet ist.
- »<max_nbytes/>« beschränkt die Ergebnisgröße in Bytes. Benötigt das Ergebnis mehr Speicherplatz, meldet Boinc einen Fehler.
- »<UPLOAD_URL/>« ist eine Substitution zu der Adresse, an die die Berechnungsergebnisse gehen. Diese Adresse ermittelt Boinc automatisch aus den Projektinformationen.
Das Slot-System erlaubt dem Entwickler einen statisch definierten Namen wie »archive_in.zip« für die Eingabedateien zu verwenden. Damit lassen sich mehrere Instanzen einer Applikation starten, die alle den virtuellen Dateinamen »archive_in.zip« zum Öffnen verwenden. Intern wird zur physikalisch vorhandenen Eingabedatei umgelenkt.
Bei Workunits mit dem Namens-Template »wu_edge_%06d.zip« wird »%06d« bei der Generierung der Workunits mit einer fortlaufenden Identifikationsnummer besetzt. Das Umlenken zu der richtigen Eingabedatei erledigen die zwei Funktionen in Listing 1.
Listing 1
Dateinamen auflösen
01 int boinc_resolve_filename(const char *logical_name, char *physical_name, int len); 02 int boinc_resolve_filename_s(const char *virtual_name, std::string &physical_name);
Die Beispielanwendung für diesen Artikel nutzt durchgehend die zweite Funktion, da sie eine potenzielle Fehlerquelle für Buffer-Overflows vermeidet. Der ermittelte physikalische Dateiname lässt sich mit »FILE* boinc_fopen(const char *path, const char *mode);« öffnen. So kommt das richtige Pfadformat für Windows beziehungsweise Unix und Linux zur Verwendung.
Konfigurationsdatei
Das Boinc-API bietet eine Bibliothek zum Verarbeiten von XML-Ausdrücken. In der implementierten Beispielanwendung erhält jede Workunit eine Konfigurationsdatei im XML-Format (Listing 2). Diese Datei ist Teil des Arbeitspakets und vom Entwickler anzulegen. In der Konfigurationsdatei stehen Parameter für die Ausführung, die angeben, welcher Copyright-Vermerk in das Ausgabebild geschrieben wird und welches Dateiformat die einzelnen Ergebnisbilder besitzen.
Listing 2
Konfigurationsdatei
01 <lmboinc> 02 <mode>edge</mode> 03 <copyright>www.bigbuckbunny.org</copyright> 04 <size>320x240</size> 05 <type>RGBA</type> 06 </lmboinc>
Listing 3 zeigt die verwendete XML-Implementierung: Zeile 2 deklariert die oben erwähnten Eigenschaften. Die Zeilen 4 bis 34 lesen die einzelnen XML-Elemente ein. »MIOFILE« dient dem Auslesen von geöffneten Dateien. »XML_PARSER« parst die XML-Tags. Zuerst müssen Zeile 10 und die folgenden den Anfang des XML-Baums ermitteln. Danach wird der gesamte Baum innerhalb einer »while-Schleife« durchlaufen, jede Zeile wird auf bestimmte XML-Tags überprüft und bei Übereinstimmung für die spätere Verwendung abgespeichert.
Listing 3
XML-Datei verarbeiten
01 typedef struct LMBoincXML {
02 string mode, copyright, size, type;
03 inline void init() { ... }
04 int parse(FILE *lmBoincXMLFile) {
05 init();
06 MIOFILE xmlMIOFile;
07 xmlMIOFile.init_file(lmBoincXMLFile);
08 XML_PARSER p(&xmlMIOFile);
09
10 if(!p.parse_start("lmboinc")) {
11 fprintf(stderr, "lmboinc.xml is not
12 formatted correctly\n");
13 return ERR_XML_PARSE;
14 }
15
16 bool is_tag = false;
17 char tag[128] = {'\0'};
18 while (!p.get(tag, sizeof(tag), is_tag)) {
19 if (!is_tag) {
20 fprintf(stderr, "unexpected text in
21 lmboinc.xml: %s\n", tag);
22 continue;
23 }
24 if (!strcmp(tag, "/lmboinc")) return 0;
25 if (p.parse_string(tag, "mode",
26 this->mode)) continue;
27 if (p.parse_string(tag, "copyright",
28 this->copyright)) continue;
29 if (p.parse_string(tag, "size",
30 this->size)) continue;
31 if (p.parse_string(tag, "type",
32 this->type)) continue;
33 }
34 return 0;
35 }
36 } LMBoincXML;
Die XML-Konfigurationsdatei »lmboinc.xml« ist eine von zwei Eingabedateien. Die zweite Datei ist ein Zip-Archiv und enthält das in eine PNG-Sequenz umgewandelte Stück der Videodatei, das die Anwendung bearbeiten soll.
Der Anwender kann die Ausführung jederzeit unterbrechen und zu einem späteren Zeitpunkt fortführen. Um nicht bei jedem Neustart das komplette Arbeitspaket neu berechnen zu müssen, bietet es sich an, den Zwischenstand – wie viele Bildsequenzen der Rechner bereits bearbeitet hat – in einer so genannten Checkpoint-Datei zu speichern. Dabei ist es wiederum dem Entwickler überlassen, wie das Dateiformat für die Zwischenspeicherung aussehen soll. Die Beispielanwendung speichert die Zahl der bereits bearbeiteten Sequenzen (Listing 4).
Listing 4
Checkpointing
01 boinc_resolve_filename_s( 02 CHECKPOINT_FILE, checkpointPath); 03 04 checkpointFile = boinc_fopen( 05 checkpointPath.c_str(), "w+"); 06 if (checkpointFile != NULL) 07 fprintf(checkpointFile, 08 "%d\n", countFilesDone); 09 fclose(checkpointFile);
Checkpoint-Dateien
Eine Checkpoint-Datei entsteht in einer atomaren, also nicht unterbrechbaren Aktion. Da jeder Plattenzugriff zu Leistungseinbußen führt, kann der Anwender im Boinc-Manager die Zeit zwischen der Erstellung von Checkpoint-Dateien definieren. Die Funktion »boinc_time_to_checkpoint()« überprüft diesen Wert. Sollte das Intervall überschritten sein, springt Boinc in den atomaren Bereich, erstellt die Checkpoint-Datei und verlässt den atomaren Bereich mit »boinc_checkpoint_completed()« .
Bei jedem Neustart der Anwendung liest Boinc die Checkpoint-Datei und springt zum zuletzt bearbeiteten Zip-Archiv-Index. Der abgespeicherte Wert lässt sich außerdem für die Fortschrittsanzeige im Boinc-Manager verwenden. Dazu zählt das Programm die im Zip-Archiv vorhandenen sowie die bereits bearbeiteten Bildsequenzen.
Die Software verwendet das Intervall zwischen 0 und 1 für den so genannten »Fraction Done« -Wert: 0 steht für den Beginn der Ausführung, 1 für eine vollständig abgearbeitete Workunit. Den Wert in Pozentpunkten gibt Boinc mit »boinc_fraction_done(countFilesDone /(double) countFilesArchive)« an den Manager weiter. Mit »boinc_report_app_status(cpuTime, checkpointCpuTime, fractionDone)« kann der Programmierer außerdem die seit dem letzten Start der Anwendung genutzte CPU-Zeit und die CPU-Zeit seit dem letztem Erstellen einer Checkpoint-Datei übergeben.
Die letztgenannte Funktion arbeitet jedoch nur ordnungsgemäß, wenn bei der Initialisierung die Option für das automatische Aktualisieren deaktiviert wurde:
BOINC_OPTIONS opt; opt.send_status_msgs = false; boinc_init_options(&opt);
Zur Bearbeitung der einzelnen Bildsequenzen (Listing 5) dient das Programm Imagemagick [6] samt der Programmierschnittstelle Magick++ [7]. Der Kasten “Installation” beschreibt, wie Anwender in wenigen Schritten eine Boinc-Installation ausführen und erste Berechnungen durchführen können. Die Autoren haben ein Starterpaket erstellt, das Einsteiger mit Hilfe einfacher Skripte bei den ersten Schritten mit Boinc unterstützt [9].
Listing 5
Bearbeitung mit Magick++
01 Magick::Blob blob((void*)imageBuffer,
02 zipFileInformation.size);
03 Magick::Image img;
04 img.size(lmBoincConfiguration.size);
05 img.magick(lmBoincConfiguration.type);
06 img.read(blob);
07 if (lmBoincConfiguration.mode == "edge")
08 image.edge();
09 if(lmBoincConfiguration.mode == "oil")
10 image.oilPaint();
11 if(lmBoincConfiguration.mode
12 == "shade")
13 image.shade();
14 if(lmBoincConfiguration.mode
15 == "negate")
16 image.negate();
17 if(lmBoincConfiguration.mode
18 == "normalize")
19 image.normalize();
20 }
21 img.fillColor("white");
22 img.fontPointsize(20);
23 img.draw( Magick::DrawableText(5, 20,
24 lmBoincConfiguration.copyright) );
Ausblick
Die Boinc-Dokumentation [11] hilft dem Entwickler auch mit Beispielcode beim Einstieg. Neben nativen Programmen, die das Boinc-API verwenden, lassen sich auch bestehende Anwendungen in einen Wrapper packen oder virtuelle Maschinen in einem Boinc-Projekt betreiben. Neben C++ eignen sich auch die Sprachen Fortran und Java. Für Python-Programmierer ist das Master-Worker-System Py MW im Angebot.
Bereits innerhalb einer Universitätsfakultät oder eines Unternehmens kann Boinc beträchtliche Ressourcen zusammenführen. Nimmt gar eine weltweite Community an einem Rechenprojekt teil, kommen ganz andere Größenordnungen ins Spiel: Die in der Boinc-Statistik registrierten Projekte greifen auf insgesamt über 6 Millionen Rechner zu. (mhu)
Infos
- Boinc-Homepage: http://boinc.berkeley.edu/download.php
- Seti@home: http://setiathome.ssl.berkeley.edu
- Big Buck Bunny: http://www.bigbuckbunny.org
- “OpenCL – The open standard for parallel programming of heterogeneous systems”: http://www.khronos.org/opencl
- “Nvidia CPU Computing Developer Home Page”: http://www.nvidia.com/object/cuda_home_new.html
- Bernhard Bablok, “Zauberlehrling”: Linux-Magazin 2008/08, https://www.linux-magazin.de/Heft-Abo/Ausgaben/2008/08/Zauberlehrling
- Magick++, C++ API for Imagemagick: http://www.imagemagick.org/Magick++/
- Boinc-Server aufsetzen: http://boinc.berkeley.edu/trac/wiki/ServerIntro
- Listings und Starterpaket zu diesem Artikel: https://www.linux-magazin.de/static/listings/magazin/2011/03/boinc/
- Boincs Software-Abhängigkeiten: http://boinc.berkeley.edu/trac/wiki/SoftwarePrereqsUnix
- Boinc-Dokumentation: http://boinc.berkeley.edu/trac/wiki/ProjectMain






