Sie sind hier: HomeRubrikenEmbeddedSoftware

Just in Time: Echtzeit für Middleware

Um eine rechtzeitige Programmausführung zu gewährleisten, werden Embedded-Software-Anwendungen oberhalb eines Echtzeit-Betriebssystems angesiedelt. Darüber hinaus verlangen Anwendungen auch Support für Middleware, z.B. Dateisysteme, Grafikbibliotheken oder Protokoll-Stacks. Der Beitrag zeigt, wie die Echtzeit-Anforderungen der Anwendung die Integration der Middleware in das System beeinflusst.

Ovidiu lordachi, Fotolia Bildquelle: © Ovidiu lordachi, Fotolia

Manchmal ist es erforderlich, dass die Middleware die Daten sofort verarbeitet, um somit die Echtzeit-Anforderungen zu erfüllen. In anderen Fällen ist die Middleware nicht Teil des Echtzeit-Pfades und muss so wenig wie möglich sein. Als Beispiel werden die Vor- und Nachteile verschiedener Implementierungen eines Dateisystems diskutiert. In diesem Beitrag wird der Begriff »Middleware« für alles verwendet, das die Anwendung mit dem Embedded-Echtzeit-Betriebssystem und seinen Treibern verbindet. Dies kann z.B. ein Dateisystem, ein TCP/IP-Stack, ein USB-Stack oder eine Grafikbibliothek sein.

Nehmen wir an, dass jeder mit dem Begriff »Echtzeit« vertraut ist. Trotzdem sollte in diesem Kontext noch einmal darüber nachgedacht werden. Ein Echtzeit-System ist imstande, spezifische Aufgaben stets rechtzeitig durchzuführen. Das Verhalten des Systems muss daher deterministisch sein. Dies heißt aber auch, dass »Echtzeit«-Systeme nicht unbedingt »schnell« sein müssen. Falls die Deutsche Bahn garantieren kann, dass ein ICE von Hamburg nach Köln nie länger als acht Stunden unterwegs ist, wäre dies ein Echtzeit-System. In Wirklichkeit ist es kein Echtzeit-System – nicht weil acht Stunden nicht »schnell« sind, sondern weil es Tage und Situationen gibt, in denen der Zug länger unterwegs ist.

Denkt man über Komponenten eines Echtzeit-Systems nach, müssen wir uns stets fragen, ob und wie das Verhalten dieser Komponenten die Ausführungszeit und damit das Echtzeit-Verhalten beeinflusst. Ist die Komponente Teil von dem, was rechtzeitig bereitstehen muss, befindet sie sich im »Echtzeit-Pfad«. Aber selbst wenn sich die Komponente nicht im Echtzeit-Pfad befindet, kann ihr Verhalten die Ausführungszeit beeinflussen.

Echtzeit-Betriebssysteme

Ein Echtzeit-Betriebssystem (RTOS) bietet alle notwendigen Mechanismen, um die Rechtzeitigkeit des Programmflusses zu garantieren. Dazu zählt ein prioritätsbasierter, präemptiver Scheduler für nebenläufige Tasks. Interrupt-Verzögerungen müssen deterministisch sein oder zumindest eine definierte Obergrenze aufweisen, um berechenbar zu werden und eine Antwort auf Interrupts in einem bestimmten Zeitrahmen zu ermöglichen. Spezielle Semaphore (»Highest Locker«) ermöglicht die Berechnung der Ausführungszeit des Programmflusses (»Rate Monotonic Analysis«). Partitionsplanung kann den Scheduler um die Funktion einer strengen Teilung und Trennung der CPU-Zeit unter Programmeinheiten (Partitionen) erweitern. Innerhalb einer Partition werden die Tasks auf Basis des zugrundeliegenden prioritätsbasierten Schedulers ausgeführt.

Treiber und Hardware

Die Interaktion mit der Peripherie wird über Gerätetreiber geregelt, die wesentliche Bestandteile eines Embedded-Systems sind. Sensordaten müssen regelmäßig verarbeitet werden, und daher müssen deren Interrupt-Handling und Taskaktivierung deterministisch erfolgen. Zeigt der Beschleunigungsmesser in einem Fahrzeug einen Aufprall/Unfall an und andere Parameter bestätigen dies, wird der Befehl ausgegeben, den Airbag innerhalb von Millisekunden zu aktivieren. Dabei muss sichergestellt sein, dass die Interrupt-Handler für die entsprechenden Sensoren und Algorithmen innerhalb bestimmter Zeitgrenzen ausgeführt werden. Das RTOS muss dies garantieren und darf diese Timing-Anforderungen weder explizit noch implizit beeinträchtigen.

Bei den Möglichkeiten von Embedded-Software wird gerne vernachlässigt, dass die Hardware selbst auch ein entscheidender Faktor ist, der das Echtzeit-Verhalten eines Echtzeit-Systems beeinflusst. Der Zugriff auf Hardware nimmt Zeit in Anspruch, unabhängig davon, ob es sich um Memory-Mapped- oder Bus-Zugriff (I²C, SPI etc.) handelt. Außerdem muss bei diesem Zugriff überprüft werden, wie deterministisch die Hardware selbst ist. Es gibt zum Beispiel MMC/SD-Card-Controller, deren Reaktionszeit im äußersten Fall 1 s betragen kann. Es ist unmöglich, ein Echtzeit-System auf so einem MMC/SD-Card-Controller zu definieren, das einen Zugriff auf das Dateisystem in weniger als 1 s garantiert – unabhängig davon, wie gut die Software und wie gering die Interrupt-Latenzzeit ist.

Middleware

Wie bereits erwähnt, müssen zwei Fälle betrachtet werden: Die Middleware befindet sich entweder im Echtzeit-Pfad oder nicht. Daher muss geprüft werden, ob die Middleware ihre Aufgabe rechtzeitig durchführen kann oder nicht. Befindet sie sich im Echtzeit-Pfad, muss das Verhalten der Middleware deterministisch sein. Dies hat Einfluss darauf, wie viele Ressourcen die Middleware unterstützen kann, wie hoch die Leistungsfähigkeit ist und wie der gleichzeitige Zugriff realisiert werden kann.

Betrachtet man z.B. die Datenübertragung über Ethernet, zeigt sich, dass Standard-Ethernet nicht imstande ist, Daten deterministisch zu übertragen. Deshalb haben sich verschiedene Standards für Echtzeit-Ethernet herausgebildet, die eine deterministische Datenübertragung ermöglichen, z.B. Ethernet/IP, Ethercat, TTEthernet, Profibus etc. Hier ist die effektive Übertragungsbandbreite wesentlich geringer als bei Standard-Ethernet. Der Grund: Die Übertragungsdauer wird statisch unter allen Beteiligten aufgeteilt oder ein Bus-Master verteilt die Zeit entsprechend bestimmter Regeln.

Ein weiterer Aspekt ist die Kommunikationsrichtung. Liest das System die Information über Middleware aus, kann es ein einziger Wert sein, der nach einem Einzelereignis rechtzeitig gelesen werden muss. Dies wäre zum Beipiel ein Sensor, der einen Zustand erkennt, auf den reagiert werden muss, so wie beim Auslösen des Airbags. Es kann aber auch ein Datenstrom sein, der ohne Unterbrechung oder Datenverlust gelesen werden muss, z.B. ein Video-Stream, der von einem Dateisystem oder einem Kommunikationsport gelesen wird.

Befindet sich die Middleware nicht im Echtzeit-Pfad, sollte sie sich so verhalten, dass sie das Echtzeit-Verhalten der anderen Komponenten im System nicht beeinflusst. Dies wird durch Zwischenspeichern der Information (Cache) und die Übertragung der Arbeitslast auf bestimmte Tasks erreicht. Diese Tasks müssen eine geringere Scheduling-Priorität aufweisen als jene im Echtzeit-Pfad. Sie sollen nur die »übrig gebliebene« Zeit nutzen.

Dieses Design findet sich in vielen echtzeitfähigen Middleware-Implementierungen, die flexible Funktionen bieten. Sie werden echtzeitfähig genannt, da sie die Echtzeit-Fähigkeit des gesamten Systems wahren. Sie nutzen Cache-Speicher und schalten keine Interrupts ab oder nutzen DMA für den Datentransfer, um die CPU nicht mit dem Transfer zu belasten. Dies mag auf den ersten Blick seltsam klingen. Wenn wir etwas »echtzeitfähig« nennen, erwarten wir, dass es sich deterministisch verhält und Garantien bietet. Sieht man genauer hin, ist dies nicht möglich – und zwar aus folgenden Gründen: Wie erwähnt, begrenzt die Hardware den Handlungsspielraum der Middleware, wenn es um die Rechtzeitigkeit der Ausführung geht. Und selbst wenn die Hardware das erforderliche Echtzeit-Verhalten unterstützt, muss die Funktion der Middleware erheblich eingeschränkt werden, damit die Algorithmen deterministisch werden.

Beispiel: Dateisystem

Betrachten wir zuerst ein generisches und flexibles Dateisystem, das verschiedene Speichermedien unterstützt, z.B. Festplatte, Flash (NAND, NOR) SD-Card, CD-ROM etc. Darüber werden andere Dateisystemformate unterstützt, z.B. FAT, FFS, ISO9660 etc. Selbst Funktionen wie Wear-Leveling für Flash-Speicher oder Journaling können mit integriert sein. Dieses Dateisystem erlaubt asynchronen und gleichzeitigen Zugriff von verschiedenen Clients, führt eine Zwischenspeicherung für das Lesen und Schreiben durch und bietet daher fast alles, was man von einem Da¬teisystem erwarten kann. Diese Art flexibler Dateisysteme sind meist nicht deterministisch, aber sie erlauben der Anwendung, Echtzeitanforderungen zu erfüllen.

Aufbau eines generischen Dateisystems Bildquelle: © Green Hills

Aufbau eines generischen Dateisystems

Beim Schreiben einer Datei, die nicht zu einer bestimmten Zeit auf dem Medium ankommen muss, findet der Schreibvorgang asynchron statt. Die Daten werden dabei über den Dateisystem-Server zuerst auf den Dateisystem-Cache geschrieben. Sobald die CPU zur Verfügung steht, wird die entsprechende I/O-Task die Daten auf das Medium schreiben (Bild).

Müssen die Daten jedoch innerhalb einer vorgegebenen Zeit zuerst auf das Medium geschrieben werden, wird dies zu einer Herausforderung. Dann ist es besser, die Daten direkt im Kontext der schreibenden Task auf den Datenträger zu bringen. Dies priorisiert gleichzeitige Zugriffe, abhängig von der Priorität der Task. Es kann auch erforderlich sein, dass gleichzeitige Zugriffe verhindert werden, da Parallelität zu Ressourcenkonflikten und Prioritätsumkehr führen kann. Schreibpuffer sind in dem Fall ebenfalls unerwünscht, da synchrones Schreiben deterministischer ist – selbst wenn es zu einer geringeren Gesamtleistungsfähigkeit führt. Hinzu kommt, dass die Zahl unterstützter Ressourcen des Dateisystems verringert werden muss. So kann nur eine begrenzte Zahl an Dateien pro Verzeichnis, Blöcken pro Datei, an Verzeichnissen, verschachtelten Verzeichnissen unterstützt werden. Dies schränkt die Flexibilität des Dateisystems ein, macht das Verhalten aber deterministisch.

Werden Dateien von einem Dateisystem gelesen, befindet sich das Dateisystem im Echtzeit-Pfad, sobald die lesende Task die Informationen nutzen muss, die vom Dateisystem gelesen werden, um so ihre Aufgabe in der vorgegebenen Zeit ausführen zu können. Hier gelten die gleichen Regeln bezüglich der Ressourcen-Beschränkung und Nebenläufigkeit wie im vorherigen Fall. In einigen Fällen wollen wir die zu lesenden Daten zwischenspeichern, z.B. wenn wir einen Video-Stream aus einem Dateisystem lesen wollen und sichergestellt sein muss, dass stets der nächste Zeitrahmen verarbeitet wird. Besteht also eine Obergrenze für den Zeitaufwand beim Lesen des nächsten Frame vom zugrundeliegenden Medium, muss sichergestellt sein, dass der Lese-Zwischenspeicher mindestens so viele Frames aufnehmen kann, um den Jitter zu kompensieren, der durch die Dateisystem-Medien und -Treiber eingeführt wird.

Middleware und Echtzeit-Verhalten

Die Middleware in Echtzeit-Systemen ist meist nicht darauf ausgelegt, Transaktionen rechtzeitig auszuführen, d.h., sie ist nicht echtzeitfähig. Der Grund ist, dass Flexibilität für die Middleware wichtiger ist als Echtzeit-Verhalten. Die Zahl unterstützter Ressourcen ist nicht begrenzt und Parallelität wird bereitgestellt. Dennoch findet sich eine Vielzahl von Middleware in Echtzeit-Systemen, da sie die Echtzeit-Funktion eines Systems nicht beeinträchtigt. Soll sich Middleware im Echtzeit-Pfad befinden, kommt es darauf an, die Funktionen der zugrundeliegenden Hardware zu berücksichtigen.

Über den Autor:

Andre Schmitz arbeitet als Field Applications Engineer bei Green Hills Software.