Kein Rätselraten mehr Trace-Visualisierung stützt das Debugging von RTOS-basierter Firmware

Autor / Redakteur: Dr. Johan Kraft * / Franz Graser

Um ein eingebettetes System auf Basis eines Echtzeitbetriebssystems umfassend zu verstehen, müssen Entwickler das Echtzeitverhalten auf der RTOS-Ebene beobachten können. Hierfür wird ein auf RTOS ausgerichtetes Tracing-Tool benötigt, das quasi ein Zeitlupenvideo der Echtzeitverarbeitung liefert.

Anbieter zum Thema

Am Puls der Software: Tracing auf der Betriebssystemebene erlaubt bessere Einblicke in die Echtzeit-Datenverarbeitung. Die Visualisierung ist dabei entscheidend für das Begreifen.
Am Puls der Software: Tracing auf der Betriebssystemebene erlaubt bessere Einblicke in die Echtzeit-Datenverarbeitung. Die Visualisierung ist dabei entscheidend für das Begreifen.
(Bild: gemeinfrei / CC0 )

Vor einigen Jahrzehnten gab es in der Embedded-Industrie eine Verlagerung des Schwerpunkts von der Assembler- zur C-Programmierung. Schnellere Prozessoren und bessere Compiler ermöglichten diese Anhebung des Abstraktionsgrads, die die Produktivität und Qualität der Entwicklung verbesserte.

Bildergalerie

Zurzeit befinden wir uns inmitten einer weiteren bedeutenden Umstellung in der Firmwareentwicklung-Technologie: die zunehmende Verwendung von Echtzeit-Betriebssystemen (Real-Time Operating Systems – RTOS) verkörpert die dritte Generation der Entwicklung von Embedded-Software.

Ein RTOS ist ein schnelles und deterministisches Betriebssystem für den Einsatz in Embedded- und IoT-Anwendungen. Seine Hauptaufgabe ist das Multithreading, um die Aufteilung der Softwarefunktionalität in mehrere ‚parallel‘ laufende Teilprogramme, so genannte ‚Tasks‘ zu ermöglichen.

Der Trend zum Echtzeit-Betriebssystem

RTOS sind kein Hype mehr, wie sie es noch vor 10 bis 15 Jahren waren, sondern befinden sich in allen möglichen Arten von Embedded-Anwendungen im Einsatz. Im Embedded Market Survey, der wohl am besten etablierten und am meisten vertrauten Studie der Branche, ist dieser Trend klar erkennbar.

Auf die Frage nach der größten technischen Herausforderung wird dort am häufigsten das RTOS genannt. Der Anteil dieser Antwort wuchs von 12 Prozent im Jahr 2013 auf 17 Prozent in 2014 und 26 Prozent im Jahr 2015. Der historisch sehr fragmentierte Markt scheint sich jetzt in einer Konsolidierungsphase zu befinden, in der sich die Entwickler zunehmend den führenden Akteuren zuwenden.

Herausforderungen bei der Anwendung eines RTOS

Was macht nun aber ein RTOS so besonders, dass man es als die dritte Generation beim Firmwaredesign bezeichnen kann? Ein RTOS übernimmt die Kontrolle über die Programmausführung und bringt mit den Tasks einen neuen Abstraktionsgrad ein. Der Kontrollfluss eines Programms lässt sich nun nicht mehr aus dem Quellcode ersehen, denn das RTOS entscheidet darüber, welche Task jeweils ausgeführt wird.

Bildergalerie

Während ein RTOS die Komplexität des Quellcodes einer Applikation verringern kann, reduziert es die der Applikation selbst innenwohnende Komplexität nicht. Eine Ansammlung scheinbar einfacher RTOS-Tasks kann, wenn sie gemeinsam als System ausgeführt wird, zu einem überraschend komplexen Laufzeitverhalten führen.

Der Entwickler muss festlegen, wie die Tasks miteinander interagieren und die Daten mit den Dienstfunktionen des RTOS teilen sollen. Dem Entwickler obliegt außerdem die Entscheidung über wichtige RTOS-Parameter wie die Task-Prioritäten (also die relative Dringlichkeit der Tasks), die durchaus nicht selbstverständlich sein müssen.

Selbst wenn Sie Ihren gesamten Code nach den bewährten Verfahrensweisen des RTOS-basierten Designs geschrieben haben, können andere Teile des Systems, ob es sich nun um Komponenten aus dem eigenen Unternehmen oder von Drittanbietern handelt, in derselben Umgebung laufen, aber sich nicht an dieselben Prinzipien halten.

Das grundlegende Problem besteht darin, dass es sich bei den RTOS-Tasks um keine isolierten Entitäten handelt. Zwischen den Tasks gibt es mindestens eine Art von Abhängigkeit, nämlich die von ihnen geteilte Prozessorzeit. Beim präemptiven Scheduling mit feststehender Priorität können praktisch jederzeit Tasks mit höherer Priorität erscheinen, die die Verarbeitung der Tasks geringerer Priorität verzögern.

Andere Arten geteilter Ressourcen (etwa globale Daten oder Hardwareperipherie) führen ebenfalls zu Abhängigkeiten zwischen den Tasks und können unvorhersehbare Verzögerungen bewirken, wenn die Synchronisation nicht korrekt geplant ist – unabhängig von den Task-Prioritäten.

Ein Beispiel für diese Art von Problemen findet man in der Pathfinder-Mission der NASA, in deren Verlauf ein Rover auf dem Mars gelandet wurde. Während dieser Mission kam es im Raumfahrzeug zu kompletten System-Resets, die zu Datenverlusten führten. Nach einigem Ärger ermittelte die NASA als Ursache ein klassisches RTOS-Problem, das als Prioritätsinversion bezeichnet wird.

Zu einer Prioritätsinversion kann es kommen, wenn ein Task hoher Priorität (Task H in der Abbildung 2 der Bildergalerie) auf eine geteilte Ressource (etwa eine Kommunikationsschnittstelle) zugreifen will, die gerade von einem Task mit geringerer Priorität (Task L) belegt wird. Task H würde normalerweise für kurze Zeit blockiert, bis Task L die geteilte Ressource freigibt.

Jetzt Newsletter abonnieren

Verpassen Sie nicht unsere besten Inhalte

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung

Eine Prioritätsinversion tritt dann auf, wenn an dieser Stelle ein Task mittlerer Priorität (Task M) Task L unterbricht und die Aufgabe mit der eigentlich höheren Priorität dadurch weiter verzögert. Bei der Pathfinder-Mission der NASA führte dieses Verhalten zu System-Resets, zum Verlust von Daten und beinahe auch zu einem Fehlschlag der gesamten Mission.

Task-Abhängigkeiten wie das Scheduling und geteilte Ressourcen werden durch das Timing, also durch Verarbeitungszeiten und das Eingangs-Timing, beeinflusst. Dies macht es nahezu unmöglich, rein auf Grund des Quellcodes Aussagen über das Echtzeitverhalten eines RTOS-basierten Systems zu machen.

Unter dem Einfluss vieler Faktoren können die Tasks langsamer als vorgesehen laufen, zufällige, unerwartete Verzögerungen aufweisen oder auch niemals ausgeführt werden. Selbst dann, wenn das System scheinbar so arbeitet wie im Labor vorgesehen, kann es zahllose andere Verarbeitungs-Szenarien mit mehr oder weniger bedeutenden Timing-Unterschieden geben, von denen einige zu Problemen führen.

Im schlimmsten Fall besteht das System zwar die Tests, stürzt aber im Praxiseinsatz möglicherweise immer wieder ab.

Das Debugging RTOS-basierter Systeme

Der Wunsch, das Debugging auf derselben Abstraktionsebene durchzuführen wie die Entwicklung, ist völlig normal, jedoch haben sich die Debugging-Tools auf den RTOS-Trend noch nicht entscheidend weiterentwickelt.

Bildergalerie

Einige Debugger wurden zwar mit so genannten ‚RTOS Awareness‘-Features aufgewertet, die Ihnen beim Debugging das Inspizieren des Status von RTOS-Objekten wie etwa Tasks und Semaphoren ermöglichen. Hierbei handelt es sich jedoch nur um Nachbesserungen an den Quellcode-Debuggern der zweiten Generation, deren Fokus strikt auf dem Quellcode und dem Debugging nach dem Run/Halt/Single-Step-Prinzip liegt.

Ein RTOS-basiertes System mit einem traditionellen Source-Level Debugger zu debuggen, ist vergleichbar mit dem Versuch, einen auf der Assembler-Ebene arbeitenden Debugger bei der C-Programmierung einzusetzen.

Um das Laufzeitverhalten eines RTOS-basierten Systems umfassend zu verstehen, müssen Sie das Echtzeitverhalten auf der RTOS-Ebene beobachten können, wofür ein auf RTOS ausgerichtetes Tracing-Tool benötigt wird.

Dieses operiert als Ergänzung zu traditionellen Debugging-Tools und stellt eine Zeitachse auf der RTOS-Ebene bereit. Ein traditioneller Debugger ähnelt sehr einem Mikroskop, mit dem sich die detaillierte Verarbeitung innerhalb eines Tasks untersuchen lässt. Das Tracing dagegen ist mehr so etwas wie ein Zeitlupenvideo der Echtzeitverarbeitung.

Hardware- versus softwarebasiertes Tracing

Es gibt zwei Arten des Tracings, die jeweils geringfügig unterschiedlichen Zwecken dienen. Das hardwarebasierte Tracing wird vom Prozessor selbst generiert. Es liefert ein detailliertes Verarbeitungs-Trace auf der Quellcode- oder Assembler-Ebene, allerdings mit wenig oder gar keiner RTOS-Orientierung.

Es wird hauptsächlich für die Überdeckungsanalyse und das Debugging besonders kniffliger Probleme verwendet, für die ein maschinennahes Instruction-Tracing benötigt wird.

Beim softwarebasierten Tracing werden dagegen kleine Tracecode-Abschnitte in die Zielsoftware eingefügt, um wichtige Ereignisse im RTOS sowie optional auch im Applikations-Code aufzuzeichnen. Meist muss man den RTOS-Trace-Code aber nicht selbst einfügen, denn viele RTOS-Kernels enthalten an strategischen Punkten bereits Trace-Makros.

Das softwarebasierte Tracing kann deshalb auf jedem Prozessor genutzt werden, beliebige Arten von Software-Ereignissen speichern und jegliche relevanten Daten einschließen. Nachteilig ist der Verarbeitungsaufwand des Tracing-Codes, allerdings verbraucht das RTOS-Tracing auf einer modernen 32-Bit-MCU nur ein paar Prozent der Prozessorzeit, da nur sehr wenige Daten aufgezeichnet werden müssen und die erfassten Ereignisse nicht sehr häufig auftreten.

Hierdurch ist ein kontinuierliches Streamen der Daten über gängige Debug-Schnittstellen oder auch über Interfaces wie USB oder TCP/IP möglich. Die geringe Datenrate lässt ebenfalls das Tracing in einen RAM-Puffer zu.

Schon wenige Kilobyte reichen aus, um ein brauchbares Trace der jüngsten Ereignisse zu bekommen. Somit ist ein Tracing auch außerhalb des Labors möglich – zum Beispiel im Zuge von Feldtests oder an schon im Einsatz befindlichen Systemen.

Für das Begreifen der Traces ist die Visualisierung entscheidend. Viele Embedded-Systeme legen ein mehr oder weniger zyklisches Verhalten an den Tag, sodass es sich beim Großteil der Trace-Daten um irrelevante Wiederholungen der ‚normalen‘ Verhaltensweisen handelt.

Interessant sind dagegen meist die Anomalien, die jedoch unter Umständen schwierig zu finden sind, wenn man nicht genau weiß, wonach man eigentlich sucht. Das menschliche Gehirn leistet allerdings Außerordentliches, wenn es um das Erkennen visueller Muster und Anomalien geht. Voraussetzung hierfür ist jedoch die korrekte Visualisierung der Daten.

Es gibt viele Tools, die ein RTOS-Trace als klassisches Gantt-Diagramm darstellen. Diese Visualisierung eignet sich aber nicht, um weitere Ereignisse (z. B. API-Aufrufe oder User-Logging) in derselben Ansicht anzuzeigen. Ein vertikales Execution Trace dagegen kann derartige Ereignisse mit Beschriftungsfeldern anzeigen, die auf das grafische Execution Trace verweisen.

Die alleinige Anzeige eines Execution Trace ist außerdem eine sehr eingeschränkte Perspektive, da aus einem RTOS-Trace deutlich mehr Informationen extrahiert werden können. Zum Beispiel lassen sich die Interaktionen von Tasks und ISRs als Abhängigkeitsgraph visualisieren, und ebenso können Trace-Ansichten angezeigt werden, die sich auf weitere relevante RTOS-Objekte wie Semaphoren, Warteschlangen und Mutexe konzentrieren.

Fazit

Der Trend zum RTOS in der Embedded-Branche ist unübersehbar – und dies aus gutem Grund. RTOS lassen sich als dritte Generation der Firmware-Entwicklung betrachten, da das Multithreading einen höheren Abstraktionsgrad und weniger Kontrolle über die Verarbeitung bietet. Dies birgt jedoch erhebliche Fallstricke, die nach besserer Debugging-Unterstützung auf der RTOS-Ebene verlangen.

Vereinfachen lässt sich das Debugging RTOS-basierter Systeme mithilfe besserer Einblicke in ihre Echtzeitverarbeitung. Hierzu bedarf es des Tracings auf der RTOS-Ebene, wobei die Visualisierung entscheidend für das Begreifen der Daten ist.

Ergänzendes zum Thema
Percepio Tracealyzer

Percepio ist ein Spezialist in der RTOS-Trace-Visualisierung und Hersteller der Tracealyzer-Tools, die Einblicke in die Laufzeitwelt bieten.

Das Visualisierungs-Tool bietet mehr als 25 interaktive Ansichten, die zahlreiche Aspekte des Echtzeitverhaltens offenbaren. Sie stützen sich dabei auf RTOS-Ereignisse, Speicherzuweisungs-Ereignisse und kundenspezifische User-Ereignisse im Applikations-Code.

Die Spanne der Visualisierungen reicht von detaillierten grafischen Traces und Test-Logs bis zu individuellen Daten-Plots, Task-Statistiken und Abhängigkeitsgraphen. Sämtliche Ansichten sind zudem miteinander verknüpft, sodass Sie sich von Anomalien in den abstrakten Darstellungen zu den einzelnen Ereignissen vorarbeiten können. Auch ein Wechsel zwischen verschiedenen Perspektiven ist problemlos möglich, ohne die Fokussierung auf das jeweilige Problem aufzugeben.

Tracealyzer ist ein eigenständiges Tool, das parallel zu einem vorhandenen Debugger verwendet werden kann. Es erfordert keinerlei besondere Hardware und ist auf praktisch jedem Prozessor lauffähig, sofern ein unterstütztes RTOS eingesetzt wird.

Kontinuierliches Streaming ermöglicht das Tracing des Systems über lange Zeitspannen hinweg, während das Tracing an einen RAM-Puffer das Sammeln von Traces ohne Debugger-Verbindung im Rahmen von Feldtests oder an bereits im Einsatz befindlichen Systemen zulässt.

Einige Kunden aktivieren Tracealyzer im Produktions-Code und erfassen Traces aus der Ferne. Dies gibt den Entwicklern detaillierte Problemdiagnosen aus dem Praxisbetrieb in die Hand, die sonst beinahe unmöglich zu reproduzieren wären.

Die Hauptansicht von Tracealyzer.
Die Hauptansicht von Tracealyzer.
( Bild: Percepio )

Die Haupt-Traceansicht (Main Trace View) visualisiert alle Daten entlang einer vertikalen Zeitachse und fokussiert sich auf die Ausführung von Tasks, sowie auf Interrupthandler und Ereignisse wie etwa RTOS-API-Aufrufe und Ihre eigenen anwenderspezifischen Ereignisse.

Jedem Task und jedem Interrupthandler wird abhängig von der Priorität eine eigene Farbe zugewiesen, die übereinstimmend in allen Ansichten benutzt wird. Mit einem Doppelklick auf einen Task, eine ISR oder ein Ereignis öffnet sich eine weitere Ansicht, die relevante Ereignisse zeigt.

Der CPU Load Graph gibt auf einer horizontalen Zeitachse an, wie viel Prozessorzeit die einzelnen Tasks und Interrupts verbrauchen. Dies bietet einen Überblick über den Trace und ermöglicht die Fokussierung auf die Haupt-Traceansicht durch einen einfachen Doppelklick im Diagramm.

User Event Logging: User Events werden in der Tracealyzer-Hauptansicht mit gelben Beschriftungsfeldern angezeigt und lassen sich nutzen, um für das Debugging oder die Performance-Analyse weitere Details über den Applikations-Kontext beizusteuern.
User Event Logging: User Events werden in der Tracealyzer-Hauptansicht mit gelben Beschriftungsfeldern angezeigt und lassen sich nutzen, um für das Debugging oder die Performance-Analyse weitere Details über den Applikations-Kontext beizusteuern.
( Bild: Percepio )

Mit User Events ist ein explizites Logging gemeint, das ähnlich wie der klassische ‚printf‘-Aufruf in den Applikations-Code eingefügt wird. Allerdings geht die Verarbeitung deutlich schneller und dauert auf den meisten 32-Bit-MCUs nur wenige Mikrosekunden. User Events werden in der Hauptansicht mit gelben Beschriftungsfeldern angezeigt und lassen sich nutzen, um für das Debugging oder die Performance-Analyse weitere Details über den Applikations-Kontext beizusteuern.

Wie in den meisten anderen Ansichten auch, ist jeder Listeneintrag mit dem zugehörigen Ereignis in der Haupt-Traceansicht verknüpft. Ein Doppelklick fokussiert die Hauptansicht somit auf das entsprechende Ereignis.

Auch die dynamische Speichernutzung lässt sich analysieren. Auch wenn die dynamische Speicherzuweisung bei Embedded-Systemen allgemein als schlechtes Verfahren gilt, ist sie gelegentlich notwendig. Tracealyzer ermöglicht Ihnen das Analysieren der Zuweisungen und wartet sogar mit einem Filter auf, mit dem sich Speicherlecks einfacher finden lassen.

Tracealyzer wird für führende RTOS-Produkte und auch für Linux-Systeme angeboten. Es bietet direkte Unterstützung für die meisten 32-Bit-Prozessoren (einschließlich ARM) und lässt sich einfach auf andere Architekturen portieren. Weitere Informationen finden Sie auf der Website https://percepio.com. Dort finden sich unter https://percepio.com/gettingstarted/ auch Tutorials.

* * Dr. Johan Kraft ... ist Gründer und CEO des schwedischen Tool-Herstellers Percepio.

(ID:44740567)