Parallelverarbeitung Auslaufmodell CPU? Wie GPUs so schnell rechnen

Von Dipl.-Ing. (FH) Michael Richter 5 min Lesedauer

Anbieter zum Thema

GPUs beschleunigen KI, Simulationen und numerische Berechnungen. Ihr Vorteil entsteht durch viele gleichzeitig bearbeitete Aufgaben. Warum CPUs anders aufgebaut sind und weshalb zusätzliche Recheneinheiten allein noch keinen schnelleren Rechner ergeben.

Architekturunterschiede: Während CPUs darauf ausgelegt sind, einzelne Aufgaben möglichst schnell abzuarbeiten, verarbeiten GPUs Tausende Datenströme gleichzeitig.(Bild:  Dall-E / KI-generiert)
Architekturunterschiede: Während CPUs darauf ausgelegt sind, einzelne Aufgaben möglichst schnell abzuarbeiten, verarbeiten GPUs Tausende Datenströme gleichzeitig.
(Bild: Dall-E / KI-generiert)

Eine Million Messwerte sollen mit einem Faktor multipliziert und anschließend um einen konstanten Wert verschoben werden. Für jeden Messwert gilt dieselbe Rechenvorschrift. Das Ergebnis des ersten Werts wird für die Verarbeitung des zweiten nicht benötigt. Ob die Berechnungen nacheinander oder gleichzeitig erfolgen, ändert daher nichts am Ergebnis.

Solche Aufgaben bieten viel Datenparallelität: Derselbe Ablauf lässt sich auf viele voneinander unabhängige Daten anwenden. Genau dafür sind GPUs ausgelegt. Dieses Muster findet sich in der Bildverarbeitung ebenso wie in wissenschaftlichen Berechnungen und neuronalen Netzen. Allerdings lässt sich daraus nicht ableiten, dass eine GPU grundsätzlich schneller rechnet als eine CPU. Entscheidend ist, welche Arbeit verteilt werden kann – und welche auf vorherige Ergebnisse warten muss.

Auch eine CPU rechnet parallel

Die Vorstellung, eine CPU erledige stets nur eine Operation nach der anderen, ist falsch. Mehrere Prozessorkerne können unterschiedliche Aufgaben gleichzeitig bearbeiten. Innerhalb eines leistungsfähigen Kerns können zudem mehrere unabhängige Maschinenbefehle parallel ausgeführt werden.

Hinzu kommen Vektoreinheiten. Sie verarbeiten mit einem Befehl mehrere Datenwerte nach dem SIMD-Prinzip: Single Instruction, Multiple Data. Ein 256 Bit breiter Vektor kann beispielsweise acht Gleitkommazahlen mit jeweils 32 Bit aufnehmen. Ein geeigneter Vektoradditionsbefehl verarbeitet dann acht Zahlenpaare. Das bedeutet allerdings nicht automatisch acht vollständig abgeschlossene Additionen je Takt; der tatsächliche Durchsatz hängt von der Mikroarchitektur ab.

Auch das eingangs beschriebene Messwertproblem lässt sich deshalb auf einer CPU parallelisieren. Der Unterschied zur GPU liegt vor allem darin, wie stark die Hardware auf diesen Arbeitsmodus zugeschnitten ist.

Die CPU beschleunigt den Programmablauf

Viele Programme bestehen aus wechselnden Aufgaben: Datenstrukturen durchsuchen, Bedingungen prüfen, Funktionen aufrufen und auf Zwischenergebnisse reagieren. Welche Speicheradresse als Nächstes benötigt wird, steht mitunter erst nach dem vorherigen Zugriff fest.

Leistungsfähige CPU-Kerne investieren deshalb viel Aufwand darin, einen einzelnen Befehlsstrom schnell voranzubringen. Eine Sprungvorhersage schätzt den weiteren Programmweg ab. Die Out-of-Order-Ausführung zieht unabhängige Befehle vor, wenn andere noch warten. Caches halten häufig benötigte Daten nahe an den Recheneinheiten. Diese Mechanismen können Wartezeiten verringern oder teilweise überdecken. Echte Datenabhängigkeiten beseitigen sie nicht.

All das benötigt Chipfläche und Energie. Diese Ressourcen dienen nicht ausschließlich zusätzlichen Addierern und Multiplizierern, sondern auch der flexiblen und schnellen Versorgung vorhandener Recheneinheiten. Das ist sinnvoll, wenn wenige zeitkritische Abläufe oder unregelmäßige Aufgaben die Laufzeit bestimmen.

Die GPU organisiert die Arbeit

Eine GPU gewichtet die Ressourcen anders. Ihre Recheneinheiten sind in Gruppen organisiert, die viele Threads bearbeiten. Ein Thread beschreibt dabei einen einzelnen Ausführungsablauf, beispielsweise die Verarbeitung eines Messwerts. Bei Nvidia werden Threads zu Warps mit jeweils 32 Threads zusammengefasst. Das Ausführungsprinzip heißt SIMT: Single Instruction, Multiple Threads. Innerhalb einer solchen Gruppe werden gemeinsame Befehle auf die jeweiligen Daten der aktiven Threads angewendet. Andere GPU-Architekturen verwenden verwandte Konzepte. Die GPU besteht damit nicht einfach aus Tausenden vollständiger CPU-Kerne. Viele Rechenbahnen teilen sich Teile der Befehlssteuerung. Eine beworbene Anzahl von GPU-Rechenkernen lässt sich deshalb nicht direkt mit der Kernzahl einer CPU vergleichen.

Jetzt Newsletter abonnieren

Verpassen Sie nicht unsere besten Inhalte

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung. Die Einwilligungserklärung bezieht sich u. a. auf die Zusendung von redaktionellen Newslettern per E-Mail und auf den Datenabgleich zu Marketingzwecken mit ausgewählten Werbepartnern (z. B. LinkedIn, Google, Meta).

Aufklappen für Details zu Ihrer Einwilligung

Auch eine Million gestarteter Threads bedeutet nicht, dass eine Million Rechenoperationen gleichzeitig auf physisch vorhandenen Einheiten laufen. Die Hardware arbeitet die Aufgaben mit ihrer verfügbaren Kapazität ab. Dabei hält sie viele Threads bereit: Wartet eine Gruppe auf Daten, können andere ausführungsbereite Gruppen zum Zug kommen.

Verzweigungen verschlechtern Auslastung

Die gemeinsame Befehlsausführung funktioniert besonders gut, wenn Threads derselben Gruppe ähnliche Wege durch das Programm nehmen. Müssen einige Werte mit Verfahren A und andere mit Verfahren B bearbeitet werden, können innerhalb eines Warps unterschiedliche Ausführungspfade entstehen.

Die GPU kann solche Verzweigungen verarbeiten. Sie muss die verschiedenen Pfade jedoch gegebenenfalls getrennt ausführen, wobei jeweils nur die zugehörigen Threads aktiv sind. Dadurch bleiben Rechenbahnen zeitweise ungenutzt. Diese Divergenz erklärt, warum unregelmäßige Aufgaben trotz hoher nomineller Rechenleistung ungünstig sein können. Nicht jede Verzweigung ist problematisch: Folgen alle Threads einer Gruppe demselben Zweig, entsteht daraus keine solche Aufteilung.

Während unregelmäßige Pfade die GPU ausbremsen, profitieren andere Domänen enorm von ihrer parallelen Struktur – angefangen bei neuronalen Netzen. Viele Rechenschritte lassen sich hier als Matrixoperationen formulieren. Bei einer Matrixmultiplikation entstehen zahlreiche Ergebniswerte aus wiederholten Multiplikationen und Additionen. Unterschiedliche Ergebnisbereiche lassen sich parallel bearbeiten. Zusätzlich können geschickt gewählte Datenblöcke mehrfach verwendet werden. Ein einmal geladener Wert trägt dann zu mehreren Berechnungen bei. Diese Wiederverwendung ist entscheidend: Sie erhöht die Zahl der Rechenoperationen im Verhältnis zur bewegten Datenmenge. Spezialisierte Matrixeinheiten, bei Nvidia etwa Tensor Cores, gehen noch weiter. Sie führen Matrix-Multiplikations- und Akkumulationsoperationen auf kleinen Blöcken aus.

Auch Simulationen enthalten geeignete Aufgaben. Lokale Berechnungen an vielen Elementen oder Gitterpunkten lassen sich häufig parallel ausführen. Bei der FEM entstehen außerdem Gleichungssysteme, deren numerische Lösung einen erheblichen Teil der Rechenzeit beanspruchen kann. Der Nutzen hängt allerdings vom Lösungsverfahren und der Datenorganisation ab. Viele FEM-Matrizen sind dünn besetzt. Ihre Verarbeitung benötigt neben Zahlenwerten zusätzliche Strukturinformationen; Speicherzugriffe und der Austausch von Zwischenergebnissen können den Durchsatz begrenzen. Teilweise lohnt deshalb eine andere Formulierung des Algorithmus. Die FEM-Bibliothek MFEM beschreibt beispielsweise Partial Assembly: Der mathematische Operator wird angewendet, ohne die vollständige globale Matrix aufzustellen. Gerade bei geeigneten Elementen höherer Ordnung kann das Speicherbedarf und Datenbewegungen reduzieren. Dafür muss auch die Vorkonditionierung zum Verfahren passen.

Warum CPUs nicht wie GPUs bauen?

CPU-Entwickler nutzen Datenparallelität längst durch Vektoreinheiten. Eine vollständige Ausrichtung auf GPU-artigen Durchsatz würde jedoch Fähigkeiten schwächen, die für andere Aufgaben wichtig sind: wenige abhängige Abläufe schnell bearbeiten, auf wechselnde Programmwege reagieren und unregelmäßige Arbeit effizient ausführen. Das lässt sich an einem Gegenbeispiel zum Messwertproblem zeigen: Hängt jeder neue Wert vom unmittelbar vorher berechneten Ergebnis ab, können die Schritte nicht ohne Weiteres auf viele Rechenbahnen verteilt werden. Ein anderer Algorithmus kann mitunter helfen. Zusätzliche Hardware allein hebt die Abhängigkeit jedoch nicht auf.

Auch die Gesamtbeschleunigung bleibt begrenzt. Ein vereinfachtes Rechenbeispiel: Lassen sich 90 Prozent der bisherigen Laufzeit hundertfach beschleunigen, während zehn Prozent unverändert bleiben, sinkt die Laufzeit auf 10,9 Prozent. Der gesamte Ablauf wird damit nur rund 9,2-mal schneller. Transferaufwand ist dabei noch nicht berücksichtigt. Deshalb ergänzen sich CPUs und GPUs. Die CPU übernimmt deshalb weiterhin Programmsteuerung und serielle Aufgaben, während die GPU die schweren rechenparallelen Pakete schultert. Ein Auslaufmodell ist die CPU damit nicht – erst ihr Zusammenspiel macht moderne Rechner so leistungsfähig. (mr)

(ID:51008197)