Ein Angebot von

Software in Echtzeitsystemen korrekt und fehlerfrei verteilen

| Autor / Redakteur: Dr. Jochen Härdtlein * / Sebastian Gerstl

Bild 1: Bosch MDG1 Motorsteuergerät (Multi-Core).
Bild 1: Bosch MDG1 Motorsteuergerät (Multi-Core). (Bild: Robert Bosch GmbH)

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.

Die nötige Leistungssteigerung für die eingebetteten Steuergeräte in Fahrzeugen kann nicht mehr wie in den vergangenen Jahrzehnten allein über eine steigende Taktfrequenz in Single-Core Rechnern bereitgestellt werden. Neben der Entwicklung hin zu Mikrocontrollern mit Multi- bzw. Many-Core Architekturen kommen auch Multi-µC Lösungen oder Domänenrechner mit Mikroprozessoren zum Einsatz.

Diese Rechnerarchitekturen bestehen aus einer Vielzahl von teils heterogenen Rechnerkernen, d.h. unterschiedlicher Rechenleistung bzw. Berechnungsfähigkeiten. Zusätzlich ist die zugehörige Speicherarchitektur vermehrt durch NUMA (Non-uniform Memory Access) gekennzeichnet, d.h. Zugriffsgeschwindigkeiten und Bandbreiten zwischen Rechnern und Speichern variieren. Die Anforderungen an die SW Architektur für aktuelle und zukünftige eingebettete Systeme wird massiv von der steigenden Parallelität und der zunehmenden Heterogenität der parallelen Systeme bestimmt.

Nebenläufigkeits- und Echtzeitfehler

Eingebettete Systeme – wie etwa Motorsteuerungssysteme für Verbrennungsmotoren – sind Systeme mit einer Mischung aus Event- und zeitgesteuerten Berechnungen, die ein hohes Maß an Echtzeitanforderungen haben, um die Korrektheit der implementierten Regelungen sicherzustellen. Darüber hinaus werden die Lösungen aufgrund der Komplexität verteilt entwickelt, an unterschiedlichen Standorten sowie in verschiedenen Unternehmen (OEM, TIER1, TIER2).

In diesem Setup ist es notwendig zu verstehen, dass die Absicherung der Systeme mit der steigenden heterogenen Parallelität zunehmen aufwändig und komplex wird. Im ersten Schritt möchten wir daher die möglichen Fehlerfälle der Software aus Nebenläufigkeits- und Echtzeitsicht verstehen, um im Nachgang Lösungen für deren Vermeidung ableiten zu können ([1], [5]).

Die eingebetteten Softwaresysteme bestehen aus mehreren hundert Funktionen, die mit spezifischer Frequenz aufgerufen werden. Das Betriebssystem hat die Aufgabe, die Berechnungen entsprechend Ihrer Aktivierungsrate zu aktivieren und ggf. laufende Berechnungen mit niederer Priorität zu unterbrechen (rate-monotonic scheduling). Jede korrekte Bearbeitung einer Funktion basiert auf Abhängigkeiten zu Funktionen – genannt Ordnung – welche vorher bzw. nachher gerechnet werden (z.B. muss ein Sensorwert aufbereitet werden, bevor er weiterverarbeitet wird). Bei Berechnungen auf einem Rechnerkern ist dies für Funktionen mit gleicher Aktivierungsrate einfach sicherzustellen (durch eine fixe Reihenfolge innerhalb der Task).

Jedoch bereits die Reihenfolge zwischen unterschiedlichen Zeitscheiben ist nur teilweise mittels Prioritäten regelbar oder kostspielig mittels Synchronisationspunkten realisierbar. Sind die Berechnungen über mehrere Rechenkerne verteilt, lässt sich die Reihenfolge nur noch über Synchronisationspunkte (etwa auch ein globales Scheduling) realisieren, was aber den Nutzen der parallelen Rechenleistung deutlich reduziert. Zusätzlich zeigt sich, dass die impliziten Annahmen der Legacy-Software in SingleCore-Systemen häufig nicht lückenlos transparent sind. Dies birgt die Gefahr, dass bei einer einfachen Verteilung der Software die notwendigen Berechnungsreihenfolgen evtl. (sporadisch) nicht eingehalten werden.

Die wohl bekanntesten Fehlerquellen bei Synchronisationen sind sicherlich Deadlocks. Verklemmungen können auftreten, wenn etwa Locks sukzessive gesetzt werden und die Reihenfolge nicht systemweit einheitlich ist. Mögliche Lösungen sind etwa Nutzung einer Ressource für alle zu schützenden Anteile oder die Sicherstellung der konformen systemweiten Locking-Reihenfolge. Erstere Lösung kann zu großen System-Overhead führen, da Beeinflussungen von Berechnungen entstehen, die inhaltlich unabhängig sind. Das vollständige Betrachten der systemweiten Locking-Reihenfolge ist im Allgemeinen extrem schwierig sicherstellen.

Dateninkonsistenzen sind die meistgenannten Fehlerquellen in nebenläufigen Systemen. Diese können entstehen, wenn gleichzeitig auf Daten gearbeitet bzw. Funktionen mehrfach aufgerufen werden. Zur Vermeidung dieser Überlappungsfehler werden häufig auch Synchronisationen eingesetzt, die wiederum Overhead erzeugen. Zusätzlich sind Zustandswechsel in Software zu beachten, da besonders Realisierungen aus der Single-Core Umgebung häufig schwer beherrschbare Zeiteffekte in parallelen Systemen.

Die letzte Kategorie behandelt die Verletzung von Echtzeitanforderungen, etwa dem Verpassen von Deadlines, was dazu führt, dass Ergebnisse anderen Funktionen zu spät bereitgestellt werden. Je nach Schwere der Auswirkung kann dies entweder irrelevant sein oder auch zur völligen Fehlfunktion des eingebetteten Systems führen.

Die aufgeführten Fehler werden typischerweise mittels Synchronisationsmechanismen wie Spinlocks vermieden. Bei steigender Auslastung des Systems steigt auch der Overhead durch das Sperren bzw. Abfragen der Locks signifikant.

Timed Communication

Eine strukturelle Lösung, den Aufwand zur Sicherstellung einer konsistenten Kommunikation in parallelen Echtzeitsysteme wurde von Henzinger et al. mit der Logical Execution Time eingeführt und in deren Giotto Framework umgesetzt ([2], [3], [4]). Mittels der Logical Execution Time werden die Kommunikationen von den Berechnungen entkoppelt und systemweit koordiniert. Dadurch reduzieren sich die individuellen Synchronisationen auf ein Minimum. Diese Kommunikationsart wird Timed Communication genannt.

Im Vergleich zur traditionellen Implementierungen, in denen Zeitscheiben die Daten direkt mit dem globalen Speicher austauschen, findet bei Timed Communication der Datenaustausch direkt zwischen zwei Zeitscheiben statt. Zusätzlich wird nur dann kommuniziert, wenn auch neue Daten verfügbar sind. Durch die zeitliche Entkopplung der Kommunikation von der Berechnung wird für zeitgesteuerte Tasks sichergestellt, dass diese immer Daten mit gleichem Alter als Input erhalten, wenn die Berechnungen inklusive der Kommunikation innerhalb der Periode beendet werden.

Mittels Timed Communication können Ordnungsfehler zwischen Zeitscheiben vermieden und Synchronisations- bzw. Überlappungsfehler (für Daten) verhindert werden. Zusätzlich strukturiert Timed Communication die deterministische, lock-freie Kommunikation und erlaubt das task-spezifische Erkennen von Echtzeitfehlern.

Darüber hinaus ist es möglich auf der Basis einer deterministischen Kommunikation mit den zeitlichen Anforderungen der Kommunikation zwischen Funktion möglich eine toolgestützte Verteilung zu erreichen, welche die zugrundeliegenden Zeitanforderungen per Konstruktion sicherstellt bzw. überprüft. Dafür sind für alle Funktionen die zeitkritischen Schnittstellen und deren Zeitanforderungen zu erfassen. Zusätzlich ist das Ausweisen der zeitkritischen Wirkketten mit deren Deadlines zu erfassen. Ebenso wird eine abstrahierte Beschreibung der zugrundeliegenden Hardware benötigt. All diese Daten sind jedoch typischerweise nur mittels Expertenwissen zu ermitteln. Diese Daten können bereits heute in dem öffentlich verfügbaren Amalthea-Format verwaltet werden [6].

Aus dem aktuell genutzten präemptiven rate-monotonic Scheduling in automotive Single-Core-Systemen resultiert bereits ein nebenläufiges Echtzeitsystem, in dem die präsentierten Fehlerzustände bereits auftreten können. Die Wahrscheinlichkeit der Fehler erhöht sich jedoch signifikant durch die Verteilung der Software auf parallele Recheneinheiten. Die Vermeidung der Fehler durch zusätzliche Synchronisationen führt zu zusätzlichem Overhead, der den Nutzen der zusätzlichen parallelen Rechenleistung zum Teil zunichtemacht und darüber hinaus schwierig abzusichern ist. Zusätzlich ist die Freiheit von Echtzeitfehlern weiterhin schwierig zu validieren. Das Timed Communiction Framework kann nun als Grundlage genutzt werden, die Zeitanforderungen der Funktionen und der Wirkketten systemweit beim Systemsetup zu sicherzustellen und dadurch den massiv steigenden und komplexeren Absicherungsaufwand in parallelen Systemen massiv zu reduzieren.

Der Autor

Der Autor: Dr. Jochen Härdtlein.
Der Autor: Dr. Jochen Härdtlein. (Bild: Robert Bosch GmbH)

* Dr. Jochen Härdtlein ist zuständiger Manager für Software Architektur und Ressourcen Management bei Diesel Gasoline Systems, Robert Bosch GmbH. In seiner Position als Software Lead Architect verantwortet er insbesondere die Plattform-Aktivitäten zur Migration der embedded Software nach ManyCore und µProcessor Architekturen.

Queuing – Warteschlangentheorie für Embedded-Software

Queuing – Warteschlangentheorie für Embedded-Software

10.10.17 - Entwickler von Embedded-Systemen müssen beim Systementwurf oft die maximale Anzahl an Messages ermitteln, die in einer Message Queue auflaufen können. Viele RTOS benötigen diese Information, um eine Queue zu erzeugen. Besonders wenn es um „harte“ Echtzeitsysteme geht, gilt es, sich auch mit Queuing-Verzögerungen auseinanderzusetzen, lesen

Echtzeit- und Deadline-Scheduling von Linux

Task-Management

Echtzeit- und Deadline-Scheduling von Linux

29.04.16 - Seit dem Linux-Kernel 3.14 steht das Deadline-Scheduling zur Verfügung. Dadurch besteht die Aussicht, dass die Parametrisierung der Tasks direkt als zeitliche Vorgabe und nicht nur als abgeleitete Priorität erfolgt. lesen

Ohne Locks für Multicore-Systeme programmieren

Multicore-Programmierung

Ohne Locks für Multicore-Systeme programmieren

15.09.11 - Viele Multicore-SOCs und auch einige Betriebssysteme bieten Möglichkeiten zur lockfreien Programmierung. Die Softwareentwicklung wird dadurch jedoch umständlicher als mit herkömmlichen Methoden. lesen

Literaturhinweise:

[1] Clarke S.J. and McDermid JA. Software fault trees and weakest preconditions: a comparison and analysis. Software Engineering Journal. 8(4):225-236, 1993.

[2] Henzinger TA, Horowitz B, Kirsch CM (2001a) Embedded control systems development with Giotto. In: Proceedings of the ACM SIGPLAN workshop on languages, compilers, and tools for embedded systems (LCTES). ACM

[3] Henzinger TA, Horowitz B, Kirsch CM (2001b) Giotto: A time-triggered language for embedded programming. In: Proceedings of the international workshop on embedded software (EMSOFT), vol 2211 of LNCS, Springer, pp 166–184

[4] Henzinger TA, Horowitz B, Kirsch CM (2003a) Giotto: A time-triggered language for embedded programming. Proc IEEE 91(1):84–99

[5] Thane, Henrik. Monitoring, testing and debugging of distributed real-time systems. Diss. Ph. D. Thesis, MRTC Report 00/15, 2000.

[6] www.amalthea-project.org, An Open Platform Project for Embedded Multicore Systems, Öffentlich gefördertes ITEA Projekt

copyright

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