>> Title << >> Preface << >> Contents << >> Bibliography <<
Es wurde bereits an dem Anwendungsbeispiel in Kapitel 4.2 gezeigt, dass die an die RACR-NET-Schnittstelle gesetzten funktionalen Anforderungen von der vorgestellten Implementierung erfüllt werden, insbesondere bezüglich einer benutzerfreundlichen objektorientierten Schnittstelle. Der Zugriff auf Spezifikation und AST-Knoten erfolgt ausschließlich über Instanzen von Racr.Specification
beziehungsweise Racr.AstNode
und alle Aufrufe von RACR sind in Methoden dieser Stellvertreter-Objekte gekapselt.
Im Folgenden soll gezeigt werden, dass RACR-NET nicht nur benutzerfreundlich, sondern auch korrekt und effizient ist.
Zum Testen von RACR-NET wurde eine umfangreiche, bereits existierende Anwendung, die den wesentlichen Funktionsumfang RACRs abdeckt, in C# reimplementiert. Das Beispiel ist eine Lösung des Language Workbench Challenge 2013 [Erdweg2013], dessen Aufgabe darin bestand, eine domänenspezifische Sprache zu schaffen, mittels welcher interaktive Fragebögen zur Datenerfassung auf einfache Weise beschrieben und ausgewertet werden können. Die Anwendung bedient sich aller Mechanismen RACRs mit Ausnahme von komplexeren Graphersetzungen. Um auch die funktionelle Korrektheit der Graphersetzungsmethoden sicherzustellen, wurden diese in einem eigenen NUnit-Test erfasst.
Die Erzeugung von Adapter-Objekten und der indirekte Zugriff auf RACRs Funktionalitäten über jene Objekte erzeugt einen Laufzeit-Overhead. Dieser wurde für eine RACR-Anwendung ermittelt, die im Folgenden beschrieben wird.
Unter Verwendung der in Kapitel 4.2 gegebenen Sprachspezifikation wurden arithmetische Ausdrücke für verschiedene Konstantenbelegungen berechnet. Um die Ausführungszeiten des C#-Programms gegenüber denen des Scheme-Programms vergleichen zu können, wurde die Anwendung in beiden Sprachen, Scheme (unter der Verwendung der RACR Scheme-Bibliothek) und C# (mittels der objektorientierten Schnittstelle), implementiert. Der Laufzeit-Overhead ist die Differenz der Ausführungszeiten beider Implementierungen in IronScheme. Die den zu berechnenden Ausdruck repräsentierenden ASTs wurden mithilfe eines Python-Skripts generiert und enthalten jeweils 5.000, 10.000 und 20.000 Binär-Operationen und ebenso viele Blatt-Knoten. Die Hälfte der Blatt-Knoten sind Konstanten, wobei insgesamt 26 verschiedene Konstanten-Definitionen benutzt werden.
Operationen | Evals | Rewrites | C# | IronScheme | Racket |
---|---|---|---|---|---|
5.000 | 1 | 0 | 1,43 | 1,36 | 0,45 |
10.000 | 1 | 0 | 2,93 | 2,92 | 0,98 |
20.000 | 1 | 0 | 6,21 | 6,03 | 2,17 |
5.000 | 1.000 | 1.000 | 72,44 | 72,20 | 24,31 |
10.000 | 1.000 | 1.000 | 150,14 | 145,81 | 71,08 |
20.000 | 1.000 | 1.000 | 330,58 | 316,97 | 217,79 |
Tabelle 5.1: Performance-Messungen (Laufzeit der letzten drei Spalten in Sekunden)
Alle Läufe wurden auf einem Rechner mit einem Intel Core i5-3350P Vier-Kern-Prozessor und 16 GB RAM unter Windows 8.1 gemessen. Das verwendete IronScheme Release war 115404, 32-Bit, vom 29. Oktober 2015. Als .NET VM wurde das Microsoft .NET Framework 4.0 verwendet. Von zwanzig Messungen pro Lauf wurde die beste Zeit genommen. Tabelle 5.1 zeigt die Messergebnisse für eine einzelne Berechnung des Attributs 'Eval
(Zeile 1 bis 3). Ferner wurden innerhalb einer Schleife jeweils der Wert einer Konstanten in deren Definition modifiziert und anschließend 'Eval
für den Wurzel-Knoten ausgewertet (Zeile 4 bis 6).
Um die Performance von IronScheme gegenüber anderen Scheme-VMs abschätzen zu können, wurden die Tests ebenfalls auf der Racket Scheme-VM durchgeführt (Racket Version 6.2). Zur Erfassung des durch die objektorientierte Schnittstelle generierten Overheads sind jedoch lediglich die für IronScheme gemessenen Ausführungszeiten relevant.
Die Messungen ergeben, dass die RACR-NET-Lösung erwartungsgemäß etwas langsamer ausführt als eine reine Scheme-Lösung. Der Performance-Overhead beträgt für 20.000 Knoten und 1.000 Auswertungen und Graphersetzungen circa 4,3% und ist damit durchaus akzeptabel. Des Weiteren wird ersichtlich, dass IronScheme zwar langsamer ist als Racket, der Faktor jedoch keine Größenordnung beträgt (Im Gegensatz zu Racket ist IronScheme ein Ein-Man-Projekt, bei dem Performance nicht im Mittelpunkt steht).
Bei dem gewählten Beispiel handelt es sich um eine Referenzattributgrammatik, deren Attributsgleichungen auf simple Addition und Multiplikation zweier Fließkommazahlen beschränkt sind. Es bleibt daher zu untersuchen, wie stark der Geschwindigkeitsvorteil von C# gegenüber IronScheme in komplexeren Gleichungen zum Tragen kommt und, ob dieser den Overhead von RACR-NET wohl möglich kompensiert.
Die Messergebnisse unterstreichen die Vorteile der RAG-gesteuerten Graphersetzung. Eine einmalige Auswertung von 'Eval
ist relativ teuer (1,43 Sekunden mittels RACR-NET), weil anfangs alle Attribut-Caches leer sind und so 'Eval
erst für jeden Teilausdruck berechnet werden muss. Da die vorgenommenen Graphersetzungen nur jeweils einen Anteil der zuvor berechneten Attributwerte invalidieren, begünstigt die inkrementelle Auswertung alle nachträglichen Berechnungen. Eintausend Berechnungen mit intermediären Graphersetzungen benötigen 330,58 Sekunden – nur circa 20% der tausendfachen Dauer der initiale Berechnung.