Multithreading (Computerarchitektur)

Interleaved/Temporal multithreadingBearbeiten

Hauptartikel: Temporales Multithreading

Grobkörniges MultithreadingBearbeiten

Die einfachste Form des Multithreading besteht darin, dass ein Thread so lange läuft, bis er durch ein Ereignis blockiert wird, das normalerweise einen Stillstand mit langer Latenzzeit verursachen würde. Ein solcher Strömungsabriss könnte ein Cache-Miss sein, der auf einen Speicher außerhalb des Chips zugreifen muss, was Hunderte von CPU-Zyklen dauern kann, bis die Daten zurückkommen. Anstatt zu warten, bis der Stillstand behoben ist, würde ein Prozessor mit Threads die Ausführung auf einen anderen Thread umschalten, der bereit ist, ausgeführt zu werden. Erst wenn die Daten für den vorherigen Thread eingetroffen sind, wird der vorherige Thread wieder in die Liste der lauffähigen Threads aufgenommen.

Beispiel:

  1. Zyklus i: Anweisung j von Thread A wird ausgegeben.
  2. Zyklus i + 1: Anweisung j + 1 von Thread A wird ausgegeben.
  3. Zyklus i + 2: Anweisung j + 2 von Thread A wird ausgegeben, eine Ladeanweisung, die in allen Caches fehlt.
  4. Zyklus i + 3: Thread-Scheduler aufgerufen, wechselt zu Thread B.
  5. Zyklus i + 4: Anweisung k von Thread B wird ausgegeben.
  6. Zyklus i + 5: Anweisung k + 1 von Thread B wird ausgegeben.

Konzeptionell ähnelt dies dem kooperativen Multitasking, das in Echtzeit-Betriebssystemen verwendet wird, bei dem Tasks freiwillig auf Ausführungszeit verzichten, wenn sie auf ein bestimmtes Ereignis warten müssen. Diese Art von Multithreading wird als Block-, kooperatives oder grobkörniges Multithreading bezeichnet.

Das Ziel der Multithreading-Hardwareunterstützung besteht darin, ein schnelles Umschalten zwischen einem blockierten Thread und einem anderen, lauffähigen Thread zu ermöglichen. Um dieses Ziel zu erreichen, besteht der Hardwareaufwand darin, die sichtbaren Programmregister sowie einige Prozessorsteuerregister (wie den Programmzähler) zu replizieren. Das Umschalten von einem Thread zu einem anderen bedeutet, dass die Hardware von einem Registersatz auf einen anderen umschaltet; um effizient zwischen aktiven Threads umzuschalten, muss jeder aktive Thread seinen eigenen Registersatz haben. Um beispielsweise schnell zwischen zwei Threads zu wechseln, muss die Register-Hardware zweimal instanziiert werden.

Zusätzliche Hardware-Unterstützung für Multithreading ermöglicht den Thread-Wechsel in einem CPU-Zyklus, was zu Leistungsverbesserungen führt. Außerdem kann sich jeder Thread dank zusätzlicher Hardware so verhalten, als würde er allein ausgeführt und keine Hardwareressourcen mit anderen Threads teilen, was den Umfang der Softwareänderungen minimiert, die in der Anwendung und im Betriebssystem zur Unterstützung von Multithreading erforderlich sind.

Viele Familien von Mikrocontrollern und eingebetteten Prozessoren verfügen über mehrere Registerbänke, um eine schnelle Kontextumschaltung für Interrupts zu ermöglichen. Solche Systeme können als eine Art Block-Multithreading zwischen dem Benutzerprogramm-Thread und den Interrupt-Threads betrachtet werden.

Interleaved MultithreadingEdit

Hauptartikel: Barrel-Prozessor

Der Zweck des interleaved multithreading ist es, alle Datenabhängigkeitsstaus aus der Ausführungspipeline zu entfernen. Da ein Thread relativ unabhängig von anderen Threads ist, ist die Wahrscheinlichkeit geringer, dass eine Anweisung in einer Pipelining-Stufe eine Ausgabe von einer älteren Anweisung in der Pipeline benötigt. Vom Konzept her ähnelt es dem in Betriebssystemen verwendeten präemptiven Multitasking; eine Analogie wäre, dass die Zeitscheibe, die jedem aktiven Thread gegeben wird, ein CPU-Zyklus ist.

Beispiel:

  1. Zyklus i + 1: ein Befehl von Thread B wird ausgegeben.
  2. Zyklus i + 2: eine Anweisung von Thread C wird ausgegeben.

Diese Art von Multithreading wurde zunächst als Fassverarbeitung bezeichnet, wobei die Dauben eines Fasses die Pipelinestufen und ihre ausführenden Threads darstellen. Interleaved, preemptive, fine-grained oder time-sliced multithreading sind modernere Begriffe.

Zusätzlich zu den Hardwarekosten, die beim Blocktyp des Multithreading diskutiert werden, hat das interleaved multithreading zusätzliche Kosten, da jede Pipelinestufe die Thread-ID der Anweisung verfolgt, die sie verarbeitet. Da in der Pipeline mehr Threads gleichzeitig ausgeführt werden, müssen auch die gemeinsam genutzten Ressourcen wie Caches und TLBs größer sein, um Thrashing zwischen den verschiedenen Threads zu vermeiden.

Simultanes MultithreadingBearbeiten

Hauptartikel: Simultanes Multithreading

Die fortschrittlichste Art des Multithreading gilt für superskalare Prozessoren. Während ein normaler superskalarer Prozessor in jedem CPU-Zyklus mehrere Anweisungen von einem einzelnen Thread ausgibt, kann ein superskalarer Prozessor beim simultanen Multithreading (SMT) in jedem CPU-Zyklus Anweisungen von mehreren Threads ausgeben. Da ein einzelner Thread nur über eine begrenzte Menge an Parallelität auf Anweisungsebene verfügt, wird bei dieser Art von Multithreading versucht, die über mehrere Threads hinweg verfügbare Parallelität zu nutzen, um die mit ungenutzten Ausgabeslots verbundene Verschwendung zu verringern.

Beispiel:

  1. Zyklus i: Die Anweisungen j und j + 1 von Thread A und die Anweisung k von Thread B werden gleichzeitig ausgegeben.
  2. Zyklus i + 1: Die Anweisung j + 2 von Thread A, die Anweisung k + 1 von Thread B und die Anweisung m von Thread C werden alle gleichzeitig ausgegeben.
  3. Zyklus i + 2: Befehl j + 3 von Thread A und die Befehle m + 1 und m + 2 von Thread C werden alle gleichzeitig ausgegeben.

Um die anderen Arten von Multithreading von SMT zu unterscheiden, wird der Begriff „temporales Multithreading“ verwendet, um zu bezeichnen, dass Befehle von nur einem Thread zur gleichen Zeit ausgegeben werden können.

Zusätzlich zu den für Interleaved Multithreading erörterten Hardwarekosten entstehen bei SMT zusätzliche Kosten dadurch, dass jede Pipelinestufe die Thread-ID jedes zu verarbeitenden Befehls verfolgt. Auch hier müssen gemeinsam genutzte Ressourcen wie Caches und TLBs für die große Anzahl aktiver Threads, die verarbeitet werden, dimensioniert werden.

Zu den Implementierungen gehören DEC (später Compaq) EV8 (nicht abgeschlossen), Intel Hyper-Threading Technology, IBM POWER5, Sun Microsystems UltraSPARC T2, Cray XMT und AMD Bulldozer und Zen Mikroarchitekturen.