Safety und Zuverlässigkeit erhöhen

Acht Schritte zu besserer ADAS-Software

23. April 2018, 14:25 Uhr | Von Dr. Alexander Hertz und Mark Forbes

Fortsetzung des Artikels von Teil 1

4. Schritt: Benchmarking

Nachdem der Baustein korrekt konfiguriert ist und läuft, muss als nächstes die Werkzeugkette gefunden werden, mit der sich ein kompakter oder schneller Code für die entsprechende Anwendung erzeugen lässt. Hierfür greifen Anwender in der Regel auf bestehende Benchmarks zurück oder nutzen eine existierende Anwendung als Referenz, die der von ihnen zu entwickelnden Applikation ähnelt. Daraufhin vergleichen sie die Laufzeiten oder disassemblieren die Komponenten, um die Gesamtgeschwindigkeit ihrer Anwendung zu ermitteln. Hiermit wollen sie herausfinden, welches Tool den kompakteren oder effizienteren Code erzeugt und ob es im Code irgendwelche Probleme gibt, die auf den Compiler zurückzuführen sind.

Es folgt eine Aufzählung gängiger Fallstricke, auf die man beim Benchmarking von Compiler-Tool-Ketten achten sollte, um aussagefähige Ergebnisse zu erhalten:

  • Standard-Benchmarks wie EEMBC werden von allen Compiler-Anbietern intensiv optimiert und sind deshalb nicht unbedingt ein gutes Indiz dafür, welche Performance Ihre Anwendung erreichen wird. Es sollte ein Benchmark-Test oder eine Applika­tion mit Parallelen zu der relevanten Anwendung gewählt werden.
  • Erheblichen Einfluss auf die Leistungsfähigkeit hat das Speicher-Layout. Ein und derselbe Code kann mit einem geringfügig anderen Layout an Variablen oder Code deutlich langsamer laufen.
  • Nach Geschwindigkeit oder Code-Umfang optimieren? Es muss in den Tools die richtigen Schalter dafür geben.
  • Die Konfiguration der Takte für den Baustein sowie der Startup-Code wirken sich generell stark auf die Performance aus. Dieser Code gehört oft zum Lieferumfang der Werkzeugkette und konfiguriert die Takte möglicherweise anders. Im Abschnitt ‚Feinabstimmung Ihrer Applikation‘ ist zu erfahren, wie sich die Takteinstellungen auch ohne Oszilloskop auf Richtigkeit prüfen lassen.
  • Den Kernel der Applikation messen und dabei anbieterspezifische Debugging-Funktionen wie printf und malloc ausschließen.
  • Anstelle der Zeit lieber den Takt oder die Zähler-Ticks vom selben Zähler messen. Die Umrechnung von Ticks in Zeit hängt von der Taktfrequenz ab und wird unter Umständen nicht korrekt ausgeführt.
  • Die Ergebnisse sollten einer Korrektheitsprüfung unterzogen werden. Zum Beispiel sollte eine Messung, die bei einem mit 300 MHz getakteten Core 10 s auf der Stoppuhr gedauert hat, rund 10 x 300 x 106 Ticks produzieren, wenn der Zähler mit der vollen Geschwindigkeit des Kerns läuft. Es ist zu beachten, dass einige Zähler nur mit einem ganzzahligen Bruchteil der Core-Geschwindigkeit laufen.
  • Einige relevante Statistiken ausrechnen: Cache-Speicher und andere Hardware-Features können eine gewisse Anlaufzeit brauchen, wodurch der erste Durchlauf eines Code-Abschnitts deutlich länger dauert als spätere Durchläufe.
  • Der Compiler ist nicht der einzige Faktor, der sich auf die Geschwindigkeit auswirkt. Man sollte darauf achten, dass die optimierten Bibliotheken für Aurix und Aurix 2G sowie die zugehörigen Hardware-Beschleuniger für den Rechenbedarf auch genutzt werden. Es kann sich dabei um Verschlüsselung, Hypervisor-Technologie und lineare Algebra für Radar- und ADAS-Anwendungen handeln.

Es ist einfach, eine Reihe von Takt-Ticks bei einer Applikation zu messen und diese mit anderen Takt-Ticks zu vergleichen. Noch einfacher ist es, das so zu tun, dass die Ergebnisse keinerlei Aussagekraft haben. Wenn die obigen Ratschläge beachtet werden, ist es möglich, in kurzer Zeit Resultate zu erhalten, die dazu beitragen, fundierte Entscheidungen in Sachen Performance zu treffen, beispielsweise in Hinsicht darauf, welche Tools richtig sind und welche Software-Architektur am besten funktioniert.

Anbieter zum Thema

zu Matchmaker+

5. Schritt: Die Software-Plattform

Die Software-Plattform besteht aus folgenden Elementen:

  • Einem vorgegebenen Bestand an Werkzeugen (spezielle Compiler-Version, Debugger, IDE usw.)
  • Software-Komponenten, darunter das Betriebssystem, BSW-Module (Basic Software), CDDs (Complex Device Drivers) und der Microcontroller Abstraction Layer (MCAL).
  • Die Plattform ist für die Verwendung mit einem bestimmten Zielbaustein optimiert, damit die Anpassung und Optimierung von BSW, CDD oder ähnlichem nicht bei jedem neuen Projekt, das auf demselben Zielbaustein basiert, von vorn durchgeführt werden muss.

Performance-Bibliotheken

Bevor mit der Entwicklung begonnen wird, muss überlegt werden, welche Funktionen selbst entwickelt werden sollen und welche sich effektiver von Drittanbietern beziehen lassen.

Einige Funktionen sind in Hinsicht auf Leistungsfähigkeit, die numerische Stabilität oder den Security-Aspekt für die Anwendung so kritisch, dass man auf gründlich geprüfte, von Experten optimierte und im praktischen Einsatz erprobte Bibliotheken zurückzugreifen sollte. Ansonsten würde man Mann­­-jahre im zweistelligen Bereich darin investieren, um eine eigene Version
von Grund auf selbst zu entwickeln.

Es kommen einige Performance-Bibliotheken in Frage:

  • Komplette BLAS-, LAPACK- und FFT-Lösungen (Hard- und Software, Single-Precision) für Anwendungen wie etwa Radar, Sensorfusion, Matlab und Simulink-Code usw.
  • Bibliotheken mit Verschlüsselungsalgorithmen (HSM oder Software-Rückfallebene mit vollständiger AUTOSAR-Integration).
  • Hard-Real-Time-Hypervisor-Technologie mit extrem wenig Overhead (z. B. ein Safety-OS-Kontextwechsel).

Man kann gleich mehrfach profitieren, wenn APIs aus diesen Standardbibliotheken als Bausteine für die Anwendung zum Einsatz kommen. Zum einen wird das Portieren der Applikation einfach, denn ein und dieselbe Anwendung lässt sich auf dem Desktop und für verschiedene Zielsysteme kompilieren. Die zugrundeliegenden Bibliotheken müssen nicht selbst portiert und optimiert werden. Darüber hinaus gibt es Informa­tionen darüber, wie sich diese Standardbibliotheken effizient nutzen lassen.

6. Schritt: Feinabstimmung der Applikation

Wenn die Applikation verifiziert und gründlich geprüft ist, das Debugging abgeschlossen ist und sich korrekt verhält, können immer noch Performance- und Timing-Probleme auftauchen, wenn die Anwendung in die Zielumgebung integriert wird. Viele Timing-Probleme lassen sich einfach lösen, indem man die Leistungsfähigkeit der Runnables verbessert, die Deadlines verpasst haben. Indem darüber hinaus die Core-Auslastung der Applikationen reduziert wird, lässt sich möglicherweise auf einen kostengünstigeren Baustein mit weniger Cores umsteigen. Die Feinabstimmung der Performance ist eine einfache Möglichkeit, diese Probleme anzugehen.

Zu diesem Performance-Tuning gehört das Optimieren der Applikation für einen bestimmten Zielbaustein. Unter folgenden Umständen ist diese Feinabstimmung möglich:

  • Es kommen selbstentwickelte Bib­liotheken zum Einsatz, die häufig aufgerufen werden und deshalb tiefgreifende Auswirkungen auf die Leistungsfähigkeit der gesamten Applikation haben.
  • Es werden maschinennahe Treiber und BSW- oder OS-Komponenten entwickelt oder adaptiert.
  • Die Grenze der vorgesehenen Core-Auslastung wurde fast erreicht oder ist bereits überschritten.
  • Es gibt ein Timing-Problem im Schedule, das sich durch Beschleunigung bestimmter Tasks lösen ließe, aber der Schedule soll nicht abgeändert werden.
  • Eine kleinere ECU soll eingesetzt werden, um Kosten zu sparen.
  • Die Leistungsfähigkeit des Kerns auf den Zielbausteinen soll sich einfach und kosteneffektiv verfolgen und verbessern lassen.

7. Schritt: Das Speicher-Layout

Typische Linker-Skripte.
Bild 4. Typische Linker-Skripte.
© Altium

Die meisten Projekte basieren auf Code aus früheren Projekten. Wenn dagegen der Entwickler von vorn beginnt, wird die Architektur in der Regel als Machbarkeitsstudie entwickelt, bevor es an das wirkliche Projekt geht. Wird Code aus einem alten Projekt oder ein neues Architekturkonzept auf einen neuen Baustein übertragen, muss die Applikation in die verschiedenen Speicher dieses Bausteins eingepasst werden. Gängige Embedded-Zielbausteine wie Aurix und Aurix 2G sind bezüglich des Speicher-Layouts recht sensibel: in Ex­tremfällen kann die Fehlplatzierung eines einzigen Datenelements die Leistungsfähigkeit um rund
eine Größenordnung einbrechen lassen.

Der für das Speicher-Layout verantwortliche Systemin­tegrator benötigt deshalb die präzise Kontrolle über das Speicher-Layout sowie erstklassige Informa­tionen über die Speicherarchitektur des Zielbausteins. Die Definition des Speicher-Layouts erfolgt üblicherweise mit Linker-Skripten – so genannten .lsl-Files (Bild 4) –, die in großen Projekten durchaus einen Umfang von 50.000 Zeilen oder mehr erreichen können.

Die manuelle Festlegung eines guten Speicher-Layouts kann viele Mannmonate dauern. Es gibt jedoch Werkzeuge, mit denen sich diese Arbeit weniger mühsam gestaltet:

  • Performance-Profiling-Tools können problemlos die Ursachen gängiger und folgenreicher Ineffizienzen beim Speicher-Layout einkreisen und Abhilfen empfehlen, sodass sich das Layout schnell optimieren lässt.
  • Ein grafisches Linker-Layout-Werkzeug unterstützt die notwendigen und sachdienlichen Arbeitsabläufe für ein erfolgreiches Speicher-Layout, abstrahiert dabei aber das umständliche manuelle Kopieren und Einfügen Tausender Linker-Skript-Zeilen.

8. Schritt: Positionsunabhängige Module

Nachdem die Applikation nach den beschriebenen Methoden realisiert wurde, geht es als nächstes an das Deployment. Das kann schon im Prüflabor mit nur wenigen Fahrzeugen schwierig sein, doch bei Fahrzeugen im Feld kann es zu einem Albtraum werden. Abgesehen von Security-Aspekten wie der Abwehr von Manipulationen und den Kosten dafür, physischen Zugang zum Fahrzeug zu bekommen, ist das Konfigurationsmanagement das wichtigste Thema.

Es gibt zahllose Fahrzeuggenerationen mit vielen verschiedenen Software-Konfigurationen. Jede muss – auch wenn es um dieselbe Funktion geht – gesondert behandelt werden, denn die Software-Module sind an ganz bestimmte physische Orte im Speicher gebunden. Das Deployment eines Moduls mit falschem Speicher-Layout aber kann die Betriebssicherheit des ganzen Fahrzeugs kompromittieren.

Over-The-Air-Updates (OTA) über GSM-Verbindungen sind immer häufiger an der Tagesordnung. OTA erlaubt das Aktualisieren der Software ohne Werkstattbesuch. Gleichzeitig wird OTA aber die Update-Frequenz erhöhen und
somit die Zahl der zu behandelnden Software-Konfigurationen in die Höhe treiben, denn abhängig von der GSM-Verfügbarkeit und den Update-Plänen erhält nicht jeder alle Updates.

An dieser Stelle wird ein Compiler mit Unterstützung für positionsunabhängige Module benötigt. Derartige Compiler generieren Software-Module (Code oder Daten), die unabhängig davon, wo sie im Speicher platziert werden, korrekt funktionieren. Dementsprechend lassen sich die Module mit jeglichen Software-Konfigurationen kombinieren, solange genügend freier Speicherplatz vorhanden ist.

Die Autoren

Dr. Alexander Hertz
Dr. Alexander Hertz
© Altium

Dr. Alexander Hertz
erhielt 2009 sein Diplom in theoretischer Physik vom Physikdepartment der Tech­nischen Universität in München. Danach beschäftigte er sich am Informatik-Lehrstuhl der TUM mit dem Design von neuen Programmiersprachen und Paradigmen zur einfachen und effizienten Formulierung von hochparallelen Programmen. 2015 verfasste er seine Doktorarbeit, zum Thema Konstruktion einer voll­automatisch parallelisierbaren Sprache und die Implementierung des dazu gehörenden Compilers. Seit Mitte 2015 arbeitet er als Compilerspezialist und Leiter der Produkt­entwicklung bei Tasking.

Mark Forbes
Mark Forbes
© Altium

Mark Forbes
arbeitet als Director of Marketing Content bei Altium. Forbes, der an der Bradley University in Peoria (Illinois/USA) ein Bachelor-Diplom in Elektrotechnik erworben hat, hält Patente im Bereich der optischen Kommunikation sowie im Antennendesign und ist Autor von mehr als 150 Fachartikeln bzw. fünf Büchern.


  1. Acht Schritte zu besserer ADAS-Software
  2. 4. Schritt: Benchmarking

Das könnte Sie auch interessieren

Verwandte Artikel

ALTIUM EUROPE GmbH