Um die Vorteile der Multicore-Parallelität nutzen zu können, müssen Entwickler im Voraus festlegen, welche Teile der Anwendung parallelisiert oder ausgelagert werden sollen. Der Code muss dann so geschrieben werden, dass diese Parallelität eindeutig ist. So kann der Entwickler zum Beispiel Code in Threads platzieren, die dann von einem SMP-Betriebssystem so eingeteilt werden, dass sie parallel laufen. Mit standardisiertem Multithreading wird sichergestellt, dass die Multicore-Software über Projekte hinweg portierbar und wiederverwendbar ist.

Posix

Posix ist eine Sammlung von APIs mit offenem Standard, die vom IEEE Betriebssystem-Dienste festgelegt wird. Posix-Threads (Pthreads) ist der Teil des Standards, der das Multithreading behandelt. Die Pthread-APIs stellen Schnittstellen für die Ablaufsteuerung der Threads, Synchronisationsoperationen und IPC-Mechanismen bereitWährend es noch andere Multithreading-Standards gibt, ist Pthreads ein generischer und allgemein gültiger Standard. Pthreads wird durch Linux, Unix und eine Vielzahl von Embedded-Betriebssystemen wie Integrity, LynxOS und QNX unterstützt. Selbst Windows unterstützt eine Posix-Schnittstelle. Aufgrund der Allgegenwärtigkeit von Posix gibt es eine große Basis von Anwendungscode, der sich für Embedded-Designs wiederverwenden lässt. Ein weiterer großer Vorteil von POSIX ist die unabhängige Konformitätsvalidierung seitens der Open Group. Bei der Programmierung über die Posix-API können Entwickler Multithreaded-Anwendungen schreiben, die sich auf jede Multicore-Plattform portieren lassen, die mit einem Posix-konformen Betriebssystem ausgestattet ist. Posix ist eine natürliche Ergänzung für Multicore-Embedded-Systeme, da Embedded-Software oft von Grund auf neu geschrieben wird, um multithreading-fähig zu sein. Hinzu kommt, dass Add-on-Softwarekomponenten meist leicht einzelnen Threads zugeordnet werden können. So kann ein TCP/IP-Netzwerk-Stack innerhalb des Kontexts eines Single-Posix-Threads ausgeführt werden. Das gleiche gilt beispielsweise für einen Dateisystem-Server oder eine Audio-Applikation. Posix-Konformität ist eine Voraussetzung für jedes Betriebssystem, das in Multicore-Systemen zum Einsatz kommen soll.

Interprozess Kommunikation (IPC)

Message Passing ist seit langem ein Mechanismus, um Parallel Computing zu implementieren, vor allem weil die lange verwendeten Multicomputer zum Verarbeiten paralleler wissenschaftlicher Berechnungen kein gemeinsames Speichersubsystem aufweisen. Vielmehr werden die Daten für parallele Berechnungen mittels IPC an die parallelen Cores gesendet, wobei die gleiche IPC als Synchronisationsmechanismus fungierte. Obwohl sich Embedded-Anwendungen von den wissenschaftlichen Berechnungen unterscheiden, ist eine IPC generell erforderlich, um Multiprozess-Systeme zu implementieren.

IPC gibt es in vielen Arten. Im wissenschaftlichen Bereich ist das Message Passing Interface (MPI) ein weit verbreiteter Standard. Posix spezifiziert eine Vielzahl von Mechanismen, einschließlich Pipes, FIFOs und Sockets, die für eine lose gekoppelte IPC entwickelt wurden.

Die richtigen Werkzeuge für Multicore-Entwickler müssen eine Vielzahl von IPC-Möglichkeiten enthalten. Verfügt die Anwendung über genügend Spielraum, den Overhead eines zugrunde liegenden Netzwerk-Stacks zu handhaben, sind Posix-Sockets der wohl am weitesten verbreitete IPC-Mechanismus.

Multicore-Laufzeit-Management

Symmetrisches Multiprocessing (SMP) ist eines der vielversprechenden Multicore-Tools für Embedded-Systeme. Ist die Anwendung bereits multithreaded, wie es bei den meisten Embedded-Designs der Fall ist, dann teilt ein SMP-Betriebssystem gleichzeitige Threads so ein, dass sie auf den zusätzlichen Cores des Systems laufen. SMP kann erhebliche Leistungsverbesserungen bieten, ohne dass Software-Änderungen erforderlich sind. SMP ist heute durchaus üblich in Embedded-Betriebssystemen, zum Beispiel Linux, Green Hills‘ Integrity und Intels VxWorks.

Eine der Herausforderungen bei SMP ist der Unterschied im Ablaufverhalten gegenüber Echtzeit-Betriebssystemen für einen Core. Da mehrere Prozesse gleichzeitig ausgeführt werden können, ist eine Prozess-Priorisierung für eine garantierte Ausführungszeit nicht unbedingt erforderlich. Das Betriebssystem Integrity von Green Hills bietet einen optionalen alternativen Ansatz, mit dem Anwendungsprozesse einen garantierten Prozentsatz an Ausführungszeit über alle Cores im System zugewiesen bekommen. Innerhalb einer Anwendung werden die Threads mit Standardprioritäten und Zeitscheibenverfahren priorisiert.

Core-Affinität

Die maximale Cache-Nutzung ist entscheidend für die Performance und das Leistungsprofil der meisten Embedded-Systeme. Die meisten SMP-Systeme bestehen aus Cores, die über unabhängige On-Chip-Cache-Speicher verfügen. Wenn ein Thread von einem Core zu einem anderen migriert, gehen der Cache-Ort des Thread-Codes und dessen Daten verloren und müssen auf den neuen Core neu geladen werden. Muss ein Thread ausgeführt werden (d.h. er ist ein ausführbarer Thread mit höchster Priorität) und steht mehr als ein Core zur Verfügung (Idle), muss das SMP-Betriebssystem intelligent entscheiden, welcher Core zu verwenden ist. Das Betriebssystem sollte also die „natürliche Affinität“ eines Threads verfolgen. Diese ist definiert als der Core, auf dem der Thread zuletzt ausgeführt wurde. Durch die Zuordnung von Threads auf die Cores, die deren natürlicher Affinität entsprechen, minimieren sich Migrations- und Cache-Misses und die Embedded-Software kann höchste Performance und Energieeffizienz erzielen.

„Benutzerdefinierte Affinität“ ist ein weiteres nützliches Tool für Entwickler, womit bestimmte Threads an bestimmte Cores gebunden werden. Die Latenz und auch die Effizienz des Gesamtsystems lassen sich so in bestimmten Situationen verbessern. Ein Gerätetreiber-Thread kann zum Beispiel immer an den gleichen Core gebunden werden, die Interrupts handhaben und damit den Einsatz von Interprozess-Interrupts (IPI) verhindern, welche die Latenz erhöhen würden. Ein anderes Szenario betrifft die gemeinsame Zuordnung mehrerer Threads, um eine bestimmte Aufgabe zu bewältigen (also gemeinsame Datenstrukturen nutzen). Die gleiche Core-Affinität dient dabei zur Minimierung von IPIs und zur maximalen Cache-Nutzung. Das SMP-Betriebssystem stellt dabei einen Systemaufruf zur Zuweisung der Core-Affinität bereit.

SMP-Hypervisor

Multicore-Prozessoren wie der P4080 von Freescale, Intels Core2 und ARMs Cortex A9 bieten eine Form von Hardware-Virtualisierungsbeschleunigung. Multicore-Architekturen verbessern die Nutzbarkeit der Hypervisor. So kann bei einem Dual-Core-System eine separate virtuelle Maschine an jeden Kern gebunden werden, was eine garantierte Quality of Service für jeden Gast ermöglicht. Mit einem fortschrittlichen Typ-1-Hypervisor wie Integrity Secure Virtualization (ISV) von Green Hills kann gewährleistet werden, dass Echtzeit-Anwendungen eine optimale Reaktionszeit aufweisen, indem sie auf einem Kern, unabhängig von den Gast-Betriebsumgebungen ablaufen.

Fortschrittlicher Typ-1 Embedded Multicore Hypervisor.

Fortschrittlicher Typ-1 Embedded Multicore Hypervisor.Green Hills Software

Ein weiterer Anwendungsfall für Multicore-Hypervisor ist die Möglichkeit eines flexibleren Power-Managements. Gast-Betriebssysteme können auf allem System-Cores ablaufen, wenn Anwendungen maximale CPU-Verfügbarkeit erfordern. Da der Hypervisor jedoch Gastbetriebssysteme auf virtuelle Cores zuweisen kann, lassen sich diese auf einer kleineren Anzahl verfügbarer Cores ausführen, wenn weniger Arbeitslast vorliegt. Damit können die restlichen Cores komplett ausgeschaltet werden.

Die Verbreitung von Multicore-Plattformen wird sich durch Hypervisor noch weiter erhöhen: ein symbiotisches Wachstum für zwei bahnbrechende Technologien.

Stop-Mode Multicore-Debugging

Multicore-Prozessoren bieten einen On-Chip Debug-Port (z.B. JTAG), der es einem Host-Debugger ermöglicht, über eine Hardware Probe mehrere Cores gleichzeitig zu debuggen. Damit können Entwickler eine synchronisierte Laufzeitsteuerung mehrerer Cores auf niedriger Ebene durchführen. Das Board Bring-up und die Gerätetreiberentwicklung sind zwei gängige Anwendungen für diese Lösung.

Für den effizienten Einsatz dieser Multicore-Hardware-Einrichtung muss das Entwicklungstool alle Cores des Systems visualisieren und jede Kombination zum Debuggen der Cores ermöglichen – optional auch in einem jeweils eigenen Fenster. Das Tool muss auch das synchronisierte Starten und Anhalten der zu debuggenden Cores steuern. Green Hills‘ Probe und Multi IDE sind ein Beispiel für ein solches Entwicklungspaket, das diese Anforderungen erfüllt.

Run-Mode Multicore-Debugging

Beim Run-Mode-Debugging werden die Cores nicht angehalten. Der Debugger steuert vielmehr die Anwendungs-Threads über einen Kommunikationskanal (meist Ethernet) zwischen dem Host-PC und einem target-seitigen Debug Agent.

Um diese Möglichkeit effizient zu nutzen, muss das Betriebssystem einen integrierten Debug Agent bereitstellen (und die dazugehörigen Kommunikations-Gerätetreiber), der flexible Optionen für die Systemabfrage bereitstellt. Das Betriebssystem Integrity bietet einen leistungsfähigen Debug Agent, der mit dem Multi-Debugger kommuniziert und die Möglichkeit bietet, jede Kombination von User-Threads auf jedem Core zu debuggen – unabhängig von der Homogenität der Core-Architektur. Der Anwender kann spezielle Breakpoints setzen, die das Anhalten anwenderdefinierter Gruppen von Threads ermöglichen, wenn ein anderer Thread auf den Breakpoint trifft. Einige Fehlerarten erfordern diese genaue Art der Kontrolle. Um Threads auf einem Core anzuhalten, der sich vom Core mit dem Breakpoint-treffenden Thread unterscheidet, muss das Betriebssystem die gesamte im Hintergrund laufende Kommunikation handhaben, die den entsprechenden Core informiert – und das mit minimaler Verzögerung zum Ereignis.

Multicore Event Analyzer

Viele Anbieter von Betriebssystemen bieten ein Event-Analyse-Tool an. Ein target-residierender Agent hält wichtige Betriebssystemereignisse fest, wie beispielsweise Service-Aufrufe, Interrupts, Kontextwechsel und anwenderdefinierte Events. Das Tool lädt diesen Event Log (während der Ausführung oder danach) und stellt die Events über der Zeit dar. Das Tool erlaubt dem Anwender zum Beispiel die Darstellung zu vergrößern, bestimmte Events für weitere Informationen auszuwählen und Ausführungsstatistiken zu generieren.

Der Event Analyzer ist ein unverzichtbares Werkzeug für Entwickler von Multithreaded-Software, da er ein einfaches Verständnis des Systemverhaltens ermöglicht und Leistungsengpässe, Livelocks und andere Probleme aufspürt. Er ist für ein Multicore-Design umso bedeutender. Er muss Events für alle Threads auf allen Cores anzeigen, wobei die Event-Streams zur gleichen Zeitskala synchronisiert sein müssen. Das Tool muss auch die IPC zwischen den Cores anzeigen.