Open Source im professionellen Einsatz

Hardware-Architektur

Cuda steht für Compute Unified Device Architecture und bezeichnet die Architektur der GPU von Nvidia. Eine der derzeit stärksten Grafikkarten, Nvidias Geforce GTX295, besteht aus 2 mal 30 Stream-Multiprozessoren (SM), die ihrerseits jeweils acht Stream-Prozessoren (SP) zusammenführen. Somit arbeiten 480 Prozessoren parallel. Jeder der Prozessoren verfügt über ein eigenes Rechenwerk für 32-Bit-Integer- und -Float-Arithmetik. Zusätzlich hat jeder SM zwei Prozessoren, die komplexere Fließkommaoperatoren erlauben. Es existiert ein Befehlswerk pro SM. Der als Nächstes auszuführende Befehl wird an alle acht SP übermittelt und dann - entsprechend SIMD - parallel bearbeitet.

Software-Architektur

Ein Kernel oder auch eine Kernelfunktion ist eine C-ähnliche Funktion, die alle Threads ausführen. Die SIMT-Technologie erlaubt es, dass der Kontrollfluss einzelner Threads verschieden ist. Die Unterschiede in der C-Programmierung sind minimal, beispielsweise gibt es keine rekursiven Funktionsaufrufe. Cuda fasst Threads in Blöcke zusammen, die ihrerseits zu einem Gitter (Grid) angeordnet sind. Für viele reale Problemstellungen bietet es sich an, die Threads und Blöcke in zwei oder drei Dimensionen anzuordnen. Abbildung 3 skizziert diese hierarchische Thread-Organisation.

Abbildung 3: Threads organisieren sich hierarchisch. Für die Programmierung ist bedeutend, dass sich nur Threads innerhalb eines Blocks synchronisieren lassen. Die eindeutige Identifikation eines Thread erfolgt über den Block- und den Thread-Index.

Abbildung 3: Threads organisieren sich hierarchisch. Für die Programmierung ist bedeutend, dass sich nur Threads innerhalb eines Blocks synchronisieren lassen. Die eindeutige Identifikation eines Thread erfolgt über den Block- und den Thread-Index.

Das zentrale Element ist ein Block von Threads, der die folgenden Eigenschaften aufweist:

  • Ein Block kann bis zu 512 Threads enthalten -
    unabhängig davon, in wie vielen Dimensionen die Threads
    angeordnet sind.
  • Die Threads in einem Block haben Zugriff auf gemeinsamen
    schnellen Speicher. Threads unterschiedlicher Blöcke tauschen
    Daten nur über den langsamen Hauptspeicher der Grafikkarte
    aus.
  • Nur Threads innerhalb eines Blocks lassen sich synchronisieren.
    Es gibt keine Möglichkeit, die Ausführung von Threads
    verschiedener Blöcke zu synchronisieren.
  • Ein Block ist genau einem SM für die Dauer der
    Kernelfunktion zugeordnet. Es findet keine Migration von Threads
    statt. Sind mehr rechenbereite Threads als SP vorhanden, dann
    führt die Hardware ein Scheduling durch.
  • In einem Block führt die GPU immer Mengen von 32 Threads
    parallel aus. Diese Gruppen werden häufig auch als Warp
    bezeichnet.

Auch bei der Synchronisation von parallel arbeitenden Kernen ist die SIMT-Technologie einfacher gehalten als bei ausgewachsenen Multicore-Systemen. Als Konsequenz der blockinternen Synchronisation ergibt sich für die Programmierung, dass der parallele Algorithmus so definiert sein muss, dass keine Annahmen über die Reihenfolge der Ausführung der unterschiedlichen Blöcke erfolgt. Sind mehrere Blöcke zu synchronisieren, kann das nur über verschiedene Kernelaufrufe erfolgen.

Innerhalb eines Blocks steht als einziges Mittel für die Synchronisation eine Barriere (Barrier) zur Verfügung. Eine solche Barriere lässt sich bildlich als großes verschlossenes Tor einer Stadtmauer vorstellen: Alle Threads warten an dem Tor, bis auch der letzte Thread angekommen ist. Erst wenn das der Fall ist, öffnet sich das Tor und alle Threads rennen weiter.

Eine Barriere setzt voraus, dass alle Threads die entsprechende Stelle im Code überhaupt erreichen (Vorsicht bei Verzweigungen in If-Anweisungen). Übertragen auf das Bild der Stadtmauer bedeutet dies, dass Threads nicht unterschiedliche Tore in die Stadt nehmen dürfen. Sonst besteht die Gefahr einer Art Deadlock: Eine Gruppe von Threads wartet auf die anderen, die aber ihrerseits an einem anderen Tor auf Einlass warten.

Zwei Beispiele zeigen einen möglichen Ansatz von Cuda unter Linux. Beide Beispiele sind anschaulich und lassen sich von der Grundidee auf andere Einsatzgebiete übertragen. Das erste Beispiel verwendet für jeden Bildpunkt einen Thread. Eine Synchronisation ist nicht notwendig. Im zweiten Beispiel müssen viele parallele Threads zusammenarbeiten und sich synchronisieren.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 7 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook