Graph Rewrite Systems for Program Optimization Uwe Aßmann

Werbung
Graph Rewrite Systems for Program Optimization
Uwe Aßmann
Universität Karlsruhe
Erschienen in
ACM Transactions on Programming Languages and Systems,
Vol. 22, No.4, Juli 2000, Seiten 583-637
Zusammengefasst von
Tobias Gutzmann
im Rahmen des Seminars
Zwischensprachen und Codegenerierung
am Institut für Innovatives Rechnen und Programmstrukturen (IPD)
Universität Karlsruhe
Karlsruhe,
18. Mai 2005
1
Motivation
Das Implementieren einer Optimierung ist eine zeitaufwendige und fehleranfällige Aufgabe. Weiterhin sind handgeschriebene Optimierungsroutinen auf eine gegebene Zwischensprache zugeschnitten,
müssen folglich für verschiedene Übersetzer individuell implementiert werden. Uwe Aßmann stellt ein
Verfahren auf Basis von Graphersetzung vor, das den Umgang mit den angesprochenen Problemen
vereinfacht. Ziel ist es, die Entwicklungszeit zu verkürzen, die Validierung zu vereinfachen, und die
Wartbarkeit zu verbessern. Dabei ist sein Ansatz nicht an eine bestimmte Zwischensprache gebunden
und somit portabel. Mit Optimix steht eine Implementierung von Aßmanns Verfahren zur Verfügung.
2
Graphersetzung
Graphbasierte Zwischendarstellungen werden zwar schon seit Jahren in modernen Übersetzern eingesetzt, Programmtransformationen auf ihnen werden aber noch in Hochsprachen implementiert, eine
Abstraktion erfolgt nicht. Mit Graphersetzungssystemen werden Optimierungen von der Zwischendarstellung abstrahiert beschrieben.
Aßmanns Ansatz arbeitet mit Σ-Graphen:
Definition Sei Σ eine endliche Menge von Konstanten, den Labels. Σ ist die disjunkte Vereinigung
zweier Mengen ΣN ∪ ΣE , den Knoten- und Kanten-labels. Dann besteht ein (relationaler) Σ-Graph
aus den folgenden Komponenten:
1. N ist eine endliche Menge von Knoten
2. Knoten werden mit Labels aus ΣN durch eine Funktion nlab : N → ΣN markiert. Ein Knoten
mit Label l wird l-Knoten genannt. Die Menge Nl = {n ∈ N |nlab(n) = l} aller l-Knoten bildet
einen Knoten-Wertebereich.
3. Die Kanten E sind eine Familie binärer Relationen E = {El }l∈ΣE , El ⊆ Nl1 ×Nl2 , l ∈ ΣE , l1 , l2 ∈
ΣN . Eine Kante mit Label l wird l-Kante genannt.
Weiterhin sind durch diese Definition implizit mehrere Funktion gegeben, wie z.B. die Funktion elab,
die einer Kante ihr zugehöriges Label zuordnet, sowie die Funktionen source und target, die den
(gerichteten) Kanten ihre zugehörigen Knoten zuordnen.
Zwei Knoten dürfen durch mehrere Kanten verbunden sein, diese müssen jedoch paarweise verschiedene Labels haben. Multigraphen sind also nicht erlaubt. Es ist möglich, das Modell so zu
erweitern, dass Knoten Attribute zugewiesen werden können. Dies entspricht im Allgemeinen einer
Erweiterung des Label-Raumes und wird hier der Einfachheit halber ausgelassen.1
Graphersetzungsregel Eine Graphersetzungsregel r = (L, R) besteht aus einer linken Seite L, die
einen zu überdeckenden Teilgraphen beschreibt, und einer rechten Seite R, die den einzusetzenden
Ersatzgraphen beschreibt. Um auf die Abwesenheit von Teilgraphen prüfen zu können, dürfen in L
negierte Kanten auftreten.2 Eine Regel r ist nun auf einen Σ-Graphen anwendbar, wenn folgende drei
Bedingungen zutreffen:
1. L ohne negierte Kanten muss als Teilgraph im zu untersuchenden Graphen vorkommen.
2. In L vorkommende negierte Kanten dürfen in diesem Teilgraphen nicht vorkommen.
3. Fügt r Kanten zum Graphen hinzu, so muss mindestens eine Kante zwischen zwei bereits im
Graphen befindlichen Knoten hinzugefügt werden, und diese Kante darf im Graphen noch nicht
existieren.
Abbildung 1 zeigt eine Graphersetzungsregel. Die Knoten werden durch ihr Label sowie einer Nummer,
die unveränderte Knoten mit gleichem Label auf der linken und rechten Seite der Regel einander
zuordnen, gekennzeichnet. Weiterhin ist der Name der Regel (Sammle-Ausdrücke-1) angegeben.
1 In
seiner Doktorarbeit untersucht Aßmann attributierte Knoten
Σ-Graph mit negierten Kanten wird als Σ¬ -Graph bezeichnet.
2 Ein
1
Abbildung 1: Graphersetzungsregel
Anmerkungen:
• Der passende Teilgraph wird Redex genannt, die dazugehörigen Knoten und Kanten entsprechend Redex-Knoten bzw. Redex-Kanten.
• Bedingung (3) verhindert, dass eine Regel den Graphen gar nicht oder nur unwesentlich ändert
und somit eine Endlosschleife verursacht.
• Kanten zu zu löschenden Knoten dürfen existieren. Solche Kanten werden versteckte Kanten
genannt. Sie werden bei der Ersetzung gelöscht, es ist nicht möglich, sie an einen anderen Knoten
umzuleiten.
• Das Label eines Knotens kann nicht geändert werden.
• Im zu untersuchenden Graphen dürfen Kanten zwischen Knoten existieren, die in L nicht vorkommen. Solche Kanten werden bei der Ersetzung nicht gelöscht. Somit müssen nicht alle möglichen Kombinationen erlaubter Relationen spezifiziert werden, was zum einen die Anzahl der
benötigten Regeln vergrößern würde, zum anderen würde bei einer Erweiterung des Modells
(z.B. Hinzufügen eines neuen Typs von Relation) die Anpassung aller bereits spezifizierten
Ersetzungsregeln notwendig.
Definition Ein (relationales) Graphersetzungssystem G = (S, Z) besteht aus einer Menge S von
Graphersetzungsregeln und einem Σ-Graphen Z, dem Axiom. Die Menge aller (relationalen) Graphersetzungssysteme wird mit RGRS3 bezeichnet.
3
Terminierung
Eine beliebige Anwendungsreihenfolge der Ersetzungsregeln kann leicht zu einer Endlosschleife führen, z.B. wenn zu einer Regel auch ihre inverse existiert. Allgemein passiert dies, wenn Mengen von
Regeln sich gegenseitig Redexe erzeugen. Weiterhin hat ein Graphersetzungssystem (im Allgemeinen) je nach Anwendungsreihenfolge der Regeln mehrere Normalformen, ist also indeterministisch.
Um diese Probleme zu umgehen, wird eine Ausführungsreihenfolge für die Regeln berechnet. Die
Idee dahinter ist, Regeln in Gruppen (Strata) zusammenzufassen. Dies wird Stratifizierung genannt.4
Grapherweiternde Regeln werden dabei zuerst angewandt, der Graph also größtmöglich „aufgebläht“.
Anschließend werden die Regeln angewandt, die die Menge der Ecken und Kanten verringern. Aßmann merkt an, dass dies meist dem intuitiven Verständnis eines Optimierungsprozesses entspricht:
3 für
engl.: relational graph rewrite systems
Konzept stammt von Datalog
4 dieses
2
Das Hinzufügen von Knoten und Kanten entspricht der vorausgehenden Analyse, das „echte“ Ersetzen
von Teilgraphen der anschließenden Optimierung.
Für bestimmte Arten von Graphersetzungssystemen kann man nun zeigen, dass sie terminieren,
und sogar eine eindeutige Normalform haben, also deterministisch sind. Diese Klassifizierungen von
RGRS werden im folgenden beschrieben.
EARS Regeln eines EARS5 fügen ausschließlich Kanten (Relationen) zwischen bestehenden Knoten
zu einem Graphen hinzu. Ein solches Graphersetzungssystem terminiert offensichtlich in jedem Fall,
da in jedem Iterationsschritt nach Bedingung (3) mindestens eine Kante hinzugefügt wird und die
Menge der Knoten im Graphen endlich ist.
AGRS Eine Obermenge der EARS bilden die AGRS6 . Jede Regel fügt mindestens eine Kante
zwischen zwei Knoten ein, von deren Typ in dieser Regelmenge keine Knoten hinzugefügt werden.
Eine Regelmenge kann damit zwar für sich sich selbst einen neuen Redex herstellen, aber nur endlich
oft. Regeln eines solchen Systems werden Kanten-akkumulierend genannt. Man kann zeigen, dass
Teilgraphen eines AGRS terminieren und somit das Graphersetzungssystem allgemein terminiert.
AGRS werden dazu verwendet, Vorkommnisse von Mustern in einem Graphen zu identifizieren und
mit einem Knoten zu markieren.
SGRS, ESGRS In einem (E)SGRS7 steht nicht das Hinzufügen, sondern das Löschen von Knoten
und Kanten im Vordergrund. Für ein ESGRS wird die Terminierung analog wie bei einem AGRS
bewiesen, nur dass hier bestimmte Kantentypen gelöscht werden. Werden zusätzlich Knoten gelöscht,
ist klar, dass ein Teilgraph spätestens dann terminiert, wenn seine Knotenmenge leer ist.
Definition Die Menge SGRS
S
AGRS wird vollständige Graphersetzungssyteme (XGRS8 ) genannt.
Abhängigkeiten Bevor Regeln zu Gruppen zusammengefasst werden, müssen Abhängigkeiten zwischen ihnen identifiziert werden. Zwei Regeln r1 und r2 können auf verschiedene Arten miteinander in
Konflikt stehen, wobei diese Abhängigkeiten in die Kategorien „paarweise harmlos“, „unterstützend“,
„gefährlich“ und „nicht-stratifizierbar“ einzuordnen sind. Beispiele für die erste Kategorie sind Regeln,
die beide auf die Anwesenheit (bzw. bei negierten Kanten Abwesenheit) von Teilgraphen prüfen. Unterstützende Abhängigkeiten treten auf, wenn eine Regel den Redex für eine andere Regel erzeugen
kann. Löscht r1 eine Kante, auf deren Abwesenheit r2 prüft, so muss Regel r1 entweder dem selben
oder einem früheren Stratum zugeteilt werden. Gefährliche Abhängigkeiten sind solche, bei denen der
Redex für die andere Regel zerstört wird, r1 beispielsweise auf die Existenz einer Kante testet, die r2
löscht. Die testende Regel muss einem Stratum mit niedrigerer Nummer als die hinzufügende (bzw.
löschende) Regel zugeteilt werden. Nicht-stratifizierbare Abhängigkeiten sind schließlich solche, die
gegenseitig ihre Redexe zerstören können. Treten solche Abhängigkeiten auf, existiert keine Stratifizierung. Eine solche Abhängigkeit tritt insbesondere jedesmal dann auf, wenn ein Knoten gelöscht
wird, da ein zu löschender Knoten von der Regel vorher getestet wird. Dies wird Selbstabhängigkeit genannt. Werden Selbstabhängigkeiten außer acht gelassen, so spricht man von einer schwachen
Stratifizierung.
Die Menge aller (schwach) stratifizierbaren Graphersetzungssysteme wird (W)STRGRS 9 genannt.
Offensichtlich ist WSTRGRS ⊂ STRGRS.
Existieren zu einem Graphersetzungssystem mehrere Stratifizierungen, so lässt sich zeigen, dass
sie zur gleichen Normalform führen. (Schwache) Stratifizierungen können bestimmte Abhängigkeiten
lösen und garantieren, dass eine fest bestimmte Normalform ausgewählt wird.
5 für
engl.:
engl.:
7 für engl.:
8 für engl.:
9 für engl.:
6 für
edge addition rewrite systems
edge accumulation graph rewrite systems
(edge) subtractive graph rewrite systems
exhaustive graph rewrite systems
(weakly) stratifiable graph rewrite systems
3
4
Codegenerierung
Der generische Algorithmus Ordnungsauswertung, der ein XGRS ausführt, basiert auf geschachtelten Schleifen. Seine Ausführungsgeschwindigkeit hängt vom maximalen Ausgangsgrad eines Knotens
bezüglich einer bestimmten Relation ab und arbeitet auf dünn besetzten Graphen besonders effizient. Aus den Regelmengen berechnete Daten werden in den als Template vorhandenen generischen
Pseudo-Code eingesetzt, aus dem wiederum Code generiert wird. Abbildung 2 stellt exemplarisch
einen Teil dieses Pseudo-Codes dar. Auf die genaue Semantik des Codefragments wird hier nicht
eingegangen, lediglich das Prinzip soll verdeutlicht werden.
forall-const(n1, n2, l) ∈ ∪r∈S E del (r) do
m := nlabL (n1);
forall y1 ∈ Nm do
forall y2 ∈ y1 .l do
if y2 .deleted then y1 .l −= y2 ;
Abbildung 2: Pseudocode des generischen Algorithmus
Das Codefragment führt drei ineinander geschachtelte Schleifen aus. forall-const ist eine Schleife,
deren Iterationsmenge statisch bekannt ist, so dass sie bei der Codegenerierung ausgerollt werden
kann.
Andere Algorithmen sind ebenfalls anwendbar und für bestimmte XGRS womöglich effizienter,
können aber Einschränkungen unterliegen. Für Datalog entwickelte Algorithmen sind beispielsweise
anwendbar, falls das Graphersetzungssystem stratifizierbar ist.
5
Evaluierung
Aßmann hat Teile der Optimierung ’faule Platzierung’10 mit Optimix implementiert, in einen Modula2 Übersetzer integriert und die Ergebnisse mit gcc und sun-cc mit Hilfe eines Benchmarks verglichen.
Dabei wurde ein Geschwindigkeitsunterschied beim Übersetzen um ca. Faktor 10 festgestellt. In einer
weiteren Messreihe wurde der Teil des generierten Codes, der die eigentliche Ersetzung durchführt,
durch handgeschriebenen Code ersetzt, lediglich der Analyseteil wurde generiert. Die handgeschriebene Version ist dabei nur unwesentlich schneller als die generierte. Da die Anzahl der benötigten
Regeln für den Analyseteil um ein Vielfaches höher als für den Transformationsteil ist, lässt sich folgern, dass bei wachsender Regelmenge zunehmend ineffizientere Algorithmen generiert werden. Hier
besteht offensichtlich Optimierungsbedarf.
6
Zusammenfassung und Ausblick
Bereits viele Aufgaben eines Optimierers können mit dem vorgestellten Ansatz spezifiziert werden.
Derzeit ist es jedoch notwendig, generierten und handgeschriebenen Code zu mischen. Doch eignet
sich das vorgestellte Verfahren, die Entwicklung von Optimierungsroutinen stark zu beschleunigen.
Mit entsprechenden Erweiterungen des vorgestellten Systems werden weitere Aufgabentypen mit vollständigen Graphersetzungssystemen darstellbar sein. Die erreichte Abstraktion von der Zwischensprache erlaubt dabei hohe Wiederverwendbarkeit vom Code. Die noch mäßige Effizienz des generischen
Ordnungsauswertungs-Algorithmus kann durch eine intelligentere Analyse und Hinzufügen von Metadaten zur Spezifikation stark verbessert werden.
10 engl.:
lazy code motion
4
Herunterladen