Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Ein Testverfahren für optimierende Codegeneratoren INGO STÜRMER, MIRKO CONRAD1 1 DaimlerChrysler AG, Forschung und Technologie, Alt-Moabit 96a, 10559 Berlin (e-mail: stuermer@acm.org, Mirko.Conrad@DaimlerChrysler.com) Hinweis: Die Originalversion dieses Artikels ist unter DOI: 10.1007/s00450-005-0189-5 erhältlich! Zusammenfassung: Die im Rahmen der Modell-basierten Entwicklung eingebetteter Steuerungs- und Regelungssoftware eingesetzten optimierenden Codegeneratoren müssen einer intensiven Qualitätssicherung unterzogen werden. Dem Einsatz von Testsuiten kommt dabei eine zentrale Rolle zu. Der Beitrag beschreibt den Aufbau einer modularen Testsuite für Codegeneratoren und schlägt einen Testansatz vor, der eine systematische Prüfung der vom Codegenerator angewendeten Optimierungstechniken ermöglicht. 1 Einführung Als Reaktion auf die gestiegenen Herausforderungen bei der Entwicklung eingebetteter Software im Kraftfahrzeug [6] vollzieht sich seit Mitte der 1990er Jahre ein Paradigmenwechsel, der durch den Übergang von der klassischen Programmentwicklung hin zu Modell-basierten Techniken gekennzeichnet ist [19], [18], [11], [27]. Kennzeichnend für die Modell-basierte Entwicklung ist die frühzeitige Beschreibung der eingebetteten Software durch ausführbare Modelle unter Verwendung von Funktionsblockdiagrammen und erweiterten Zustandsautomaten. Ein für diese Zwecke gebräuchliches Modellierungs- und Simulationswerkzeug, das sowohl im akademischen als auch im industriellen Umfeld weite Verbreitung gefunden hat, ist MATLAB/Simulink/Stateflow1 [15]. Während MATLAB als Basisumgebung fungiert, stellen die Erweiterungen Simulink und Stateflow graphische Editoren und Simulatoren für Blockschaltbilder bzw. Statecharts zur Verfügung. Derartige graphische Modelle dienen als Basis aller weiteren konstruktiven Entwicklungsschritte bis hin zur Implementierung der zu realisierenden Software. Während in der Vergangenheit eine manuelle Implementierung der Software die Regel war, existieren mittlerweile Codegeneratoren, wie z.B. TargetLink [25] oder der Real-Time Workshop [23], die automatisch effizienten Code direkt aus dem Softwaremodell generieren können (Modellbasierte Codegenerierung). Bei einem Codegenerator handelt es sich prinzipiell um einen Compiler, der eine Quellsprache (hier eine graphische Modellierungssprache wie Simulink/Stateflow) in eine Zielsprache (hier eine prozedurale Programmiersprache wie C oder ADA) übersetzt. In der automobilen Softwareentwicklung ist dabei der konsequente Einsatz 1 Weltweit ist von ca 100.000 Simulink/Stateflow-Anwendern auszugehen. von Optimierungstechniken durch die beschränkte Speicherkapazität auf der Zielhardware unverzichtbar. Die Modell-basierte Codegenerierung ermöglicht deutliche Effizienzgewinne bei der Implementierung der Modelle. Voraussetzung hierfür ist aber, dass der Codegenerator bei der Übersetzung bereits getesteter Modelle keine Fehler in die Software einbringt. Eine mögliche Fehlerquelle sind dabei eben jene Optimierungen, die die notwendige Effizienz des generierten Codes im Hinblick auf Ausführungsgeschwindigkeit und Speicherverbrauch gewährleisten. Codegeneratoren haben aber noch nicht die Betriebsbewährtheit von C- und ADA Compilern erreicht und müssen daher einer intensiven Qualitätssicherung durch Testen unterzogen werden. Der vorliegende Beitrag beschreibt ein praxisorientiertes und systematisches Testverfahren für Codegenerator-Optimierungen. Die Codegenerierung wird dabei über das erfolgreiche Durchlaufen einer Testsuite abgesichert. Vorgestellt werden sowohl der generelle Aufbau einer solchen Testsuite, als auch ein Ansatz zur systematischen Erzeugung von Testfällen. Letztere prüfen die vom Codegenerator verwendeten Optimierungen. Der weitere Aufbau des Artikels ist wie folgt gegliedert: Kapitel 2 führt in die Modell-basierte Codegenerierung, Kapitel 3 in die dabei verwendeten Optimierungstechniken ein. In Kapitel 4 wird der generelle Ansatz zum Test von Codegeneratoren erläutert. Dieser wird in Kapitel 5 am Beispiel des Tests von Optimierungen umgesetzt. Kapitel 6 beschließt den Beitrag mit einer Zusammenfassung. 2 Modell-basierte Codegenerierung Die Modell-basierte Entwicklung eingebetteter Steuerungs- und Regelungssoftware ist durch den durchgehenden Einsatz ausführbarer Modelle in allen Entwicklungsphasen charakterisiert [11]. Die zu realisierende Funktion tritt dabei in verschiedenen, aufeinander aufbauenden Repräsentationsformen auf (Modellevolution): Ein (physikalisches) Funktionsmodell wird dabei um Realisierungsaspekte ergänzt, überarbeitet und schließlich mittels Codegeneratoren in optimierten Programmcode einer imperativen Programmiersprache (meist C) überführt. Der generierte Code kann auf verschiedenen Ausführungsplattformen (Host-PC, Evaluation Bord) analysiert bzw. getestet und anschließend in das eingebettete System (im Automobilbereich auch elektronisches Steuergerät (ECU) genannt) integriert werden (Abb. 1). Am Anfang der Modellevolution steht häufig ein sog. physikalisches Modell2. Es definiert die Schnittstelle der zu entwickelnden Softwarefunktion und beschreibt deren Außenverhalten in ausführbarer Form. Insbesondere enthält es bereits die notwendigen Steuerungs- und Regelalgorithmen. Das physikalische Modell kann nach beliebigen Kriterien strukturiert sein. Zweck des physikalischen Modells ist es, die zu entwickelnden Algorithmen darzustellen, ohne dabei bereits Realisierungsdetails beachten zu müssen. Die Beschreibung der Algorithmen erfolgt daher üblicherweise unter Verwendung von Gleitkomma-Arithmetik. Aus Effizienzgründen und aufgrund der Tatsache, dass ggf. von der Zielplattform abstrahiert wurde, kann das physikalische Modell nicht direkt als Basis für die Ableitung von Code für Seriensteuergeräte dienen. Daher wird es zuerst unter Realisierungsaspekten überarbeitet (z.B. Aufteilung von Funktionsteilen auf Tasks) und um notwendige Implementierungsdetails (z.B. Datentypen und Skalierungsinformationen) angereichert. In der Regel wird dabei die Gleitkomma-Arithmetik des physikalischen Modells durch Festkomma-Arithmetik ersetzt. Ergebnis der Überarbeitung ist ein Implementierungsmodell, das alle für die Codegenerierung notwendigen Informationen enthält und die Erzeugung von effizientem C-Code erlaubt. Optimierender Codegenerator Loader Compiler / Linker Host 100110 010010 111010 Target Modell *.mdl C Code *.c; *.h Maschinencode *.obj Abbildung 1: Prinzip der automatischen Codegenerierung Die automatische Codegenerierung stellt einen der Hauptvorteile der Modell-basierten Entwicklung dar. So führt die Verwendung eines Codegenerators zu einer deutlichen Effizienzsteigerung in der Implementierungsphase der Software. Einzelne Studien belegen eine erreichbare Verkürzung der Softwareentwicklungszeit von bis zu 20% durch den Einsatz der Codegenerierung [27]. Wenn zusätzlich der Verifikationsprozess auf Codeebene reduziert werden kann, werden Einsparungen bis zu 50% erwartet. Diese Zahlen decken sich mit Aussagen anderer Nutzer, so dass von erreichbaren Effizienzsteigerungen von 20-50% ausgegangen werden kann. Die Autoren weisen jedoch darauf hin, dass auf die Prüfung des generierten Codes nicht gänzlich verzichtet werden kann, da durch ungeeignete Modellierung oder falsche Anwendung des Codegenerators ungewollt Fehler in den Code eingebracht werden können, obwohl der Codegenerator korrekt funktioniert. 2 Der Begriff physikalisches Modell wird hier nicht für die physikalische Abbildung der Umgebung im Streckenmodell, sondern für ein frühes Funktionsmodell verwendet. Der Einsatz der Codegenerierung wird darüber hinaus mit einer hohen Reife des Softwareentwicklungsprozesses assoziiert: So hat z.B. das japanische MathWorks Advisory Board (JMAAB) fünf Reifegradstufen für die Modell-basierte Entwicklung definiert. Die beiden höchsten Stufen können danach nur erreicht werden, wenn eine automatische Seriencodegenerierung erfolgt. 3 Codegenerator Optimierungstechniken Soll Codegenerierung bei der Entwicklung eingebetteter Software zum Einsatz kommen, sind die Entwickler speziell im Automobilbereich auf die großflächige Anwendung von Optimierungstechniken angewiesen, da die Software auf einer Hardware mit streng limitierten Ressourcen integriert wird. Zu den typischen Optimierungstechniken zählen: ‰ Standardoptimierungen: Anwendung von bekannten Techniken aus dem Übersetzerbau, wie z.B. Konstanten Faltung (constant folding), Entfernung von redundanten oder nicht erreichbaren Code (dead-path elimination) [17], ‰ Interblock-Optimierungen: Kombination bzw. Verschmelzung verschiedener SimulinkBlöcke oder Stateflow-Anteile zu effizienten Codemustern [8], ‰ Einsatz von Codemuster-Bibliotheken: Diese ersetzen spezifischer Modellteile (Einzelblöcke oder Modellpattern) durch vorgefertigte, in Bibliotheken abgelegte Codefragmente (z.B. in Maschinensprache). Auf diese Weise können für eine bestimmte Kombination aus Compiler und Zielprozessor besonders effiziente Pattern ausgewählt werden [24]. Beispiel Der Einsatz von Optimierungen kann anhand eines einfachen Implementierungsmodells mit zwei Switch-Blöcken veranschaulicht werden. Die Funktionsweise eines Switch-Blocks ist in Abb. 2 (links) dargestellt. Während unoptimierter Code für das Beispiel in Abb. 2 (rechts) aus zwei verschachtelten If-Then-Else-Statements bestehen würde, kann ein optimierender Codegenerator einige Vereinfachungen vornehmen: Da der mittlere Eingang (control) des ersten Switch-Blocks (Switch1) konstant 0 und damit immer kleiner als der interne Schwellwert τ=0.5 ist, wird stets der untere Eingang, also InPort1, durchgeleitet. Das If-Statement (Switch1) kann wegoptimiert werden. Auf diese Weise liegt der Wert von InPort1 stets am oberen und am unteren Eingang des zweiten Switch-Blocks an und wird unabhängig vom Wert des Steuereingangs dieses Switch-Blocks weiterpropagiert. Ein optimierender Codegenerator könnte das Beispielmodell demnach durch eine einfache Zuweisung der Form OutPort = InPort1 realisieren. Abbildung 2: Optimierbares Simulink-Modell mit zwei Switch-Blöcken 4 Test von Codegeneratoren Trotz der erreichten Fortschritte im Bereich der formalen Methoden stellt der dynamische Test weiterhin eines der wichtigsten Verfahren für die Sicherung der Softwarequalität dar. Da ein vollständiger Test nicht realisierbar ist, muss aus der Menge der möglichen Testfälle eine Teilmenge ausgewählt werden, die eine umfassende Prüfung des Testobjektes gewährleistet. Die Auswahl der Testfälle entscheidet dabei über Umfang und Qualität des gesamten Tests. Die zentrale Herausforderung beim Test von Codegeneratoren besteht demnach in der systematischen Auswahl einer handhabbar kleinen Menge von Testfällen, die geeignet erscheinen, vorhandene Fehler im Codegenerator mit hoher Wahrscheinlichkeit aufzudecken (Fehler-sensitive Testfälle). Bei oberflächlicher Betrachtung bestehen Testfälle für Codegeneratoren aus gültigen und ungültigen Testmodellen (hier: Simulink/Stateflow-Modelle). Der Test des Codegenerators gilt als erfolgreich, wenn: ‰ ungültige Testmodelle vom Codegenerator zurückgewiesen, d.h. nicht in C Code übersetzt werden (ungültige Testfälle) und ‰ gültige Testmodelle durch den Codegenerator übersetzt werden und sich der daraus generierte Code hinreichend ähnlich zum Modell verhält (gültige Testfälle). Für die ungültigen Testfälle ist diese Sichtweise ausreichend, da die Testmodelle zurückgewiesen, nicht aber ausgeführt werden müssen. Für die gültigen Testfälle stellt sich die Situation komplexer dar: Um die hinreichende Verhaltensähnlichkeit von Testmodell und daraus generiertem Code zu überprüfen, müssen beide mit den gleichen Eingabedaten (Testvektoren) stimuliert und die zugehörigen Ergebnisse (Testoutput) von Modell und Code miteinander vergleichen werden. Gültige Testfälle für Codegeneratoren bestehen also im allgemeinen Fall aus graphischen Modellen (Testfälle 1. Ordnung) und aus geeigneten Eingabedaten (Testfälle 2. Ordnung), mit denen diese Modelle stimuliert werden müssen. Beide Aspekte sind beim Aufbau einer Test- suite für Codegeneratoren zu berücksichtigen, d.h. es sind sowohl Testfälle 1. Ordnung (Testmodelle) als auch die zugehörigen Testfälle 2. Ordnung (Testvektoren) bereitzustellen. Da die betrachteten graphischen Modelle innere Zustände besitzen können, ist es nicht ausreichend, sie kurzzeitig mit konstanten Werten zu stimulieren. Vielmehr können Testvektoren und Testergebnisse zeitveränderliche Größen sein. Basierend auf diesen Überlegungen ergibt sich der in Abb. 3 dargestellte prinzipielle Ansatz für den Test eines Codegenerators. Ob die Übersetzung der Modelle in C-Code korrekt funktioniert, wird dabei durch einen Vergleich zwischen den Testmodellen und dem daraus generierten Code (kurz: Autocode) sichergestellt. Diese Vorgehensweise bezeichnet man auch als Back-to-Back Test. Testmodell und Autocode werden hierfür mit denselben Testvektoren stimuliert und die jeweiligen Systemreaktionen im Rahmen der Testauswertung auf hinreichende Ähnlichkeit geprüft. Codegeneratortestsuite Testfallerzeugung für Testsuitemodul i (Testfälle 1. Ordnung) (Testfälle 2. Ordnung) Testvektorgenerierung Testmodellerzeugung Testmodell Testvektor i(t) Testoutput o(t)Mod Testauswertung Modell 1 ? Codegenerator 1 C Code ≈ ; : Testoutput o(t)Code Testdurchführung/-management Abbildung 3: Codegeneratortest - Grundprinzip Bei der Realisierung des Testansatzes sind neben den beiden Aspekten der Testfallerzeugung (Abb. 3, Testmodellerzeugung und Testvektorgenerierung) auch geeignete Verfahren für den robusten Vergleich der Testoutputs von Modell und Code (Abb. 3, Testauswertung) sowie eine leistungsfähige Werkzeugunterstützung für die Verwaltung und Ausführung der Tests (Abb. 3, Testdurchführung/ -management) bereitzustellen. Um einen modularen Aufbau der Testsuite zu ermöglichen, sollten Testfallerzeugung und Testdurchführung bzw. -management getrennt voneinander erfolgen. Neben dem in diesem Beitrag vorgestellten systematischen Test von Optimierungen erfordert eine umfassende Absicherung eines Modell-basierten Codegenerators weitere Testsuitemodu- le, z.B. für den intensiven Test der Elementarblöcke/-konstrukte von Simulink/Stateflow oder für die Einbeziehung komplexer Modelle aus dem Anwendungskontext (siehe auch [31] für eine Übersicht über die benötigten Module einer Testsuite für Codegeneratoren). 5 Systematischer Test von Optimierungen Der systematische Test von Optimierungen kann gemäß dem in Kapitel 4 vorgestellten Grundprinzip erfolgen. Dabei ergeben sich die in Abb. 4 dargestellten Schritte, s.a. [21]. C B Testvektor Optimierungsregel Testmodell n n 1 A 1 r RHS LHS Testvektorgenerator Modellgenerator Reactis, ET-Tool ModeSSa Testfallerzeugung Testmodell r,x Testoutput o(t)r,x,y,Mod Testvektor i(t)r,x,y Modell •MIL E 1 ? Codegenerator TargetLink D 1 ≈ ; : Testoutput o(t)r,x,y,Code Signalvergleicher MEval, MTest Back-to-back Testumgebung MTest C Code •SIL/PIL Testdurchführung/-management Abbildung 4: Codegeneratortest – Systematischer Test der Optimierungen 5.1 Testfallerzeugung Ausgangspunkt für die Bestimmung geeigneter Testmodelle ist eine informelle, verbale Spezifikation einer Optimierungsregel r des Codegenerators, die z.B. durch den Hersteller des Codegenerators bereitgestellt wird. Die hierauf aufbauenden, zur Testfallerzeugung gehörenden Schritte, werden im Folgenden erläutert. Formalisierung der Optimierungsregeln (A) Die zu testende Codegenerator-Transformationsregel (z.B. eine Interblock-Optimierung) wird als Graphersetzungsregel (auch Graphtransformationsregel vgl. [29]) formalisiert. Eine solche Darstellung ermöglicht ein klares Verständnis darüber, wie Muster des Eingabegraphen (Modell) ausgetauscht, ergänzt oder gelöscht und in Code transformiert werden. Die Verwendung von Graphtransformationsregeln ist hierbei nicht ungewöhnlich, stellen sie doch eine allgemein akzeptierte und formale Spezifikationstechnik für Compiler bzw. Codegeneratoren dar [2]. Beispiel Abb. 5 zeigt die eine vereinfachte Variante der Graphtransformationsregel für die Optimierung von If-Statements, die bei der Übersetzung von Switch-Blöcken zur Anwendung kommt. Der Switch-Block mit dem Schwellwert τ wird dabei durch den Knoten D repräsentiert, seine Eingänge durch die Knoten A bis C und der Ausgang durch den Knoten E. Kann auf Grund vorangegangener Berechnungen festgestellt werden, dass der Wert des Steuereingangs B stets größer gleich oder stets kleiner als der Schwellwert τ ist, kann im Code auf die If-Abfrage verzichtet werden. Die sich ergebenden Alternativen werden durch die 3 rechten Regelseiten veranschaulicht. RHS 1 A LHS C RHS 2 In1 A B control B , if C.value always >= τ E D , if C.value always < τ E E then In2 Node Attributes: D.type= switch D.threshold= τ F RHS 3 A If (C >= τ) else E , else B Abbildung 5: Graphtransformationsregel für die Vereinfachung von If-Statements Testmodellerzeugung (B) Die Graphtransformationsregel dient als eine Art "Blaupause" für die Bestimmung der Testmodelle. Zu diesem Zweck wird ihr möglicher Eingaberaum näher betrachtet. Der Eingaberaum definiert sich als die Menge der Graphinstanzen, bei denen die Regel eine Graph Ersetzung durchführen könnte. Diese Menge kann prinzipiell unbegrenzt sein. Daher verwenden wir die Klassifikationsbaum-Methode [5] als unterlagertes Testverfahren, um den Eingaberaum der Graphtransformationsregel systematisch in Äquivalenzklassen zu zerlegen. Eine geeignete Kombination der Äquivalenzklassen zu Testfällen kann automatisiert mit dem Klassifikationsbaum-Editor CTE/XL [14] vorgenommen werden. Die im CTE/XL definierten Tests können als abstrakte Beschreibungen der Testfälle 1. Ordnung, also der Testmodelle aufgefasst werden. Beispiel Abb. 6 oben stellt den Eingaberaum der Graphregel aus Abb. 5 in Form eines Klassifikationsbaums dar. Jeder der drei Eingänge A, B, C des Switch-Blocks (Teilbaum Inputs) kann dabei mit einer Konstanten oder einem variablen Ausdruck verbunden werden. Außerdem können zwei oder gar alle drei Eingänge des Switch-Blocks aus ein und der selben Quelle gespeist werden (Teilbaum EqualSignals). Im unteren Teil von Abb. 6 sind die zugehörigen Testfälle (Testcase 1 … Testcase 40) dargestellt. Testcase 37 (vgl. mit Abb. 7) repräsentiert beispielsweise alle Switch-Blöcke mit drei variablen Eingängen, bei denen die Eingänge A und C aus der selben Quelle gespeist werden. Abbildung 6: Klassifikationsbaum und Kombinationstabelle für die Vereinfachung von If-Statements Die Anzahl der Testfälle, die sich durch die Kombination der gewählten Klassen ergeben, kann schnell anwachsen: Einige hundert Testfälle sind nicht unüblich. Da es aufwendig und fehleranfällig ist, die Modelle manuell auf Basis der abstrakten Testfallbeschreibungen zu erstellen, wurde dieser Schritt automatisiert. Die Instanziierung einer CTE/XLTestfallbeschreibung durch ein konkretes Testmodell erfolgt dabei durch den Testmodellgenerator ModeSSa (Model Generator for Simulink and Stateflow [7]). ModeSSa erzeugt für jeden im CTE/XL beschriebenen Test ein repräsentatives Testmodell. Hierfür wird eine XMLDarstellung des Klassifikationsbaums erstellt und unter Verwendung der Graphtransformationssprache GReAT [10] in eine XML-Darstellung eines dazu passenden Simulink/StateflowModells überführt. Der Transformationsphase folgt die Generierung von ausführbaren Testmodells mit SimEx [22], einem Werkzeug, das die Transformation von XML-Darstellungen in Simulink/Stateflow-Modelle ermöglicht. Beispiel Abb. 7 zeigt das mit ModeSSa erzeugte Implementierungsmodell für Testcase 37. Abbildung 7: Repräsentatives Testmodell für Testcase 37 Die Gesamtheit der so erzeugten Testmodelle ergibt die Testfälle 1. Ordnung, die die Funktionalität des Codegenerators im Hinblick auf die gewählte Optimierungsregel r systematisch abprüfen. Bevor jedoch das Verhalten des Codegenerators überprüft werden kann, benötigen wir passende Eingabedaten (Testfälle 2. Ordnung), um die Modelle zu stimulieren. Testvektorgenerierung (C) Um Aussagen über die Verhaltensähnlichkeit von Modell und Autocode machen zu können, genügt es nicht, bei der Testdurchführung nur einzelne Teile des Modells zu durchlaufen. Vielmehr müssen alle möglichen "Simulationspfade" des gegebenen Testmodells und auch des daraus generierten Codes stimuliert werden. Dies begründet sich daher, dass Modell und Code zwar strukturelle Ähnlichkeiten aufweisen [1] (z.B. Kontrollflusspfade), es aber auch Fälle gibt, in denen Unterschiede in der Struktur auftreten können. So werden z.B. durch Optimierungen Teile des Modells verworfen (diese sind im Code nicht mehr zu finden). Ferner können im Code zusätzliche Strukturelemente generiert werden, wie z.B. eine Kontrollstruk- tur, die bei einer Division einen möglichen Null-Divisor abfängt. Ebenso können Modellpattern wie z.B. Subsysteme mehrfach im Code auftauchen (Inlining) oder zu einzelnen Funktionsaufrufen zusammengefasst werden. Hieraus ergibt sich die Notwendigkeit, jedem Testmodell/Code Testvektoren beizuordnen, die eine ausreichend hohe Strukturüberdeckung auf Modell- wie auf Codeebene gewährleisten (White-box Test). Um diese Aufgabe zu automatisieren, können Testvektorgeneratoren eingesetzt werden. Zunächst werden dafür unter Verwendung eines Testvektorgenerators wie Reactis Tester [20] aus dem Testmodell automatisch Strukturtestdaten erzeugt, die eine ausreichend hohe Modellüberdeckung erwarten lassen. Aufgrund der strukturellen Ähnlichkeiten zwischen Modell und Autocode kann in der Regel davon ausgegangen werden, dass diese, wenn sie zum Test des Autocodes verwendet werden, auch zu einer ähnlich hohen Codeabdeckung führen. Sollten wegen der oben angeführten Fälle strukturelle Unterschiede auftreten, müssen fehlende Testvektoren auf Codeebene ggf. ergänzt werden. Hierfür kann z.B. das Evolutionäre Testtool ET [28] eingesetzt werden. Beispiel Eine 300ms dauernde Stimulation von Input1 mit i1(t)37.1=t und Input2 mit ⎧0 , 0.0 ≤ t < 0.1 ⎪1 ⎩ , 0.2 ≤ t ≤ 0.3 i2(t)37.1= ⎪⎨0.5 , 0.1 ≤ t < 0.2 lässt eine vollständige Strukturüberdeckung auf Modellebene erwarten. Zusätzlich wird in (D) die mit diesen Testvektoren tatsächlich erreichte Überdeckung auf Modell- und auf Codeebene gemessen. Ist die erreichte Überdeckung auf Modell- oder Codeebene unzureichend, ist manuell zu prüfen, ob Testvektoren ergänzt werden müssen, oder ob es sich um tatsächlich unerreichbare Strukturelemente handelt. Die Wahl der Überdeckungsmaße auf Modell- und Codeebene erfolgt in Abhängigkeit von der Kritikalität der Anwendung. Für eine Übersicht verschiedener Modell- und Codeüberdeckungsmaße siehe [1]. Die Schritte (A) bis (C) werden für alle Optimierungsregeln des Codegenerators durchgeführt. Auf diese Weise entsteht mit dem Modul zum systematischen Test der Optimierungen ein zentraler Baustein einer umfassenden Testsuite für Codegeneratoren. 5.2 Testdurchführung und -management Die Testsuitekomponente zum systematischen Test von Optimierungsregeln kann ebenso wie andere Module der Codegeneratortestsuite in die Modell-basierte Testumgebung MTest [12], [16] importiert und dort ausgeführt werden. Beispiel: Abb. 8 zeigt die zur If-Statement-Optimierung gehörenden Teile der Codegenerator Testsuite in MTest. Für jeden im Klassifikationsbaum definierten Testfall (vgl. Abb. 6: Testcase x) findet sich ein Simulink-Modell (switchSystem_x), sowie die zugehörigen Testvektoren (TestData) und Testergebnisse (Testoutput bzw. OutputData). … Testmodell switch, 37 Testvektor i(t)switch,37,1 Testoutput o(t)switch,37,1,Mod Testoutput o(t)switch.37.1,Code Abbildung 8: Teil der Optimierungstestsuite in MTest Back-to-back-Test von Modell und Code (D) Die vorhandenen Tests können nun einzeln oder im Batchbetrieb ausgeführt werden. Zunächst werden die Modelle und der daraus erzeugte Code nacheinander mit den gleichen Testvektoren stimuliert. Dabei werden die Testoutputs von Modell und Code, sowie die erreichten Modell- und Codeüberdeckungen von der Testumgebung protokolliert. Je nach Anwendungszweck kann der zum Vergleich verwendete C-Code auf dem Entwicklungsrechner (Software-in-the-Loop Test, SIL) auf einer zielnahen Hardware (Processor-inthe-Loop Test, PIL) oder auf beiden Plattformen ausgeführt werden. Testauswertung (E): Um Aussagen zur Verhaltensähnlichkeit von Modell und Code treffen zu können, sind die Systemreaktionen von Modell- und Code miteinander zu vergleichen. Für jeden Output ist hierbei ein Vergleich zeitveränderlicher Signale erforderlich. Dieser Vergleich ist nicht so trivial, wie er auf den ersten Blick erscheint: Während die Simulation des Modells typischerweise unter Verwendung von Gleitkommaarithmetik erfolgt, handelt es sich beim generierten Code aus Effizienzgründen i.d.R. um Testkomma-Code (siehe [12] für Informationen zum Unterschied von Fest- und Gleitkommaarithmetik). D.h. Modell und Code verwenden unterschiedliche Datentypen und Genauigkeiten. Darüber hinaus sind die Ausführungsgeschwindigkeiten der verschiedenen Ausführungsplattformen nicht notwendigerweise identisch. Aufgrund dieser Sachverhalte ist es nicht zielführend, absolute Gleichheit (Identität) zwischen den Testoutputs von Modell und Code zu fordern. Vielmehr muss zwischen beiden Signalen eine geeignete Ähnlichkeitsrelation bestehen. In einfachen Fällen genügt es, die symmetrische absolute Differenz der Abtastpunkte von o(t)r,x,y,Mod und o(t)r,x,y,Code zu berechnen und anschließend die über alle Abtastpunkte bestimmte maximale Abweichung zu ermitteln. Beide Signale sind ähnlich, wenn die derart ermittelte Abweichung kleiner als eine vorgegebene Akzeptanzschwelle ist, die in Abhängigkeit von der Quantisierungsgenauigkeit (Auflösung) des betrachteten Outputs gewählt wird. Für komplexere Fälle bietet sich eine Vorverarbeitung mit dem in MEval [30] implementierten Differenzmatrixverfahren [3], [33] mit anschließender Differenzbildung an. Diese Vorgehensweise ermöglicht die getrennte Analyse von zeitlichen Abweichungen und Abweichungen im Wertebereich und damit die Tolerierung definierter zeitlicher Abweichungen. Über eine geeignete Parametrierung kann auch hier die Akzeptanzschwelle angepasst werden. Beispiel In Abb. 9 sind die Systemreaktionen von Modell und Code (SIL) übereinander geplottet, Abb. 10 zeigt die skalierungsbedingt auftretenden Differenzen. Da diese stets kleiner als die vorgegebene zulässige Abweichung sind, ist die Verhaltensähnlichkeit von Modell und Code gegeben, d.h. der abgebildete Test war erfolgreich. Testoutput o(t)switch,37,1,Mod Testoutput o(t)switch.37.1,Code Abbildung 9: Outputdaten Testoutput o(t)switch,37,1,Code -Testoutput o(t)switch.37.1,Mod Abbildung 10: Signalvergleich Sind alle Outputsignalpaare eines Testmodells zueinander ähnlich ist dies ein Indiz dafür, dass der Codegenerator und die weiteren benutzten Werkzeuge (z.B. Compiler, Linker) für diesen Testfall korrekt arbeiten. Eine Unähnlichkeit bei einem oder mehreren Signalpaaren kann mehrere Ursachen haben. Mögliche Gründe sind eine fehlerhafte Implementierung des Codegenerators, ein Problem mit einem der anderen involvierten Werkzeuge, ein fehlerhaft erzeugtes Testmodell oder an einer unvollständigen bzw. fehlerhaften Spezifikation der Optimierung (unzulässige Graphtransformation). Die entsprechenden Fehlerfälle müssen manuell untersucht werden. 6 Zusammenfassung In vorliegenden Beitrag wurde ein an den Erfordernissen der Praxis orientiertes Testverfahren für optimierende Codegeneratoren beschrieben. Das Verfahren leistet einen wichtigen Beitrag zur Absicherung der in der Modell-basierten Entwicklung eingebetteter Steuerungs- und Regelungssysteme eingesetzten Codierungswerkzeuge, die die graphische Modellierungssprache Simulink/Stateflow in C-Code umsetzen. Ein wesentlicher Vorteil des Testverfahrens ist das hohe Automatisierungspotential, das insbesondere durch den Modellgenerator ModeSSa gewährleistet wird. Aussagen zur Korrektheit der durch den Codegenerator ausgeführten Transformationen werden dabei durch Back-to-Back-Tests von Ursprungsmodell und daraus generiertem Code gewonnen: Sind die Reaktionen von Modell und Autocode auf Stimulation mit den gleichen Eingaben hinreichend ähnlich, kann für den betrachteten Fall auf eine korrekte Transformation geschlossen werden. Verallgemeinerungen derartiger Aussagen sind möglich, wenn der Funktionsumfang des Codegenerators systematisch durch Testfälle abgedeckt wird, wobei Testfälle immer eine Kombination aus Testmodellen und zugehörigen Testvektoren zur Stimulation sind (Testfälle 1. und 2. Ordnung). Schwerpunkt des vorgestellten Ansatzes ist daher eine Systematik zur Erzeugung von Testfällen für Codegeneratoren. Die Testfälle werden verwendet, um die im Codegenerator implementierten Optimierungen zu überprüfen: In einem ersten Schritt werden aus einer formalen Repräsentation des Eingaberaums einer Optimierung systematisch Simulink/StateflowModelle erzeugt, die bei der Übersetzung in C-Code die betreffende Optimierung auslösen. Für jedes dieser Testmodelle werden in einem zweiten Schritt Testvektoren generiert, die eine Strukturüberdeckung von Testmodell und zugehörigem Autocode gewährleisten. Modell und Code werden dann unter Verwendung dieser Testvektoren einem Back-to-Back-Test unterzogen. Ein robuster Signalvergleich der Systemreaktionen entscheidet dann über die erforderliche Verhaltensähnlichkeit. Das vorgeschlagene Verfahren geht in mehreren Punkten über die in der Literatur vorhandenen Ansätze hinaus (vgl. [32], [4], [26]): Erstens werden die Testmodelle systematisch aus einer formalen Beschreibung der Optimierungen eines Codegenerators abgeleitet. Dies ist eine Erweiterung existierender Ansätze, die Testfälle auf Basis der Grammatik der Eingabesprache erstellen oder von ad-hoc zusammengestellten bzw. auf Erfahrung basierten Mengen von Testmodellen ausgehen. Zweitens werden die erforderlichen Eingaben für diese Testmodelle sowie für den generierten Code auf Basis von White-Box-Überdeckungsmaßen generiert. Die so erreichte hohe strukturelle Überdeckung auf Modell- und Codeebene geht über die Ergebnisse hinaus, die mit manuell erstellten oder zufällig generierten Testdaten (vgl. [Toe99]) erreicht wurden. Drittens erlauben die angewendeten robusten Signalvergleichsverfahren die Tolerierung von Unterschieden zwischen der Ausführung von Modell und Code, die beim Übergang von Gleitkomma- auf Festkommaarithmetik unvermeidbar sind. Der Back-to-Back-Test zwischen Modell und Code erfolgt weitgehend automatisiert in der einer Modell-basierten Testumgebung wie z.B. MTest. Dies sichert die Regressionsfähigkeit der Testsuite und ermöglicht die zeitnahe Überprüfung neuer Versionen oder Konfigurationen des Codegenerators. Die Testfälle zur Prüfung der Optimierungen bilden einen Kernbestandteil einer umfassenden modularen Testsuite für Codegeneratoren. Weitere Module der Testsuite, die auf andere Aspekte der Codegenerierung fokussieren, werden derzeit bei verschiedenen Automobilherstellern und -zulieferern entwickelt. Diese Module der Testsuite können mit denen der Hersteller des Codegenerators (s.a. [9]) zu einer umfassenden Testsuite für Codegeneratoren kombiniert werden. Die Autoren sind der Überzeugung, dass eine solche Testsuite zukünftig eine zentrale Rolle in der anwendungsunabhängigen Absicherung des Einsatzes von Codegeneratoren, z.B. deren Zertifizierung, spielen wird. Referenzen 1. Baresel, A., Conrad, M., Sadeghipour, S., Wegener, J. (2003) The Interplay between Model Coverage and Code Coverage. Proc. 11. Europ. Int. Conf. on Software Testing, Analysis and Review (EuroSTAR 03), Amsterdam (NL). 2. Baldan, P.; König, B.; Stürmer, I. (2004) Generating Test Cases for Code Generators by Unfolding Graph Transformation Systems. Proc. Int. Conf. on Graph Transformation (ICGT'04), LNCS Bd. 3256, S. 194-210. 3. Conrad, M.; Fey, I.; Pohlheim, H. (2003) Automatisierung der Testauswertung für Steuergerätesoftware. Proc. 11. Int Kongress Elektronik im Kraftfahrzeug, VDI-Berichte, Bd. 1789, VDI Verlag, Düsseldorf (D), S. 299-315. 4. Edwards, P.D. (1999) The Use of Automatic Code Generation Tools in the Development of Safety-Related Embedded Systems. Vehicle Electronic Systems, Europ. Conf. and Exhibition, ERA Report #99-0484. 5. Grochtmann, M.; Grimm, K. (1993) Classification Trees for Partition Testing. Software Testing, Verification and Reliability, S. 63-82. 6. Grimm, K. (2005) Software-Technologie im Automobil. In: Liggesmeyer, P., Rombach, D.: Software-Engineering eingebettete Systeme, Spektrum, Verlag S. 299-315. 7. Heck, S. (2005) Entwurf eines Modellgenerators für den systematischen Test optimierender Codegeneratoren. Diplomarbeit, TU Berlin (D). 8. Hanselmann, H., Kiffmeier, U., Köster, L., Meyer, M. (1999) Automatic Generation of Production Quality Code for ECUs. Proc. Embedded Intelligence, Nürnberg (D). 9. Jungmann, J.; Beine, M. (2003) Automatische Code-Generierung für sicherheitskritische Systeme. Automotive Electronics, Heft II. 10. Karsai, G., Agrawal, A., Shi, F., Sprinkle, J. (2003) On the use of Graph Transformation in the Formal Specification of Model Interpreters. Journal of Universal Computer Science, Vol. 9(11), S. 1296-1321. 11. Klein, T., Conrad, M., Fey, I., Grochtmann, M.: Modellbasierte Entwicklung eingebetteter Fahrzeugsoftware bei DaimlerChrysler. Proc. Modellierung 2004, Marburg (D), März 2004, Lecture Notes in Informatics, Vol. P-45, S. 31-41. 12. Lamberg, K., Beine, M., Eschmann, M., Otterbach, R., Conrad, M., Fey, I. (2004) Model-based testing of embedded automotive software using MTest. Proc. SAE World Congress 2004, Detroit (USA), März 2004, SAE technical paper #2004-01-1593. 13. Lapsley, P., Bier, J., Shoham, A., Lee, E. A. (1997) DSP Processor Fundamentals. IEEE Press, New York (USA). 14. Lehmann, E., and Wegener, J. (2000) Test Case Design by Means of the CTE/XL. Proc. 8. Europ. Int. Conf. on Software Testing, Analysis and Review (EuroSTAR '00), Copenhagen (DK). 15. MATLAB/Simulink/Stateflow (Produktinformationen). The MathWorks Inc., www.mathworks.com/products. 16. MTest (Produktinformationen). dSPACE GmbH, www.dspace.de. 17. Muchnick, S. S. (1997) Advanced Compiler Design and Implementation. Morgan Kaufmann, San Francisco (USA). 18. Rau, A. (2003) Model-Based Development of Embedded Automotive Control Systems. Dissertation, Dept. of Computer Science, Universität Tübingen (D). 19. Reinfrank, M. (1994) Modellbasierte Funktionsentwicklung für Motorsteuerungen - Ein Pilotprojekt in der MSREntwicklungsumgebung MESA. Proc. 5. Int. Tagung Elektronik im Kraftfahrzeug, VDI-Berichte, Bd. 1152, VDI Verlag, Düsseldorf (D), S.253ff. 20. Reactis Simulator / Tester (Produktinformationen). Reactive Systems Inc.. www.reactive-systems.com. 21. Stürmer, I.; Conrad, M. (2003) Test Suite Design for Code Generation Tools. Proc. of 18th. Int. IEEE Automated Software Engineering Conference (ASE'03), S. 286-290. 22. SimEx (Produktinformationen). IT power Consultants, www.itpower.de/simex.html. 23. Real-Time Workshop (Produktinformationen). The MathWorks Inc., www.mathworks.com/products. 24. Thomsen, T. (2003) Integration of International Standards for Production Code Generation, Society of Automotive Engineers. SAE technical paper #2003-01-0855. 25. TargetLink (Produktinformaitionen). dSPACE GmbH, www.dspace.de. 26. Toeppe, S., Ranville, S., Bostic, D., Wang, C. (1999) Practical Validation of Model Based Code Generation for Automotive Applications. Proc. of 18. AIAA/IEEE/SAE Digital Avionics System Conference, St. Louis (USA). 27. Ueda, T.; Ohata, A. (2004) Trends of Future Powertrain Development and the Evolution of Powertrain Control Systems. Proc. of 30. Int. Congress on Transportation Electronics (Convergence ‘04), Detroit (USA), SAE #2004-21-0063, S. 439-449. 28. Wegener, J.; Stahmer, H.; Baresel, A. (2001) Evolutionary Test Environment for Automatic Structural Testing. Special Issue of Information and Software Technology, Vol. 43, S. 851-854. 29. Rozenberg, G. (ed.) (1997) Handbook of Graph Grammars and Computing by Graph Transformations Vol.1. World Scientific, 1997. 30. MEval (Produktinformationen). IT power Consultants, www.itpower.de/meval.html. 31. Stürmer, I. (2004) Integration of the Code Generation Approach in the Model-based Development Process by Means of Tool Certification, Journal of Integrated Design and Process Science, Vol. 8 (2), S. 1-11. 32. Bourjawah, A. S., Saleh, K. (1997) Compiler Test Case Generation Methods: A Survey and Assessment, Information and Software Technology, Vol. 39, S. 617-625. 33. Conrad, M., Sadeghipour, S., Wiesbrock, H. (2005) Automatic Evaluation of ECU Software Tests, SAE World Congress 2005, Detroit (US),April 2005, SAE Paper 2005-01-1659. Teile dieses Beitrags und der darin beschriebenen Arbeiten sind im Rahmen des BMBF geförderten Verbundprojekts IMMOS – Integrierte Methodik zur modellbasierten Steuergeräteentwicklung (Förderkennzeichen 01ISC31D) entstanden. www.immos-projekt.de View publication stats