Suchen

Tracing und Visualisierung in Linux-basierten Embedded-Systemen

| Autor / Redakteur: Johan Kraft * / Franz Graser

Tracing ist eine wichtige Methode, um Programmfehlern in Embedded-Systemen auf die Spur zu kommen. Visualisierungs-Tools helfen bei der Einordnung der Tracing-Resultate.

Firmen zum Thema

Bild 1: Hauptansicht von Tracealyzer mit Scheduling und verschiedenen Ereignissen
Bild 1: Hauptansicht von Tracealyzer mit Scheduling und verschiedenen Ereignissen
(Bild: Percepio)

Das Debugging kann ein anspruchsvoller und zeitraubender Faktor bei der Entwicklung von Embedded-Systemen sein. Schließlich wirft das Aufdecken eines Fehlers bei der Programmausführung die Frage auf, wie die Software in den fehlerhaften Zustand geraten ist, welche Kombination von Eingangssignalen und zeitlichen Abläufen den Fehler verursacht hat und warum der Fehler auftrat.

Die Antworten auf diese Fragen lassen sich häufig durch Tracing finden. Beim Tracing wird das Verhalten der Software zur Laufzeit aufgezeichnet, sodass die gesammelten Trace-Daten nachträglich analysiert werden können. Auch wenn das Tracing meist während der Entwicklung erfolgt, eignet es sich gut für den Produktionseinsatz. Es ist dann ununterbrochen aktiv und kann Fehler erfassen, die nach dem Deployment auftreten.

Dieses Production Tracing kann eine effektive Technik zum Aufdecken von Fehlern sein, die selten vorkommen und sich deshalb mit einem Debugger schwierig reproduzieren lassen. Das Tracing kann in der Hardware (also im Prozessor) oder softwaremäßig erfolgen. Während das Hardware-Tracing eine detaillierte Historie der verarbeiteten Befehle liefert, konzentriert sich das softwarebasierte Tracing auf ausgewählte Ereignisse, üblicherweise im Betriebssystem und an Schnittstellen auf der Applikationsebene.

Per Hardware generierte Traces enthalten Details zum Kontrollfluss und haben keine Rückwirkungen auf die Arbeitsweise des untersuchten Systems. Diese Technik setzt aber spezielles Equipment und eine für das Tracing geeignete Hardwareplattform voraus.

Das Software-Tracing kommt dagegen ohne besondere Hardware aus und lässt sich sogar in bereits im Einsatz befindlichen Produkten installieren – ähnlich wie die Blackbox in einem Flugzeug. Das Software-Tracing ermöglicht außerdem das Abspeichern von Daten, während das Hardware-Tracing in der Regel auf den Kontrollfluss beschränkt ist.

Das Software-Tracing belastet zwar die CPU, jedoch beträgt der Overhead üblicherweise weniger als ein Prozent. Zum Abspeichern der Trace-Daten ist das Software-Tracing (zumindest anfangs) auf das RAM des Systems angewiesen. Normalerweise sind die RAM-Puffer jedoch konfigurierbar, sodass die richtige Balance zwischen dem Speicherbedarf und der Länge der aufgezeichneten Verarbeitungshistorie gefunden werden kann.

Tracing in Linux mit dem Werkzeug LTTng

Besonders wichtig ist das Tracing für Systeme mit integriertem Betriebssystem. Ein zentrales Feature der Betriebssysteme ist das Multi-Threading, also die Fähigkeit zur Verarbeitung mehrerer Programme (Threads) auf einem Prozessor, indem schnell zwischen verschiedenen Verarbeitungskontexten hin- und hergeschaltet wird. Durch das Multi-Threading wird das Verhalten der Software jedoch komplexer, und der Entwickler hat weniger Kontrolle über das Verhalten zur Laufzeit, da die Verarbeitung vom Betriebssystem unterbrochen werden kann.

Schema: Transparentes Tracing von Funktionsaufrufen mit Wrapper-Funktionen und LD_PRELOAD
Schema: Transparentes Tracing von Funktionsaufrufen mit Wrapper-Funktionen und LD_PRELOAD
(Bild: Percepio)

LTTng ist eine Open-Source-Technologie für das softwarebasierte Tracing in Linux. LTTng ist praxiserprobt und wird von den meisten Linux-Distributionen unterstützt. Der LTTng Kernel Tracer kann Scheduling-Events, Systemaufrufe, IRQs, das Speichermanagement und weitere Aktivitäten auf der Kernel-Ebene aufzeichnen. Der LTTng User-Space Tracer (LTTng-UST) dagegen zeichnet vom Anwender definierte Ereignisse im Anwendungscode auf.

Die Trace-Daten werden im RAM abgelegt, können aber fortlaufend auf eine Disk übertragen oder über eine Netzwerkverbindung an ein anderes System übermittelt werden. Eine weitere Option ist das Ablegen der Trace-Daten in einem zyklischen RAM-Puffer, in dem die jeweils ältesten Daten von den neuen überschrieben werden.

Obwohl LTTng auf dem Instrumentieren der Software beruht, erfordert es keinen Rebuild des Linux-Kernels. Stattdessen nutzt LTTng so genannte Tracepoints, die sich bereits an strategisch wichtigen Stellen des Kernels befinden. Diese Tracepoints fungieren als Platzhalter für Funktionsaufrufe, die normalerweise inaktiv sind, aber von LTTng aktiviert werden können.

Mit LTTng-UST können Entwickler individuelle Ereignisse in Anwender-Applikationen und Library-Code aufzeichnen. Es ist sogar möglich, ausgewählte Funktionsaufrufe ohne Modifizieren des Quellcodes zu verfolgen. Hierzu wird eine geteilte Objektdatei mit Wrapper-Funktionen (siehe Schema) erstellt. Diese enthält Tracepoints, die beim Starten der Applikation in LD_PRELOAD spezifiziert werden.

Das Funktions-Wrapping von LTTng-UST ist für den Applikations-Code völlig transparent und erfordert keine Neukompilierung. Beim ersten Aufruf schlägt die Wrapper-Funktion die Adresse der Original-Funktion nach und legt sie in einem Funktionszeiger ab (im Bild am Beispiel von malloc gezeigt).

Visualisierung von LTTng-Traces in Tracealyzer

Da LTTng binäre Datendateien ausgibt, wird für die Auswertung ein Tool benötigt. Zwar könnte man die Trace-Daten mit Babeltrace in Textdateien umwandeln, jedoch ist es schwierig, angesichts des enormen Umfangs an Trace-Daten im Textformat den Überblick zu behalten. Deutlich vereinfacht wird die Analyse durch ein Visualisierungs-Tool.

Die schwedische Firma Percepio (Vertrieb in Deutschland, Österreich und der Schweiz durch Embedded Tools) hat unter dem Namen Tracealyzer eine Familie von Trace-Visualisierungstools entwickelt. Tracealyzer for Linux ist für die Visualisierung von LTTng-Trace-Daten konzipiert und stellt mehrere grafische Ansichten zur Verfügung. Tracealyzer erkennt und markiert Abhängigkeiten zwischen zusammenhängenden Ereignissen in den Trace-Daten (z. B. das Senden und Empfangen eines Semaphorsignals). Durch das Markieren solcher Abhängigkeiten lässt sich das Verhalten des Betriebssystems leichter verstehen (weshalb etwa einige Threads blockiert und andere getriggert werden).

Die Haupt-Traceansicht von Tracealyzer stellt die Ereignisse als farbcodierte Labels entlang einer Zeitachse dar. Die Labels lassen sich auf verschiedene Weise filtern und werden automatisch so ausgerichtet, dass es nicht zu Überschneidungen kommt. Die Hintergrundfarbe der Labels kennzeichnet den Status und den Typ der Verarbeitung (siehe Bild 1). So werden rote Labels für Systemaufrufe verwendet, die den aufrufenden Thread anhalten. Anwenderspezifische Applikations-Ereignisse aus LTTng-UST lassen sich so konfigurieren, dass sie als Dienstaufrufe (wie malloc) oder als Anwender-Ereignisse (generische Debug-Meldungen) erscheinen.

Neben der Hauptansicht gibt es mehr als 20 weitere Ansichten, die Auskunft über die CPU-Auslastung, Reaktionszeiten, Kernel-Blockierungen, die Scheduling-Intensität, Kernel-Aufrufe und andere Ereignisse geben. Anwenderspezifische Ereignisse können separat in einer Text-Log-Ansicht dargestellt werden, und die Argumente von Anwender-Ereignissen lassen sich als Signal-Plots visualisieren.

Sämtliche Ansichten sind zudem miteinander verknüpft: durch Anklicken einer Task, eines Ereignisses oder eines Datenpunkts erscheint somit eine neue Ansicht, in der das angeklickte Element markiert ist. Diese Verknüpfung erleichtert den Umgang mit mehreren Ansichten bei der Untersuchung eines bestimmten Intervalls im Trace.

* Johan Kraft ist Gründer und CEO der schwedischen Softwarefirma Percepio, die sich auf die Visualisierung von Tracing-Ergebnissen spezialisiert hat.

(ID:42675792)