en
de

Dualcore, Quadcore, Hektocore – Mobile-Grafikchips als App-Beschleuniger

28 Oktober 2013
| |
Lesezeit: 6 Minutes

In Mobilgeräten schlummert ein meist ungenutztes Potential an Rechenpower. Die meisten Anwendungen nutzen zur Ausführung nur die CPU. Wird parallelisierbare Anwendungslogik aber auf dem Grafikchip ausgeführt, kann sie enorm beschleunigt werden. Mit GPGPU (General Purpose Computing on the Graphics Processing Unit) kann Anwendungscode auf der Grafikkarte zur Ausführung gebracht werden, ohne auf Treiber-Niveau zu programmieren.

Die Vorteile von GPGPU

In der Welt der Desktop-Computer wird GPGPU schon seit Jahren für diverse rechenintensive Anwendungen genutzt. Mit verschiedenen neuen ARM-SoCs (System on Chip) der aktuellen Generation auf Android-Mobilgeräten ist es nun möglich, dieses Potential auch auf Smartphones, Tablets oder im Embedded-Bereich zu nutzen. Anders als im Desktop Computing ergeben sich auf Mobilgeräten neben dem reinen Geschwindikeitsgewinn weitere Anreize, GPGPU zu nutzen:

  • Datenverarbeitung, die bislang auf Server ausgelagert werden musste, kann durch Nutzung der GPU lokal durchgeführt werden. Das schont die Datenverbindung und damit auch den Akku. In Anbetracht der ohnehin kurzen Akkulaufzeiten von Smartphones und Tablets kann dies sehr wichtig sein.
  • Werden Verarbeitungsprozesse auf dem Gerät schneller ausgeführt, kann sich dadurch schon eine Energieeinsparung ergeben.
  • Smartphones und Tablets haben eine Vielzahl von Sensoren, durch deren Kombination Anwendungsfälle wie Virtual Reality interessant werden. Da hierfür aber ein hoher Datendurchsatz meist die Grundvoraussetzung ist, kann GPGPU manche dieser Anwendungsfälle überhaupt erst möglich machen.

Frameworks und Hardware

Für Mobilgeräte steht nur ein kleiner Teil der Frameworks zur Verfügung, die aus dem Dektop-GPGPU bekannt sind, da die meisten davon speziell auf Desktop-Grafikkarten bestimmter Hersteller zugeschnitten sind. Übrig bleibt im Wensentlichen nur OpenCL und — auf der Android-Plattform — RenderScript.

OpenCL ist ein offener Standard, und als solcher genießt er auch eine weite Verbreitung und unterstützt die meisten Prozessorarchitekturen. RenderScript dagegen ist noch relativ jung, wird aber von Google aktiv für die Nutzung von GPGPU auf Android-Geräten beworben und unterstützt.

Doch welche Hardware unterstützt aktuell wirklich OpenCL oder RenderScript? Aus der aktuellen Gerätegeneration bieten nur die GPUs Adreno 302 und höher, ARM Mali T-604 und höher sowie PowerVR der Serie 5XT eine Unterstützung für GPGPU via OpenCL.

In einem internen Projekt haben wir die Technologie untersucht, dazu hatten wir die folgenden Geräte zur Verfügung:

  • Google Nexus 10: Dieses 10-Zoll-Tablet verwendet als SoC den Samsung Exynos 5250, welcher wiederum als GPU den ARM Mali T-604 verwendet. Diese GPU ist mit RenderScript und OpenCL kompatibel.
  • Google Nexus 4: Dieses Smartphone ist mit dem Qualcomm Snapdragon S4 Pro APQ8064 mit Qualcomm Adreno 320 GPU ausgestattet. Sowohl RenderScript als auch OpenCL konnten erfolgreich genutzt werden.
  • Samsung Galaxy S4: Das Smartphone kommt regionsabhängig in zwei Varianten, welche beide die geforderten Frameworks unterstützen sollen:
    • GT-I9500: Ausgestattet mit dem Exynos 5 Octa, welcher die IT PowerVR SGX544MP3 GPU verwendet.
    • GT-I9505: Ausgestattet mit dem Qualcomm Snapdragon 600, welcher die Qualcomm Adreno 320 GPU verwendet.
    • Getestet wurde das GT-I9500. Dabei lief RenderScript erfolgreich, OpenCL jedoch nicht.

RenderScript vs. OpenCL

Die Nutzung von RenderScript ist voll in die Android-Entwicklung integriert. Geschrieben werden die Verarbeitungsroutinen in C99, welches durch die Erweiterung der RenderScript-API ergänzt wird. Die RenderScript-Verarbeitung kann direkt aus dem Android-Java-Code heraus angesprochen werden. Sowohl Eclipse als auch Android Studio können bei der Entwicklung unterstützen. Auch der Build-Prozess in beiden Entwicklungsumgebungen berücksichtigt die Kompilierung und Paketierung der nativen RenderScript-Resourcen.

Eine Besonderheit von RenderScript ist, dass der Code nur einmal für die RenderScript-API geschrieben werden muss und die Ausführung — abhängig von der verfügbaren Hardware — automatisch auf der GPU, DSP oder CPU geschieht. Dies bleibt vor dem Entwickler verborgen und kann auch nicht gezielt gesteuert werden.

Bei OpenCL hingegen muss der Entwickler explizit angeben, ob der Code auf der GPU oder der CPU ausgeführt werden soll, vorausgesetzt, OpenCL ist auf dem Gerät überhaupt nutzbar. Das Ansprechen der GPU-Verarbeitung mit OpenCL auf Android wird dadurch erschwert, dass Android-Apps in Java geschrieben und in der Dalvik-VM ausgeführt werden.

Es gibt zwar Java-APIs für OpenCL, jedoch sind diese in erster Linie für die Ansteuerung aus gewöhnlichem Java-Bytecode in der Hotspot-VM entworfen, nicht für Dalvik-Bytecode. Es gibt zwar bereits erfolgreiche Versuche, OpenCL auf Android aus Java anzusprechen, beispielsweise über eine angepasste Version des aparapi-Frameworks. Hierbei handelt es sich jedoch nur um Experimente, keinesfalls um eine stabile API.

Eine bessere Möglichkeit zur Ansteuerug von OpenCL aus dem Android-Code ist die Nutzung der nativen Android-Schnittstellen über das Android Native Development Kit (NDK) . Hierzu werden Code-Module in C oder C++ geschrieben, die via NDK aus dem Android-Code angesprochen werden und ihrerseits wiederum die GPU-Verarbeitung durch OpenCL steuern. Diese Code-Module können mit dem NDK kompiliert und zusammen mit einer App ausgeliefert werden. Der Build-Prozess hierfür wird zwar nicht „out of the box“ von den Android-IDEs unterstützt, kann aber manuell den automatischen Build-Routinen hinzugefügt werden.

Erste Messungen mit RenderScript brachten nicht die erhofften Ergebnisse , was möglicherweise daran lag, dass für die Ausführung intern die CPU verwendet wurde.

Die ersten OpenCL Ergebnisse hingegen, bei denen die GPU zur Ausführung des Codes verwendet wurde, waren vielversprechend. Entsprechend haben wir uns für unsere Versuche im Weiteren für OpenCL entschieden, da gezielte Versuche auf der GPU unser Hauptanliegen waren.

Performance-Gewinn

In der von uns entwickelten Beispiel-App sollte eine Pipeline aus verschiedenen Bildfiltern auf dem Live-Kamerabild aufgesetzt werden, die den Full-HD-Video-Stream von der Kamera in Echtzeit filtert. Mangels Zeit konnte kein aufwendigeres Beispiel wie z.B. Texterkennung implementiert werden. Wir implementierten eine einfache Filterkette ohne direkten praktischen Nutzen, die jedoch für einen guten Vergleich der Performance zwischen CPU und GPU dienen konnte.

Die Pipeline beinhaltete die folgenden Schritte:

  • YUV-Bild von der Android-Kamera in RGB-Bild umwandeln
  • Luminanzbild (Graustufen) erzeugen
  • Sobel-Filter (Kantenerkennung)
  • Kontrastspreizung zur besseren Erkennbarkeit

Mit dieser Filter-Pipeline wurden Messungen hinsichtlich der Performance und des Energieverbrauches durchgeführt. Für die Messungen werden, während die Applikation läuft, die Ergebnisse in einer lokalen Liste gesichert. Da sich der Akku des Gerätes in verschiedenen Ladezuständen anders verhält, werden die Testläufe erst ab einer Batterierestkapazität von 80% gestartet. Dies ist programmatisch gelöst und Testdaten werden erst ab diesem Batteriestand aufgezeichnet.

Bei jedem Testlauf werden die Berechnungsdurchläufe gezählt und die benötigten Zeiten  erfasst. Ein Testlauf ist beendet, wenn eine definierte Batterierestkapazität erreicht ist. Getestet wurde jeweils mit 1%, 5%, 20%, 40% und 60% an verbrauchter Kapazität. Somit haben wir ein optimales „Batteriefenster“ von ca. 80% bis 20% Restkapazität des Akkus ausgenutzt. In diesem Mittelbereich der Akkukapazität sollten die Messergebnisse am stabilsten sein.

Der Geschwidnigkeitsgewinn zeigte sich qualitativ schon ohne Messungen: Die GPU Version lief spürbar schneller. Durch Profiling der Pipeline-Ausführung konnte auch eine quantitative Aussage getroffen werden:  Die Geschwindigkeit bei Verwendung der GPU lag etwa um Faktor 2 höher als beim Einsatz der vorhandenen CPU. Dies entsprach in etwa den Erwartungen, da das SoC des verwendeten Geräts über zweimal so viele GPU-Kerne wie CPU-Kerne verfügt.

Grafische Darstellung der App-Performance-Messungen

Profiling.Ergebnisse unserer App mit GPGPU

Überraschend fielen hingegen die Ergebnisse hinsichtlich des Energieverbrauchs aus: Hier lag die Zahl der durchlaufenen Berechnungsschritte relativ zur verbrauchten Batteriekapazität auf der GPU etwa um den Faktor 3,5 höher als auf der CPU. Die Erwartung wäre gewesen, dass sich auch der Energieverbrauch nur halbiert, da die GPU für dieselbe Menge an Berechnungen nur die halbe Zeit braucht, aber sie arbeitet offensichtlich noch sparsamer.

Grafische Darstellung der Energieverbrauchs-Messungen

Messergebnisse des Energieverbrauchs

Portierung von Algorithmen

Neben der Analyse des Performance-Gewinns ging es bei der Umsetzung des Projekts auch um die Frage, wie einfach die Portierung von Algorithmen auf die GPU ist. Um überhaupt Anwendungslogik auf die GPU übertragen zu können, ist es zunächst nötig, die Architektur von Grafikkarten und die Arbeitsweise des GPGPU-Frameworks zu verstehen. Auf Basis dessen ist es hilfreich, zunächst mit Hilfe des NDK einen Rahmen in C/C++ zu entwickeln, der von der Android-App genutzt werden kann und den Großteil an Boilerplate Code bei der funktionalen Erweiterung der GPU-Logik wegkapselt. Die folgende Grafik gibt einen groben Überblick über die Arbeitsschritte der GPU-Verarbeitung und die dabei verwendeten Artefakte.

Blueprint-Architecture

Die eigentliche Überführung der Filter-Logik aus Java in sogenannte GPU-Kernels stellte sich als trivial heraus. Wenn in Java die Verarbeitung beispielsweise in einer for-Schleife oder in geschachtelten for-Schleifen durchgeführt wurde, musste nur der Körper der Schleife(n) in C-Code überführt und die Datentypen angepasst werden, um daraus einen GPU-Kernel zu erstellen. Schließlich galt es noch, die Daten aus Java in Native- und schließlich in OpenCL-Buffer zu überführen, dann war die Portierung im Wesentlichen abgeschlossen. Der umgekehrte Weg, also die Portierung von OpenCL-Kernen in Java-Logik war im Grunde sogar noch einfacher zu bewältigen. Die Parallelisierung der Logik innerhalb von Java, insbesondere in Hinblick auf die Synchronisation der Rechenergebnisse, war dagegen weit schwieriger. Dies lag vor allem daran, dass im Grunde der von OpenCL bereitgestellte Rahmen in Java nachgebaut werden musste.

Es kann also festgehalten werden, dass zwar die Portierung von serieller Java-Logik auf die GPU durchaus etwas Aufwand bedeutet, dieser jedoch geringer ausfällt als der Aufwand für die Parallelisierung der Logik in Java.

GPGPU in der Praxis

Unsere Erwartungen an die GPU-Verarbeitung auf Mobilgeräten konnten wir im Wesentlichen bestätigen. Es zeigt sich ein deutlicher Gewinn an Performance, in Hinblick auf sowohl die Ausführungszeit als auch den Energieverbrauch, welcher sich mit zukünftigen SoCs eventuell sogar noch steigern wird. Auch die Portierung von Logik auf die GPU ist mit überschaubarem Aufwand möglich. Der im Lauf des Projekts entstandene NDK-Rahmen für die Ansteuerung von Filterstufen in OpenCL kann direkt in zukünftigen Projekten verwendet werden, um schneller zu einer lauffähigen Umgebung zu gelangen.

Für die App-Entwicklung als solche sollte man jedoch – Stand heute – darauf achten, auf welchen Geräten GPGPU überhaupt genutzt werden kann, da nicht alle Prozessorfamilien Unterstützung dafür bieten. Für den Embedded-Bereich hingegen könnte die Technologie in Moment sogar noch interessanter sein als für Mobilgeräte, da man sich dort gezielt auf eine Hardware-Plattform festlegen kann, die die nötigen Voraussetzungen mitbringt.

Immer mehr Geräte sind miteinander verbunden – die Anforderungen der Nutzer an die Leistung ihrer mobilen Geräte sind hoch. Wir haben uns mit alternativen Lösungswegen auseinandergesetzt und hier beschrieben. Wie geht Ihr mit dem Thema um?

Kommentare (2)

[…] für letztere Frage ist die Vorarbeit meiner Kollegen Michael Sattler und Stephan Wirth wertvoll. Interessante Ansätze zur Bilderkennung […]

Avatar

edmundo

25 Mai 2014 um 15:44

Very nice blog post. I certainly love this website.

Keep it up!

×

Updates

Schreiben Sie sich jetzt ein für unsere zwei-wöchentlichen Updates per E-Mail.

This field is required
This field is required
This field is required

Mich interessiert

Select at least one category
You were signed up successfully.

Erhalten Sie regelmäßige Updates zu neuen Blogartikeln

Jetzt anmelden

Oder möchten Sie eine Projektanfrage mit uns besprechen? Kontakt aufnehmen »