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