Fotolia_152233409_monsitj_XXL_preview

(Bild: monsitj/Fotolia)

Die berühmte Aussage, dass wir nur zehn Prozent unseres geistigen Potenzials verwenden, ist nach aktueller Forschung eindeutig ein Mythos. Ihren Ursprung hat sie auch nicht bei Alfred Einstein, dem dieses Zitat oft fälschlich zugeschrieben wird. Als eine von mehreren Quellen für die Aussage gilt etwa der Verhaltensforscher Karl Lashley, der um 1940 mit Rattenhirnen experimentierte. Er trainierte die Ratten dazu, ein Labyrinth zu durchqueren und  fügte danach den Gehirnen der trainierten Ratten an verschiedenen Stellen einen Schaden zu.

Wie sich herausstellte, konnte Lashley bis zu 90 Prozent des Rattengehirns verletzen, ohne dass die Ratten den Weg durch das Labyrinth oder die Fähigkeit, diesen Weg zu erlernen, verloren. Es schien also, als ob 90 Prozent des Gehirns gar nicht nötig waren, um diese Aufgabe zu lösen. Heute weiß man, dass verschiedene Sinne und verschiedene Arten von Erinnerungen ausreichen, um das Problem zu lösen. Diese können auch über weite Teile des Gehirns verteilt sein. Das Gehirn kann den Verlust von großen Anteilen erstaunlich gut kompensieren. Diese Anteile sind aber deswegen nicht nutzlos, sondern werden dauernd gebraucht. Entsprechend hoch ist auch das tatsächlich genutzte Potenzial des Gehirns.

Anders sieht es dagegen bei Entwicklung von Software für Embedded-Systeme aus. Dass hier häufig nur ein Bruchteil des vorhandenden Hardware-Potenzials auch tatsächlich ausgeschöpft wird, ist leider kein Mythos, sondern alltägliche Realität. Welche Methoden und Tools es ermöglichen, das volle Potenzial zu nutzen, untersucht dieser Beitrag am Beispiel von Infineons Aurix-Prozessor der ersten und zweiten Generation.

Bibliotheken

Schon bei der Entscheidung für eine Softwarebibliothek kommt es oft zu Fehleinschätzungen. So erscheint die Verwendung von Softwarebibliotheken eines Drittanbieters auf den ersten Blick wenig effizient, wenn ein Unternehmen über eine ausreichend große Software-Entwicklungsabteilung verfügt. Die Kosten für Bibliotheken eines Drittanbieters müssen meist gerechtfertigt werden, wogegen die eigenen Ingenieure unmittelbar verfügbar sind.

Häufig gelingt auch in relativ kurzer Zeit ein Konzeptentwurf, der genügend Potenzial zeigt, um das eigentliche Ziel zu erreichen. Von diesen vorläufigen Ergebnissen ausgehend, wird dann häufig versucht, die Kosten für einen Drittanbieter zu sparen. Funktionalität, die mithilfe einer kommerziellen Bibliothek zur Verfügung stünde, sollen die Mitarbeiter schnell selbst entwickeln. Die Erfahrung zeigt aber, dass diese Rechnung in den meisten Fällen nicht auf geht. Die Kosten für die Entwicklung eines vollständigen Softwareprodukts, das anders als ein bloßer Prototyp hoch performant, sehr stabil und gut getestet sein muss sowie über die passende Dokumentation verfügt, um sinnvoll von anderen Entwicklern eingesetzt zu werden, sind meist deutlich höher als erwartet. In den meisten Fällen rechnet sich eine Eigenentwicklung nur dann, wenn sich das fertige Softwareprodukt später an sehr viele Kunden verkaufen lässt.

Dagegen erleichtert die Verwendung von Standardbibliotheken für Kryptographie, Vektor- und Matrixberechnungen sowie das Lösen linearer Gleichungssysteme und Fourier-Transformationen die Entwicklung deutlich. Damit spart man sich den eigenen Entwicklungsaufwand nicht nur für die Erstellung der Bibliothek selbst, sondern auch für die Optimierung der Bibliothek für verschiedene Zielarchitekturen – wie zum Beispiel den Aurix. Darüber hinaus gibt es weitere Vorteile: Das Risiko eines schwer auffindbaren Problems in der Numerik oder einer fatalen Schwachstelle im Kryptoalgorithmus ist deutlich reduziert, wenn für diese Standardaufgaben von Experten entwickelte und verifizierte Bibliotheken verwendet werden.

Für die meisten Architekturen verfügbare und auf diese entsprechend optimierte Blas/Lapack-Bibliotheken (Basic Linear Algebra Subprograms/Linear Algebra Package) sind zudem oft um bis zu 70 Prozent schneller als eine nicht an die Zielarchitektur angepasste Variante. Applikationen, welche auf die Blas/Lapack-API aufsetzen, müssen bei einer Portierung auf eine neue Architektur nicht angepasst oder optimiert werden, wenn es entsprechende Bibliotheken für diese Hardware gibt.

Compiler

Bild 1: Taskings Performance Libraries stellen die vollständigen Blas/Lapack-Routinen für den Aurix optimiert und in aktueller Version zur Verfügung. Tasking

Für den Aurix/Aurix 2G empfehlen sich die seit April 2017 verfügbaren Tasking Lapack Performance Libraries, welche die vollständigen Blas/Lapack-Routinen für den Aurix optimiert und in aktueller Version für C99 zur Verfügung stellen (Bild 1). Die numerische Stabilität und das äquivalente Verhalten zur wissenschaftlichen Variante der für Embedded-Systeme entwickelten Bibliothek werden durch weitreichende Tests überprüft und für den Benutzer transparent dokumentiert, sodass sich die Bibliotheken bedenkenlos einsetzen lassen. Zusätzlich bietet Tasking Bibliotheken für FFT und Kryptoalgorithmen, die je nach verwendeter Architektur die Berechnungen hardwarebeschleunigt oder in Software durchführen.

Viele ADAS/Sensorfusions-Anwendungen verarbeiten Radarsignale mittels FFT und wären ohne hardwaregestütze FFT auf einem Mikrocontroller wie dem Aurix gar nicht möglich. Durch die Verwendung von Standardbibliotheken wie Blas/Lapack/FFT wird es einfach, solche Anwendungen auf leistungsfähigen Desktop-Computern vorzuentwickeln. Diese können dann performant auf einen für Safety-Anwendungen geeigneten Mikrocontroller – wie den Aurix – portiert und mit den üblichen MIL/SIL/PIL-Tests abgesichert werden, da Matlab die Verwendung von Blas/Lapack unterstützt.

Zusätzliche Security-Anforderungen an zukünftige Applikationen benötigen auch eine zunehmende Verschlüsselung etwa von CAN-Nachrichten, da beispielsweise bei einem Over-the-Air-Update kein Fremdcode auf die MCU gelangen darf. Nimmt man an, dass nur 100 aller CAN-Nachrichten pro Sekunde ver- oder entschlüsselt werden müssen, ergibt sich daraus bereits eine Prozessorlast von ungefähr 33 Prozent bei aktuellen TriCore-Prozessoren. Durch die Verwendung einer hardwarebeschleunigten Kryptobibliothek lässt sich die zusätzliche Sicherheit auch ohne große Geschwindigkeitseinbußen realisieren. Falls keine Hardwareunterstützung zur Verfügung steht, erlauben die Tasking Performance Libraries stattdessen auch die Verwendung von einem optimierten Softwarefallback.

Standardfunktionalitäten wie Blas/Lapack/FFTW und Kryptoalgorithmen lassen sich also sehr effektiv über Standardbibliotheken abdecken. Interessant wird die Applikation aber erst durch den Teil des Codes, der die Bibliotheken anspricht und deren Funktionalität zu einer einzigartigen Anwendung zusammenfügt.

Compiler

Compiler übersetzen Hochsprachen wie C99 in den Befehlssatz (Assembler) der Zielarchitektur wie beispielsweise Aurix/TriCore. Häufig gibt es viele verschiedene Möglichkeiten, C-Statements durch Assemblerbefehle auszudrücken. Die einfachste Möglichkeit besteht darin, jedes Konstrukt aus C einzeln zu betrachten und diesem jeweils eine Sequenz von Assemblerbefehlen zuzuordnen. Dies führt zu Programmen, die sehr langsam und umfangreich sind. Die Kunst eines optimierenden Compilers besteht darin zu beweisen, dass sich viele Berechnungen vereinfachen, umformen und kombinieren lassen und dabei das exakt gleiche Rechenergebnis produziert wird – wobei die konkret ausgeführten Umformungen davon abhängen, ob bessere Performanz oder eine kleinere Codegröße bevorzugt wird.

Auf großen Server- und Desktoparchitekturen wie Intel und Cortex-A verfügt die Hardware selbst über Optimierungen wie Out-of-Order-Execution, Advanced-Branch-Prediction oder Register-Renaming, welche den Durchsatz im Mittel deutlich erhöhen. Bei komplexen Embedded-Architekturen wie dem Aurix/TriCore, die RISC, DSP und spezielle Hardwarebeschleunigungselemente wie FFT vereinen, ist man auf einen Compiler angewiesen, der alle relevanten Möglichkeiten, ein C-Konstrukt auf Assembler abzubilden, nicht nur kennt, sondern diese auch optimal kombiniert. Die Hardware selbst bietet aus Platz- und Energieeffizienzgründen und auch weil sie harte Echtzeitgarantien geben muss, nur wenige Optimierungsmöglichkeiten.

Tasking hat über 100 Mannjahre in die eigene Compilertechnik und speziell in das Verständnis und die optimale Kombination von C-Konstrukten und Assemblerbefehlen investiert. Die Technologie erlaubt es, eine große Anzahl an Abbildungen von C zum Assembler komplexer Architekturen wie dem TriCore einfach und kompakt zu definieren und automatisch die beste Kombination (je nach Optimierungsziel auf Größe oder Geschwindigkeit) zu finden.

Dieses im Compiler enthaltene umfangreiche Wissen unterscheidet den Tasking-Compiler von alternativen, generischen Compilertechnologien. So bietet etwa der Open-Source Compiler LLVM  gute Tools und Unterstützung für Standardfeatures von Desktop- und Serverarchitekturen wie beispielsweise eine große Cache-Hierarchie. Bei einer gänzlich verschiedenen Mikrocontrollerarchitektur, die nicht in das Grundschema des Compilers passt, muss ein Großteil des nötigen Wissens über die Zielarchitektur für LLVM von Grund auf neu beschrieben werden, sodass ein neuer TriCore-Compiler nur wenig vom LLVM-Framework profitieren würde.

Das umfangreiche Wissen über die Aurix/TriCore Architektur im Tasking-Compiler und die allgemeine Ausrichtung auf eingebettete Systeme führt dazu, dass dieser um 20 und mehr Prozent performanteren Code bei vergleichbarer Codegröße erzielt.

Profiling

Das Expertenwissen aus professionellen Bibliotheken und im Compiler sorgt für optimale Performanz im C-Code: Geschwindigkeitsvorteil von 90 Prozent und mehr im Vergleich zu handgeschriebenem oder schlecht optimiertem Code sind nicht außergewöhnlich.

Neben dem Code selbst haben aber auch die Konfiguration der Hardware (Caches) und das Speicherlayout der Daten und Funktionen (Linkerskript) sowie die Compileroptionen einen starken Einfluss auf die Geschwindigkeit und die effektive Ressourcennutzung einer Anwendung. Allein das Ermitteln eines akzeptablen Speicherlayouts dauert selbst für erfahrene Spezialisten typischerweise zwei Mannmonate pro Projekt. Häufig ist unklar, an welcher der tausenden von Stellschrauben (Compileroptionen, Linkerskript, Hardwarekonfiguration) man drehen sollte, um eine relevante Verbesserung zu erreichen. Mittels Erfahrungswerten, zeit- und kostenaufwendigen Tracingverfahren sowie ausgiebigem „Try and error“ versuchen die meisten Anwender sich langsam an eine Lösung heranzutasten, die wenigstens die größten Probleme behebt.

Generell möchte man möglichst effizienten Code erhalten, teilweise müssen aber auch spezifische Timingprobleme gelöst werden, etwa wenn die maximal erlaubte Ende-zu-Ende Latenz einer Sequenz von RTOS-Tasks überschritten wird. Das Schedule des Echtzeitbetriebssystem zu ändern, sollte vermieden werden, da man sich dabei durch das Lösen eines Problems mehrere neue Probleme einhandeln kann. Hier stellt sich automatisch die Frage, mit welcher minimalen Änderung im Code, den Compileroptionen, der Hardwarekonfiguration oder des Speicherlayouts sich der größte Geschwindigkeitsgewinn erzielen lässt.

Im Desktopbereich gibt es dafür Standardwerkzeuge wie beispielsweise den vTune-Profiler. Diese zeigen nach kurzer, nicht intrusiver Messung des Laufzeitverhaltens einer Software auf einer speziellen Architektur an, weisen auf die größten Performanzprobleme und deren Ursache im Code hin und schlagen Verbesserungen vor. So ist es möglich, ohne Expertenwissen über die Hardware binnen Minuten die Codestelle mit dem größten Optimierungspotenzial zu identifizieren, den Code oder die entsprechende Einstellung anzupassen und den Erfolg der Optimierung durch eine zweite Messung zu verifizieren. Das Expertenwissen über die Hardware, wie man diese optimal anspricht und konfiguriert, wird über einen solchen Profiler dem Entwickler zugänglich gemacht. Die Probleme können schnell identifiziert und systematisch abgearbeitet werden.

Compiler

Bild 2: Wie oben, in der ersten Zeile des „Summary“ ersichtlich, greift Core 0 sehr häufig auf den lokalen Speicher von Core 2 (DSPR2) zu, was zu einer langsamen Ausführungsgeschwindigkeit führt. Tasking

In Kürze wird der Tasking Embedded-Profiler veröffentlicht. Dies ist das einzige auf dem Markt erhältliche Tool, welches die einfache Anwendung eines Profilers, wie auf dem Desktop üblich, auch für Aurix-Prozessoren möglich macht. In Bild 2 sieht man das Ergebnis einer Speicheranalyse. Diese ist eine von mehreren möglichen Analysen, welche dem Benutzer tieferen Einblick in durch unzureichendes Speicherlayout verursachte Performanz-Probleme bietet.

In der Tabelle für speicherintensive Funktionen („Data access intensive functions“) sieht man, dass die globale Variable „x“, auf die in der Funktion „main“ von Core 0 aus zugegriffen wird, für die ineffizienten Zugriffe auf den Speicher DSPR2 verantwortlich ist. Das Tool schlägt als Lösung vor, die Variable „x“ in DSPR0 zu verschieben.

Compiler

Bild 3: Liegt die Variable „x“ in DSPR2, erfolgt der Speicherzugriff über den SRI und ist entsprechend langsam (roter Pfeil). Verschiebt man „x“ in den lokalen DSPR0, dann kann ohne Umweg auf den Speicher zugegriffen werden (grüner Pfeil). Tasking

Führt man die vorgeschlagene Verschiebung von „x“ durch und vergleicht die Analyseergebnisse mithilfe des Profilers, dann zeigt sich eine Verbesserung der Ausführungsgeschwindigkeit um den Faktor 7,6 für die Beispielanwendung (Bild 3). Neben der Analyse von Speicherzugriffsverzögerungen unterstützt der Profiler den Entwickler auch bei der richtigen Konfiguration von Daten- und Instruktionscaches sowie der Clocks auf dem Aurix.

Over-the-Air-Updates

Neben der Geschwindigkeit der Applikationen selbst gewinnen auch die Verbesserungen von Softwarekomponenten nach der Endfertigung zum Beispiel eines Fahrzeugs an Bedeutung. So können mittels Over-the-Air-Updates Komfortfunktionen auch nach der Auslieferung und ohne Werkstattbesuch erworben werden, und nötige Softwareupdates lassen sich auch ohne einen kostenintensiven Rückruf im Feld aufspielen. Dies funktioniert aber nur dann zufriedenstellend, wenn das Update über Funk sicher, schnell und unkompliziert funktioniert.

Um die Geschwindigkeit des Updates zu verbessern, bietet der Tasking-Compiler verschiedene Kompressionsmethoden an. Darüber hinaus wird der Updateprozess durch die Unterstützung von Position Independent Modules (PIM) für TriCore im Tasking Compiler vereinfacht und beschleunigt. Mit PIM muss die neue Softwarekomponente nicht mehr speziell an das Speicherlayout der Software auf der Ziel-ECU angepasst werden, sodass das bestehende Speicherlayout nicht mehr vor dem Update abgefragt werden muss und keine Gefahr besteht, eine Komponente mit inkompatiblem Layout auszuliefern. Der Tasking-Compiler unterstützt komplett statische PIM, sodass auf der ECU kein Linker benötigt wird, der die Komponente während des Updates anpasst.

 

Eck-DATEN

Um Prozessor-Applikationen mit guter Qualität zu erzeugen, ist die Kombination von professionellen Bibliotheken mit den richtigen Tools gefragt. Ein Verzicht auf das Expertenwissen, das in den Tools und Bibliotheken enthalten ist, birgt die Gefahr, die Kosten für das fertige Produkt unnötig in die Höhe zu treiben. Denn die mangelhafte Ausnutzung der Hardwareressourcen durch die Software muss dann durch teurere und leistungsfähigere Hardware ausgeglichen werden.

Dr. Alexander Herz

(Bild: Tasking)
Leiter der Produktentwicklung bei Tasking

(ku)

Sie möchten gerne weiterlesen?

Unternehmen

Tasking GmbH

Eltingerstr. 61
71229 Leonberg
Germany