Multicore-Plattformen

Dr. René Graf | Günter Herkommer,

Chancen und Risiken der neuen Prozessor-Architekturen

Immer schneller und leistungsfähiger lautet der Tenor in der Automatisierungswelt. Deshalb halten zunehmend Multicore-Prozessoren Einzug. Doch mehr Prozessorkerne sorgen nicht zwingend für eine kürzere Software-Laufzeit.

© Siemens

Die Computerentwicklung der letzten Jahre zeigt, dass die Steigerung der Leistungsfähigkeit der Prozessoren nicht mehr alleine über eine Erhöhung der Taktfrequenz zu erreichen ist. Dies liegt in erster Linie an der damit einhergehenden Erhöhung der Verlustleistung, die in Form von Wärme abgeführt werden muss. Daher erfolgt die Steigerung der Rechenleistung durch die Erhöhung der Anzahl der Rechenkerne. Da sich das Moore´sche Gesetz in erster Linie auf die Anzahl der Transistoren pro Fläche bezieht, bleibt diese Steigerung quasi erhalten; nur dass diese Transistoren sich auf viele Kerne verteilen, die sogenannten Multicore-Prozessoren.

Bei der Anwendung in der Automatisierungswelt hat dies allerdings dramatische Auswirkungen auf die Leistungssteigerung aus Sicht der Software. Denn während früher die Leistungssteigerung mit der Verwendung der neuesten Prozessoren automatisch und ohne Änderungen an der Software erfolgte, liegt die Verantwortung diesbezüglich bei der Verwendung von Multicore-Plattformen nun vollständig in den Händen der Software-Entwickler.

Die Erwartungshaltung steigt

Welche Konsequenzen der Übergang von einem Single-Core- auf einen Dual-Core-Prozessor hat, wird anhand eines realen Automatisierungsgerätes deutlich, das implizit zwei Aufgaben erfüllt:
Zum einen wird ein Steuerungsprogramm mit Echtzeit-Anforderungen ausgeführt und zum anderen eine Benutzerschnittstelle grafisch und per Kommunikation bereitgestellt. Diese beiden Software-Anwendungen laufen auf jeweils eigenen Betriebssystemen, sind voneinander unabhängig und kommunizieren vollständig asynchron miteinander, so dass sie sich nicht gegenseitig blockieren können.

Anzeige

Bild 1. Systemmigration von Single- auf Dual-Core-Prozessor.

© Siemens

Die linke Seite in Bild 1 zeigt das System vor der Migration. Dabei teilen sich die beiden Software-Blöcke – bestehend aus Betriebssystem und Applikation(en) – einen Prozessorkern, indem dessen Rechenzeit per Hardware-Timer zu 70 % für Echtzeit- und zu 30 % für Nicht-Echtzeit-Aufgaben aufgeteilt wird. Die Peripherie am PCI-Bus ist ebenfalls streng der einen oder der anderen Seite zugeordnet, so dass auch hier keine Zugriffskonflikte entstehen können.
Somit erscheint die Migration auf einen Dual-Core naheliegend, da das System softwaretechnisch ideal für eine Aufteilung geeignet ist. Die rechte Seite von Bild 1 zeigt das neue System mit zwei Rechenkernen. Anstelle der zeitlichen Aufteilung werden die Software-Blöcke durch Verwendung der sogenannten Core-Affinity getrennt, indem beide fest an jeweils einen Rechenkern gebunden werden. Die Erwartungen an die Laufzeit der Software sind, dass die Echtzeit-Seite unverändert bleibt, während die Nicht-Echtzeit-Seite signifikant schneller läuft, da sie jetzt über 100 % der Rechenleistung eines Kerns verfügt, statt über 30 % wie zuvor.

Die Realität hat gezeigt, dass die Erwartung an die Nicht-Echtzeit-Seite voll erfüllt wurde. Die Erwartung an die Echtzeit-Seite hingegen wurde massiv verfehlt! Das heißt: Die Laufzeiten der Echtzeit-Applikation waren im schlechtesten Fall um mehrere Faktoren höher als zuvor. Eine erste Analyse ergab, dass vermutlich der PCI-Bus involviert ist. Folglich wurde die Nicht-Echtzeit-Applikation durch eine kontrollierbare Last-Applikation am PCI-Bus ersetzt, um diesen Einfluss genauer messen zu können. Diese kopiert permanent 4 KByte große Datenblöcke über den Bus.

Laufzeiten der beiden Systeme

© Siemens

Die Tabelle zeigt die Laufzeiten auf beiden Systemen, jeweils mit und ohne die künstlich erzeugte PCI-Last. Die Echtzeit-Applikation besteht aus einem Achsregler (AC) und einem überlagerten Positionsregler (MC). Der AC läuft bei jedem Takt des Systems von 1,5 ms, während der MC dazu untersetzt auch nur jeden zweiten oder vierten Takt laufen kann.

Die Messwerte zeigen, dass sich die maximale Laufzeit der Echtzeit-Applikation auf einem Kern um mehr als den Faktor zwei erhöht und die Gesamtlaufzeit (AC + MC) sich der maximal möglichen Zykluszeit von 1,5 ms bedenklich annähert. Diese dramatischen Anstiege der Laufzeit sind dadurch erklärbar, dass zum einen der PCI-Bus einen Flaschenhals darstellt, durch den alle Daten laufen, und zum anderen das Lesen eines Wertes am PCI-Bus um den Faktor sechs langsamer ist als das Schreiben.

Jeder Lesezugriff – auch wenn nur ein Wert gelesen wird – dauert aufgrund der PCI-Architektur und des Protokolls zirka 1 μs, während ein Schreibzugriff in der Regel in einem FIFO-Puffer des PCI-Controllers endet und somit nach etwa 20 ns beendet ist. Der PCI-Arbiter, der die Buszugriffe verwaltet, arbeitet paritätisch, so dass jeder Teilnehmer am Bus gleich behandelt wird. Dies führt dazu, dass zwischen zwei Schreibzugriffen der Echtzeit-Seite ein Lesezugriff der Nicht-Echtzeit-Seite ausgeführt wird und sich somit die Laufzeit von 40 nsec auf mindestens 1040 nsec erhöht.

Da die Ursachen der Laufzeit-Verschlechterung in der nicht änderbaren Hardware liegen, ist die Software anzupassen. Im Wesentlichen stehen zwei Möglichkeiten zur Verfügung: Zum einen kann der PCI-Bus als explizite Ressource in der Software betrachtet und entsprechend verwaltet werden. Da die Echtzeit-Seite streng periodisch aktiviert wird, kann die Nicht-Echtzeit-Seite die potenziellen Zugriffe während deren Laufzeit blockieren und erst nach dem Ende der kritischen Phase wieder freigeben. Zum anderen lässt sich die Eigenschaft des PCI-Busses dahingehend nutzen, dass das Schreiben sehr viel schneller erfolgt als das Lesen. Moderne Peripheriegeräte können eigenständig Buszugriffe initiieren, so dass die Software die Daten bereits im Hauptspeicher vorfindet und nicht über den Bus zugreifen muss.

Mit diesen beiden Maßnahmen ließ sich das System entsprechend verbessern, so dass die Software-Laufzeiten sich wieder in unkritischen Bereichen bewegen.

Hyperthreading mit Tücken

Neben den echten Multicore-Prozessoren mit mehreren Rechenkernen gibt es noch eine abgeschwächte Variante, die in der x86-Welt als Hyperthreading bekannt ist. Dabei wird kein vollständiger Prozessorkern hinzugeführt, sondern nur seine wichtigsten und gleichzeitig einfachsten Einheiten.

Ein moderner Prozessor besteht aus vielen Einheiten, die spezielle Aufgaben übernehmen und teilweise auch mehrfach vorhanden sein können. Beispiele für einfache Einheiten repräsentiert die LSU (Load Storage Unit) zum Lesen und Schreiben von Daten in den Hauptspeicher oder die ALU (Arithmetic Logical Unit) für Ganzzahl- und Logik-Operationen. In die Kategorie komplexe Einheiten fällt beispielsweise die FPU (Floating Point Unit) zur Berechnung von Fließkommazahlen.

Bild 2: Aufbau eines Hyerthreading-Prozessors: Die Maschinenbefehle zweier Programme werden in einem Hyperthreading-Prozessor so verteilt, dass diese optimal ausgelastet sind.

© Siemens

Während der Ausführung durchläuft ein Befehl die sogenannten Pipeline-Stufen. Diese übernehmen einzelne Aufgaben wie das Lesen des Befehls oder dessen Decodierung. Letztere verteilt ihn auf die oben genannten Einheiten, die den Befehl ausführen und damit auch in einem Single-Core voll parallel arbeiten können. Über vorgeschaltete Puffer können einer Einheit auch mehrere Befehle ohne Wartezyklen zugeteilt werden. Dadurch wird ein Durchsatz von bis zu einem Befehl pro Taktzyklus erreicht, obwohl die Ausführung der einzelnen Befehle meist mehrere Zyklen dauert.

In einem Hyperthreading-Prozessor besteht ein physikalischer Rechenkern aus zwei logischen Kernen, deren einfache Einheiten auch doppelt vorliegen, während die komplexen Einheiten nur einmal vorhanden sind. Die Software sieht den Unterschied zunächst nicht und nutzt diese logischen Kerne genauso wie physikalische. Beide Kerne haben eine eigene Befehlsliste (instruction queue), in der die Maschinenbefehle des Programms stehen. Diese beiden Listen werden in der Pipeline-Sequenz vermischt, um die vorhandenen Einheiten optimal – also möglichst permanent – auszulasten. Dazu werden die Befehle nicht abwechselnd aus beiden Listen genommen, sondern abhängig vom aktuellen Belegungsgrad der Einheiten.

Die linke Seite in Bild 2 zeigt dieses Verfahren und veranschaulicht, wie aus einer deterministischen Reihenfolge einer Befehlsliste eine zufällige und in der Reihenfolge nicht mehr vorhersagbare Liste wird. Für die Software bedeutet dies, dass ihre Laufzeit noch stärker von dem Programm auf dem anderen logischen Rechenkern abhängt. Da dieses Programm bei jeder Messung ein anderes sein wird, ist die Laufzeit nicht bestimmbar.

Die Messwerte zeigen die Auswirkungen von Hyperthreading.

© Siemens

Um die Maximalwerte der Laufzeit zu messen, wurde auf einem solchen Prozessor ein Echtzeit-System installiert. In der Anwendung laufen zwei Threads – einer mit (RT = Real-Time) und einer ohne (NRT = Non-Real-Time) Echtzeit-Eigenschaften. Der RT-Thread wird wie ein Regler zyklisch über einen Software-Timer aktiviert, während der NRT-Thread im Hintergrund auf dem anderen logischen Kern läuft.

Die Messwerte in der Tabelle zeigen die Auswirkungen von Hyper­threading auf die Laufzeit eines Echtzeit-Threads. Läuft dieser alleine auf einem logischen Kern, so ist seine Laufzeit relativ konstant, wobei sich durch Betriebssystemprogramme auf dem zweiten logischen Kern die maximale Laufzeit dennoch erhöht. Läuft auf dem zweiten logischen Kern hingegen der NRT-Thread, so dass beide Threads sich die FPU teilen müssen, liegt die maximale Laufzeit annähernd bei dem doppelten Wert des ungestörten Betriebs und selbst der Mittelwert liegt deutlich näher am maximalen statt am minimalen Wert.

Aus diesem Grund wird bei Echtzeit-Anwendungen Hyperthreading abgeschaltet; zumindest auf den physikalischen Kernen, auf denen zeitkritische Programme laufen. Dadurch wird jedoch Rechenleistung verschenkt, die sich für Nicht-Echtzeit-Anwendungen nutzen ließe.

Vorfahrtsregeln für Multicore

Zur Nutzung dieser Rechenleistung wurde in das Echtzeit-Betriebssystem ein Mechanismus eingebaut, der den Echtzeit-Threads entsprechend Vorfahrt einräumt. Das System muss zunächst die Threads klassifizieren können, um diese Entscheidung zu treffen. Des Weiteren wurde die Gesamtapplikation so verteilt, dass alle Echtzeit-Threads auf einem logischen Kern ablaufen, während die Nicht-Echtzeit-Threads sich auf beide logischen Kerne verteilen.

Bild 3. Kontrolle des Echtzeit-Verhaltens: Der Einfluss des Programms auf dem zweiten Rechenkern kann kontrolliert werden, indem dort ein bekanntes „Programm“ (die Warteschleife) ausgeführt wird, während das Echtzeit-Programm läuft.

© Siemens

Wird ein RT-Thread durch ein Ereignis (Timer, Interrupt etc.) aktiviert, so schickt das Betriebssystem eine Meldung an den zweiten logischen Kern. Dies kann beispielsweise als Interrupt (Inter Processor Interrupt – IPI) erfolgen, damit dieser Kern möglichst schnell seinen aktuell laufenden NRT-Thread unterbricht und in eine Warteschleife verzweigt. In dieser Schleife liest der Kern beispielsweise den Inhalt einer lokalen Speicherzelle. Somit werden zum einen nur Prozessoreinheiten verwendet, die jeder logische Kern besitzt, und zum anderen erfolgen keine Zugriffe auf Peripherie außerhalb des Prozessors, die – wie zuvor beschrieben – den anderen Kern ausbremsen können. Selbst ein konkurrierender Speicherzugriff lässt sich ausschließen, da die zu lesende Speicherzelle spätestens nach dem ersten Zugriff im Cache liegt.

Die linke Seite in Bild 3 zeigt das Verfahren aus Applikationssicht. Sobald ein RT-Thread gestartet wird, wird der zweite logische Kern in die Warteschleife gezwungen. Auf der rechten Seite ist dieses Vorgehen aus Prozessorsicht dargestellt, insbesondere die Füllung der Prozessor-Pipeline. Wenn auf beiden logischen Kernen nur NRT-Threads laufen, ist die Reihenfolge der Befehle zufällig und nicht vorhersagbar. Läuft hingegen ein RT-Thread und parallel dazu die Warteschleife, so mischen sich aufgrund der exklusiv im zweiten logischen Kern zur Verfügung stehenden Einheiten die Befehle de­terministisch. Die Laufzeit des RT-Threads ist  damit vollständig vorhersagbar, wie die Messwerte in der Tabelle (unten) zeigen.

Messwerte der laufzeit eines RT-Threads

© Siemens

Selbst wenn der RT-Thread alleine läuft, verbessert sich die Deterministik seiner Laufzeit erheblich, da auch alle Betriebssystem-Aktivitäten auf dem zweiten Kern durch die Warteschleife unterbunden werden. Im Falle eines NRT-Threads auf dem zweiten Kern, der die gleichen Prozessoreinheiten verwendet, ist die Verbesserung noch signifikanter, da keine nennenswerte Verschlechterung der Messwerte mehr auftritt.

Das beschriebene Verfahren lässt sich nicht nur für Hyperthreading-Prozessoren anwenden, sondern kann auch bei echten Multicore-Prozessoren dazu dienen, Peripheriezugriffe auf anderen Kernen sicher auszuschließen, wenn auf einem Kern zeitkritische Software läuft. Der Vorteil gegenüber den oben genannten Maßnahmen ist, dass die Applikation nicht verändert werden muss beziehungsweise auch nicht im Quellcode vorliegende Software kontrollierbar ist.

Genaue Kenntnis der Hardware unabdingbar

Wie die bisherigen Ausführungen zeigen, birgt die Verwendung von Multicore-Prozessoren in der Automatisierungstechnik sehr viele Chancen und kann den Trend zu mehr Leistung in den Steuerungen unterstützen. Auf der anderen Seite bringen diese Prozessoren neue Probleme mit sich, die in den bisherigen Anwendungsgebieten nicht relevant waren.

Daher lässt sich die Software eines Automatisierungsgerätes nicht mehr ohne genaue Kenntnis der zugrunde­liegenden Hardware entwickeln, da diese implizite Abhängigkeiten enthalten kann, die vielleicht nicht zwingend die Funktion, aber mit Sicherheit das Zeitverhalten der Software negativ beeinflussen. Mit anderen Worten: Weil in Echtzeit-Systemen die Daten nicht nur inhaltlich, sondern auch zeitlich korrekt sein müssen, kann der Umstieg auf Multicore-Prozessoren zu Fehlverhalten der Software führen, selbst wenn dabei zwei mehr oder weniger unabhängige Anwendungen auf einem Prozessor mit mehreren Kernen konsolidiert werden.

Die Lösung ist entweder die Anpassung der Software sowie die explizite Verwaltung von eigentlich eher unsichtbaren Hardware-Ressourcen wie Speicher und Bussystemen oder die Ertüchtigung des Betriebssystems dahingehend, die kritische Software zu erkennen und entsprechend auf Basis definierter Vorfahrtsregeln zu bevorzugen.

Autor: Dr. René Graf ist Gruppenleiter Vorfeldentwicklung bei Siemens.

  • Xing Icon
  • LinkedIn Icon
Anzeige
Anzeige

Das könnte Sie auch interessieren

Anzeige

Siemens

Edge-Rack-Server in robust

Der Trend zu hyperkonvergenten Infrastrukturen macht auch vor der Fertigungs- und Auto-matisierungsindustrie keinen Halt. Siemens hat nun einen ersten Edge-Rack-Server in robuster Industrie-PC-Qualität auf dem Markt gebracht. Wie ist das Innenleben...

mehr...
Anzeige
Anzeige
Anzeige

Siemens

Für den Eigenbedarf

Siemens betreibt an seinem Standort in Frankfurt Vertical Farming für den Eigenbedarf. Zum Einsatz kommt dabei Siemens-Technologie. Was hier im Kleinen funktioniert, ist auch ein Zukunftsfeld für die Landwirtschaft im Allgemeinen.

mehr...
Anzeige
Anzeige
Anzeige

Im Fokus: Agriculture

Das E-Paper der Ausgabe 05/2024

Um Strategien für die Zukunft geht es unter anderem in der aktuellen Computer&Automation. Lesen Sie, welche Reformen Verbände von der Politik fordern, welche Chancen Technologien wie ChatGPT und SPE mit sich bringen und welche Rolle Roboter bei...

mehr...
Jetzt Newsletter abonnieren