Virtualisierung Echtzeit für Multicore

Immer häufiger kommen Multicore-Prozessoren in Embedded Systemen zum Einsatz. Allerdings gibt es auch Vorbehalte, denn der effiziente Einsatz solcher Bausteine erfordert ein Umdenken bei den Designern, um das Performance-Potenzial überhaupt erst nutzbar zu machen. Allerdings gibt es da mehrere Ansätze: Ist nun ein symmetrisches oder eine asymmetrisches Multi-Processing besser? Und wie ist die Inter-Prozess-Kommunikation zu implementieren? Ist da die Embedded-Virtualization oder ein »Global Objects«-Netzwerk besser?

Bevor Multicore-Prozessoren verfügbar waren, lösten sich viele Performanceprobleme einfach von selbst: durch den Einsatz höher getakteter Prozessoren und zusätzlichen Ressourcen wie mehr Cache und mehr Speicher. Bestehende Applikationen wurden damit wieder schneller und somit an erhöhte Performancebedingun-gen angepasst, ohne dass der Kern der Applikationen signifikanten Änderungen unterworfen wurde.

Im Falle von Embedded Systemen ist der Kern dieser Applikationen oft das wertvollste IP eines OEMs, das über Jahre generiert, optimiert und zertifiziert wurde. Somit möchte man diese Applikationen am besten unangetastet lassen. Bestehende Designs auf Basis eines Einzelkernprozessors dazu zu bewegen, die volle Performance eines »Mehrkerners« auszureizen und dabei bestehende Applikationen intakt zu lassen, benötigt spezielle Technologien, die wir nun im Folgenden beschreiben wollen.

Symmetrisches Multi-Processing

Betriebssysteme wie Windows verwenden den symmetrischen Multi-Processing-Ansatz (SMP), um zusätzliche Prozessorkerne nutzen zu können. Der Begriff SMP-System trifft zu, wenn ein Betriebssystem zwei oder mehr Prozessorkerne für die zu startenden Applikationen zuteilt. SMP bedeutet ebenfalls, dass der Systemspeicher allen Kernen gleichzeitig zur Verfügung steht und somit auch die Applikationen in einen gemeinsam verfügbaren Speicher geladen werden, wie das auch bei einem Single-Core-System der Fall ist.

Der Betriebssystem-Scheduler sorgt dann dafür, dass die Threads möglichst gleichmäßig auf die vorhandenen Prozessorkerne verteilt werden. Das Betriebssystem verwaltet sämtliche I/Os und deren Interrupts, die typischerweise auch von allen Prozes-sorkernen erreichbar sind. Die Performance von SMP-Implementierungen wird begrenzt durch Engpässe beim Speicherzugriff und dem zusätzlichen Verwaltungsaufwand, der durch die Zuteilung auf die vorhandenen Prozessorkerne entsteht. Eine Daumenregel besagt, dass dieser Ansatz typischerweise ab mehr als sechs Kernen und einer größeren Anzahl von Applikationen schlechtere Ergebnisse liefert.

Bild 1 zeigt vier CPUs, verwaltet von einem SMP-Betriebssystem. Größere Applikationen werden über mehrere Kerne verteilt, wohingegen mehrere, kleinere Applikationen auch auf einem CPU-Kern laufen können, um die Nutzung der verfügbaren Prozessorkapazitäten zu optimieren. Sämtliche I/Os werden von einem Betriebssystem gesteuert und sind somit auch allen Applikationen zugänglich. Dieser Multi-Processing-Ansatz ist für die meisten Echtzeitapplikationen nicht zielführend.

Scheduler von Echtzeitbetriebssystemen müssen Thread-Prioritäten mit einbeziehen und gleichzeitig auf externe, asynchrone Ereignisse zeitgerecht reagieren. Es ist sicherzustellen, dass Ereignisse in definierter Folge innerhalb einer deterministischen Zeit verarbeitet werden können. Der SMP-Scheduler muss somit vielfache Bedingungen einbeziehen, um ein deterministisches Echtzeitverhalten des Systems zu gewährleisten.

Derartige Anforderungen erhöhen den Scheduler-Overhead gewaltig, was den Einsatz von SMP für Echtzeitapplikationen stark einschränkt und im Falle von mehr als acht Kernen nahezu unmöglich macht. Zusätzlich generieren die gemeinsamen I/O-Interrupts Probleme, da diese auch Applikationen betreffen, die nichts mit diesen I/Os zu tun haben. Das kann massive Probleme speziell im Debugging von großen Applikationen verursachen.

Asymmetrisches Multi-Processing

In der Vergangenheit wurden Echtzeitapplikationen immer in AMP-Umgebungen programmiert, wo auf jedem CPU-Kern ein oder auch gar kein Betriebssystem verwendet wurde und jeder Kern somit immer über eigene Ressourcen verfügte. AMP-Systeme haben den wesentlichen Vorteil, eine genau definierbare Umgebung mit vorhersagbarem Zeitverhalten zur Verfügung zu stellen - unbeeindruckt von anderen, davon unabhängigen Prozessen.

Diese geschützte Umgebung macht es erst möglich, auch komplexe Steuerungsapplikationen noch debuggen zu können. AMP hilft auch sicherzustellen, dass sich keine Race-Conditions und Prioritätsinversionen einstellen. Dies ist ein entscheidendes Element einer Echtzeitsteuerungsapplikation.

Aufgrund der Arbeitsweise von AMP-Systemen sind spezielle I/Os nebst ihren Interrupts direkt Applikationselementen zugeordnet. Somit können nur von der Kommunikation betroffene Applikationen unterbrochen werden. Dadurch arbeitet das System effizienter und kann gleichzeitig mehr Interrupts verarbeiten.

Bild 2 zeigt vier CPUs in einer AMP-Konfiguration. Jede CPU verfügt über ein eigenes Betriebssystem und über dediziertes I/O.

CPU 1 ist komplett ausgelastet mit App.1, die möglicherweise schneller laufen könnte, wenn mehr CPU-Leistung zur Verfügung stünde, während im Falle von App.3 und App.4 die CPU-Kerne nur halb ausgelastet werden.

In einer derartigen Konfiguration hat jede CPU und ihre assoziierte Applikation nur ihr dediziertes I/O nebst Interrupts, das die Verarbeitung unterbrechen kann.

Normalerweise ist AMP die bessere Methode für den Einsatz bei Echtzeitapplikationen, weil es dem Entwickler deutlich mehr Kontrolle über das Management der Ressourcen gibt (Tabelle 1), aber es gibt auch Grenzen zu überwinden. Multiprozessor-Systeme erfordern typischerweise, dass Applikationen und Prozesse miteinander kommunizieren können, die auf den unterschiedlichen Kernen laufen.

Die IPC (Inter-Process-Communication) ist der typische Weg dorthin, und deren Implementierung erfordert spezielle Designaspekte. Prozesse, die auf unterschiedlichen CPUs laufen, kommunizieren meistens über Shared-Memory-Bereiche.

Mithilfe spezifischer Middleware, die Polling- und Spinning-Mechanismen umfasst, wird das Senden und Empfangen von Nachrichten koordiniert. Obwohl diese Methoden gängig sind, sind sie tendenziell ineffizient und somit keine optimale Option für die Implementierung der IPC.

Eine bessere Strategie besteht darin, einen Prozess zu generieren, der einen Interrupt auf der CPU auslöst, die vom sendenden Prozess ein Signal zur Kommunikation erhalten soll. Das benötigt aber oftmals zusätzliche Interrupt-Management-Hardware, die Kosten und Komplexität in die Höhe treibt.