Rechnen wie geölt

Kommt es auf maximale Rechenleistung an, muss der Programmierer die besonderen Eigenschaften des Prozessors ausnutzen. Leider sind die so entstandenen Programme nicht mehr portabel. Die Bibliothek liboil kann Abhilfe schaffen.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 4 Min.
Von
  • Michael Riepe

Nicht alle Rechner sind gleich. Ein Lied davon können die Nutzer von Supercomputern singen: Einen guten Teil ihrer Zeit verbringen sie damit, ihre Software für den vorhandenen Rechner zu optimieren. Wechseln sie irgendwann auf ein anderes Modell, geht die Arbeit von vorn los.

Ähnlich geht es den Entwicklern von Multimedia-Anwendungen oder Audio- und Video-Codecs. Programmiert man allein in der Hochsprache, läuft die Software zu langsam. Nutzt man die Besonderheiten der Prozessorarchitektur – etwa MMX/SSE-Befehle bei AMD- und Intel-CPUs oder die Altivec-Einheit beim PowerPC –, ist sie hingegen nicht länger portabel.

Sowohl bei wissenschaftlichen als auch bei Multimedia-Anwendungen verbringt die CPU viel Zeit in Programmschleifen. Daher lohnt es sich, die in die Schleife eingebetteten Anweisungen zu untersuchen und gegebenenfalls zu optimieren – oder durch vorgefertigte, optimierte Routinen zu ersetzen.

Mehr Infos

Eine Sammlung solcher Routinen bietet die Library of Optimized Inner Loops liboil (siehe Kasten „Onlinequellen“) von David Schleef, dem Entwickler des Dirac-Video-Codecs Schrödinger. Sie kommt sowohl dort als auch im Multimedia-Framework gstreamer zum Einsatz und bietet aktuell gut 400 Funktionen für das Rechnen mit Vektoren und Matrizen.

Für jede Funktion gibt es eine Referenzimplementierung, die den Maßstab für Geschwindigkeit und Genauigkeit setzt. Daneben kann es mehrere optimierte Varianten geben. Beim ersten Aufruf wählt liboil automatisch die schnellste. Versionen, die falsch rechnen oder unbekannte Befehle verwenden, schließt die Bibliothek jedoch aus.

Vor dem ersten Funktionsaufruf muss das Programm mit oil_init(); die Bibliothek initialisieren. Die Namen der übrigen Funktionen folgen dem Schema oil_<funktion>_<argumenttypen>: oil_conv_f64_s32 etwa rechnet 32-Bit-Integer vom Typ int32_t in 64-Bit-Gleitkommazahlen (double) um. Die entgegengesetzte Operation heißt oil_clipconv_s32_f64. Sie rundet gebrochene Zahlen zur nächstliegenden ganzen Zahl; ob 0.5 auf- oder abgerundet wird, hängt von der jeweiligen Implementierung ab. Der Zusatz clip im Funktionsnamen deutet an, dass sich bei der Konversion nicht alle Werte auf den neuen Typ abbilden lassen und die Funktion daher gegebenenfalls den Wertebereich begrenzen (clippen) muss.

Als Argumente erwarten die Funktionen in der Regel Vektoren – in C also Zeiger auf das erste Element des Vektors. Mitunter muss man für jeden Vektor eine Schrittweite („stride“) angeben, außerdem die Zahl der zu berechnenden Elemente. oil_conv_f64_s32 etwa benötigt fünf Argumente (siehe Listing 1).

Mehr Infos

Listing 1

void oil_conv_f64_s32(
/* Zielvektor und Schrittweite */
double *dest,
int dstr,
/* Quellvektor und Schrittweite */
const int32_t *src,
int sstr,
/* Zahl der zu berechnenden Elemente */
int n)
{
while (n > 0) {
*dest = round((double)*src);
dest += dstr;
src += sstr;
--n;
}
}

Durch die variablen Schrittweiten lassen sich Funktionen wie oil_conv_f64_s32 universell einsetzen.

Mit oil_permute_<typ> lassen sich die Elemente eines Vektors neu anordnen. Spezialfälle wie das bei der MPEG-Video-Kompression vorkommende Transponieren 8 x 8 Elemente großer Makroblöcke oder die „Zickzack“-Konvertierung erledigen oil_trans8x8_<typ>, oil_zigzag8x8_<typ> und oil_unzigzag8x8_<typ>.

Daneben beherrscht liboil die gängigen (Vektor-)Operationen mit jeweils mehreren Datentypen. Zusätzlich zu den elementweise durchgeführten Grundoperationen lassen sich das Skalarprodukt, die Summe der Elemente und der Betrag eines Vektors berechnen, Konstanten zu den Elementen addieren oder Vektoren mit Skalaren multiplizieren.

Außerdem gibt es eine Reihe von Operationen für MPEG-Makroblöcke wie Matrix-Multiplikation, die Berechnung des Unterschieds zweier Blöcke oder die Diskrete Cosinus-Transformation (DCT, IDCT). Daneben existieren optimierte Funktionen für die Pixel-Manipulation und das Konvertieren zwischen verschiedenen Farbdarstellungen wie ARGB und AYUV.

Definitionsgemäß ist liboil ein Projekt, das niemals fertig wird. Kommen neue Prozessoren auf den Markt, ergeben sich neue Gelegenheiten, den Code zu optimieren. Außerdem lassen sich jederzeit neue nützliche Funktionen hinzufügen. Hier sind vor allem die Anwendungsentwickler aufgerufen, ihren Teil beizusteuern.

iX-Link (mr)