In heutigen PCs steckt mit der Grafikkarte gewaltiges Rechenpotential das nicht
nur für Computergrafik verwenden werden kann. Nachfolgend wird beispielhaft gezeigt
wie mit der Grafikkarte Matritzen multipliziert werden können.
Warum mit der Grafikkarte rechnen?
Beim Vergleich der Leistungdaten einer Grafikkarte wie zB die Geforce GTX 285 mit
einer Leistung von 1062,7 GigaFLOPS und einem Pentium 4 mit 3,2 GHz der “nur” auf
6,4 GigaFLOPS kommt wird klar dass dieses Potential genutzt werden kann.
Warum ist die Grafikkarte (GPU – graphics processing unit) so schnell?
Eine CPU ist universell ausgelegt und kann prinzipiell alles berechnen während GPUs
auf Computergrafik optimiert sind. Zudem arbeiten GPUs als Vektorprozessoren und sind somit hochgradig parallel.
Wie kann mit der Grafikkarte gerechnet werden?
In den Anfängen von GPGPU wurden Float-Arrays in Bitmaps verpackt um somit eine
beliebige Anwendung als Grafikproblem zu tarnen. Wie man sich leicht vorstellen
kann ist das Tarnen als Bitmap eine eher schwierige Aufgabe denn das Ergebnis wieder
korrekt aus dem Bitmap zu entpacken ist schon eine Kunst.
Mit dem Projekt Accelerator von Microsoft Research wird dieses Verfahren
verwendet.
Firmen wie zB Nvidia haben erkannt dass GPGPU ein neues Geschäftsfeld sein kann
und bieten eine Programmierschnittstelle (API) an. Im Falle von Nvidia ist dies
die Compute Unified Device Architecture [2]. CUDA ist eine Erweiterung für die Programmiersprache
C aber es gibt glücklicherweise einen Wrapper für C# – CUDA.net. Diese Variante kann nur verwendet werden wenn
eine Nvidia-Grafikkarte vorhanden ist. Zusätzlich muss das SDK dazu während der
Entwicklung vorhanden sein.
Mit diesen zwei Projekten steht die Möglichkeit für GPGPU für jeden zur Verfügung.
Es liegt aber beim Entwickler abzuwägen ob die Aufgabe für GPGPU geeignet ist.
Ich finde die Verwendung von Accelerator angenehmer da diese auf DirectX aufsetzt
und somit keine Bindung zu einer spezifischen Grafikkarte existiert. Bei CUDA ist
es außerdem nachteilig dass in einer C++-ähnlichen Syntax mit der Grafikkarte interagiert
werden muss.
Beispiel
Als Beispiel sei der “Klassiker” für die Parallelisierung – die Matritzenmultiplikation
– mit dem Accelerator-Projekt implementiert. Das Projekt besteht nur aus einer DLL
und ist somit einfach zu verwenden – es braucht nur die Assembly eingebunden werden
(Verweis hinzufügen).
Der Code ist relativ einfach:
private static float[,] MatMulGPU(float[,] a, float[,] b)
{
// GPU aktivieren:
ParallelArrays.InitGPU();
// Die Matritzen für die GPU erstellen:
DisposableFloatParallelArray x =
new DisposableFloatParallelArray(a);
DisposableFloatParallelArray y =
new DisposableFloatParallelArray(b);
// Matrix Multiplikation durchführen:
FloatParallelArray z = ParallelArrays.Multiply(x, y);
// Das Ergebnis der GPU-Berechnung "greifbar"
machen:
float[,] c;
ParallelArrays.ToArray(z,
out c);
// Speicher freigeben:
x.Dispose();
y.Dispose();
// GPU deaktivieren:
ParallelArrays.UnInit();
return c;
}
Siehe auch