Ein Angebot von

OpenAMP – Ein Open Source Framework für asymmetrisches Multiprocessing

| Autor / Redakteur: Frank Storm* / Sebastian Gerstl

Heterogene Multicores sind in SoCs mittlerweile weit verbreitet. Der Einsatz unterschiedlicher Betriebssysteme auf den einzelnen Kernen stellt Entwickler aber häufig vor Schwierigkeiten. Hier setzt das Framework OpenAMP der Multicore Association an.
Heterogene Multicores sind in SoCs mittlerweile weit verbreitet. Der Einsatz unterschiedlicher Betriebssysteme auf den einzelnen Kernen stellt Entwickler aber häufig vor Schwierigkeiten. Hier setzt das Framework OpenAMP der Multicore Association an. (Bild: The Multicore Association (MCA))

Heterogene Multicore-Prozessoren gehören in modernen SoCs zum Standard. Doch existiert keine einheitliche Lösung, um diese mit unterschiedlichen Betriebssystem zu betreiben und die Kerne gleichzeitig miteinander kommunizieren zu lassen. OpenAMP soll diese Problematik adressieren und lösen.

Fast alle großen SoCs kommen heute mit mehr als einem Prozessor daher. Im oberen Segment sind ARM-Prozessoren als Quad-Core inzwischen Standard, ob als A53, A57 oder als big.LITTLE Kombination aus A15 und A7 (z.B. NXP i.MX8, Marvell Armada oder Xilinx Zynq UltraScale+). Im mittleren Segment hat man dann eher Dual-Core Systeme (z.B. Xilinx Zynq 7000). Da die typischen Applikationsprozessoren (ARM A) nicht für alle Applikationen ideal sind, stellen die Hersteller den Applikationsprozessoren auch noch andere Cores zur Seite. Das sind dann entweder spezielle Real-Time Prozessoren, wie der Cortex-R5 beim Zynq UltraScale+, oder typische Mikrocontroller-Cores, wie der Cortex-M4 beim i.MX8. Sogar im unteren Segment wird einem Cortex-M4 noch ein Cortex-M0+ zur Seite gestellt, wie in der NXP Controllerfamilie LPC54000.

Bereits in der Vergangenheit hat es diese Kombination aus Universalprozessor und Spezialprozessor gegeben, wie die im Mobilfunkbereich lange Zeit verbreitete OMAP Familie. Der Spezialprozessor war in diesem Fall ein DSP, der für die Abarbeitung des GSM Stacks zuständig war.

Schaut man sich die Verwendung der Zusatzprozessoren an, so werden diese sehr oft gezielt für Echtzeitaufgaben eingesetzt, sei es zur Abarbeitung eines Funkprotokoll-Stacks oder zur Antriebsregelung im Industriebereich. Dem Applikationsprozessor fallen dann die Aufgaben zu, sich um die Schnittstellen nach außen zu kümmern, das Human Machine Interface (Display oder Web-Server) zu realisieren, und nebenbei noch „House-Keeping“ zu betreiben.

Wir haben in vielen Kundenanwendungen gesehen, dass diese Aufteilung auch bei Systemen mit zwei Applikationsprozessoren gemacht wird, wie dem Zynq-7000, der über zwei Cortex-A9 Cores verfügt. Hier ist es nahezu Standard, auf dem ersten Core ein Linux laufen zu lassen, das sich um Schnittstellen wie Ethernet und USB kümmert und eine komfortable Umgebung für ausgewachsene Web-Server bietet. Auf dem zweiten Core läuft dann ein schlankes Echtzeit-Betriebssystem, wie z.B. FreeRTOS oder µC-OS, oder eben auch gar kein Betriebssystem (Bare Metal).

Herausforderungen beim Einsatz heterogener Multicore-Systeme

In der Praxis bringen diese heterogenen Systeme eine Reihe von Herausforderungen mit sich. Dabei kann es auch eher hinderlich sein, wenn die Prozessoren zu eng miteinander verzahnt sind. Typische Problemstellungen sind die Aufteilung des Speichers, das Festlegen eines Shared-Memorys, das von beiden Cores zum Austausch von Daten genutzt wird, das Verteilen der System-Ressourcen (wer darf sich z.B. um den CAN-Bus kümmern), und auch die Frage nach der Interrupt-Verteilung (wer unterbricht wen, läuft dies über einen gemeinsamen Interrupt-Controller oder vielleicht über eine spezielle Mailbox-Hardware). Da wird auch die Frage wichtig, wie MMU oder MPU konfiguriert werden müssen, oder welche Bereiche nicht gecacht werden dürfen. Je mehr Flexibilität der SoC-Hersteller in den Chip gelegt hat, umso mehr muss der Anwender bei der Umsetzung beachten.

Die Erfahrung hat gezeigt, dass Applikation-Notes zum AMP-Betrieb der Cores dankend aufgenommen werden, meistens aber nur der erste Schritt sind. Je komplexer ein Betriebssystem ist, desto schwieriger wird es auch, z.B. in das Speicher und Cache-Management einzugreifen. Bei einem Bare Metal Programm stellt man noch mal eben ein, welche Speicherbereiche nicht gecacht werden sollen. Bei einem Linux möchte man sich damit gar nicht erst beschäftigen müssen. Leider hat auch hier die Erfahrung gezeigt, dass man sich spätestens dann damit beschäftigen muss, wenn Interrupts verschluckt werden, und die Performance unter bestimmten Bedingungen plötzlich nicht mehr ausreicht.

Auch die Fragen nach dem sogenannten Lifecycle-Management, also dem Laden und Starten von Programmen, sowie dem gezielten Schlafenlegen, Herunterfahren und Neuladen, sind nicht unbedingt trivial.

OpenAMP für standardisierte Kommunikation in heterogenen Systemen

Der Wunsch kommt also ganz schnell auf, hier auf etwas existierendem, stabilem und standardisiertem aufsetzen zu können. Weil das auch Hersteller von SoCs, Betriebssystemen und Tools erkannt haben, haben sich etliche Firmen zur Multicore Association (MCA) zusammengeschlossen. Die Multicore Association erarbeitet in Arbeitsgruppen Standards und Implementierungen, die das Zusammenspiel von Multi-Core Systemen regeln und vereinfachen sollen.

Einer dieser Standards ist OpenAMP - das Open Assymetric Multiprocessing Framework. OpenAMP stellt dabei ein Open-Source Framework zur Verfügung, was die standardisierte Kommunikation einer Vielzahl von heterogenen Systemen miteinander ermöglicht. Die entsprechende Arbeitsgruppe bei der MCA kümmert sich dabei um die Standardisierung der Schnittstellen.

Man hat dabei einen pragmatischen Ansatz gewählt. Anstatt einen allgemeinen Ansatz zu wählen, der alle möglichen Szenarien abdecken soll, hat man sich auf die in der Praxis typischen Fälle konzentriert und auf bestehende Software Schnittstellen aufgesetzt.

Konkret bedeutet das Folgendes: OpenAMP unterscheidet zwischen einem Master oder Host Prozessor, dem die komplette Kontrolle unterliegt, und einem Remote Prozessor. Auf dem Master Prozessor läuft typischerweise ein Linux, auf dem Remote Prozessor ein RTOS oder ein Bare-Metal Programm. Als Interface-Komponente für das Life-Cycle Management (LCM) wird remoteproc verwendet, für die Inter-Prozessor Kommunikation (IPC) findet RPMsg Verwendung. Beide Komponenten sind Bestandteil des Linux-Kernels ab Version 3.4. remoteproc und RPMsg setzen beide auf virtIO auf, einem Layer, der virtuellen Device-Treibern die direkte Kommunikation mit dem Host-OS oder einem Hypervisor erlaubt.

Das gilt zwar für Linux auf der Host-Seite, aber nicht für ein auf Remote-Prozessor Seite verwendetes RTOS. Deswegen ist es Aufgabe von OpenAMP, hier eine Implementierung zur Verfügung zu stellen, die sich in ein RTOS einbinden lässt.

Zusätzlich zu LCM und IPC kommt bei OpenAMP noch eine dritte Komponente hinzu. Ein auf dem Remote-Prozessor laufendes Programm soll schließlich auch Ausgaben machen können, die man gerne zusammen mit den Ausgaben des Host-Prozessors in einem Terminal-Fenster sehen möchte. Außerdem wäre es vorteilhaft, wenn der Remote-Prozessor (kontrollierten) Zugang zum File-System des Hosts hätte, sei es um Konfigurationsdateien zu lesen oder autonom auf Daten zugreifen zu können. Hierfür gibt es eine Proxy-Infrastruktur, die I/O- und File-Zugriffe des Remote-Prozessors über den Host abwickelt.

OpenAMP übernimmt zwar einiges an Arbeit, ohne ein paar Vorarbeiten bei der Installation des Linux-Kernels kommt man aber nicht aus. Glücklicherweise beschränken sich diese hauptsächlich auf das Hinzukonfigurieren von remoteproc und RPMsg (falls diese nicht sowieso schon aktiv sind), und dem Hinzufügen von ein paar Einträgen im Device-Tree, die gemeinsam genutzte Speicherbereiche und Interrupts definieren und die Verbindung zu remoteproc herstellen.

Ein Beispiel zur Verwendung von OpenAMP

Anhand eines kleinen Beispiels soll gezeigt werden, wie sich OpenAMP aus Sicht des Anwenders darstellt. Das Beispiel ist ein Programm, was auf dem Remote Prozessor eine FFT berechnet und dann die berechneten Daten zurückschickt.

Über die Datei firmware im Sysfs-Filesystem wird das Programm auf den Remoteprozessor geladen:

# echo fft_server > /sys/class/remoteproc/remoteproc0/firmware

Gestartet wird es dann auf ähnliche Weise durch Schreiben des Wertes „start“ auf die Sysfs-Datei state:

# echo start > /sys/class/remoteproc/remoteproc0/state

Im User Programm gestaltet sich die Kommunikation dann recht einfach. Es wird das entsprechende RPMsg Device geöffnet und die FFT Eingangsdaten hineingeschrieben. Anschließend werden die berechneten Ausgangsdaten ausgelesen.

int fd;

int input_data[512];

int output_data[512];

fd = open("/dev/rpmsg0", O_RDWR);

write(fd, input_data, sizeof(input_data));

read(fd, output_data, sizeof(output_data));

Das Programm auf dem Remote-Prozessor gestaltet sich etwas aufwändiger.

int output_data[512];

void rpmsg_read_cb(

struct rpmsg_channel *rp_chnl,

void *data, int len,

void *priv, unsigned long src)

calculate_fft(data, output_data);

rpmsg_send(rp_chnl, output_data, sizeof(output_data));

struct hil_proc *hproc;

struct rsc_table_info rsc_info;

hproc = platform_create_proc(proc_id);

rsc_info.rsc_tab = get_resource_table((int)rsc_id,

&rsc_info.size)

remoteproc_resource_init(&rsc_info, hproc,

rpmsg_channel_created,

rpmsg_channel_deleted,

rpmsg_read_cb, &proc, 0);

Über remote_proc_resource_init wird die Callback-Funktion rpmsg_read_cb registriert, die beim Empfang von Daten angesprungen wird und dann den eigentlichen Service (hier Berechnung der FFT) übernimmt.

Abhängig von der Funktion, die das Programm auf dem Remote-Prozessor zu erfüllen hat, ist natürlich noch etwas mehr zu tun. Im User Programm kann es auch empfehlenswert sein, das Abschicken der Eingangsdaten und das Empfangen der berechneten Daten durch Threads zu entkoppeln.

Was bekommt man nun als Anwender?

Die Sourcen für OpenAMP und Beispielprogramme werden über GitHub zur Verfügung gestellt. Von Xilinx gibt es inzwischen eine Application-Note, die den Umgang mit OpenAMP beschreibt. Außerdem stellt Xilinx in seinem Software Development Kit bereits Templates für OpenAMP Projekte zur Verfügung. Von NXP gibt es eine Ressourcen sparende RPMsg Implementierung (RPMsg-Lite), die ebenfalls über GitHub zur Verfügung gestellt wird. Von Mentor Graphics gibt es inzwischen mit dem Mentor Embedded Multicore Framework die erste kommerzielle Implementation des OpenAMP Standards.

Warum nicht OpenCL?

Dort, wo man mit richtig vielen Cores (> 1000) zu tun hat, sprich, im Bereich der GPUs, existieren bereits Frameworks zur Verwaltung von Multicore-Architekturen. Diese sind entweder proprietär (wie CUDA von NVIDIA) oder offen wie OpenCL der Khronos Group. Man kann sich jetzt natürlich die Frage stellen, ob sich ein Framework wie OpenCL nicht auch für die oben beschriebenen AMP-Szenarien verwenden ließe und warum man mit OpenAMP ein neues Framework geschaffen hat.

OpenCL ist dafür konzipiert worden, mit einer generischen Anzahl von Cores umgehen zu können. Mit OpenCL entwickelte Programme sollen auf unterschiedlichen Systemen laufen können, die unterschiedlich viele Prozessoren zur Verfügung stellen. Abzufragen, wie viele Prozessoren das System hat, um daraufhin einen Algorithmus generisch zu verteilen, ist eine der ersten Aufgaben einer OpenCL Initialisierung. Das führt zu einem mächtigen aber auch komplexen API. OpenAMP adressiert hingegen Systeme, die typischerweise einen oder vielleicht zwei Remote-Prozessoren zur Verfügung stellen. Hier ist die Aufgabe des Remote-Prozessors klar umrissen und das Hardware-Setup von vornherein bekannt. Dadurch kann aber auch der Overhead wesentlich geringer ausfallen als in einer Umgebung, bei der beliebig viele Cores verwaltet werden müssen. OpenAMP agiert dadurch wesentlich schlanker, was nicht zuletzt auch den Lernaufwand gegenüber OpenCL drastisch reduziert.

Wie geht es weiter?

Momentan hält OpenAMP bei den ersten Entwicklern Einzug. Die ersten Fragen nach Erweiterungen kommen auch bereits (“Wir hätten gerne noch einen C++ Layer”). Manch einer, der bereits eine Lösung hat, wird sich auch mit der Adaption Zeit lassen. Mit OpenAMP steht jetzt aber erstmals ein Standard zur Verfügung, auf dem man bei der Implementierung von AMP-Systemen aufsetzen kann, ohne selber wieder das Rad neu erfinden zu müssen.

Software in Echtzeitsystemen korrekt und fehlerfrei verteilen

Software in Echtzeitsystemen korrekt und fehlerfrei verteilen

06.02.18 - Fehler, die durch nebenläufige Software-Ausführung entstehen, verursachen meist großen System-Overhead und schränken die Verteilbarkeit bzw. die effektive Nutzung der parallelen Rechenleistung massiv ein. Dieser Beitrag betrachtet typische Fehlerfälle nebenläufiger Echtzeit-Software, bietet konstruktive Mechanismen zu deren Vermeidung und erläutert, wie mit Tools eine korrekte Softwareverteilung erreicht werden kann. lesen

EMB² = Parallel + Heterogen

EMB² = Parallel + Heterogen

12.06.17 - Die Embedded Multicore Building Blocks (EMB²) sind eine als Open-Source-Software zur Verfügung stehende Bibliothek für die parallele Programmierung von eingebetteten Systemen. EMB² basiert auf MTAPI (Multicore Task Management API), einem Standard für das Task-Management in mit C/C++ implementierten Applikationen. Im Folgenden geben wir einen Überblick über EMB² und zeigen auf, wie sich Parallelität über die Grenzen von klassischen Multicore-Prozessoren hinaus mittels MTAPI nutzen lässt. lesen

Quo vadis, Multicore?

Quo vadis, Multicore?

12.06.17 - Welche Lehren sind aus den ersten Einsätzen von Multicore-Systemen zu ziehen, und welche Richtung wird in naher Zukunft eingeschlagen, um den Hunger nach mehr Rechenleistung bei gleichzeitiger Energie-Diät zu stillen? lesen

* * Frank Storm ist als Applikationsingenieur und Embedded Specialist bei der Avnet Silica im Bereich Xilinx FPGAs und SoCs tätig.

Kommentar zu diesem Artikel abgeben

Schreiben Sie uns hier Ihre Meinung ...
(nicht registrierter User)

Zur Wahrung unserer Interessen speichern wir zusätzlich zu den o.g. Informationen die IP-Adresse. Dies dient ausschließlich dem Zweck, dass Sie als Urheber des Kommentars identifiziert werden können. Rechtliche Grundlage ist die Wahrung berechtigter Interessen gem. Art 6 Abs 1 lit. f) DSGVO.
Kommentar abschicken
copyright

Dieser Beitrag ist urheberrechtlich geschützt. Sie wollen ihn für Ihre Zwecke verwenden? Infos finden Sie unter www.mycontentfactory.de (ID: 45379840 / Multicore)