Files
sdes_lab/sdes_skipt_mkdocs/docs/3_grundlagenwissen.md

6.6 KiB

3. Grundlagenwissen

3.1. Echtzeitsysteme

Ein Echtzeitsystem wird nicht durch seine Schnelligkeit definiert, sondern durch das Einhalten von Zeitschranken und damit verbundene Rechtzeitigkeit. Das Ergebnis der Berechnung eines Echtzeitsystems ist nur dann brauchbar, wenn es rechtzeitig vorliegt. Echtzeitanforderungen können in harte und weiche Echtzeitanforderungen unterschieden werden. Entsprechend Ihrer Betitelung sind harte Anforderungen unter allen Umständen einzuhalten, da sonst das Ergebnis des Systems als nicht brauchbar gilt. Als Beispiel hierfür gilt die Auslösung des Airbags im Auto. Weiche Echtzeitanforderungen hingegen werden durch die bei ihrer Verletzung verursachten Kosten definiert. Je stärker die vorgegebene Zeitschranke verletzt wird, desto höher fallen die damit verbundenen Kosten in Form von Rechenzeit oder materiellem Verlust aus. Die Eigenschaft der Gleichzeitigkeit impliziert die korrekte Verarbeitung paralleler Arbeitsabläufe. Als Beispiel kann die Regelung der Lage des im Praktikum verwendeten Roboters gesehen werden, der Bewegungssensordaten und Motorsteuerung gleichzeitig bearbeiten muss. Diese Aufgaben werden in Form von Tasks umgesetzt. Wichtig ist dabei, dass ein höherpriorer Prozess einen niederprioren Prozess verdrängen kann (preemptiv), und dass das System nicht überlastet ist. So wird Vorhersagbarkeit garantiert.

3.2. Debugging

Es gibt nicht nur eine bestimmte Methode des Debuggings, sondern mehrere Möglichkeiten. Sie unterscheiden sich in ihrer Leistungsfähigkeit, dem Anwendungsgebiet, den Kosten, den Anforderungen an die Hardware und auch in der Pinanzahl. Außerdem gibt es große Unterschiede in ihrem Einfluss auf das Zeitverhalten des Debugger (zu debuggendes System). Die einfachste Möglichkeit einen Einblick in ein laufendes Programm zu bekommen, ist die Ausgabe von Variablen zur Laufzeit über eine serielle Schnittstelle. Das Printf Debugging ist simpel und reicht für einfache kleine Programme ohne Taskstruktur und ohne strikte Anforderungen an Echtzeitfähigkeit aus. Die nächst-mächtigere Methode des Debuggings stellt JTAG-Debugging dar. Es ermöglicht die Steuerung des Programmablaufs via Single-Stepping, also das kontrollierte Anhalten des Programms und das Setzen von Halte-, Verfolgungs- und Überwachungspunkten. Außerdem ermöglicht es den vollständigen Lese- und Schreibzugriff auf den Speicher des Programms. Mit diesen Werkzeugen lassen sich einfach Fehler finden und beheben. Problematisch wird es dann, wenn unvorhergesehene Fehler zur Laufzeit auftreten, deren Ursprung und Wirkung im Code entweder zeitlich oder programmierhierarchisch weit auseinander liegen. Die bisher bekannten Debugmethoden können ihre Möglichkeiten aufgrund für den Menschen schwierig erkennbarer Zusammenhänge nicht ausspielen, was die Fehlersuche sehr erschwert. Außerdem ist es auch hier nahezu unmöglich, das Zeitverhalten des Programms umfangreich zu analysieren. An dieser Stelle hilft es Trace-Tools als Debugmethode zu verwenden. Zusätzlich zur Steuerung der CPU wird nun der Programmablauf teilweise oder vollständig aufgezeichnet. Aus diesem kann dann wahlweise auf Assemblerebene bis hin zum Ablauf in der Hochsprache nachvollzogen werden in welcher Reihenfolge das Programm ablief. Diese Daten helfen zu rekonstruieren wo das Programm anders als gewünscht ablief und ermöglichen es den Stand des Programms vor dem Absturz zu betrachten und damit auch eine mögliche Fehlerquelle zurück zuschließen.

3.2.1 Debugging-Prozess

Um Programme zu debuggen, sollte zunächst definiert sein, was ein Fehler ist und wie an ihn herangegangen wird. Der Begriff Fehler ist im Deutschen mehrdeutig belegt und lässt sich mit Hilfe der englischen Begriffe differenzierter betrachten (siehe Abbildung 3.1). Ein Error ist ein nicht korrekt programmierter Code oder eine falsch implementierte Nutzeranforderung. Dieser Error im Programmcode kann einen Fault auslösen. Es kann sich zum Beispiel um einen Speicherüberlauf handeln. Der Fault muss nicht nach außen sichtbar sein. Das extern zu beobachtende Fehlverhalten des Systems wird Failure genannt. Ist ein Failure erkannt worden, muss die Stelle im Quellcode gefunden werden, die den Fault auslöst und den Error beschreibt. Die Ursache des Fault muss analysiert und korrigiert werden. Sollten mehrere Fehlverhalten gleichzeitig auftreten, deren Symptome sich überlagern, kann es vorkommen, dass die Betrachtung eines einzelnen nicht funktionierenden Programmteils alleine nicht zur Lösung des Problems führt. An dieser Stelle kann viel Zeit gespart werden, indem nicht sofort versucht wird herauszufinden was nicht rich- tig arbeitet, sondern was überhaupt funktioniert. Je konsequenter das Programm in modularisierter Form geschrieben wurde, desto einfacher und schneller geht dieser Schritt vonstatten. Es ist möglich Eingabedaten in ihrer Größe oder in ihrem Inhalt zu variieren, um ihren Einfluss auf Fehler zu untersuchen. Es sollten Hypothesen zur Fehlerursache aufgestellt und das Programm systematisch darauf getestet werden. Sofern es sich nicht um triviale Fehler handelt, ist es sinnvoll, das Wissen um die Ursache des Fault festzuhalten, um den Hergang des Problems sowie seine Lösung zu dokumentieren.

3.2.2 Grundlagen des Debuggens eingebetteter Systeme

Debugging in der Softwareentwicklung für Desktopanwendungen ist wesentlich zugänglicher und komfortabler als im Kontext der eingebetteten Systeme. So programmieren die meisten Anwendungsentwickler auf den Systemen, auf denen die von ihnen entwickelte Software später auch ausgeführt wird. Die Steuerung des Programmablaufs, das Betrachten von Variablen und andere Debugwerkzeuge sind ohne große Umwege nutzbar. Um eingebettete Systeme zu programmieren, kommt oft die Technik des Cross-Compilings und des Cross-Debuggings zum Einsatz. Es wird also nicht auf der Zielhardware kompiliert und debuggt, sondern auf einem Anwendungscomputer. Das zu programmierende System hat eventuell nicht ausreichend leistungsfähige Hardware, um ein Anwenderbetriebssystem samt Entwicklungsumgebung auszuführen oder es ist schlicht nicht gewünscht das System zu beeinflussen. Auch die Architektur der Systeme unterscheidet sich für gewöhnlich. Diese Trennung von Entwicklungsplattform und Laufzeitplattform erschwert die Beobachtbarkeit und Steuerbarkeit eingebetteter Systeme und verkompliziert somit deren Debugging. Dennoch ist die Anwendung von Debugging notwendig, weil es unter Umständen zu Fehlern kommt, die erst während der Laufzeit des Systems auftreten, deren Entstehung aus dem Code nicht ersichtlich ist oder das Projekt zu umfangreich ist.

Screenshot Abbildung 3.1.: Entwicklung eines Fehlers: Error->Fault->Failure