Parallelprogrammierung bei Android

Herb Sutter postulierte 2005, dass die Zeit des "kostenlosen Mittagessens" für Softwareentwickler vorbei sei: Weitere Performancesteigerungen ließen sich nur noch durch Parallelisierung erreichen. Mittlerweile ist dieser Zustand auch unter Android erreicht.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 15 Min.
Von
  • Tam Hanna
Inhaltsverzeichnis

Herb Sutter postulierte 2005, dass die Zeit des "kostenlosen Mittagessens" für Softwareentwickler vorbei sei: Weitere Performancesteigerungen ließen sich nur noch durch Parallelisierung erreichen. Mittlerweile ist dieser Zustand auch unter Android erreicht.

Der Gedanke an Mehrkernprozessoren im Handcomputerbereich ist alt: schon auf der Symbian Smartphone Show 2009 wurde auf After-Show-Partys über die Vor- und Nachteile der Parallelisierung von Smartphone-Prozessoren gesprochen. Das erfolgte angesichts der rapide anwachsenden Taktraten: Nach dem Verkauf von Intels ARM-Chipsparte lieferten sich Qualcomm und Co. einen heftigen Wettbewerb um die schnellste CPU.

Auf dem Mobile World Congress 2011 boten sich Samsung und LG einen harten Kampf: Die bisher meist unterlegenen rosa Mannen landeten mit dem LG Optimus 2X einen Achtungserfolg, der sie sogar ins Guiness-Buch der Rekorde brachte. Vierkernprozessoren folgten nur kurze Zeit später. MediaTek preschte sogar mit einem aus acht (eher primitiven) Kernen bestehenden Chip vor.

Apples iPhone diente als Auslöser für einen zweiten interessanten Trend. Die aufwendigen Animationen der Benutzerschnittstelle wurden nicht mehr auf der CPU realisiert: Steve Jobs Leute nutzten die GPU. Das brachte dem iPhone der ersten Generation einen immensen Vorsprung gegenüber der Konkurrenz: Nokia bereute die Entscheidung schon bald bitterlich, die im N95 verbaute GPU im N96 auszulassen.

Die beim Anzapfen der in der GPU steckenden Leistung auftretenden Probleme gestalten sich am Handy und am Desktop ähnlich. Wer einen Grafikchip ausnutzen möchte, kann nicht einfach einen weiteren Thread starten. Zudem sind die auf der GPU abzuarbeitenden Algorithmen unter Berücksichtigung der vorgesehenen Schnittstelle an die neue Hardware anzupassen.

Deshalb stellte Google schon 2011 für Android eine eigene Shadersprache namens RenderScript vor. Wer sich an die Vorgaben des Betriebssystemherstellers hält, wird mit fast universeller Kompatibilität belohnt: Dank einer Hilfsbibliothek ist das Framework sogar auf Android 2.2 verfügbar.

Android bietet mit RenderScript eine eigene Programmiersprache an, die die Entwicklung von als Kernel bezeichneten Codestücken erlaubt. Sie werden vom System je nach Situation entweder auf der CPU oder auf der GPU ausgeführt. Google erreicht das über einen zweistufigen Kompilierprozess: Am Desktop läuft eine LLVM-Instanz, die den RenderScript-Code in eine Intermediärsprache umwandelt. Im Rahmen der erstmaligen Zuweisung an CPU oder GPU läuft im Mobilgerät ein zweiter LLVM-Vorgang ab, der den Intermediärcode an den vorliegenden Chip anpasst. Dieser wandert danach in einen Cache, um bei weiteren Starts sofort bereitzustehen. Die RenderScript-Bibliothek funktioniert derzeit nur mit Eclipse zuverlässig: Das Gradle-basierte Android Studio genießt anscheinend beim RenderScript-Team nur marginale Beliebtheit.

Nach dem Start der IDE wird eine neue .rs-Datei namens firsttest.rs erstellt, die neben MainActivity.java zum Liegen kommt. Ihr Inhalt orientiert sich an einem von Google vorgegebenen Tutorial:

#pragma version(1) 
#pragma rs java_package_name(com.tamoggemon.heiserenderscript1)
#pragma rs_fp_relaxed

uchar4 __attribute__((kernel)) firsttest(uchar4 in, uint32_t x, uint32_t y) {
uchar4 out = in;
out.r = 255 - in.r;
out.g = 255 - in.g;
out.b = 255 - in.b;
return out;
}

An der Stelle sind mehrere Faktoren relevant. Im Header erfolgt die Festlegung der Sprachversion (im Moment gibt es nur 1.0), des Aufenthaltsorts der zu generierenden Klasse und der erforderlichen Genauigkeit der Gleitkommaarithmetik. RenderScript kennt die drei in der Tabelle gezeigten Stufen, die sich stark auf die Performance des resultierenden Kernels auswirken:

Bezeichnung Aktivierte Funktionen
#pragma rs_fp_full Volle Genauigkeit gemäß IEEE-Standard
#pragma rs_fp_relaxed Erlaubt Flush-To-Zero und Round-Towards-Zero
#pragma rs_fp_imprecise - FP-Relaxed plus -0.0==+0.0 und f(NAN)//f(INF)==undef

Während der Kompilierung des Projekts führt Eclipse einen Compiler aus, der den .rs-Code auf grundlegende Fehler überprüft und eine Hilfsklasse für den einfachen Zugriff aus Android heraus erstellt. Das Resultat der Mühen ist die in Abbildung 1 gezeigte Datei – sie entsteht nur, wenn Shader-Funktion und Datei denselben Namen aufweisen.

RenderScript erstellt JNI-Code automatisch (Abb. 1)

Der Compiler weist derzeit einen Fehler auf: Einmal aufgetretene Fehler verschwinden auch nach dem Beheben nicht aus der Fehlerliste der IDE. Das Problem lässt sich durch Rechtsklick auf die Fehlergruppe beheben: erst im Kontextmenü auf Delete klicken und dann die Warnmeldung bestätigen.

Compiler-Fehler sind von Hand zu löschen (Abb. 2).

Es ist darauf zu achten, dass das Verwenden "fremdnamiger" Kernels erst ab der SDK-Version 16 erlaubt ist: In früheren Varianten der Entwicklungsumgebung muss der Kernel auf den Namen root hören und mit einer vorbestimmten Parameterliste ausgestattet sein.