[Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 ||...

86
Kapitell0 Organisation der prograrnrnierten Graphred uktion Als Technik zur Implementierung parallelisierter Kombinatorsysteme haben wir die programmierte Graphreduktion gewahlt. Das Programm wird also als Graph reprasentiert, der wahrend der Ausfiihrung transformiert wird. Die Reduktion des Graphen wird durch die Ausfiihrung von Maschineninstruktionen gesteuert. Zu jeder der in Definition 8.2.3 definierten Graphreduktionsregeln wird eine Maschi- nencodesequenz erzeugt, die die Durchfiihrung des entsprechenden Graphredukti- onsschrittes in der Maschine definiert. Die Graphreduktionsregeln sind eindeutig bestimmt durch die Markierung und den Auswerter des Wurzelknotens des Gra- phen auf der linken Regelseite. Die Ubersetzung eines Programms umfaflt also Maschinensequenzen fiir alle Kombinationen von nicht-nullstelligen Markierungen und Auswertern. Bereits in Kapitel 2 haben wir gezeigt, welche Vorteile die programmierte Graphreduktion bietet. Ein entscheidender Vorteil ist etwa die Moglichkeit, Daten- rechnungen konventionell mittels eines Datenkellers anstatt aufwendiger Graph- transformationen durchzufiihren. Dies fiihrt zu sehr vielen Parallelen zur konven- tionellen umgebungsbasierten Implementierung, wie wir im folgenden noch sehen werden. Wir beschreiben in diesem Kapitel die Organisation programmierter Graphre- duktion, die bisher nur in sequentiellen Reduktionsmaschinen verwendet wurde [Johnsson 84, Fairbairn, Wray 86], in unserer parallelen Maschine mit verteiltem Speicher. 1m erst en Abschnitt beginnen wir mit der Spezifikation der Darstellung R. Loogen, Parallele Implementierung funktionaler Programmiersprachen © Springer-Verlag Berlin Heidelberg 1990

Transcript of [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 ||...

Page 1: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

Kapitell0

Organisation der prograrnrnierten Graphred uktion

Als Technik zur Implementierung parallelisierter Kombinatorsysteme haben wir die programmierte Graphreduktion gewahlt. Das Programm wird also als Graph reprasentiert, der wahrend der Ausfiihrung transformiert wird. Die Reduktion des Graphen wird durch die Ausfiihrung von Maschineninstruktionen gesteuert. Zu jeder der in Definition 8.2.3 definierten Graphreduktionsregeln wird eine Maschi­nencodesequenz erzeugt, die die Durchfiihrung des entsprechenden Graphredukti­onsschrittes in der Maschine definiert. Die Graphreduktionsregeln sind eindeutig bestimmt durch die Markierung und den Auswerter des Wurzelknotens des Gra­phen auf der linken Regelseite. Die Ubersetzung eines Programms umfaflt also Maschinensequenzen fiir alle Kombinationen von nicht-nullstelligen Markierungen und Auswertern.

Bereits in Kapitel 2 haben wir gezeigt, welche Vorteile die programmierte Graphreduktion bietet. Ein entscheidender Vorteil ist etwa die Moglichkeit, Daten­rechnungen konventionell mittels eines Datenkellers anstatt aufwendiger Graph­transformationen durchzufiihren. Dies fiihrt zu sehr vielen Parallelen zur konven­tionellen umgebungsbasierten Implementierung, wie wir im folgenden noch sehen werden.

Wir beschreiben in diesem Kapitel die Organisation programmierter Graphre­duktion, die bisher nur in sequentiellen Reduktionsmaschinen verwendet wurde [Johnsson 84, Fairbairn, Wray 86], in unserer parallelen Maschine mit verteiltem Speicher. 1m erst en Abschnitt beginnen wir mit der Spezifikation der Darstellung

R. Loogen, Parallele Implementierung funktionaler Programmiersprachen© Springer-Verlag Berlin Heidelberg 1990

Page 2: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.1. GRAPHREPRASENTATION 231

der Berechnungsgraphen in der Maschine. Jede Reduktionseinheit enthalt in ihrem lokalen Speicher eine Graphkomponente. Zur Ermoglichung paralleler Reduktio­nen erfolgt eine verteilte Abspeicherung des Programmgraphen. 1m darauffolgen­den Abschnitt wird der lokale Zustandsraum der Reduktionseinheiten definiert. Nach Einfiihrung der Maschinenbefehle mit formaler Definition der Befehlsseman­tik wenden wir uns dann der Compilation parallelisierter Kombinatorsysteme in Maschinencode zu. 1m AnschluB an die formale Spezifikation der Reduktionsein­heiten diskutieren wir anhand eines Beispiels nochmals die wesentlichen Mecha­nismen, die in den Reduktionseinheiten zur ProzeBverwaltung verwendet werden.

10.1 Graphreprasentation

Graphen werden in unserer abstrakten Maschine als Abbildung von Graphadressen in die Menge der Graphknoten dargestellt. Dies ist zunachst lediglich eine andere Sichtweise, bei der die Knotennamen der Berechnungsgraphen aus Abschnitt 8.1 als Graphadressen interpretiert werden.

Da der Graph allerdings verteilt abgespeichert wird, zerlegen wir den globalen AdreBbereich in disjunkte lokale GraphadreBbereiche fUr die verschiedenen Re­duktionseinheiten. Jede globale Adresse besteht aus zwei Komponenten, emer Prozessoridentifikation und einer lokalen Adresse:

globale Adresse = ( Prozessornummer, lokale Adresse ).

Der Einfachheit halber numerieren wir die Prozessorelemente durch. 1m fol­genden bezeichnen wir die Anzahl der Prozessorelemente immer mit n. Prozes­sornummern sind also die Zahlen von 1 bis n. Als lokale Adressen benutzen wir natiirliche Zahlen.

10.1.1 Definition 1. Die Bereiche LAdr der lokalen und GAdr der globalen Graphadressen definieren wir durch:

• LAdr:= lN,

• GAdr:= {1, ... ,n} x LAdr.

2. Bezeichnet GNode die Menge der Graphknoten, die wir im folgenden noch spezifizieren werden, so wird die Menge Graph der M aschinengra­phen durch

Graph := {g I 9 : LAdr- ~ GNode}

festgelegt.

Zur Spezifizierung der Knoten der Maschinengraphen gehen wir von den Be­rechnungsgraphen der in Kapite18 definierten Graphreduktionssemantik aus. Den Knoten dieser Graphen sind folgende Informationen zugeordnet:

Page 3: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

232 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

• die durch die Funktion lab gegebene Markierung,

• die durch die Funktion E bestimmten Nachfolgerknoten, welche die Argu­mentausdriicke des Gesamtausdruckes reprasentieren,

• die durch die Funktion evt gegebene "evaluation transformer" -Annotierung SOWle

• der durch die Funktion state gegebene Zustand des Knotens, der den Aus­werter des von den Knoten ausgehenden Berechnungsgraphen angibt und anzeigt, ob der Graph einen parallelen ProzeB und/oder einen Ausdruck in Kombinatornormalform reprasentiert.

Bis auf die "evaluation transformer", die direkt in den Maschinencode eingear­beitet werden, enthalten auch die Knoten der Graphkomponenten in den lokalen Speichern der Reduktionseinheiten obige Informationen. Die Statusinformatio­nen sind allerdings urn ein Vielfaches komplexer, da durch die Programmierung nicht alle Graphtransformationsschritte explizit durchgefiihrt werden, sondern z.T. lediglich zu Transformationen der Statusinformationen fiihren. Die Kontrollstruk­turen (if, case, let, let par) werden ebenfalls in den Code eingebettet und treten nicht mehr als Markierung in den Maschinengraphen auf. Wir unterscheiden in der parallelen Maschine vier Arten von Graphknoten:

• Task- oder ProzeBknoten*,

• Argumentknoten,

• terminale Knoten und

• Verweisknoten.

Taskknoten entsprechen den Wurzelknoten von nicht vollstandig reduzierten Be­rechnungsgraphen. Argumentknoten reprasentieren die Graphen nicht-strikter Ar­gumente, deren Auswertung verzogert wird. Terminale Knoten bilden die Wurzel von Graphen, die Ausdriicke in Kombinatornormalform reprasentieren. In den Be­rechnungsgraphen der Graphreduktionssemantik wurden diese Knoten mit t anno­tiert. Verweisknoten sind Platzhalter fur die Wurzelknoten von Teilgraphen, die im Speicher einer anderen Reduktionseinheit abgelegt sind. Sie werden nur auf Grund der verteilten Abspeicherung des Programmgraphen benotigt. Die Wur­zelknoten von den Teilgraphen, die verteilt abgespeichert werden, wurden in den Berechnungsgraphen der Graphreduktionssemantik mit p annotiert.

·Wir bevorzugen den Terminus Taskknoten, da wir unter Prozessen parallele Prozesse verste­hen. Die Taskknoten werden allerdings nicht nur fiir parallele Prozesse erzeugt, sondern fUr aUe Kombinatoraufrufe und auch fUr verzogerte Argumentberechnungen. Als Tasks bezeichnen wir im folgenden Berechnungsteile, fiir die ein Taskknoten erzeugt wird.

Page 4: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.1. GRAPHREPRASENTATION 233

Taskknoten kennzeichnen die Wurzel reduzierbarer Graphen. 1m allgemeinen reprasentieren sie vollstandige Kombinator- oder Basisfunktionsapplikationen und entsprechen dann quasi den Aktivierungsblocken konventioneller Stackimplemen­tierungen. Insbesondere werden parallele Prozesse, die ja bei der Ausfiihrung par­allelisierter Kombinatorsysteme durch vollstandige Kombinatorapplikationen be­schrieben werden, auf diese Weise dargestellt. Zur verzogerten Auswertung nicht strikter Argumente werden wir ebenfalls Taskknoten generieren. Ein Taskknoten hat folgende globale Struktur:

I TASK I Marke I Argumentliste II Statusinformationen I·

Die erste Komponente ist ein Etikett (tag) zur Kennzeichnung des Knotentyps. Die zweite Komponente enthalt die Markierung, die denselben Zweck erfiillt wie die Markierung der Berechnungsgraphen. Als Marken treten allerdings nur Kom­binatornamen, Basisfunktionen und das Kennzeichen 'arg' auf, welches Tasks, die fiir Argumentauswertungen generiert werden, markiert. Die Programmausfiihrung beginnt mit einer sogenannten 'Urtask' auf irgendeinem Prozessorelement. Diese Urtask tragt als Marke das Kennzeichen 'ur'.

Die Argumentliste entspricht der Liste der N achfolgerknoten, die Wurzelknoten der Teilgraphen sind. Bei Applikationen von Kombinatoren und Basisfunktionen entsprechen die Teilgraphen oder Teilausdriicke genau den Argumentausdriicken. Zur Optimierung werden Konstanten direkt in der Argumentliste reprasentiert. AIle iibrigen Argumente sind durch die Adressen ihrer Graphdarstellung gegeben. Zur Unterscheidung von Wert en und Adressen wird ein Tag benutzt.

Eintrage in der Argumentliste und, wie wir noch sehen werden, in den Kellern sind also Elemente folgender Menge

Eintriige = ({V} x (A U U r(€,d))) U ({P} x GAdr x Evset). dED

Werte aus AU UdED r(€,d) werden direkt angegeben und durch das Tag V (value) gekennzeichnet.

Adressen werden als glob ale Adressen notiert und durch das Tag P (pointer) markiert. Zu Adressen wird immer der Auswerter, mit dem die Auswertung des zugehorigen Teilgraphen angestoBen wurde, vermerkt. Diese Information ist vor allem fur globale Adressen von Bedeutung, da durch die Kenntnis des Auswerters (uberflussige) Mehrfachaktivierungen vermieden werden konnen.

Zur Unterstutzung der Parallelausfiihrung enthaIt ein Taskknoten in der Sta­tusinformation samtliche Informationen, die zur Reduktion des zugehorigen Aus­druckes notwendig sind. Dazu gehort der Auswerter, der den Auswertungsgrad bestimmt. Wurde die Auswertung einer Task noch nicht angestoBen, so besteht

Page 5: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

234 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

label argument list evaluator

TASK ev

ip data stack variable stack pc lists of addresses

~ ~ lq I gq

Bild 10.1: Allgemeine Struktur eines aktivierten Taskknotens

die Statusinformation nur aus dem Auswerter ~o. Ansonsten hat diese Kompo­nente der Taskknoten, wie auch in Bild 10.1 verdeutlicht, folgende Struktur

(ev, ip, ds, lv, pc, lq, gq),

wobei

• ev E Evset der Auswerter (evaluator) der Task sei.

• ip E PAdr ist der Befehlszahler (instruction pointer), der die Adresse der nachsten auszufiihrenden 1nstruktion anzeigt. PAdr bezeichne dabei die Menge der Programmadressen.

• ds E Eintriige* ist der Datenkeller (data stack) zur Ausfiihrung von Basis­funktionen. Wie wir spater sehen werden, existiert zu jeder Basisoperation j E n ein Befehl EXEC j, der die Argumente von j als Werte auf dem Da­tenkeller erwartet und durch das Resultat der Applikation von j auf diese Werte ersetzt.

• Iv E Eintrage* ist ein Keller zur Verwaltung lokaler Variablen (local variable stack). Er enthalt Eintrage derselben Struktur wie der Datenkeller und die Argumentliste.

• pc E 1N ist der Zahler (pending count) der parallelen Teilprozesse, auf de­ren Ergebnis die vorliegende Task warten muB. 1st dieser Zahler von Null verschieden, so ist die Ausfiihrung der Task unterbrochen.

Die letzten beiden Komponenten der Zustandsinformation sind Listen von Adres­sen von Tasks, die wiederum auf das Ergebnis der vorliegenden Task warten.

• lq E LAdr* ist eine Liste von lokalen Adressen (local address queue), also von Zeigern auf wartende Tasks auf demselben Prozessorelement.

Page 6: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.1. GRAPHREPRASENTATION 235

• gq E GAdr* ist eine Liste von globalen Adressen (global address queue), an die das Ergebnis der Task iibermittelt werden muB.

In seiner Statusinformation enthalt ein Taskknoten mit dem Befehlszahler, dem Datenkeller und dem Keller zur Verwaltung lokaler Variable quasi den Zustands­raum einer sequentiellen Stackmaschine zur lokalen Ausfiihrung der Task. Der Keller zur Verwaltung lokaler Variable ist das Fragment eines Funktions- (oder Prozedur-)kellers zur Unterstiitzung der durch das let- bzw. letpar-Konstrukt gegebenen Blockstrukturierung der Ausdriicke.

Die lokale Organisation von Befehlszahler, Daten- und Verwaltungskeller wurde zur Vereinfachung der Beschreibung des Multitasking-Betriebs in den Reduktions­einheiten gewahlt. Jede Reduktionseinheit muB die Fahigkeit haben, die Aus­fiihrung mehrerer unabhangiger paralleler Prozesse und unabhangiger Tasks zu verwalten. Natiirlich ist dies auch mit einem globalen Befehlszahler, Datenkeller und Verwaltungskeller pro Reduktionseinheit moglich. MuB die Ausfiihrung einer Task allerdings auf Grund fehlender Ergebnisse von Subtasks Qder auf Grund von Daten, die auf einem anderen Prozessorelement liegen und noch beschafft wer­den miissen, unterbrochen werden, so miissen die Inhalte des Befehlszahlers und der Keller gerettet werden. Welche Art der Organisation gewahlt wird, mochten wir auf dem abstrakten Level unserer parallelen Maschine offenlassen. Denn eine Entscheidung fiir die globale oder die dezentrale Verwaltung der Zustandsraum­komponenten wird letztendlich davon abhangen, welche Organisationsform besser hardwarema:Big unterstiitzt werden kann.

Wichtig bei einer dezentralen Organisation ist natiirlich, daB die Keller wegen der Lokalitat zu den Tasks eine beschrankte Lange haben. Dies ist aber gewahr­leistet, da Tasks nicht rekursiv sind. Rekursive Kombinatoraufrufe fiihren zur Erzeugung neuer Taskknoten und damit neuer Tasks.

Wahrend der Befehlszahler und die beiden Keller zur Durchfiihrung der Task­auswertung benotigt werden, dienen die letzten drei Komponenten der Statusin­formation der Einbettung der lokalen Taskauswertung in die Gesamtberechnung. MuB eine Task auf die Ergebnisse anderer i.a. Subtasks warten, so wird der 'pen­ding count' auf die Anzahl der benotigten Ergebnisse gesetzt und die Adresse der nun wartenden Task in den Adressenlisten der Taskknoten der Subtasks vermerkt. Nach Beendigung einer Task wird dann veranlaBt, daB der 'pending count' der in den Adressenlisten vermerkten Tasks dekrementiert wird und daB das Ergebnis diesen Tasks zuganglich gemacht wird. Auf welche Weise dies geschieht, werden wir im nachsten Kapitel erlautern.

Das Pendant zu den Adressenlisten ist in der konventionellen stackbasierten Implementierung die Rucksprungadresse, die angibt, an welcher Stelle die Berech­nung nach Beendigung einer Task fortgesetzt werden soll. Durch die Parallelitat

Page 7: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

236 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

kann es nun mehrere Stellen geben, an denen die Berechnungen nach Beendigung einer Task fortgesetzt werden konnen.

Von der Erzeugung bis zur Uberschreibung durchlauft ein Taskknoten La. fol­gendes Zustandsdiagramm

schlafend

! aktiv +-+ wartend

! terminiert.

Die Zustande werden dabei wie folgt charakterisiert:

• 'schlafend' bedeutet, daB der Auswerter ~o ist,

• 'aktiv' heiBt, daB der Auswerter von ~o verschieden ist und daB der 'pending count' gleich Null ist,

• 'wartend' bedeutet, daB der 'pending count' von Null verschieden ist und

• 'terminiert' heiBt, daB der Taskknoten mit dem Resultat iiberschrieben wer­den kann.

Formal wird die Menge der Taskknoten damit wie folgt erklart.

10.1.2 Definition Die Menge Tasknodes der Taskknoten definieren wir durch:

Tasknodes:= {TASK} x Marken x Eintrage'" x Statusinj,

wobei

• Marken:= Fun U 0+ U {arg, ur}

• Eintrage:= ({V} x (AUUdEnr(£,d»)) U ({P} x GAdr x Evset) und

• Statusinj:= {~o} U ( Evset \{~o} (Auswerter) x PAdr (Befehlsziihler) x Eintrage'" (Datenkeller) x Eintrage'" (Verwaltungkeller

10kaler Variablen) x 1N ('pending count') x LAdr'" (lokale Adressenliste) x GAdr"') (globale Adressenliste).

Page 8: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.1. GRAPHREPRASENTATION 237

Einen Taskknoten notieren wir i.a. in der Form

(TASK, /-l, arglist, ( ~, ip, ds, lv, pc, lq, gq ))

mit

• /-l E Marken,

• arglist = arg1 : ... : argh mit argi E Eintrage (1 ::; i ::; h),

• ~ E Evset,

• ip E PAdr,

• ds = dm : ... : d1 mit di E Eintrage* (1 ::; i ::; m) (Kellerspitze rechts!),

• Iv = 11 : ... : 1j mit 1i E Eintrage* (1 ::; i ::; j) (Kellerspitze links!),

• pc E IN, • lq = ladr1 ... ladrk mit ladri E LAdr (1::; i::; k),

• gq = gadr1 ... gadrl mit gadri E GAdr (1 ::; i ::; 1).

Argumentknoten werden fUr nicht-strikte Argumente erzeugt, deren Auswer­tung verzogert wird. Sie entsprechen schlafenden Tasks, denn bei der Aktivierung eines Argumentknotens wird derselbe mit einem Taskknoten, der die Marke 'arg' erhalt, iiberschrieben. Argumentknoten haben die folgende Struktur:

I ARGUMENT I Umgebung I Codeadressen I

Die Umgebung enthalt eine Liste mit Argumenten und einen Keller mit Adres­sen der Graphen lokaler Variablen, die zur Auswertung des Argumentes benotigt werden konnen. AuBerdem sind drei Codeadressen angegeben, die die Codese­quenzen, die im Falle einer Auswertung mit 6,6 oder 6 ausgefiihrt werden sol­len, bestimmen**. Bei einer Aktivierung eines Argumentknotens mit Auswerter ~i wird der Argumentknoten mit einem Taskknoten iiberschrieben, der die Argu­mentliste und den Verwaltungskeller lokaler Variablen aus dem Argumentknoten iibernimmt. Als Auswerter erhalt der Taskknoten ~i und der Befehlszahler wird mit der i-ten Codeadresse aus dem Argumentknoten initialisiert.

Fiir nicht-strikte Argumente wird somit i.a. ein einzelner Graphknoten erzeugt, der neben den Umgebungsinformationen einen Zeiger auf die Ubersetzung des Argumentausdruckes in Maschinencode enthalt. Dies hat den Vorteil, daB die Reprasentation von nicht-strikten Argumenten unabhangig von der GroBe solcher

.. Falls nur der Auswerter el in Frage kommt, wird die Codeadresse fur 6 der Einfachheit halher dreimal eingetragen.

Page 9: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

238 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Argumente ist. Der Aufwand fUr die Behandlung nicht-strikter Argumente ist also konstant. Aufierdem erfolgt auf diese Weise auch die Auswertung nicht-strikter Ar­gumente, falls sie erforderlich wird, durch die Ausfiihrung von Maschinencode und nicht interpretativ, wie etwa in der G-Maschine [Johnsson 84]. Dort wird namlich jedes nicht-strikte Argument durch einen Graphen reprasentiert, der die gesamte Struktur des Argumentes wiederspiegelt. Bei einer eventuellen Auswertung erfolgt eine Interpretation des Graphen. Diese Handhabung nicht-strikter Argumente er­fordert zum einen fiir komplexe Argumente einen moglicherweise unnotigen Auf­wand zur Konstruktion der Graphdarstellung des Argumentes. Zum anderen ver­liert man bei einer interpretativen Auswertung die Optimierungsmoglichkeiten, die bei einer Codesteuerung vorhanden sind. AuBerdem werden spezielle Codesequen­zen fiir die Kontrollstrukturen let par und case und fiir beliebige Applikationen hoherer Ordnung in Argumentausdriicken benotigt, die bei der hier beschriebenen Technik keine gesonderte Behandlung erfordern.

Die Ersetzung von A rgumentgraphen durch Zeiger auf Code zur Auswertung der Argumente wurde erstmals in [Fairbairn, Wray 87] vorgeschlagen. Dort wird eine einfache sequentielle abstrakte Maschine entwickelt, in der nicht-strikte Argumente durch sogenannte 'Frames' oder 'Closures' bestehend aus einer Codesequenz und einer Liste der Variablenbindungen, auf die in der Codesequenz Bezug genommen wird, dargestellt werden. Die in unserer Arbeit verwendeten Argumentknoten entsprechen diesen 'Closures'. Durch den hier betrachteten machtigeren Kalkiil und die Beriicksichtigung der Auswerter haben die Argumentkrl.oten eine etwas komplexere Struktur als allgemeine 'Closures'.

Die 'Closure'-Technik, d.h. die Verwendung von 'Closures' bei der Implemen­tierung funktionaler Sprachen geht natiirlich bereits auf die SECD-Maschine von Landin zuriick. Selbst in konventionellen Implementierungen imperativer Spra­chen werden call-by-name Argumente durch 'closure'-ahnliche Objekte reprasen­tiert. Die in [Fairbairn, Wray 87] vorgestellte abstrakte Maschine zeigt also die Integration altbekannter, bereits bei der Implementierung imperativer Sprachen benutzter Techniken mit neuen, speziell fiir funktionale Sprachen entwickelten Im­plementierungsmethoden.

10.1.3 Definition Die Menge Argnodes der Argumentknoten wird wie folgt de­finiert:

Argnodes:= {ARGUMENT} x (Eintriige* x Eintriige*) x PAdr3 •

Terminale Knoten stehen fiir Ausdriicke in Kombinatornormalform, d.h. Kon­stante aus A, Konstruktorapplikationen sowie partielle Applikationen von Kombi­natoren, Basisfunktionen und Konstruktoren.

Konstante aus A werden durch einfache Datenknoten der Form

Page 10: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.1. GRAPHREPRASENTATION 239

I BDATA I Wert

reprasentiert. Da wir Konstante in Argumentlisten und Datenkellern direkt repdi­sentieren, werden diese Knoten nur benotigt, urn Taskknoten mit ihrem Ergebnis zu uberschreiben.

Konstruktorapplikationen werden durch Graphen dargestellt, deren Wurzel­knoten ein Datenknoten der Form

I SDATA I Konstruktor I Komponentenliste Auswerter

ist. Die Komponentenliste hat dieselbe Struktur wie Argumentlisten. Der Aus­werter gibt an, bis zu welchem Grad die Struktur bereits ausgewertet ist.

Fur partielle Applikationen fUhren wir einen neuen Knotentyp ein. Wir nennen diese Knoten Funktionsknoten, da partielle Applikationen Objekte vom funktiona­lem Typ reprasentieren. Durch Hinzufiigen weiterer Argumente konnen Funktions­knot en 'vervollstandigt' und dann durch Taskknoten ersetzt werden. Sie enthalten das Funktionssymbol, die partielle Argumentliste und die Anzahl der 'fehlenden' Argumente:

I FUNCTION I 'Y Argumentliste Anzahl fehlender Argumente

Als Funktionssymbol 'Y konnen nicht nur Kombinatoren, sondern auch Konstruk­toren oder Basisfunktionen auftreten. In diesen Fallen ist die Argumentliste aber leer, da partielle Applikationen im Kombinatorkalkul nur entsprechend dem Typ der Funktionssymbole erlaubt sind.

Terminale Knoten konnen belie big oft kopiert werden, ohne daB es zu Mehr­fachauswertungen von Ausdrucken kommt. Fur Datenknoten ist diese Aussage trivial. Fur Funktionsknoten gilt dies, weil wir fUr parallelisierte Kombinatorsy­sterne die Superkombinatoreigenschaft vorausgesetzt haben.

10.1.4 Definition Die Menge der terminalen Knoten wird somit wie folgt defi­niert:

Terminalnodes := ( {BDATA} x A) U ({SDATA} x r x Eintriige* x Evset) U ({FUNCTION} x ((Fun x Eintriige* x IN)

U ((Our) x {E} x IN))).

Verweisknoten treten in den Maschinengraphen an den Stellen auf, an denen Teilgraphen auf anderen Prozessorelementen liegen. Die Verteilung des Graphen

Page 11: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

240 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

erfolgt durch die Aktivierung paralleler Prozesse, deren Taskknoten dann auf an­deren Prozessorelementen abgespeichert werden. Auf dem Prozessorelement, auf dem die Aktivierung vorgenommen wird, werden die urspriinglichen (schlafenden) Taskknoten mit Verweisknoten folgender Form iiberschrieben:

I INDIRECTION I ? I Auswerter I Adressenlisten I Da die in den Taskknoten vorhandene Information nicht mehr benotigt wird,

enthalt der Verweisknoten keinerlei Informationen iiber die Art der Task. Das Fragezeichen in der zweiten Komponente des Verweisknoten zeigt an, daB die neue Adresse der Task nicht bekannt ist. Ais weitere Informationen enthalt der Knoten den Auswerter, mit dem die Aktivierung erfolgte, sowie Adressenlisten, die wie die entsprechenden Listen in den Statusinformationen von Taskknoten aufgebaut sind und auch denselben Zweck erfiilIen. Erfolgt ein Zugriff auf einen Verweisknoten, so wird die entsprechende Task suspendiert, indem der 'pending count' inkrementiert wird. Die Adresse der Task wird in der Adressenliste des Verweisknoten eingetra­gen. N ach Beendigung eines parallelen Prozesses wird der zu dem ProzeB gehorige Verweisknoten mit der Wurzel des Ergebnisses des Prozesses iiberschrieben. Der 'pending count' der in der lokalen AdreBliste vermerkten Tasks wird dekremen­tiert. An aIle im Verweisknoten vermerkten globalen Adressen wird das Ergebnis weitergeleitet.

Verweisknoten sind immer Platzhalter fUr Knoten, die auf anderen Prozes­sorelementen liegen. Sie werden auch angelegt, wenn eine Task ein Argument benotigt, das in der Argumentliste durch eine globale Adresse gegeben ist. In die­sem Fall kann die Adresse des globalen Knotens, auf den der Verweisknoten zeigt, in demselben eingetragen werden.

Zur Vermeidung iiberfliissiger Kopien ist es manchmal sinnvolI, Taskknoten nach Beendigung mit einem Verweisknoten auf das Resultat zu iib erschreib en. Solche lokalen Verweisknoten bestehen einfach nur aus einem Tag und einer lokalen Adresse.

10.1.5 Definition Ais Verweisknoten konnen die Maschinengraphen die Ele­mente folgender Menge enthalten:

Indnodes := ({INDIRECTION} X (GAdr U {?}) x Evset X LAdr* x GAdr*)

U ({LOCAL-IND} x LAdr).

Damit ergibt sich als Menge aller Graphknoten:

10.1.6 Definition Die Menge GNode der Maschinengraphknoten wird definiert durch:

Page 12: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.1. GRAPHREPRASENTATION 241

• Taskknoten

label argument list evaluator

TASK

ip data stack variable stack pc lists of addresses

E 0 I

• Argumentknoten

ARGUMENT I .. ,'ro,m",

• Terminale Knoten

Datenknoten

1 BDATA I'''''' Strukturknoten

constructor components evaluator

SDATA

- Funktionsknoten function partial argument list counter

FUNCTION

• Verweisknoten

address evaluator lists of addresses

INDIRECTION I

lokale Verweisknoten local address

LOCAL-IND

Bild 10.2: Graphknoten

Page 13: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

242 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

GNode := Tasknodes U Argnodes U Terminalnodes U Indnodes.

Bild 10.2 gibt eine graphische Ubersicht der verschiedenen Graphknotentypen.

Die Struktur der in jeder Reduktionseinheit vorhandenen Graphkomponente ist damit vollstandig spezifiziert. 1m folgenden Abschnitt diskutieren wir die iibrigen lokalen Komponenten der Reduktionseinheiten.

10.2 Der lokale Speicher der Red uktionseinhei­ten

Der Zustandraum einer jeden Reduktionseinheit besteht aus den Komponenten des lokalen Speichers, auf die nur die Reduktionseinheit zugreifen kann, und aus den Komponenten des gemeinsamen Speichers von Reduktions- und zugehoriger Kommunikationseinheit. Der Graphreduktionsprozefi wird durch die Komponen­ten des lokalen Speichers bestimmt, die wir in diesem Abschnitt formal definieren werden (siehe auch Bild 10.3).

Der lokale Speicher einer Reduktionseinheit enthalt sieben Komponenten:

• den Arbeitsmodus: mode,

• den Zeiger auf die zur Zeit bearbeitete Task: atp (active task pointer),

• den Graphen: G,

• die nachste freie Graphadresse: gp (graph pointer),

• eine lokale Warteschlange fiir Tasks: ltq (local task queue),

• eine Liste von Adressen von Datenstrukturknoten, deren Auswerter erhoht wurde und deren Komponenten ebenfalls mit hoheren Auswertern aktiviert werden miissen: al (activation list) und

• den Programmspeicher ps (program store).

Ein lokaler Zustand hat also i.a. folgende Struktur

( mode, atp, g, gp, ltq, aI, ps ).

Vier Arbeitsmodi werden fUr Reduktionseinheiten unterschieden: der Kommu­nikationsmodus (em), der Wartemodus (wm), der Reduktionsmodus (rm) und der Aktivierungsmodus (am).

Page 14: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.2. DER LOKALE SPEICHER DER REDUKTIONSEINHEITEN 243

Inports

1 I

Netzwerk-

adapter

Kommunika-

tions-

prozessor

Reduktions-

prozessor

I

--

Outports

i

Eingabe­schlange

Red.­schlange

! Zeiger auf aktive Task

r------ f-------/

Programm­speicher

I

i Ausgabe­schlange

t

lokaler Speicher der

Kommunikationseinheit

Kom.­schlange

D Flag zur ProzeB­anforderung

Graph

(~( I I \ I I

1 I

I

D Arbeits­modus

lokale Task­warte-

schlange

-I Aktivierungsliste -

Bild 10.3: Zustandsraum der Reduktionseinheit

K o M M U N I K A T I o N S E I N H E I T

R E D U K T I o N S E I N H E I T

Page 15: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

244 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

1m Kommunikationsmodus bearbeitet die Reduktionseinheit Nachrichten, die ihr von der Kommunikationseinheit iibermittelt werden. AIle Aktivitaten der Reduktionseinheit in diesem Modus sind spezifisch fUr die Parallelisierung und gehoren zu dem Organisationsaufwand, der von der Reduktionseinheit fUr die Par­allelitat aufgebracht werden muB.

1m Wartemodus (wm) ist die Reduktionseinheit ohne Arbeit und wartet auf eine Nachricht von der Kommunikationseinheit.

1m Reduktionsmodus erfolgt die eigentliche Programmausfiihrung, die durch den Maschinencode gesteuert wird. Welche Zustandsanderungen die Maschinen­befehle bewirken, werden wir im nachsten Abschnitt spezifizieren.

1m Aktivierungsmodus wird die Aktivierungsliste, in der Datenstrukturknoten vermerkt sind, deren Auswerter erhoht wurde, abgearbeitet, indem die Auswerter der Komponenten ebenfalls erhoht werden, was zur Aktivierung von Tasks und auch Prozessen fiihren kann.

Die Maschinencodesequenz, die ausgefiihrt wird, hangt von der gerade in Be­arbeitung befindlichen Task ab, die durch den Zeiger atp (active task pointer) angezeigt wird. Genau genommen zeigt der Zeiger auf den K noten der aktiven Task. Er ist also eine lokale Graphadresse. Eine Reduktionseinheit kann zu einem Zeitpunkt hochstens eine Task ausfUhren, obwohl mehrere aktive Tasks vorhanden sein konnen. Enthalt eine Reduktionseinheit in ihrem Speicher keine aktive Task, so hat der 'active task pointer' den Wert 'nil'. In diesem Fall wartet die Redukti­onseinheit darauf, daB ihr von der Kommunikationseinheit ein neuer ProzeB iiber­mittelt wird. Sie befindet sich also im Wartemodus.

Die Graphkomponente, die wir bereits im vorigen Abschnitt formal definiert haben, bildet den Kern des lokalen Speichers einer Reduktionseinheit. Wir abstra­hieren in der Definition der abstrakten Maschine zur Vereinfachung von jeglicher 'Garbage Collection' zur Bestimmung freier Graphadressen. Ais lokale Grapha­dressen haben wir daher den unendlichen Bereich aller natiirlichen Zahlen gewahlt (vgl. Definition 10.1.1). Zur Bestimmung neuer Graphadressen bei der Erzeu­gung neuer Graphknoten benutzen wir einen einfachen Zahler, den Graphzeiger gp (graph pointer), der immer auf die nachste freie Graphadresse zeigt.

Die lokale Taskwarteschlange ltq (local taskqueue) enthalt die Graphadressen lokaler aktiver Tasks, die zur Ausfiihrung bereit sind. Dies konnen Subtasks 10-kaler Tasks sein, die nicht parallel ausgefiihrt werden sollen. Es kann sich auch urn Tasks handeln, deren Ausfiihrung auf Grund fehlender Informationen unter­brochen wurde und die inzwischen reaktiviert wurden, weil die benotigten Infor­mationen nun verfUgbar sind. Die lokale Taskwarteschlange ist notwendig zur Organisation des Multitaskingbetriebs der Reduktionseinheit.

Die Aktivierungsliste al (activation list) wird benotigt, wenn nachtraglich, d.h. nach Beendigung der Auswertung von Strukturen, der Auswerter erhoht wird, so

Page 16: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.2. DER LOKALE SPEICHER DER REDUKTIONSEINHEITEN 245

daB eine weitere Auswertung der Komponenten der Strukturen moglich wird. Die Steuerung der Aktivierung erfolgt anhand der Eintrage in der Aktivierungsliste, die aus folgender Menge sind:

LAdr x (IN x Evset) * .

Ein Eintrag der Form (ladr, (il,evt} ... (ik,evk)) bedeutet, daB die Komponenten i l - ik des Datenstrukturknoten mit der lokalen Adresse ladr mit den Auswertern eVl - eVk aktiviert werden konnen. Die Abarbeitung der Aktivierungsliste erfolgt im Aktivierungsmodus.

SchlieBlich enthalt der lokale Speicher jeder Reduktionseinheit einen Programm­speicher ps, der aus funf Komponenten besteht:

• den Codeadressentabellen ca-c und ca-f, die zu Kombinatoren (bzgl. Auswer­tern und Aktivierungsarten) bzw. Basisfunktionen die Codeanfangsadressen angeben:

ca-c : Fun x Evset x {dir, indir}- -t PAdr und ca-f: n+ -t PAdr,

• der Rangfunktion rg: Fun- -t IN,

• einer Funktion c-evt, die die kontextfreien 'evaluation transformer' von Kon­struktoren beschreibt:

c-evt : r x Evset -t (IN x Evset) *

und

• dem eigentlichen Codebereich c, der durch eine Abbildung von den Pro­grammadressen in die Maschinenbefehle Instr beschrieben wird:

c: PAdr- -t Instr.

Zu Kombinatoren werden die Codeanfangsadressen in Abhangigkeit des Aus­werters und der Aktivierungsart angegeben. Dabei werden zwei verschiedene Ak­tivierungsarten unterschieden - die sogenannte direkte Aktivierung (dir) und die sogenannte indirekte Aktivierung (indir). Hierauf werden wir spater noch genau eingehen.

Fur die Funktion c-evt gilt:

c-evt(c,ev) = (il,evt} ... (ik,evk)'

falls

Page 17: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

246 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

ETi,(c)(ev) = eVj mit eVj 1= €o fiir 1 ~ i ~ k

und

Wird der Auswerter eines Datenstrukturknotens mit Konstruktor c und lokaler Adresse ladr auf e erhoht, so wird die Aktivierungsliste urn den Eintrag

(ladr, e-evt( c, e))

zur Steuerung der Aktivierung der Komponentenstrukturen erweitert.

Als Programmadressen wahlen wir die Menge der natiirliehen Zahlen. Zur Vereinfachung werden wir annehmen, dafi alle Reduktionseinheiten in ihren Pro­grammspeiehern die Ubersetzung des gesamten parallelisierten Kombinatorpro­gramms enthalten.

Die Menge Instr der Masehinenbefehle wird im naehsten Abschnitt definiert. Dort wird auch die Semantik der einzelnen Befehle festgelegt.

10.2.1 Definition Der lokale Zustandsraum einer Reduktionseinheit LStRE (lo­cal store) wird festgelegt durch:

LStRE .- {rm, em, wm, am} (Arbeitsmodus) x (LAdr U {nil}) ('active task pointer') x Graph (Graphkomponente) x LAdr (Graphzeiger) x LAdr* (lokale Taskwarteschlange) x (LAdr x (IN x Evset)*)* (Aktivierungsliste) x Pstore (Programmspeicher)

wobei mit PAdr := IN

Pstore := [Fun x Evset x {dir, indir}- -t PAdr] x [0+ -t PAdr] x[Fun- -t IN] x [r x Evset -t (IN x Evset)*] x[PAdr- -t Instr].

Die Menge Instr der Masehineninstruktionen wird im naehsten Abschnitt spezifiziert.

Wie wir noch sehen werden, ist die explizite Angabe des Arbeitsmodus im Zu­standsraum der Reduktionseinheit nicht notwendig. Wir haben diese Komponente aus didaktischen Griinden zur Klassifizierung der verschiedenen Transitionen der Reduktionseinheiten in den Zustandsraum aufgenommen.

Page 18: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 247

10.3 Die Maschineninstruktionen

In der parallelen Maschine werden vier Klassen von Maschinenbefehlen unterschie­den.

• die Datenkellerbefehle,

• die Sprungbefehle,

• die Graphbefehle und schliefilich

• die Prozefibefehle.

Wir beginnen mit der formalen Definition des Befehlssatzes:

10.3.1 Definition Die Menge Instr der Maschinenbefehle der abstrakten paral­lelen Maschine ist definiert durch:

Instr := DSlnstr U Clnstr U Glnstr U Plnstr,

wobei

DSlnstr·- { LIT v I v E U neE,S) U U r(E,d)} .- sES dED U { EXEC J I J E n+} U { NODE (c,~) ICE r+}

die Menge der Datenkellerinstruktionen (data stack instructions),

Clnstr:= {JMP 1, JPFALSE 1 11 E PAdr} U { CASE (( C1 , It), ... , ( Ck, 1 k)) I 3d ED: r( d) = {C1' ... , cd,

1t, ... ,lk E PAdr} die Menge der Sprung- oder KontrollbeJehle (control instructions),

Glnstr:= {LOAD i, LOADLOC iii E IN} U { GET m, STORE m, POP m I m E IN} U { SPLIT} U { ARGNODE (11,12 ,13 ) Iii E PAdr (1 ~ i ~ 3)} U { MKNODE (J.1-, i) I J.1- E Fun U r+ Un, i E IN} U { APPLY iii E IN}

die Menge der GraphbeJehle (graph instructions) und

Plnstr:= {EVALUATE~, ACTIVATE~, INITIATE ~ I ~ E Evset} U { INITARG (i,~), INITLOC (i,~) liE IN,~ E Evset} U {GETARG (i,~), GETLOC (i,~) liE IN,~ E Evset} U { WAIT m I m E IN} U { RET ~ I ~ E Evset} U {PUSH (F,i) I FE Fun,i E IN}

die Menge der ProzepbeJehle (process instructions) ist.

Page 19: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

248 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Die einzelnen Befehle bewirken jeweils eine Transformation des lokalen Zu­standsraumes der Reduktionseinheit, wobei die Datenkeller- und Variablenkeller­transformationen sich jeweils auf die Keller der durch den 'active task pointer' angezeigten Task beziehen. Die ProzeBbefehle konnen auBerdem zur Erzeugung von Nachrichten fiihren. Da die Adressenbehandlung von der Nummer des Pro­zessorelementes abhangt, tritt diese als Parameter der Befehlssemantik auf.

Die Befehlssemantik hat also folgenden allgemeinen Typ

C: Instr x {I, ... , n} --+ LStRE- --+ LStRE x RedMes·,

wobei RedMes die Menge der von Reduktionseinheiten erzeugten Nachrichten be­zeichnet. Diese nennen wir auch Reduktionsnachrichten, da sie fur die Paralleli­sierung des Reduktionsprozesses essentiell sind. Eine formale Spezifikation dieser Nachrichtenmenge wird spater angegeben. Wie wir sehen werden, gilt fiir Instruktionen ins ~ Plnstr, falls pnr E {I, ... , n} und st E LStRE

proj2(C[ins]pnr st) = E.

Wir definieren die Befehlssemantik daher im folgenden zunachst jeweils fiir die verschiedenen Instruktionsklassen.

10.3.1 Datenkellerbefehle

Die Datenkellerbefehle beschreiben die operativen Fahigkeiten des Datenkellers. Sie konnen in eindeutiger Weise den Basisfunktionen und Konstruktoren zugeord­net werden.

• LIT v ermoglicht das Laden von nullstelligen Basisfunktionen bzw. nullstel­ligen Konstruktoren auf den Datenkeller.

• EXEC f appliziert die Basisfunktion f auf die obersten Elemente des Da­tenkellers entsprechend der Stelligkeit von f. Diese Argumente miissen als Werte auf dem Datenkeller vorliegen. Sie werden durch das Ergebnis der Applikation ersetzt.

• NODE (c,~) erzeugt einen Konstruktordatenknoten mit Konstruktor c, Aus­werter ~ und den obersten m Elementen des Datenkellers als Komponenten, wenn m die Stelligkeit von c ist. Die vom Datenkeller genommenen Kompo­nenten werden durch einen Zeiger auf den neu erzeugten Datenknoten ersetzt (siehe Bild lOA).

Die Befehlssemantik der Datenkellerbefehle wird wie folgt festgelegt:

Page 20: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 249

atp

argument list evaluator

variable stack

code:

NODE (C,~)

atp

argument list

variable stack

constructor components

d1 : ••• : dm

code: SDATA c

NODE (C,~)

Bild 10.4: Der Befehl NODE (c,~)

Page 21: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

250 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

10.3.2 Definition

Cos: DSlnstr x {l, ... ,n} ~ LStRE- ~ LStRE

wird definiert durch:

Cos [LIT v] pnr (rro, atp, G[atp/(TASK, j.L, arglist, (~, ip, ds, lv, 0, lq, gq ))], gp, ltq, al, ps) t

:= (rro, atp, G[atp/(TASK, j.L, arglist, (~, ip+l, ds:(V,4>(v)), Iv,O,lq,gq))], gp, ltq, aI, ps).

Cos [EXEC J] pnr (rro, atp, G[atp/(TASK,j.L, arglist, (~, ip, ds:(V,al): .. ': (V,a m ), lv, 0, lq, gq ))], gp, ltq, al, ps)

:= (rro, atp, G[atp/(TASK,j.L, arglist,

gp, ltq, al, ps),

Cos [NODE (c,~)] pnr (rro, atp,

(~, ip+l, ds:(V, 4>(f)(al,"" am)), lv, 0, lq, gq ))],

G[atp/ (TASK, j.L, arglist, (e, ip, ds:d1 : ... : dm , lv, 0, lq, gq ))], gp, ltq, al, ps)

:= (rro, atp, G[atp/(TASK, j.L, arglist, (e, ip+l, ds:(P,(pnr, gp), ~), lv, 0, lq, gq) )],

gp /(SDATA, c,d1 : ••. : dm,~)], gp+l, ltq, al, ps),

10.3.2 Kontrollbefehle

Die Sprung- oder Kontrollbefehle sind die Befehle, die zur Ubersetzung von kondi­tionalen Ausdriicken benotigt werden.

t Diese Schreibweise bedeutet, daB die Befehlssemantik nur fUr Zustii.nde dieser Form definiert ist.

Page 22: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 251

• JMP 1 bewirkt einen unbedingten Sprung zur Programmadresse 1.

• JPFALSE 1 testet das oberste Element des Datenkellers, das die Form (V, b) mit b e {T, F} haben mu6. 1st b = F erfolgt ein Sprung nach I. Sonst wird der Befehlszahler lediglich inkrementiert. Der boolesche Wert auf dem Datenkeller wird geloscht.

• CASE {(Cl' h), ... , (Ck' lk)) hat als Parameter eine Sprungtabelle. Das ober­ste Element des Datenkellers mu6 einen Konstruktor reprasentieren, also von der Form

- (V,c) mit C e r(E,d) fur ein d e D sein oder von der Form

- (P, (pnr,ladr), e), wobei pm die Nummer des betrachteten Prozessor-elementes ist und G(ladr) = (SDATA, c, arglist', €).

1st C = Cj fur ein j e {I, ... , k}, so erfolgt ein Sprung nach Ij . Das ober­ste Datenkellerelement wird dabei geloscht. Ansonsten ist der Befehl nicht definiert.

10.3.3 Definition

Cc: Clnstr x {I, ... ,n} - LStRE- - LStRE

wird definiert durch:

Cc [JMP I] pnr (rm, atp, G[atp/(TASK, It, arglist, (~, ip, ds, lv, 0, lq, gq ))], gp, ltq, al, ps)

:= (rm, atp, G[atp/(TASK, It, arglist, (~,l, ds, lv, 0, lq, gq ))], gp, 1tq, al, ps).

Cc[JPFALSE I] pm (rm, atp, G[atp/(TASK, It, arglist, (~, ip, ds:(V, b), lv, 0, lq, gq) )], gp, 1tq, al, ps)

(rm, atp, G[atp/(TASK, It, arglist, (~, I, ds, lv, 0, lq, gq ) )], gp, 1tq, al, ps) falls b = F,

(rm, atp, G[atp/(TASK, It, arglist, (~, ip+I, ds, lv, 0, lq, gq ))], gp, 1tq, al, ps) falls b = T.

Page 23: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

252 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Cc[CASE ((CI' It), .. . , (Ck' lk))] pnr (rm, atp, G[atp/(TASK, J-l, arglist, (~, ip, ds:do, lv, 0, lq, gq ))], gp, ltq, aI, ps)

:= (rm, atp, G[atp/(TASK, J-l, arglist, (~, ii, ds, lv, 0, lq, gq ))], gp, ltq, aI, ps),

falls do = (V, Ci) mit Ci E r(€,d) (d E D) oderdo = (P, (pnr, ladr), e) mit

G(ladr) = (SDATA, Ci, arglist', t).

10.3.3 Graphbefehle

Die Graphbefehle ermoglichen die Manipulation der Graphkomponente:

• LOAD i Hidt das i-te Argument der aktuellen Task auf den Datenkeller.

• LOADLOC i ladt das i-te Element des Kellers zur Verwaltung der lokalen Variablen auf den Datenkeller.

• GET m ersetzt die lokalen Zeiger auf Datenknoten unter den obersten m Datenkellerelementen durch die in den Datenknoten gespeicherten Werte. Dieser Befehl wird etwa vor einem EXEC f mit m-stelligem f ausgefiihrt, da letzterer auf dem Datenkeller Werte erwartet.

• STORE m schiebt die obersten m Elemente des Datenkellers auf den Ver­waltungskeller lokaler Variablen.

• POP m loscht die obersten m Elemente des Verwaltungskellers.

• SPLIT zerlegt die Datenstruktur, auf die das oberste Element des Daten­kellers zeigt, in ihre Komponenten. Die Komponentenliste wird auf den Verwaltungskeller lokaler Variablen geladen.

• MKNODE (J-l, i) erzeugt einen neuen Taskknoten, falls J-l ein Kombinator mit Rang i oder eine Basisfunktion mit Stelligkeit i ist. Ais Markierung wird J-l in den Taskknoten eingetragen. Die i obersten Elemente des Datenkellers werden als Argumentliste genommen. Ais Status wird der Auswerter ~o gewahlt (siehe Bild 10.5a).

1st J-l ein Kombinator mit Rang rp, > i oder eine Basisfunktion bzw. ein Konstruktor und i = 0, so wird ein Funktionsknoten generiert. Wiederum werden i Elemente vom Datenkeller in die Argumentliste des neu erzeugten Knotens iibernommen (siehe Bild 10.5b).

Page 24: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 253

atp

label argument list evaluator

TASK data stack variable stack

code:

MKNODE (J-t, i)

atp

argument list

variable stack

argument list label evaluator code: TASK ~o

MKNODE (J-t, i) falls J-t E Fun mit rg(J-t) = i oder J-t E n+

Bild lO.5a: Generierung eines schlafenden Taskknotens mittels MKNODE

Page 25: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

254 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

atp

code:

MKNODE (J-L, i)

atp

code:

MKNODE (J-L, i)

argument list

variable stack

o

argument list

variable stack

function

FUNCTION J-L

partial argument list

d1 : ••• : di

counter

m-t

falls J-L E Fun mit rg(J-L) = m > i oder J-L E n(Sl ... Sm,S) und m > i = 0 oder J-L E r(sl ... sm,d) und m > i = O.

Bild lO.5b: Generierung eines F\mktionsknotens mittels MKNODE

Page 26: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 255

Die vom Datenkeller genommenen Argumente werden durch die Adresse des neu erzeugten Knotens ersetzt .

• ARGNODE (11,12, h) erzeugt einen Argumentknoten mit den als Parameter gegebenen Codeadressen. Ais Umgebung werden in den Argumentknoten die Argumentliste und der Verwaltungskeller der lokalen Variablen des gerade ausgefiihrten Taskknoten iibernommen .

• APPLY i erwartet auf der Spitze des Datenkellers einen lokalen Zeiger auf einen Funktionsknoten und darunter i Argumente, mit denen der Funktions­knot en vervollstandigt werden solI (siehe Bild 1O.6a).

Die i + 1 obersten Elemente des Datenkellers werden ersetzt durch einen Zei­ger auf den neu erzeugten Knoten, der dadurch entsteht, daB die (partielle) Argumentliste des Funktionsknoten urn die i auf dem Datenkeller gegebenen Argumente erweitert wird.

Ergibt sich eine vollstandige Applikation, so wird ein Taskknoten mit Zu­stand ~o oder, falls die Markierung ein Konstruktorsymbol ist, ein Daten­strukturknoten mit Auswerter 6 erzeugt (Bild 10.6 b-c). Anderenfalls wird wieder ein Funktionsknoten generiert (Bild 10.6 d).

10.3.4 Definition

CG : Instr x {I, ... ,n} -t LStRE - -t LStRE

wird definiert durch:

CG [LOAD i] pnr (rm, atp, G[atp/(TASK, fL, arg1 : ... : argk' (~, ip, ds, lv, 0, lq, gq })] gp, ltq, al, ps)

:= (rm, atp, G[atp/(TASK, fL, arg1 : ... : argk' (~, ip+1, ds:argi, lv, 0, lq, gq })],

gp, ltq, aI, ps) (k ~ i)

CG [ LOADLOC i] pnr (rm, atp, G[atp/(TASK, fL, arglist, (~, ip, ds, it : ... : 1m , 0, lq, gq })], gp, Itq, al, ps)

:= (rm, atp, G[atp/(TASK, fL, arglist, (~, ip+1, ds:li, it : ... : 1m , 0, lq, gq ) )],

gp, Itq, al, ps) (m ~ i)

Page 27: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

256 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

a) Zustand vor Ausfiihrung eines APPLY-Befehls

function partial argument list counter

FUNCTION arglist k

code:

APPLY i

b) Folgezustand falls J.L E Fun U 0+ und k = i

argument list

variable stack

function partial argument list counter

FUNCTION arglist k

code: label argument list

TASK arglist : d1 : ••• : di APPLY i

Bild 10.6 alb: Der APPLY-Befehl

Page 28: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN

c) Folgezustand falls Jl E r (also k = i, arglist = €)

code:

APPLY i

code:

APPLY i

argument list

variable stack

function partial argument list counter

FUNCTION arglist

components

arglist : d1 : ••. : di

d) Folgezustand falls Jl E Fun und k > i

argument list

variable stack

FUNCTION partial argument list

arglist

k

function partial argument list counter

FUNCTION arglist : d1 : •. : di k - i

Bild 10.6 c/d: Der APPLY - Befehl

257

Page 29: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

258 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

CG[GET m] pnr (rm, atp, G[atp/(TASK, jL, arglist, (~, ip, ds:dm : ... : d1 , Iv,O,lq,gq})], gp, ltq, aI, ps)

:= (rm, atp, G[atp/(TASK, jL, arglist,

(~, ip+l, ds:(V, am) : ... : (V,al), lv, 0, lq, gq })], gp, ltq, al, ps)

wobei fUr i E {I, ... , m} : di = (V, ai) oder di = (P, (pnr, pd,6) mit G(Pi) = (BDATA, ai)

CG [STORE m] pnr (rm, atp, G[atp/(TASK,jL, arglist, (~, ip, ds:d1 : ... : dm , lv, 0, lq, gq })], gp, ltq, al, ps)

:= (rm, atp, G[atp/(TASK,jL, arglist, (~, ip+l, ds, d1 : ••• : dm:lv, 0, lq, gq })],

gp, ltq, al, ps)

CG [SPLIT] pnr (rm, atp, G[atp/(TASK, jL, arglist, (~, ip, ds:do, lv, 0, lq, gq })], gp, ltq, al, ps)

:= (rm, atp, G[atp/(TASK, jL, arglist,

gp, ltq, al, ps)

CG [POP m] pnr

(~, ip+l, ds:do, arg't : ... : arg'm : lv, 0, lq, gq })],

wobei do = (V,c) mit c E UdED r(€,d) und m = ° oder do = (P, (pnr, ladr), ~"} und

G(ladr) = (DATA, c, arg'l : ... : arg'm, e)

(rm, atp, G[atp/(TASK, jL, arglist, (~, ip, ds, it : ... : 1m :lv, 0, lq, gq })], gp, ltq, al, ps)

:= (rm, atp, G[atp/(TASK, jL, arglist, (~, ip+l, ds, lv, 0, lq, gq })], gp, Itq, al, ps)

CG[MKNODE (jL, i)] pnr (rm, atp, G[atp/(TASK, jL', arglist, (~, ip, ds:d1 : ... : d j , lv, 0, lq, gq })], gp, ltq, al, ( ca-c, ca-f, rg, c-evt, c ) )

Page 30: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 259

(rm, atp, G[atp/(TASK,J,t', arglist, (~, ip+1, ds:(P,(pnr, gp),~o), lv, 0, lq, gq))

gp/(TASK, J,t, d1 : ••• : di, ~o)], gp+ 1, ltq, al, ( ca-c, ca-f, rg, c-evt, c ))

(rm, atp,

falls J,t E Fun und rg(J,t) = i oder J,t E O(SI .•. S"s)

G[atp/(TASK,J,t', arglist,(~,ip+1, ds:(P,(pnr,gp)'~l),lv,O, lq, gq )), gp/(FUNCTION, J,t, d1 : ••• : di , m - i)),

gp+ 1, ltq, al, ( ca-c, ca-f, rg, c-evt, c )) falls J,t E Fun und rg(J,t) = m > i oder J,t E O(SI ... Sm,S) mit m > i = 0 oder J,t E r(sl ... s m,d) mit m > i = O.

CG[ ARGNODE (h, 12 , 13 )] pnr (rm, atp, G[atp/(TASK, J,t, arglist, (~, ip, ds, lv, 0, lq, gq ))], gp, ltq, al, ps)

:= (rm, atp, G[atp/(TASK, J,t, arglist, (~, ip+1, ds:(P,(pnr,gp),~o), lv, pc, lq, gq )),

gp /(ARGUMENT, (arglist, Iv), (h,12,13)))' gp+ 1, ltq, aI, ps)

CG[APPLY i] pnr (rm, atp, G[atp/(TASK, J,t, arglist,

(~, ip, ds:d1 : ••. : di : (P,(pnr,ladr), 6), lv, 0, lq, gq )), ladr/(FUNCTION, J,t', arglist',k)],

gp, Itq, al, ps)

(rm, atp, G[atp/(TASK,J,t, arglist, (~,ip+1, ds:(P,(pnr,gp),~o),lv,O,lq,gq )),

ladr/(FUNCTION, J,t', arglist', k), gp / (TASK, J,t', arglist' : d1 : •.• : di , ~o)),

gp+ 1, ltq, al, ps) falls k = i,J,t' E 0 U Fun

(rm, atp, G[atp/(TASK,J,t, arglist, (~,ip+1, ds:(P,(pnr,gp)'~l),lv,O,lq,gq )),

ladr/(FUNCTION, J,t', arglist', k), gp /(SDATA, J,t',d1 : .•• : di'~l))'

gp+1, ltq, al, ps) falls J,t' E r (und damit k = i, arglist' = €)

Page 31: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

260 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

(rm, atp, G[atp/(TASK,p, arglist,(~,ip+l, ds:(P,(pnr,gp)'~l),lv,O,lq,gq )),

ladr/(FUNCTION, p', arglist', k), gp /(FUNCTION, p', arglist' : d1 : ••• : di, k - i)],

gp+l, ltq, al, ps) falls k > i,p' E Fun

10.3.4 Prozefibefehle

Mittels der ProzepbeJehle erfolgt die Steuerung des Berechnungsablaufes. Zu den Prozefibefehlen zahlen also die Befehle zur Aktivierung, Suspendierung und Ter­minierung von Tasks. Dabei konnen Nachrichten an Prozessorelemente erzeugt werden, die in den gemeinsamen Speicher von Reduktionseinheit und Kommu­nikationseinheit geschrieben werden. Bevor wir die Semantik der Prozefibefehle formal spezifizieren, geben wir, wie wir es auch fur die anderen Befehlsklassen getan haben, eine kurze informale Beschreibung der einzelnen Befehle.

Aktivierung von Tasks

Zur Aktivierung von Berechnungen dienen die Instruktionen EVALUATE, AC­TIVATE, INITIATE, INITARG, INITLOC, GETARG und GETLOC. Die einzel­nen Befehle beschreiben jeweils spezielle Formen der Aktivierung.

Eine Task kann entweder lokaloder parallel ausgefiihrt werden. Dementsprech­ned unterscheiden wir lokale Aktivierungen mittels EVALUATE bzw. INITIATE und parallele Aktivierungen mittels ACTIVATE bzw. INITARG, INITLOC, GE­TARG oder GETLOC.

Je nachdem, ob die Berechnung der strikten Argumente einer Task vor de­ren Aktivierung initiiert wurde oder nicht, sprechen wir von einer direkten oder indirekten Aktivierung der Task.

Wird eine Task indirekt aktiviert, so wird zu Beginn ihrer Auswertung eine spezielle Codesequenz durchlaufen, die zunachst die - gemafi den durch den kon­textfreien 'evaluation transformer' der Taskmarkierung gegebenen Informationen - strikten Argumente der Task auswertet bzw. deren Auswertung anstofit. Diese Codesequenz braucht bei einer direkten Aktivierung nicht durchlaufen zu werden, da in diesem Fall die Argumentauswertung bereits durch den vor der Aktivierung ausgefiihrten Code initiiert wurde, der insbesondere auf kontextsensitiven Strikt­heitsinformationen basiert.

Page 32: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 261

Indirekt aktivierte Tasks entsprechen entweder Applikationen in nicht-strikten Argumentpositionen, deren Auswertung zunachst verzogert wurde, oder dyna­misch - mittels Funktionen hOherer Ordnung - erzeugten vollstandigen Appli­kationen.

Die Befehle EVALUATE und ACTIVATE dienen der direkten Aktivierung von Tasks, wahrend die iibrigen Befehle im Falle der Aktivierung eines schlafenden Taskknoten eine indirekte Aktivierung bewirken.

1m einzelnen haben die verschiedenen Befehle also folgende Bedeutungen:

• EVALUATE ~ bewirkt die direkte Aktivierung einer lokalen Task mit Aus­werter ~. Die zu aktivierende Task ist durch das oberste Datenkellerelement der zur Zeit aktiven Task gegeben.

Lokale Aktivierung bedeutet, dafi die Statusinformation des Taskknoten er­weitert wird und daB die Adresse der Task in die lokale Taskqueue geschrie­ben wird. Die gerade ausgefiihrte Task wird dabei zunachst nicht suspendiert (siehe Bild 10.7) .

• ACTIVATE ~ bewirkt die Erzeugung eines parallelen Prozesses mit Auswer­ter ~. Die parallel auszufiihrende Task ist wiederum durch das Element auf der Spitze des Datenkellers gegeben.

Parallele Ausfiihrung einer Task bedeutet, dafi eine Beschreibung der Task an ein anderes Prozessorelement iibermittelt werden mufi. Dies geschieht mit­tels einer sogenannten Prozefinachricht (process-message), die i.a. folgende Struktur hat:

[PROCESS, Kombinatorname, Argumentliste, Auswerter, Aktivierungsart, Heimatadresse].

Neben den im Taskknoten gegebenen Informationen und dem neuen Aus­werter der Task enthalt die Proze:Bnachricht zwei weitere Komponenten: die Aktivierungsart und die Heimatadresse.

Die Aktivierungsart wird durch ein Tag (dir/indir) angegeben, das anzeigt, ob es sich urn eine direkte oder indirekte Aktivierung der Task handelt. Die­ses Tag bestimmt die Codeadresse, mit der die Ausfiihrung der Task beginnt. Bei einer direkten Aktivierung kann, wie wir bereits erlautert haben, eine spatere Codeeinsprungstelle gewahlt werden, da vorausgesetzt werden kann, dafi die Argumentberechnungen bereits so weit wie moglich initiiert wurden. Mittels der ACTIVATE-Instruktion erfolgt immer eine direkte Aktivierung des parallelen Prozesses.

Page 33: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

262 KAPITEL 10" PROGRAMMIERTE GRAPHREDUKTION

atp

1 label argument list I evaluator

TASK ip I data stack

I B (P, ,~o) variable stack I pc I lists of addresses

DO """I"""

J /

label argument list evaluator

code: TASK J.L argl : """ : argk ~o

MKNODE(J.L, k) '--+- EVALUATE

atp

1 label argument list evaluator

TASK ip I data stack

I ~ """ (P, , ~) variable stack I pc I lists of addresses

00"""1"""

J label argument list evaluator

code: TASK J.l argl : """ : argk ~

ip data stack variable stack pc lists of addresses

~ § 0 - I -MKNODE(J.l, k) EVALUATE ~

I....+-Codeanfang zu lokale Task-

(J.L, ~ ,dir) warteschlange -BUd 10.7: Lokale Aktivierung einer Task

Page 34: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 263

Die Heimatadresse ist die urspriingliche Adresse des Tasklmoten, der nach der Erzeugung der ProzeBnachricht mit einem Verweisknoten iiberschrieben wird. An diese Adresse wird der Wurzelknoten des Ergebnisses des Prozesses zuriickgesendet.

Die parallele Aktivierung einer Task erfolgt also dadurch, daB eine ProzeB­nachricht erzeugt und an die Kommunikationseinheit weitergeleitet wird. Der Tasklmoten wird mit einem Verweislmoten iiberschrieben, in dem der Auswerter der Task notiert ist (siehe Bild 10.8).

Bemerkenswert ist, daB die ProzeBnachricht keine Zieladresse hat, d.h. es bleibt in der aktivierenden Reduktionseinheit unbekannt, an welches Pro­zessorelement der parallele ProzeB weitergeleitet wird. Die Verteilung der parallelen Prozesse ist die Aufgabe der Kommunikationseinheit.

• INITIATE ~ bewirkt die Aktivierung von Knoten, die mittels der APPLY­Instruktion erzeugt wurden. Der zu aktivierende Knoten ist durch eine lokale Adresse auf der Spitze des Datenkellers gegeben. Es sind drei Knotentypen maglich:

- ein Funktionsknoten,

- ein Tasklmoten mit Auswerter ~o oder

- ein Datenstrukturknoten mit Auswerter ~1'

Handelt es sich um einen Funktionsknoten, so hat der Befehl bis auf die Inkrementierung des Befehlsziihlers keine Auswirkung.

Zeigt die Datenkellerspitze auf einen schlafenden Taskknoten, so erfolgt eine lokale indirekte Aktivierung der zugehOrigen Task mit dem Auswerter~. In diesem Fall entspricht die Task einer dynamisch erzeugten Applikation. Es kann nicht davon ausgegangen werden, daB die Argumente dieser Task be­reits aktiviert wurden. Ais Codeeinsprungstelle wird also die Stelle gewahlt, bei der zunachst die Aktivierung der strikten Argumente erfolgt. Ansonsten erfolgt die Aktivierung wie bei der EVALUATE-Instruktion. Nach Erwei­terung der Statusinformation der Task, wird ihre Adresse zur lokalen Task­queue hinzugefUgt.

1m Falle eines Datenstrukturknoten mit Auswerter 6 braucht nur, falls ~ > ~1' die weitere Auswertung der Datenstruktur mit ~ veranlaBt zu werden. Dies geschieht, indem die Adresse des Datenstrukturknoten zusammen mit den Auswertern fUr die Komponenten in der Aktivierungsliste vermerkt wird.

Mittels der Befehle INITARG (i,O, INITLOC (i,~), GETARG (i,~) und GET­LOC (i,~) wird die Auswertung von Argumenten und Bindungen lokaler Variablen

Page 35: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

264 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

atp

1 label argument list evaluator

TASK ip I data stack

I ~ ... (P, ,~O) variable stack I pc I lists of addresses

§ 0 ... I ...

) /'

label argument list evaluator I code:

TASK J.l argl : ... : argk ~o

MKNODE (J.l, k) '--+- ACTIVATE

atpG--j TASK

,label , argument list , evaluator

ip , data stack

I ~ ... \(P, , ~)J variable stack, pc lists of addresses

§ 0 ... I ...

) /'

address evaluator lists of addresses

code: INDIRECTION ? ~ -

I -

MKNODE (J.l, k) ACTIVATE ~ & folgende Nachricht wird erzeugt:

[PROCESS, J.l, argl ..... argk, ~,du, ]

Bild 10.8: Parallele Aktivierung einer Task

Page 36: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 265

angesto:Ben. Der erste Parameter beschreibt jeweils die Position der zu aktivieren­den Variablenbindung in der Argumentliste bzw. im Keller der lokalen Variablen. Der zweite Parameter gibt den Auswerter an, mit dem die Aktivierung erfolgen solI.

Bei diesen Instruktionen kann im Gegensatz zu den zuvor beschriebenen Ak­tivierungsbefehlen EVALUATE und ACTIVATE, bei denen auf dem Datenkeller ein lokaler Zeiger auf einen Taskknoten liegt, der zu aktivierende Teilgraph von beliebiger Art sein. Es sind folgende FaIle zu unterscheiden:

1. 1st das i-te Argument oder der i-te Eintrag des Verwaltungskellers lokaler Variablen ein Wert, so wird lediglich der Befehlszahler erhoht.

2. 1st der zu aktivierende Graph durch eine globale Adresse mit Auswerter e gegeben, so zeigt sich folgender Unterschied zwischen den INIT ... - und den GET ... -Instruktionen:

Wahrend die INIT ... -Instruktionen lediglich die Aktivierung von Teilberech­nungen bewirken, verlangen die GET ... -Instruktionen zudem, dafi der Wur­zelknoten des Ergebnisses lokal zuganglich gemacht wird.

Bei der INIT ... -Instruktion wird an die globale Adresse eine Aktivierungs­nachricht der Form

[INITIATE, globale Adresse, Auswerter]

geschickt, falls der in der Instruktion gegebene Auswerter ~ starker ist als der bei der globalen Adresse vermerkte Auswerter. Der neue Auswerter wird bei der globalen Adresse eingetragen, damit erneute Aktivierungsnachrichten an diese Adresse nach Moglichkeit vermieden werden. 1st der gegebene Auswer­ter der globalen Adresse hingegen starker, so bleibt die INIT ... -Instruktion bis auf die Erhohung des Befehlszahlers ohne Effekt.

Bei einer GET ... -Instruktion wird an eine globale Adresse auf jeden Fall eine Anfragenachricht geschickt, die eine Aktivierung bewirkt, aber insbesondere auch auch eine Adresse enthalt, an die das Ergebnis (Wurzelknoten) der aktivierten Berechnung geschickt werden solI:

[REQUEST, globale Adresse, Auswerter, Antwortadresse].

Dazu wird ein neuer Verweisknoten erzeugt, der als Platzhalter fur das Er­gebnis dient und in dem die globale Adresse sowie der maximale Auswerter eingetragen werden. In der Argumentliste bzw. im Keller lokaler Variablen wird die globale Adresse durch die lokale Adresse des Verweisknotens er­setzt, damit bei einem eventuellen erneuten Zugriff auf das Argument oder

Page 37: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

266 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

die lokale Variable keine weitere 'REQUEST'-Nachricht geschickt wird. Die lokale Adresse des Verweisknoten bildet auch die Antwortadresse der Anfra­genachricht. Ais Auswerter wird wie zuvor das Maximum des bei der Adresse vermerkten und des in der Instruktion gegebenen Auswerters gewahlt. Bild 10.9 veranschaulicht die Auswirkungen eines GETARG-Befehls in dem Fall, in dem das zu aktivierende Argument durch eine glob ale Adresse gegeben ist.

3. 1st der zu aktivierende Eintrag eine lokale Adresse, so haben INIT ... - und GET ... -Instruktionen dieselbe Wirkungsweise, da in diesem Fall feststeht, dafi der Wurzelknoten des Ergebnisses der zu aktivierenden Berechnung 10kal verfiigbar sein wird.

1st der zur lokalen Adresse vermerkte Auswerter grof3er oder gleich dem in der Instruktion gegebenen Auswerter, so braucht keine weitere Aktivierung zu erfolgen. Denn die zu den Adressen notierten Auswerter sind immer kleiner oder gleich den tatsachlichen Auswertern der Teilgraphen, auf die sie zeigen. Gleichheit kann auf Grund von 'Sharing' nicht garantiert werden.

Scheint eine weitere Aktivierung notwendig, so muf3 der Auswerter, der im Graphknoten notiert ist, iiberpriift werden. Dabei sind folgende Falle zu unterscheiden:

(a) Handelt es sich urn einen Taskknoten mit Auswerter ~o, also urn eine noch nicht aktivierte Task, so wird diese als paralleler Prozef3tt akti­viert. Es wird also eine Prozef3nachricht an die Kommunikationseinheit geschickt und der Taskknoten mit einem Verweisknoten iiberschrieben. Die Art der Aktivierung ist indirekt.

(b) 1st der zu aktivierende Graphknoten ein aktiver oder wartender Task­knot en mit von ~o verschiedenem Auswerter, so wird der Auswerter der Task aktualisiert. Dabei wird der in der Instruktion gegebene Auswer­ter als neuer Auswerter der Task eingetragen, wenn dieser starker ist als der vorherige Auswerter. Die Auswertung der Task wird allerdings mit dem urspriinglichen Auswerter fortgesetzt. Erst bei Beendigung der Task wird die Information des neuen Auswerters ausgenutzt, urn eine weitere Auswertung des Ergebnisses zu initiieren.

(c) Bezieht sich die Instruktion INIT ... oder GET ... auf einen Argument­knoten, so wird dieser mit einem Taskknoten iiberschrieben, der als Marke 'arg' erhalt und die Argumentliste sowie den Keller lokaler Va­riablenbindungen aus dem Argumentknoten iibernimmt. Ais Auswerter wird der Instruktion gegebene Auswerter gewahlt. Mittels dieses Aus­werters wird auch die Codeadresse aus dem Argumentknoten ermittelt,

tt Dies zeigt die zusii.tzlich zum letpar-Konstrukt vorhandene Parallelitii.t.

Page 38: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN

data stack

code:

GETARG (i, €)

TASK data stack

~

code:

GETARG (i, €)

label argument list evaluator

.. : ai-l: (P,gadr,€,) :ai+1 : ..

variable stack

§

gadr sei eine globale Adresse.

label argument list evaluator

... : ai-l ai+l : ...

variable stack

§

& folgende Nachricht wird erzeugt:

[REQUEST, gadr, €",

Dabei sei €" = max{€,€,}.

Bild 10.9: Generierung einer Anfragenachricht durch den Befehl GETARG

267

Page 39: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

268 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

mit der der Befehlszahler initialisiert wird. Alle iibrigen Komponenten des Taskknotens werden mit € bzw. 0 vorbesetzt. Die Aktivierung von Argumentknoten fiihrt immer zu lokalen Tasks, d.h. die Adresse des iiberschriebenen Argumentknoten wird zur lokalen Taskqueue hinzugefiigt.

(d) 1m Falle von Terminalknoten ist eine Erhohung des Auswerters nur fiir Datenstrukturknoten moglich. Liegt ein solcher Knoten vor und ist der in der Instruktion gegebene Auswerter starker als der im Knoten no­tierte Auswerter, so wird die lokale Adresse dieses Knotens zusammen mit den Auswertem fiir die Komponenten, die in der Programmspei­cherkomponente c-evt fiir den Konstruktor des Datenknotens und den starkeren Auswerter gegebenen sind, in der Aktivierungsliste vermerkt. Die Abarbeitung der Aktivierungsliste erfolgt zu einem spateren Zeit­punkt. Auf diese Weise wird sichergestellt, dafi jede Maschineninstruk­tion nur beschrankt viel Zeit benotigt.

(e) Handelt es sich bei dem zu aktivierenden Knoten urn einen Verweis­knoten, in dem ein schwacherer Auswerter eingetragen ist, so wird der schwachere Auswerter mit dem neuen Auswerter iiberschrieben. Zu dem Zeitpunkt, zu dem der Verweisknoten mit einem terminalen Kno­ten iiberschrieben wird, erfolgt dann, wenn notwendig, eine weitere Aus­wertung der Struktur. Handelt es sich urn einen lokalen Verweisknoten, so wird in der Ar­gurnentliste oder im Verwaltungskeller die Adresse dieses Knotens mit der in dem Verweisknoten gegebenen Adresse iiberschrieben und der INIT ... - oder GET ... -Befehl fiir diese Adresse ausgefiihrt.

Die INIT ... - und GET ... - Befehle sind sehr komplexe Befehle, da sie die Ak­tivierung beliebiger Graphstrukturen behandeln.

Zusammenfassend ergibt sich folgende Klassifikation der Befehle zur Aktivie­rung von Berechnungen:

II lokal parallel

direkt EVALUATE ~ ACTIVATE ~

indirekt INITIATE ~ GET ARG

(i, ~) INIT LOC

Suspendierung von Tasks

Da der gesamte Berechnungsgraph verteilt abgespeichert ist, kann es zu Situatio­nen kommen, in denen eine Task globale Informationen, d.h. Informationen, die

Page 40: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 269

auf anderen Prozessorelementen liegen, zur weiteren Berechnung benotigt. So lie­gen im allgemeinen die Argumente eines parallelen Prozesses zunachst nicht auf dem Prozessorelement, auf dem der ProzeB zur Ausfiihrung gelangt. Sie miissen erst durch Anfragenachrichten angefordert werden.

Benotigt ein Prozefi zur Fortsetzung seiner Berechnungen globale Argumente, die noch nicht lokal verfiigbar sind, so mufi er suspendiert werden. Ebenso miissen Tasks, die die Ergebnisse paralleler Subtasks benotigen, solange unterbrochen wer­den, bis diese Ergebnisse vorliegen .

• Die Suspendierung einer Task erfolgt gegebenenfalls durch die Ausfiihrung der Instruktion WAIT m (m ~ 1), die testet, ob die obersten m Elemente des Datenkellers zur Kombinatornormalform ausgewertet und lokal vorhan­den sind, d.h. entweder Werte oder Zeiger auf lokale Datenknoten sind. Flir jeden Zeiger auf einen Taskknoten oder Verweisknoten wird der 'pending count' der aktiven Task urn eins erhoht. Die Adresse der aktiven Task wird in den lokalen Adressenlisten der Task- bzw. Verweisknoten vermerkt, da­mit bei Termination der Tasks bzw. beim Uberschreiben der Verweisknoten der 'pending count' der wartenden Task dekrementiert werden kann. Der 'active task pointer' wird auf nil gesetzt, d.h. es erfolgt, falls moglich, ein Taskwechsel. Bild 10.10 zeigt ein Beispiel fiir eine Tasksuspendierung.

Solange der 'pending count' einer Task von Null verschieden ist, ist diese suspendiert. Sobald der 'pending count' auf Null dekrementiert ist, kann die Ausfiihrung der Task fortgesetzt werden. Die Adresse des Taskknoten wird dazu in die lokale Taskqueue geschrieben.

Der WAIT-Befehl dereferenziert Zeiger auf lokale Verweisknoten, d.h. er er­setzt solche Zeiger durch den im Verweisknoten angegebenen Zeiger. Daher kann bei den auf diesen Befehl folgenden Instruktionen immer davon ausge­gangen werden, daB keine Zeiger auf lokale Verweisknoten auf dem Daten­keller liegen.

Termination von Tasks

Zur Termination von Tasks unterscheiden wir zwei Befehle.

• RET e (e E Evset) ist der allgemeine Befehl, der zur Terminierung einer Task zur Verfiigung steht. Durch die Ubersetzungsregeln, die im folgenden Abschnitt beschrieben sind, ist sichergestellt, daB das Resultat der Task auf der Spitze des Datenkellers als Wert oder als lokaler Zeiger auf das Ergebnis gegeben ist.

Liegt das Resultat in Kombinatornormalform, also als Wert oder Zeiger auf einen Terminalknoten vor, so wird der 'pending count' aller in der lokalen

Page 41: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

270 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

atp

1 label argument list evaluator

TASK ip data stack variable stack pc lists of addresses

I ~ ... I(p, ,~)I(P'I £)1 0 0 ... I

. .. ~ )

/' ~ address evaluator lists of addresses

INDIRECTION ... . .. ... I

. ..

"'-code: )

label argument list evaluator

TASK '--- WAIT 2

ip I data stack variable stack pc lists of addresses

D 0 ... I

. ..

r---------------------------------------atp~

label argument list evaluator

TASK " ip data stack variable stack pc lists of addresses

I ~ ···I(P, ,~)I(P'I ,e)1 0 2 ... I

. .. --" ) )

/' ~ address evaluator lists of addresses

INDIRECTION .. . ... .•. ~ I . ..

~ "- 7 code: )

label argument list evaluator

TASK WAIT 2

ip I data stack variable stack pc lists of addresses '--- D 0 ... \ I ...

'" Bild 10.10: Suspendierung einer Task

Page 42: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 271

Adre:Bliste notierten Taskknoten dekrementiert. Wird ein 'pending count' dabei zu Null, so wird die Adresse der entsprechenden Task in die lokale Taskqueue geschrieben.

Dies zeigt, dafi die Ausfiihrung einer Task immer auf dem Prozessorele­ment beendet wird, auf dem sie begonnen wird. Prozesse oder Tasks, deren Ausfiihrung begonnen wurde, werden also niemals weiter verschickt.

Weiterhin wird das Resultat der Task an alle Adressen, die in der globalen Adre:Bliste des Taskknoten vermerkt sind, geschickt. Dies geschieht mittels sogenannter Antwortnachrichten der Form

[ANSWER, Adresse, Terminalknoten],

die das Ergebnis bzw. den Wurzelknoten des Ergebnisses als Terminalknoten enthalten. Schlie:Blich wird der Taskknoten mit seinem Ergebnis iiberschrie­ben und der 'active task pointer' auf den Wert 'nil' gesetzt.

Zeigt die Spitze des Datenkellers auf einen nicht terminalen Knoten, so wird falls moglich mit der Auswertung dieses Knotens fortgefahren. Die AdreBli­sten im Status der Task werden in den Status des noch nicht vollstandig ausgewerteten Ergebnisses kopiert und der Taskknoten wird mit einem loka­len Verweisknoten auf das Ergebnis iiberschrieben.

Der Auswerter, der als Parameter der RET-Instruktion auf tritt, ist der Aus­werter, mit dem die Aktivierung der Task erfolgte. Er wird benotigt, um festzustellen, ob der Auswerter wahrend der Ausfiihrung der Task erhoht wurde. 1st dies der Fall und liegt das Ergebnis in Kombinatornormalform vor, so erfolgt zur weiteren Aktivierung der Komponenten des Ergebnisses ein entsprechender Eintrag in der Aktivierungsliste. 1st das Ergebnis noch nicht vollstandig ausgewertet, so wird der Auswerter der Task, die das Er­gebnis berechnet, aktualisiert .

• PUSH (F, m) mit F E Fun und m E IN dient der Realisierung von 'tail'­rekursiven Kombinatoraufrufen. Die Marke des aktuellen Taskknoten wird mit F iiberschrieben, die Argumentliste mit den m obersten Elementen des Datenkellers. Der Auswerter bleibt erhalten. Der Instruktionszahler wird auf die im Programmspeicher fUr den Kombinator Fund den aktuellen Auswer­ter bei direkter Aktivierung gegebene Codeeinsprungstelle gesetzt. Daten­keller und Verwaltungskeller lokaler Variablen werden geloscht. Der PUSH­Befehl vermeidet auf diese Weise die Konstruktion eines neuen Taskknoten, wenn das Ergebnis der Task dem Ergebnis des neuen Kombinatoraufrufes entspricht.

Page 43: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

272 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Prozejlnachrichten: [PROCESS, Kombinatorname, Argumentliste, Auswerter, Aktivierungsart, Heimatadresse]

Aktivierungsnachrichten: [INITIATE, globale Adresse, Auswerter]

Anfragenachrichten: [REQUEST, globale Adresse, Auswerter, Antwortadresse]

Antwortnachrichten: [ANSWER, Adresse, Terminalknoten]

Bild 10.11: Nachrichten

N achrichten

Bevor wir die formale Spezifikation der Prozefibefehle angeben, stellen wir die Nachrichtenarten zusammen, die fUr die Parallelisierung des Graphreduktionspro­zesses notwendig sind. Es werden im wesentlichen vier Nachrichtentypen benotigt:

1. Prozejlnachrichten zur Verteilung von Prozessen,

2. Aktivierungsnachrichten zur Aktivierung der Auswertung von Graphteilen, die auf anderen Prozessorelementen liegen,

3. A nfragenachrichten zur Anforderung von globalen Graphknoten und schlieB­lich

4. A ntwortnachrichten zur Beantwortung von Prozefi- und Anfragenachrichten.

Die Struktur dieser Nachrichten wurde bereits kurz beschrieben und ist in Bild 10.11 nochmals zusammengestellt. In folgender Definition erfassen wir die Be­schreibungen formal:

10.3.5 Definition Die Menge RedMes der Reduktionsnachrichten der parallelen abstrakten Maschine wird wie folgt formal definiert:

RedMes := PraMes U InitMes U ReqMes U AnsMes,

wobei

Page 44: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN

ProMes := {PROCESS} x Fun x Eintriige* x Evset x {dir, indir} x GAdr

InitMes := {INITIATE} x GAdr x Evset ReqMes := {REQUEST} x GAdr x Evset x GAdr AnsMes := {ANSWER} x GAdr x Terminalnodes

Proze:Bnachrichten notieren wir i.a. in der Form

[PROCESS, F, argl .,. argk, ~, act, hadr],

wobei

F E FUN der Kombinatorname,

argl ... argk E Eintriige* die Argumentliste der Kombinatorapplikation,

~ E Evset der Auswerter,

act E {dir, indir} die Aktivierungsart und

hadr E GAdr die Heimatadresse des parallelen Prozesses sei.

Aktivierungsnachrichten haben die Form

[INITIATE, adr, ~]

273

und enthalten lediglich die Zieladresse und den Auswerter, mit dem die Auswer­tung des Teilgraphen mit der Adresse adr erfolgen solI.

Anfragenachrichten

[REQUEST, adr, ~, returnadr]

enthalten neben der Zieladresse und dem Auswerter die Adresse, an die der Wur­zelknoten des Ergebnisgraphen, der sich durch Auswertung des Knotens mit der Adresse adr ergibt, geschickt werden solI.

Antwortnachrichten haben die allgemeine Form

[ANSWER, adr, tnode]'

wobei adr die Zieladresse bezeichnet, unter der der Terminalknoten tnode abge­speichert werden solI.

Page 45: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

274 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Formale Befehlssemantik

Die Befehlssemantik der Prozefibefehle wird damit wie folgt festgelegt. Da Pro­zefibefehle die Erzeugung von Nachrichten bewirken konnen, bildet die Befehlsse­mantik Zustande auf Paare aus Zustanden und Nachrichtensequenzen abo

10.3.6 Definition

Cp : Plnstr X {I, ... ,n} -t LStRE - -t LStRE X RedMes*

wird definiert durch:

Cp[EVALUATE e] pnr (rm, atp, G[atp / (TASK,/L,arglist,(~, ip, ds:(P,(pnr,ladr),~o),lv,O,lq,gq))

ladr / (TASK,F ,arglist', ~o)], gp, 1tq, al, ( ca-c, ca-f, rg, c-evt, c ))

:= ( (rm, atp, G[atp / (TASK,/L,arglist,(~,ip+1,ds:(P,(pnr,ladr),e),lv,O,lq,gq)),

ladr/ (TASK,F,arglist',(e, ca-c(F, e, dir), €,€,O,€,€))], gp, ltq: ladr, al, ( ca-c, ca-f, rg, c-evt, c )),

€ )

falls F E Fun und ca-c(F, e, dir) E PAdro

Cp[ACTIVATE e] pnr (rm, atp, G[atp /(TASK,/L,arglist, (~,ip,ds:(P,(pnr,ladr),~o),lv,O,lq,gq))

ladr / (TASK,F ,arglist', ~o)], gp, 1tq, al, ps)

:= ( (rm, atp, G[atp /(TASK,/L,arglist, (~,ip+1,ds:(P,(pnr,ladr),e),lv,O,lq,gq )),

ladr/(INDIRECTION, ?, e, €, E)], gp, ltq, al, ps),

[PROCESS, F, arglist',e, dir, (pnr, ladr)] )

C p[INITIATE e] pnr (rm, atp, G[atp/(TASK,/L,arglist, (~,ip,ds:(P,(pnr,ladr)i),lv,O,lq,gq))], gp, 1tq, aI, ps)

{ ((rm, atp, G[atp/(TASK,/L,arglist,(~, ip+ 1, ds:(P,(pnr,ladr),6),lv,O,lq,gq))],

.- gp, 1tq, al, ps), E),

Page 46: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 275

falls G(ladr) = (FUNCTION, jl', arglist', k)

((rm, atp, G[atp/(TASK,jl,arglist,(~, ip+l, ds:(P,(pnr,ladr),e},lv,O,lq,gq}),

ladr/(TASK,j.t' ,arglist', W, ca(jl'), E, E, 0, E, E})], gp, Itq: ladr, aI, ps),

E}, falls G(ladr) = (TASK, jl', arglist', ~o) und ca ( ') _ { ca-c(j.t', e, indir) falls j.t' E Fun,

jl - ca-f(jl') falls jl' E O.

((rm, atp, G[atp/(TASK,jl,arglist,(~, ip+l, ds:(P,(pnr,ladr),e},lv,O,lq,gq}),

ladr/(SDATA, c, arglist', e)] gp, ltq, al', ps),

E}, falls G(ladr) = (SDATA, c, arglist',6) und aI' = { al:(ladr, c-evt (c, e)) falls e > ~,

al falls e = 6

Cp[INITARG (i,e)] pnr (rm, atp, G[atp/(TASK, jl, argl : ... argkl (~, ip, ds, lv, 0, lq, gq })], gp, ltq, al ps)

{ ((rm, atp,

._ G[atp/(TASK,jl, argl : ... : argkl (~, ip+l, ds, lv, 0, lq, gq })],

.- gp, ltq, al, ps), E}

. - { .-

falls e = ~o oder argi = (V, a) oder argi = (P, adr, e') und ~" ~ e .

((rm, atp, G[atp/(TASK,jl, arg1 : ... argi ... : argkl (~,ip+l,ds,lv,O,lq,gq})], gp, ltq, al, ps),

[INITIATE, gadr, e] } falls argi = (P, gadr, e') mit ~" < e und gadr (j. {(pnr, ladr) Iladr E LAdr}, argi = (P, gadr, ~').

Page 47: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

276 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

{(rm, atp, G[atp/(TASK,p, argl : ... arg~ ... : argk, (~,ip+l,ds,lv,O,lq,gq}),

ladr/(INDIRECTION, ?, e, €, f)], gp, 1tq, al, ps),

[PROCESS, F, arglist',~', indir, (pnr, ladr)] } falls argi = {P, (pnr, ladr),~o)

{(rm, atp,

mit G(1adr) = (TASK, F, arglist',~o), FE Fun, und arg~ = {P, (pnr,ladr),e).

G[atp/(TASK,p, arg1 : ••• arg~ ... : argk' (~,ip+l,ds,lv,O,lq,gq})], ladr/(TASK,p', arglist', {{', ip', ds', lv', pc', lq', gq'} )]

gp, 1tq, al, ps), €}

{(rm, atp,

falls argi = {P, (pnr, ladr) , {} mit G(ladr) = (TASK, p', arglist',

({, ip', ds', lv', pc', lq', gq'}), wobei {, := max{{,e} und argi = (P,(pnr, ladr), {'}.

G[atp/(TASK,p, argl : ... argi ... : argk, (~,ip+l,ds,lv,O,lq,gq}), ladr/(TASK,'arg', arglist',{ e,lj,€, lv',O,€,€})],

gp, 1tq:ladr, al, ps), €}

{(rm, atp,

falls argi = {P, (pnr, ladr), ~o} mit G(1adr) = (ARGUMENT,{ arglist', Iv'), (It,12,13)) e = ~j fur ein j E {I, 2, 3}, und argi := {P, (pnr, ladr), e }.

G[atp/(TASK,p, arg1 : ... arg~ ... : argh{~,ip+l,ds,lv,O,lq,gq}), ladr/(SDATA, c, arglist',{')],

gp, 1tq, al', ps), €}

falls argi = {P, (pnr, ladr), {} mit G(ladr) = (SDATA, c, arglist, () wobei {' := max{e,{}, argi := {P, (pnr, ladr), {'}

Page 48: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 277

.-{ .-

.-{ .-

((rm, atp,

und aI' := { aall: (ladr, c-evt (c, e)) falls e ~ ~ sonst

G[atp/(TASK,jl, arg1 : ••• arg~ ... : argk' (~,ip+l,ds,lv,O,lq,gq))], gp, ltq, aI, ps)

E)

((rm, atp,

falls e = 6 und argi := (P, (pnr, ladr) , ~o) mit G(ladr) = (SDATA, ... ) oder G(ladr) = (FUNCTION, ... ), wobei argi = (P, (pnr, ladr)'~l)'

G[atp/(TASK,jl, argl : ... argi ... : argk, (~,ip+l,ds,lv,O,lq,gq)), ladr/(INDIRECTION, ?, ~, lq', gq')],

gp, ltq, aI, ps) E)

((rm, atp,

falls argi := (P, (pnr, ladr) , [), mit G(ladr) = (INDIRECTION, ?, ~, lq', gq'), wobei ~, := max{~, e} und argi = (P, (pnr, ladr),€'),

G[atp/(TASK,jl, argl : ... arg~ ... : argkl (~,ip+l,ds,lv,O,lq,gq)), ladr/(INDIRECTION, gadr, ~', lq', gq')]'

gp, ltq, aI, ps), mes)

((rm, atp,

falls argi := (P, (pnr, ladr),[), mit G(ladr) = (INDIRECTION, gadr, ~, lq', gq'), wobei~' := max{e,~}, mes := { ~INITIATE, gadr, e] falls e > ~,

c sonst und arg~ = (P, (pnr, ladr)i'),

G[atp/(TASK,jl, arg1 : ... argi ... : argk' (~, ip, ds, lv, 0, lq, gq ))], gp, ltq, aI, ps),

E) falls argi := (P, (pnr, ladr),~),

Page 49: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

278 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

mit G(ladr) = (LOCAL-IND, ladr'), wobei arg~ = (P, (pnr, ladr')l).

Die Semantik des Befehls INITLOC (i,e) wird vollkommen analog zur Se­mantik von INITARG (i, e) erkHirt, wobei an die Stelle des i-ten Argumentes argi der i-te Eintrag des Variablenkellers Iv tritt.

Wir verzichten daher auf die explizite Angabe von C p [INITLOC (i, e)].

Der Befehl GETARG (i, e) unterscheidet sich vom Befehl INITARG (i, e) nur in der Behandlung globaler Adressen. Wir fiihren daher die Semantik von GETARG groBtenteils auf die Semantik von INITARG zuruck.

Cp[GETARG (i,e)] pnr (rm, atp, G[atp/(TASK, j.l, argl : ... : argk, (~, ip, ds, lv, 0, lq, gq })], gp, ltq, aI, ps)

((rm, atp, G[atp/(TASK,j.l, arg1 : .•• argi ... : argk, (~,ip+l,ds,lv,O,lq,gq)),

gp/(INDIRECTION, gadr, [',E,E)], gp+l, ltq, aI, ps),

[REQUEST, gadr, [', (pnr, gp)] } falls argi = (P, gadri) mit gadr f/. {(pnr, ladr) Iladr E LAdr}, t,' =I ~o,{':= max{{,t,'} und argi := (P, (pnr, gp)i'),

'- { .-

Cp[INITARG(i,e)]pnr (rm, atp, G[atp/(TASK, j.l, argl: ... : argk' (~, ip, ds, lv, 0, lq, gq ) )], gp, ltq, aI, ps)

sonst.

Page 50: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN 279

Cp[WAIT m] pnr (rm., atp, G[atp/(TASK, IL, arglist, (~, ip, ds: d1 : .•• : dm , lv, 0, lq, gq ))], gp, ltq, al, ps)

(rm., atp, G[atp/(TASK, IL, arglist, (~, ip, ds: d1 : ••• : dm, lv, k, lq, gq )),

ladril / (TASK/INDIRECTION, ... ,lqil : atp, gqil )'

ladri,,/ (TASK/INDIRECTION, ... ,lqi" : atp, gqiJ), gp, ltq, al, ps),

€) wobei fiir 1 :5 i :5 m

d-· -1-

(P, (pnr, ladri), ~i), falls di = (P, (pnr, dil),~i) mit G(di,) = (LOCAL-IND, di,+l ) fiir 1 :5 I :5 ki - 1, G(di" ) fI. {(LOCAL-IND, la) Ila E LAdr}, . und ladri = di". fiir ki ~ 1.

di sonst und {i1, ... ,ik}:= {j E {1, ... ,m} I

dj = (P,(pnr,ladrj),~j) mit G(ladrj) fI. Terminalnodes}

ist nicht leer, also k ~ 1.

'-{ .-

(rm., atp, G[atp/(TASK, IL, arglist, (~, ip+1, ds: d1 : ••• : dm" lv, 0, lq, gq ))), gp, Itq, al, ps),

f), wobei fiir 1 :5 i :5 m

(P, (pnr, ladri), ~i), falls di = (P, (pnr, dil),~i) mit G(di,) = (LOCAL-IND, di /+ l )

di = fiir 1 :5 1 :5 ki - 1, G(di" ) fI. {(LOCAL-IND, la) Ila E LAdr}, . und ladri = di" fUr ki > 1. . -

di sonst und {j E {1, ... ,m} I dj = (P,(pnr,ladrj),~j)

mit G(ladr j) fI. Terminalnodes} = 0

Page 51: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

280 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

C p [RET e] pm (rm, atp, G[atp/(TASK,Jl,arglist,(~,ip,ds: do,lv,O,ladrl ... ladrm, gadrl ... gadrn))] gp, ltq, al, ps)

((rm, nil, G[atp/(tnode,

ladrt/(TASK,JlI' arglist l , (e, iPI' dsl , lVI, pCI - 1, lql' gql)),

ladr m / (TASK,Jlm, arglistm, (~m,iPm,dsm,lvm,pcm -1,lqm,gqm))],

gp, ltq: ladril ... ladrill al, ps), [ANSWER, gadrl' tnode] : [ANSWER, gadr2' tnode] : ...

: [ANSWER, gadrn' tnode] )

falls do = (V,a) mit a E A und tnode = (BDATA, a) oder do = (V, a) mit a E UdED r(f,d)

und tnode = (SDATA, a,E,6) oder do = (P, (pm, ladr)l)

mit G(ladr) E Terminalnodes und (SDATA, c', arglist',~) falls G(ladr) =

tnode = (SDATA, c', arglist',~) mit ~ < ~

G(ladr) sonst. oder do = (P, (pm,pt},[) und

3k ~ I,PI, ... ,Pk : G(pd = (LOCAL-IND, pi+d fUr i < k und G(Pk) E Terminalnodes,

(SDATA, c', arglist', ~) falls G(ladr) =

tnode = (SDATA, c', arglist',~) mit ~ < ~

G(ladr) sonst. und G(ladrd=(TASK,Jli' arglisti' (e, iPi' dsi, lVi, pCi' lqi' gqi))

mit pCi > ° (1 ~ i ~ k) und {ladril' ... ' ladri/}

:= {ladri /1 ~ i ~ k, pCi = ~ladr. (ladrl ... ladrm)} , wobei ~ladri(ladrl ... ladrm) die Anzahl der Vorkommen von ladri in ladrl ... ladrm bezeichne,

Page 52: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.3. DIE MASCHINENINSTRUKTIONEN

{ al: (atp, c-evt( c, 0)

falls ~ > e und al' := al tnode = (SDATA, c, arglist',~)

sonst

((rm, natp, G [atp / (LOCAL-IND ,ladr),

ladr / (TASK, j.l', arglist', ((', ip', ds', lv', pc',

281

lq' : ladrl : ... : ladrm, gq' : gadrl : ... : gadrm)], gp, ltq', aI, ps),

€) falls do = (P,(pnr, ladr),~) mit

G(1adr )=(TASK,j.l' ,arglist', ((, ip', ds' , lv' , pc' , lq', gq') ) oderdo = (P, (pnr, pd,~),

G(pi) = (LOCAL-IND, PHd (1 ~ i ~ k - 1), G(Pk) = (TASK, j.l', arglist', ((, ip', ds', lv', pc', lq', gq')) und Pk = ladr

und (, = max{~,n, ltq' entsteht aus ltq durch Streichen von ladr,

{ ladr falls pc' = 0, natp = .1

ill sonst.

((rm, nil, G[atp/(LoCAL-IND, ladr),

ladr/(INDIRECTION, ., (', lq' : ladr! : ... : ladrm,

gp, ltq, aI, ps), €)

gq' : gadrl : ... : gadrm)],

falls do = (P, (pnr, ladr) , ~) mit G(ladr) = (INDIRECTION, ... , t, lq', gq')

oderdo = (P, (pnr,Pl'~) mit G(Pi) = (LOCAL-IND, Pi+d (1 ~ i ~ k - 1), und G(Pk) = (INDIRECTION, ... ,(, lq', gq'), sowie Pk = ladr

und (':= max{(,O.

Page 53: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

282 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

C p [PUSH (j.l', m )] pnr (rm, atp, G[atp/(TASK, j.l, arglist, (~, ip, ds: d1 : •.. : dm , lv, 0, lq, gq ))], gp, ltq, aI, ( ca-c, ca-f, rg, c-evt, c ))

:= (rm, atp, G[atp/(TASK, j.l', d1 : ••• : dm , (~, ca-c(j.l',~, dir), E,E, 0, lq, gq ))], gp, ltq, aI, ( ca-c, ca-f, rg, c-evt, c )).

Damit haben wir die Semantik aller Instruktionen formal erkHirt. Fur die Datenkeller-, Kontroll- und Graphinstruktionen haben wir dabei zunachst eine speziellere Semantik definiert als fUr die ProzeBbefehle, die zur Erzeugung von Nachrichten fuhren konnen. Allgemein legen wir die Befehlssemantik daher nun wie folgt fest.

10.3.7 Definition Die Befehlssemantik

C: Instr x {I, ... , n} -t LStRE- -t LStRE x RedMes*

wird fUr ins E Instr, pnr E {I, ... , n} und st E LStRE erklart durch:

{ (Cns[ins] pnr st,E)

C[ins] nr st := (Cc[~ns] pnr st, E) p (CG[ms] pnr st,E)

Cp[ins] pnr st

falls ins E DSlnstr, falls ins E Clnstr, falls ins E Glnstr, falls ins E Plnstr.

Bevor wir die Semantik der Befehle benutzen, urn die Zustandsubergange der Reduktionseinheiten im Reduktionsmodus zu beschreiben, gehen wir im nachsten Abschnitt zunachst auf die Ubersetzung von annotierten parallelisierten Kombi­natorsystemen in Maschinencodesequenzen ein.

10.4 Compilation von parallelisierten Kombina­torprogrammen

Die Compilation annotierter parallelisierter Kombinatorprogramme wird durch folgende Ubersetzungsfunktionen beschrieben:

TRANS: PROGan -t PAM-CODE,

COMTRANS: Comdern x (Evset \ {~o}) x IN* -t PAM-Code,

Page 54: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.4. CODEERZEUGUNG 283

EVALRET: ParExpan x (Evset \ {~o}) x IN* x [Loc ~fin IN]f X IN ~ PAM-Code,

EVAL: ParExpan x (Evset \ {~o}) x IN* X [Loc ~fin IN] X IN ~ PAM-Code,

INIT: ParExpan X Evset x IN* x [Loc ~fin IN] X IN ~ PAM-Code,

DELAY: ParExpan X IN* X [Loc ~fin IN] X IN ~ PAM-Code.

Dabei bezeichne PROCan die Menge aller annotierten parallelisierten Kom­binatorprogramme (vgl. Definition 6.3.1 bzw. 7.1.2), Comdern die Menge aller annotierten Kombinatordefinitionen und ParExpan die Menge aller annotierten parallelisierten applikativen Ausdrucke.

Die Annotierung einer Kombinatordefinition besteht aus dem kontextfreien 'evaluation transformer' fUr den Kombinator und den kontextsensitiven Annota­tionen des Kombinatorrumpfes. Dnter kontextsensitiven Ann~tationen von Aus­drucken verstehen wir die kontextsensitiven 'evaluation transformer' des Aus­druckes und seiner Teilausdriicke. Fur case-Ausdriicke betrachten wir allerdings die 'evaluation transformer' der Alternativen als "kontext-sensitive" Annotierung.

In dem erzeugtem Maschinencode werden als Programmadressen baumstruk­turierte Marken 1 E IN* zugelassen. Dies vereinfacht die Bestimmung von neuen Sprungadressen. Zur Ubertragung des Maschinencodes in den Programmspeicher der Reduktionseinheiten setzen wir die Existenz eines einfachen Ladeprogramms voraus, das die baumstrukturierte durch eine lineare Adressierung ersetzt. Der bei der Ubersetzung erzeugte Code hat die in folgender Definition beschriebene allgemeine Struktur.

10.4.1 Definition Sei Instr die Menge der Maschineninstruktionen, in denen als Programmadressen Marken aus IN* auftreten. Dann definieren wir

PAM-Code := ((IN*)* X Instr')+(IN*)*.

Zur Bezeichnung von Codesequenzen aus PAM-Code vereinbaren wir fol­gende Schreibweisen:

• Worte w E IN* schreiben wir in der Form

mit i l , ... ,ik E IN und k E IN.

t [Loc -fin IN·] bezeichnet die Menge aller partiellen Funktionen von Loc nach IN mit lee­rem oder endlichem Definitionsbereich. 1m folgenden bezeichnen wir die Funktion mit leerem Definitionsbereich mit 0"0.

Page 55: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

284 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

• Worte U E (IN*)* notieren wir in der Form

U = WI : W2 : ••• : Wl

mit WI, .•• ,Wl E IN*,l E IN .

• Codesequenzen code E PAM-Code notieren wir allgemein wie folgt:

mit Ui E CIN*)*, insi E Instr' (1 SiS n), Un+1 E (IN*)*, n ? 1. Falls 1nstruktionen insi keine Marken haben (Ui = E), so schreiben wir einfach insi anstatt ui : insi (1 SiS n).

Das Ladeprogramm zur Linearisierung des durch die Ubersetzungsfunktionen erzeugten Codes hat folgenden Typ:

Lade: PAM-Code -t [PAdr -t Instr] x [IN* -t PAdr].

Die erste Komponentenfunktion Ladel liefert den linearisierten Code in der Form, in der er im Programmspeicher abgelegt wird. Die zweite Komponentenfunktion Lade2 beschreibt die Adref3transformation.

Die Ubersetzungsfunktion TRANS erzeugt zu einem Kombinatorprogramm eine Maschinencodesequenz, die sich aus Codesequenzen fUr den Hauptprogrammaus­druck, fiir die verschiedenen Kombinatordefinitionen und fUr die Basisfunktionen zusammensetzt. 1st der Typ des Hauptausdruckes oder der Zieltyp eines Kombi­nators eine Datenstruktursorte, so werden fiir jeden moglichen Auswerter - also insgesamt 3 verschiedene - Codesequenzen fUr den Ausdruck bzw. den Kombina­tor generiert. Urn eine unnotige Explosion des Codes durch diese 'Verdreifachung' zu vermeiden, konnte man natiirlich die yom Auswerter unabhangigen Codeteile iiberlagern und zu Auswerter-spezifischen Codeteilen mittels eines speziellen Test­befehls, der in Abhangigkeit yom Auswerter einer Task verzweigt, springen. Dies hat den Nachteil, daf3 wiihrend der AusfUhrung einer Task zusatzliche Tests des Auswerters durchgefUhrt werden miissen. Es bringt aber auch den Vorteil, daf3 eine Anderung des Auswerters wahrend der AusfUhrung einer Task sofort beriicksich­tigt wird, wahrend bei disjunkten Codesequenzen fUr verschiedene Auswerter eine Anderung des Auswerters erst bei der Termination der Task bemerkt wird und dann verzogert zur weiteren Aktivierung von Teiltasks fUhrt.

Wir wahlen hier zur Vereinfachung die Methode, separate Codesequenzen fiir verschiedene Auswerter zu erzeugen.

Fiir die AusfUhrung von Basisfunktionen miissen ebenfalls spezielle Codese­quenzen erzeugt werden, da wahrend der AusfUhrung eines Kombinatorprogramms

Page 56: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

lOA. CODEERZEUGUNG 285

durch Applikationen h6herer Ordnung Tasks entstehen k6nnen, deren Marke eine Basisfunktion ist.

Diese Codesequenzen haben allesamt dieselbe Struktur. Sie bestehen aus einer Folge von GETARG- und LOAD-Instruktionen zur Auswertung der Argumente. Schliefilich folgt ein WAIT-Befehl, der uberpruft, ob aIle Argumente lokal und ausgewertet vorliegen und falls dies nicht der Fall ist, die Task solange suspendiert, bis diese Situation vorliegt. Mit einem GET-Befehl werden schlief31ich die Argu­mentwerte auf den Datenkeller geladen, so daB dann die Basisfunktionsapplikation berechnet werden kann. Der RET-Befehl schliefit die Ausfiihrung der 'Task' abo

Konstruktorapplikationen, die durch Applikationen h6herer Ordnung entste­hen, werden, wie wir bereits bei der Definition des APPLY-Befehles gesehen haben und im nachsten Abschnitt noch genauer diskutieren werden, gesondert behandelt. Fur diese ist daher kein Code notwendig. 1m Programmspeicher werden allerdings zu ihrer Behandlung die 'evaluation transformer' der Konstruktoren abgespeichert.

10.4.2 Definition

TRANS: PROGan --+ PAM-Code

wird fur (n,e,AN(R,e)} mit AN(R,e) = (AN(k,e) , AN(R,e) , AN(k,e») und

n = (Fi(Xl, ... ,Xr ,) = ei 11 $ i $ k}

wie folgt festgelegt:

e habe den Typ s E SUD, ei habe den Typ ti fur 1 $ i $ r.

TRANS [(n,e,AN(R,e)}]

:= code(e, AN(R,e)(e))

wobei

comcode( (Fl (Xl, ... , Xr1 ) = el}, ET(Ft} , AN(R,e)(el))

comcode( (Fk(Xl, ... , Xrk ) = ek}, ET(Fk), AN(R,e)(ek)) basiccode

0.1: EVALRET[(e,AN(R,e)(e))](6,0.1,<70,0) falls S E S,

code(e, AN(R,e)(e)) := 0.1: EVALRET[(e, AN(R,e)(e))](6, 0.1, <70, 0) 0.2: EVALRET[(e, AN(R,e) (e))](6, 0.2, <70, 0) 0.3: EVALRET[(e, AN(R,e)(e))](6, 0.3, <70, 0)

falls SED,

Page 57: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

286 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

und fiir 1 ~ i ~ k:

comcode( (Fi(XI, ... , Xr ,) = ei), ET(Fi), AN(R,e) (ei»

i.1: COMTRANS[( (Fi(XI, . .. , Xr,) = ei), ET(Fi),AN(R,e)(ei»](6,i.1) falls ti ¢ D,

i.1: COMTRANS[({Fi(Xl, ... ,Xr ,) = ei), ET(Fi), AN (R,e) (ei) )](6, i.1)

i.2: COMTRANS[({Fi(XI, ... ,xr,) = ei), ET(Fi), AN(R,e) (ei»](6, i.2)

i.3: COMTRANS[( {Fi(Xb ... , xr ,} = ei), ET(Fi),AN(R,e)(ei»](6,i.3) falls ti E D.

basiccode bezeichnet die Folge der Codesequenzen fUr Basisfunktionen:

Sei 0+ = {h, ... , II}. Fiir j E {I, ... , I} habe Ii die Stelligkeit mj > o. Dann ist

basiccode:= 0.0.1: bcode(fd

0.0.1 : bcode(fz),

wobei bcode(li) = GETARG(1,6); LOAD 1;

GETARG(mj,6); LOAD mj; WAIT mj; GET mj; EXEC Ii; RET 6;

fiir j E {I, ... ,I}.

Das Ubersetzungsschema COMTRANS erzeugt Maschinencode fUr die Reduk­tion von Kombinatorapplikationen. Ais Parameter erhaIt das Schema neben der annotierten Kombinatordefinition den Auswerter, mit dem die Reduktion erfolgen solI, und die Anfangscodeadresse zur eindeutigen Bezeichnung neu zu erzeugender Programmadressen.

Der von COMTRANS generierte Code beginnt mit einer Sequenz von INITARG­Instruktionen zur Aktivierung der Berechnung von strikten Argumenten. Die A~swerter in diesen Instruktionen werden mittels des kontextfreien 'evaluation transformer' des Kombinators bestimmt. Die Foige der INITARG-Instruktionen wird lediglich bei einer indirekten Aktivierung einer Applikation des Kombina­tors ausgefUhrt, bei der keine Informationen tiber die Argumente vorhanden sind, kontextsensitive Striktheitsinformationen also nicht ausgenutzt werden konnen.

Page 58: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.4. CODEERZEUGUNG 287

Den Hauptteil der Ubersetzung eines Kombinators bildet der Code, der fUr die Auswertung des Kombinatorrumpfes generiert wird. Dieser Teil des Codes wird bei jeder AusfUhrung einer Applikation des Kombinators ausgefUhrt.

10.4.3 Definition

COMTRANS: Comdern x Evset x IN* ~ PAM-Code

wird fUr ((F(Xl, ... ,Xr) = e),ET(F),AN(e)) E Comdern, ~ E Evset,w E IN* definiert durch:

COMTRANS[(F(Xl,"" xr) = e, ET(F), AN(e))] (~, w)

INITARG (1, ETl(F)(~)); ... ; INITARG (r,ETr(F)(~)); w.1 : EVALRET[(e, AN(e))](~, w.1, 0"0, 0)

INITARG-Befehle mit Auswerter ~o konnen natiirlich gestrichen werden.

Die Ubersetzungsfunktion EVALRET generiert Code fiir die Auswertung von Kombinatorriimpfen und die anschlieBende Termination der zugehOrigen Task. Die Definition eines speziellen Ubersetzungsschemas fUr die Auswertung von Aus­driicken mit Termination ermoglicht die spezielle Behandlung von 'tail-rekursiven' Kombinatoraufrufen mittels des PUSH-Befehls.

Die Definition der Ubersetzungsfunktion erfolgt strukturell rekursiv iiber den in der ersten Parameterposition gegebenen Ausdruck. Dabei werden allerdings nur die Falle gesondert behandelt, bei denen sich das EVALRET-Schema von dem EVAL-Schema unterscheidet. AIle iibrigen FaIle werden auf das EVAL-Schema zuriickgefUhrt.

Neben dem Ausdruck, dem Auswerter und der Anfangscodeadresse werden zur Verwaltung der, durch let- und letpar-Ausdriicke definierten, lokalen Variablen eine Funktion 0" E [Lac ~fin IN*] und eine natiirliche Zahl m als weitere Parameter iibergeben.

Die Funktion 0" gibt zu den frei in dem zu iibersetzenden Ausdruck vorkommen­den lokalen Variablen die Position an, die den Variablen auf den Verwaltungskeller lokaler Variablen bei der AusfUhrung des Codes zugeordnet sein wird. Die Zahl m gibt die Tiefe des Verwaltungskellers an, deren Kenntnis notwendig ist, da die Adressierung der Kellerelemente relativ zur Kellerspitze erfolgt.

10.4.4 Definition

EVALRET : ParExpan X Evset X IN* X [Lac ~fin IN*] ~ PAM-Code

wird induktiv iiber die Struktur des zu iibersetzenden Ausdruckes definiert.

Sei ~ E Evset \ {~o}, w E IN*, 0" E [Lac ~fin IN*], mE IN.

Page 59: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

288 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

1. EVALRET[(if e then el else e2 ti, AN( e) U AN( eI) U AN( e2))D (~,w,u,m)

EVAL[e, AN(e))] (6 , w.o, u, m) WAIT 1; GET 1; JPFALSE w.2; EVALRET[(el, AN(eI))](~, w.l, u, m)

w.2 : EVALRET[(e2, AN(e2))](~' w.2, u, m).

2. EVALRET ((case e of CI(Yn, ... , Ylml) : el; .. ·; Ck(Ykb.·., Ykm,J : ek esac, {(case ... esac, ETal,Cl ... ET&i,c,,)} U AN(e) U U7=1 AN(ej))]

(~,w,u,m) EVAL[(e, AN(e))](6, w.O, u, m) WAIT 1; SPLIT; CASE ((Cb w.l), ... , (Ck' w.k)};

w.l :INITLOC (I,ET:i,cl(~)); ... ; INITLOC (ml,ET~;Cl(~)); EVALRET[(el, AN(el))]

(~, w.l, U[YlmJm, ... , Yn/m + ml - 1], m + m2) w.2: ...

w.k :INITLOC (I,ETti,C"'(~)); ... ; INITLOC (mk,ET~~C"(~)); EVALRET leek, AN(ek))]

(~,w.k,u[Ykm,,/m, ... , Ykdm + mk -1],m + mk)

3. EVALRET [(let Yl = el and ... and Yk = ei in e, {(let ... , ETCS)} U AN(e) U U7=1 AN(ej))D (~, w,u, m)

:= INIT [eel, AN(el)](ETlS(~)' w.l, u, m)

INIT leek, AN(ek))D(ETkS(~), w.k, u, m) STORE k; EVALRET [(e,AN(e))]

(~, w.O, U[Yk/m, ... , Ydm + k -1], m + k)

4. EVALRET [(Fi(el, ... , er;), (Fi( .. . ), ETCS) U Uj=l AN(ei))](~, w, u, m) := INIT [(el,AN(eI))](ETlS(~),w.l,u,m)

INIT [(er" AN(er.))](ET~:(~), W.Ti,U, m) PUSH (Fi' Ti);

Page 60: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.4. CODEERZEUGUNG

5. EVALRET [( let par YI = FI(en, .. . ,ell}) if eVI and and YP = Fp(epI' ... ,eplp ) if evp in e,

{(letpar ... in e, ETCS)} U AN(e)U Uj=1 (Fj(ejl, ... , ejl,) , AN(Fj( .. . )))] (~, w,a, m)

:= pcode(FI (en, ... ,eIlt), AN(.F\ (en, ... ,ellJ),

289

ETlS(~),~, eVI,w.1,a,m)

pcode(Fp( epl, ... ,eplp )' AN(Fp( epl, ... ,eplp ))'

ET;S(~),~, evp,w.p,a,m) STOREp; EVALRET [(e, AN(e))](~, w.O, a [yI/m + p - 1, ... , yp/m], m + p),

wobei pcode(Fj( ejl, ... ,ejl ), AN(Fj( ejl, ... ,ejl ), ~j, ~, ev j, w.j, a, m)

J _ J .

INIT[( ejl, AN( ejt) )](ET1S(Fj( ejl, ... ,ejIJ) )(~J), w.j.1, a, m)

INIT[(ejl ,AN(ejl ))](ET{S(Fj (eji, ... , ejl ))(~j), w.j.lj, a, m) J _ J J . J

MKNODE (Fj,lj);ACTIVATE e; falls ~ 2: ev j

INIT[(Fj (ejl, ... ,ejl,), AN(Fj( ejl, ... ,ejIJ) )](~j, w.j, a, m) falls ~ < eVj

6. Fur aIle ubrigen annotierten parallelisierten Ausdrucke gilt:

EVALRET [(e, AN(e))](~, w, a, m) := EVAL [(e, AN(e))](~, w,a, m) RET~;

Die Codeerzeugung fUr Verzweigungsausdriicke erfolgt wie ublich so, daB zu­nachst mittels des Schemas EVAL Code zur Auswertung der booleschen Bedingung erzeugt wird. Der WAIT-Befehl sorgt dafUr, daB der ProzeB, wenn notig, so­lange suspendiert wird, bis das Ergebnis der booleschen Bedingung lokal vorliegt. Der GET-Befehlladt den booleschen Wert auf den Datenkeller, wo er mittels des JPFALSE-Befehls getestet wird und die weiter auszufiihrende Befehlssequenz be­stimmt. Der Code fUr die beiden Alternativen des Verzweigungsausdruckes kann wiederum mittels des Schemas EVALRET erzeugt werden.

Auch die Auswertung von case-Ausdriicken wird so organisiert, daB zunachst der Datenstrukturausdruck, des sen Top-level Konstruktor den weiteren Verlauf der Berechnung bestimmt, mit Auswerter 6 ausgewertet wird. Liegt das Ergebnis

Page 61: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

290 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

dieser Auswertung vor, so werden zunachst mittels des SPLIT-Befehls die Kompo­nenten der Datenstruktur auf den Variablenkeller geladen. Sodann erfolgt mittels des CASE-Befehls der Sprung zum Code der durch den Konstruktor bestimmten Alternative. Dieser Code beginnt mit einer Sequenz von INITLOC-Befehlen, bei denen die Kenntnis der kontextsensitiven 'evaluation transformer' der Alternativen ausgenutzt wird, urn die Auswertung der Komponenten anzustoBen. Der eigentli­che Code fUr die Ausdrucke der Alternativen wird wiederum mittels des Schemas EVALRET erzeugt.

Der kontextsensitive 'evaluation transformer' von let-Ausdriicken bestimmt die Auswerter, mit denen die Berechnungen der lokal deklarierten Ausdrucke initiiert werden konnen. Der Code zur Aktivierung dieser Berechnungen wird nicht mittels des Ubersetzungsschemas EVAL, sondern mittels des Schemas INIT erzeugt. Der Unterschied zwischen den beiden Schemata besteht darin, daB EVAL Code gene­riert, der sicherstellt, daB das Ergebnis einer Berechnung lokal, d.h. an der Stelle, an der die Aktivierung stattfindet, zuganglich ist, wahrend INIT Berechnungen lediglich initiiert und bei globalen Berechnungen nicht verlangt, daB das Ergebnis an die Stelle der Aktivierung der Berechnung geschickt wird. Nach der Definition der beiden Schemata EVAL und INIT werden wir genauer auf die Unterschiede eingehen und die sorgfaltige Unterscheidung zwischen globalen Berechnungen, de­ren Ergebnis benotigt wird und solchen, deren Ergebnis (noch) nicht notwendig ist, begrunden. Die Zeiger auf die Graphen der Teilausdrucke werden durch den STORE-Befehl auf den Verwaltungkeller geladen: Die Ubersetzung des Rumpfes des let-Ausdruckes erfolgt wiederum mit EVALRET.

Bei cler Ubersetzung von Kombinatoraufrufen zeigt sich cler Vorteil, den clas Schema EVALRET bietet. Prinzipiell k6nnte man namlich das Schema EVALRET wie unter Punkt 6 in obiger Definition, also mittels des durch das Schema EVAL erzeugten Codes gefolgt vom allgemeinen RET -Befehl, definieren. In diesem Fall wurden aber 'tail-rekursive' Kombinatoraufrufe nicht erkannt und nicht in opt i­mierter Weise behandelt werden k6nnen. Das Schema EVALRET erm6glicht die Behandlung von 'tail-rekursiven' Aufrufen als Sprung in den Code des neuen Kom­binators. Die Erzeugung eines neuen Taskknoten wird verhindert; ein ProzeBwech­sel wird vermieden. Zu beachten ist, daB der Code fur die Argumente des Kombi­nators mit dem Schema INIT generiert wird.

Die Ubersetzung von letpar-Ausdrucken zeigt die Erzeugung von parallelen Prozessen mittels der ACTIVATE-Instruktion. Der Code eines letpar-Ausdruckes besteht aus den Codesequenzen fur die moglicherweise parallel auszuwertenden Kombinatorapplikationen, die jeweils einen Zeiger auf den Graphen der Applika­tion auf dem Datenkeller erzeugen, einem STORE-Befehl, der diese Zeiger auf den Verwaltungskeller schiebt und dem Code fur die Auswertung des Rumpfes. Der Auswerter ~, mit dem das letpar-Konstrukt ausgewertet werden sol1, bestimmt,

Page 62: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.4. CODEERZEUGUNG 291

welche Kombinatorapplikationen parallel ausgewertet werden und welche lokal. 1st der im letpar-Ausdruck einer Kombinatorapplikation zugeordnete Auswerter eVj

starker als ~, so solI keine Parallelauswertung der Applikation erfolgen, d.h. es wird mittels INIT lediglich Code zur lokalen Auswertung der Applikation generiert. Zur Erzeugung eines parallelen Prozesses werden zunachst die Argumente des Prozes­ses aktiviert und nach der Erzeugung eines Taskknoten wird derselbe mittels der ACTIVATE-Instruktion parallel (und direkt) aktiviert. Der Auswerter, mit dem die Kombinatorapplikation (parallel oder lokal) ausgewertet wird, ist durch den kontextsensitiven 'evaluation transformer' des letpar-Ausdruckes bestimmt.

In allen nicht explizit definierten Fallen ergibt sich der Code des EVALRET­Schemas aus dem des EVAL-Schemas durch Anhangen des RET-Befehls.

Den Kern der Ubersetzung parallelisierter Kombinatorsysteme in Maschinen­code bilden die drei Ubersetzungsfunktionen EVAL, INIT und DELAY, deren De­finition wir nun angeben werden. Wahrend EVAL und INIT Maschinencode zur Auswertung von Ausdriicken erzeugen, behandelt DELAY die Codeerzeugung fUr nicht-strikte Argumente, deren Auswertung verzogert werden muB. Das Ergebnis der AusfUhrung einer Codesequenz wird immer durch das oberste Element des Datenkellers gegeben.

Das Schema EVAL wird zur Ubersetzung von Ausdriicken benutzt, deren Wert zur Fortsetzung der lokalen Berechnung benotigt wird. Solche Ausdriicke sind vor allem die Argumente von Basisfunktionen sowie die Testausdriicke in konditiona­len Ausdriicken. 1st ein solcher Ausdruck ein Parameter, der durch eine globale Adresse gegeben ist, so muB an diese globale Adresse eine REQUEST-Nachricht geschickt werden, damit der Wert des Parameters in einer ANSWER-Nachricht zuriickgeschickt wird. Der durch das Schema INIT erzeugte Code unterscheidet sich fUr Variablen von dem durch EVAL generierten Code, da Variablenbindungen wahrend der Ausfiihrung globale Adressen sein konnen. Das Schema EVAL erzeugt den Befehl GETARG/LOC fUr Variable. Dieser Befehl bewirkt im Falle einer glo­balen Adresse in der Variablenposition, daB eine REQUEST-Nachricht an diese Adresse geschickt wird. Das Schema INIT generiert den Befehl INITARG/LOC, durch den an eine globale Adresse lediglich eine Aktivierungsnachricht geschickt wird. Die Unterscheidung von 'benotigten' und 'aktivierbaren' Wert en ist in einer verteilten Umgebung wichtig, urn zu verhindern, daB Graphknoten an Prozesso­relemente verschickt werden, in denen sie nicht benotigt werden [Burn SSe]. Die Striktheit eines Kombinators in einem Argument heiBt ja nicht notwendig, daB das Argument im Kombinatorrumpf als Argument einer strikten Basisfunktion oder in einer vergleichbaren Position auftritt. Es ist vielmehr moglich, daB der Kombi­nator parallele Teilprozesse startet, an die das Argument weitergereicht wird, die aber auf anderen Prozessorelementen ausgefUhrt werden. Es ist also sinnvoll, an

Page 63: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

292 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

glob ale Teilgraphen nur dann Anfragenachrichten zu schicken, wenn sichergestellt ist, daB der als Antwort geschickte Terminalknoten auch verwertet wird.

Da sich die Ubersetzungsfunktionen EVAL und INIT nur geringfiigig durch die Erzeugung unterschiedlicher Befehle fUr die Aktivierung von Variablen unterschei­den, benutzen wir eine Hilfsiibersetzungsfunktion ETRANS, auf die wir die Defini­tion von EVAL und INIT zuriickfUhren. Das Schema ETRANS erhalt einen weiteren Parameter v E {eval, init}, der anzeigt, ob der Wert des zu iibersetzenden Aus­druckes lokal verfiigbar gemacht werden muB oder nicht. Die Funktionen EVAL und INIT entsprechen dann Aufrufen von ETRANS mit v = eval bzw. v = init.

10.4.5 Definition Das Ubersetzungsschema

1. ETRANS: ParExp~; x (Evset \ {~o}) x IN* x [Loc -fin IN] X IN x {eval, init} - PAM-Code

wird durch strukturelle Induktion iiber die parallelisierten annotierten Ausdriicke definiert.

Sei ~ E Evset \ {~o}, w E IN*, CT E [Loc -fin IN], m E IN und v E {eval, init}.

(a) ETRANS [(v,0)](~,w,CT,m,v) := LIT V; falls v E UsES O(£,s) U UdED r(£,d).

(b) ETRANS [(f-t,0)](~,w,CT,m,v) := MKNODE (f-t,O); falls f-t E 0+ U r+ U{F E Fun I rg(F) > a}.

(c) ETRANS [(Xi, 0)](~, W, CT, m, v) ._ { GETARG (i,O;LOAD i; falls v = eval } .- INITARG (i,~);LOAD i; falls v = init (Xi E A1Y).

(d) ETRANS [(y,0)](~,w,CT,m,v) GETLOC (m - CT(y),~); LOADLOC m - CT(Y);

INITLOC (m - CT(y),~); LOADLOC m - CT(y);

falls v = eval (y E Loc).

falls v = ini t

(e) ETRANS [(if e then el else e2 fi, AN(e) U AN(et) U AN(e2)]

EVAL [(e, AN(e»](6, w.o, CT, m) WAIT 1; GET 1; JPFALSE w.2; ETRANS [(el,AN(et)](~,w.l,CT,m,v)

(~, w, CT, m, v)

Page 64: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.4. CODEERZEUGUNG

JMP w.3j w.2 : ETRANS [(e2' AN(e2))](~' w.2, u, m, v) w.3 :

esac,

293

{ (case, ETal,Cl ... ETal,c,,)} U AN( e) U U7=1 AN( ek))] (~,w,u,m,v)

EVAL [(e, AN(e))] (6 , w.O, u, m) WAIT Ij SPLITj CASE ((Cb w.l), ... , (Ck' w.k))j

w.l :INITLOC (1,ET;I,Cl(~))j ... j INITLOC (ml,ET~;Cl(~))j ETRANS [el,AN(eI)]

w.2 :

(~, w.l, u[Yn/m + ml - 1, ... Ylml /mJ, m + mb v) POP mlj JMP w.(k + l)j

w.k :INITLOC (1,ET;I,c"(~))j ... j INITLOC (mk,ET~t"(~))j ETRANS [ek, AN(ek)]

(~, w.k, u[Ykl/m + mk - 1, ... Ykm,,/mJ, m + mk, v) POP mkj

w.(k + 1):

(g) ETRANS [(let YI = el and ... and Yk = ek in e, {(let ... , ETCS)} U AN(e) U U7=1 AN(ek))](~' w, u, m, v)

:= INIT [(el,AN(el)](ETfS(~),w.l,u,w)

INIT [(ek, AN(ek)](ETkS(~), w.k, u, w) STORE kj ETRANS [(e, AN(e))]

(~, w.O, u[yI/m + k - 1, ... , Yk/m], m + k, v) POP kj

(h) ETRANS [(J(eb"" ek), U7=1 AN(ej))](6, w, u, m, v) := EVAL [(el' AN(el))](~I' w.l, u, m)

EVAL [(ek,AN(ek))](~I,w.l,u,m) WAIT kj GET kj EXEC Ij

falls I E n(Bl ... B/"B)(Sb"" Sk, S E S)

Page 65: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

294 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

(i) ETRANs [ (c(el, ... ,ek), {c( .. . ), ETCf(c)} U U7=1 AN(ej»](~, w, (J, m, v)

:= INIT [(eI,AN(ed)](ETff(c)(~),w.l,(J,m)

INIT [(ek' AN(ek))](ETkf(c)(~), w.k, (J, m) NODE (c,~)j

(j) ETRANs [(F(el,'" ,ek), {(F( ... ),ETCS)} U U7=1 AN(ej»] (~, W,(J, m, v)

INIT[(el, AN(ed)](ETfS(~), w.l, (J, m)

INIT[(ek, AN(ek»](ETkS(~), w.k, (J, m) MKNODE (F, k)j EVALUATE ~j

DELAY[(eb AN(et})](w.l, (J, m)

DELAY[(ek, AN(ek»](w.k, (J, m) MKNODE (F,k)j

(k) ETRANs [(ap(e,el,'" ,ek),

falls rg(F) = k

falls rg(F) > k

{(ap(e,eb .. ' ,ek),ETCS)} U U~=l AN(ej) U AN(e»] (~,w,(J,m,v)

:= INIT [(el' AN(el»](ETfS(~), w.l, (J, m)

INIT [(ek, AN(ek))](ETkS(~), w.k, (J, m) EVAL [e,AN(e))](ETfS(~),w.O,(J,m) WAIT ljtt APPLY kj INITIATE ~j

(1) ETRANs [(letpar YI = i\ (ell, ... ,ellJ if eVI and and YP = Fp(epI"" ,eplp ) if evp in e, {(letpar ... , ETCS)} U U~=l AN(Fj(eil,"" ejl,)) UAN(e»)] (~, w, (J, m, v)

:= pcode(FI (ell,"" ell l ), AN(FI (ell, ... , ell l », ETlS(~),~, eVI, w.l, (J, m)

ttDieser WAIT-Befehl wird nur zur Dereferenzierung von lokalen Verweisknoten benotigt.

Page 66: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

lOA. CODEERZEUGUNG 295

pcode(Fp (epl, ... , eplp )' AN(Fp(epI, ... , epl p ))'

ET;S(€),€, evp,w.p,O',m) STOREp; ETRANS [(e,AN(e))D

(€, w.O, O'[YI/m + p - 1, ... , yp/m] , m + p, v) POP Pi

wobei pcode(Fj(ejI, ... , ejl,) , AN(Fj(ejl, ... , ejl,)), €j ,€, eVj, w.j, 0', m)

wie in Definition 10.4.4 (5) festgelegt ist.

2. Die Schemata EVAL und INIT werden damit wie folgt definiert:

• EVAL: ParExp~: x (Evset \ {€o}) x IN* x [Loc -tfin IN] x IN -t PAM-Code

wird fUr (e,AN(e)) E ParExp~:, € E Evset \ {€o}, w E IN*, 0' E [Loc -tfin IN] und m E IN festgelegt zu

EVAL[(e,AN(e))](€, w, 0', m) := ETRANs[(e, AN(e))I(€, w, 0', m, eval) .

• INIT: ParExp~: x Evset x IN* x [Loc -t fin IN] X IN -t PAM-Code wird fiir (e, AN(e)) E ParExp~:, € E Evset, w E IN*, 0' E [Loc -tfin

IN] und m E IN festgelegt zu:

INIT[(e,AN(e))](€, w, 0', m) ._ {ETRANS[(e,AN(e))](€,w,O',m,init) falls € =J €o, .- DELAY[(e, AN(e))](w, 0', m) falls € = €o.

Wiihrend die Ubersetzungsfunktion EVAL immer nur aufgerufen wird, wenn ein von €o verschiedener Auswerter vorliegt, kann das Schema INIT auch mit dem Aus­werter €o aufgerufen werden. In diesem Fall wird der Code fiir den Ausdruck aber mit dem Schema DELAY erzeugt, da keine Auswertung des Ausdruckes stattfinden soU.

Der mittels EVAL und INIT erzeugte Code hat im Falle eines von €o verschiede­nen Auswerters dieselbe Struktur und unterscheidet sich nur fUr Variablen. Zusam­mengesetzte Ausdriicke werden gro:Btenteils wie bei der Ubersetzung mittels EVAL­RET behandelt. Da man aber nicht davon ausgehen kann, daB die ausfiihrende Task nach Auswertung des Ausdruckes terminiert, miissen bei den Verzweigungs­ausdriicken Sprungbefehle eingefiigt werden, die den KontroUflu:B explizit steuern. Bei Ausdriicken mit lokalen Deklarationen werden au:Berdem POP-Befehle ein­gefiigt, die nach Auswertung der Ausdriicke die lokalen Variablenbindungen vom Verwaltungskeller loschen.

Page 67: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

296 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Besonderer Betrachtung bedarf die Codeerzeugung fUr Applikationen. Zur Auswertung einer Basisfunktionsapplikation ist die vollstandige Auswertung aller Argumente notwendig. Die Ergebnisse dieser Auswertung mussen aufierdem lokal vorhanden sein. Die Ubersetzung der Argumentausdrucke mufi daher mittels des EVAL-Schemas erfolgen. Der WAIT-Befehl bewirkt eine Unterbrechung der Task­ausfuhrung, falls nicht aIle Argumentwerte vorliegen. Sobald aIle Argumentwerte lokal vorliegen, konnen diese mittels eines GET-Befehls auf den Datenkeller gela­den werden und mittels des EXEC-Befehls kann die Berechnung der Applikation durchgefUhrt werden.

Bei der Berechnung einer Konstruktorapplikation sind zur Erzeugung des Kon­struktorknotens lediglich die Adressen der Komponentenreprasentationen notwen­dig. Die Auswertung der Komponenten braucht weder abgeschlossen zu sein, noch mufi das Ergebnis der Berechnung lokal vorliegen. Aus diesem Grund werden die Berechnungen der Komponentenausdrucke entsprechend den durch den 'evalua­tion transformer' der Applikation gegebenen Auswertern lediglich aktiviert. Der dazu notwendige Code wird mit dem Schema INIT erzeugt.

Bei Kombinatorapplikationen mufi zwischen vollstandigen (reduzierbaren) und partiellen Applikationen, welche in Kombinatornormalform sind, unterschieden werden. Fur vollstandige Applikationen wird zunachst mittels der Funktion INIT Code fUr die Aktivierung der Argumentausdrucke erzeugt. Die Auswerter fUr die Argumente sind durch den kontextsensitiven 'evaluation transformer' der Appli­kation bestimmt. Schlief31ich wird ein neuer Taskknoten erzeugt, der sofort mittels des EVALUATE-Befehls lokal aktiviert wird.

Fur partielle Applikationen wird die Auswertung der Argumente verzogert. Mittels des DELAY-Schemas wird Code zur Erzeugung einer Reprasentation der Argumente erzeugt. Der MKNODE-Befehl bewirkt schlief31ich die Erzeugung eines Funktionsknoten zur Reprasentation der partiellen Applikation.

Zur kompakten Darstellung von nicht-strikten Argumenten, deren Auswertung verzogert wird, haben wir Argumentknoten eingefUhrt. Das Schema DELAY, das zur Codeerzeugung fur solche Argumente benutzt wird, wird also i.a. solche Ar­gumentknoten erzeugen. Nur in einigen Fallen weichen wir von dieser Regel abo

• Fur nicht-zusammengesetzte Ausdrucke, also Konstante oder Variable wurde die Erzeugung eines Argumentknoten einen unnotigen Mehraufwand bedeu­ten, da diese direkt reprasentiert werden konnen (Konstante) bzw. bereits eine Reprasentation haben (Variable). Diese Ausdrucke konnen also wie bei den anderen Schemata behandelt werden, aufier dafi im Fall von Variablen naturlich keine Aktivierung erfolgt .

• Eine weitere Ausnahmebehandlung erfolgt fur vollstandige Kombinatorap­plikationen in nicht-strikten Argumentpositionen. Der Grund hierfur liegt

Page 68: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.4. CODEERZEUGUNG 297

in der Organisation des Parallelisierungsalgorithmus, bei dem zwei Quellen fUr Parallelitat unterschieden wurden. Zum einen wurde mittels des let par­Konstruktes Parallelitat von strikten Argumenten explizit gemacht. Zum anderen wurden aber auch nicht-strikte Argumente, fiir die im Falle einer spateren Aktivierung eine Parallelauswertung sinnvoll schien, durch Kom­binatorapplikationen ausgedriickt. Aus diesem Grund werden wir Kombi­natorapplikationen in nicht-strikten Argumentpositionen durch schlafende Taskknoten reprasentieren, die im Falle einer verzogerten Aktivierung sofort zur Erzeugung eines parallelen Prozesses fiihren.

10.4.6 Definition Das Schema

DELAY : ParExp~; x IN* x [Loc -+ fin IN] X IN - PAM-Code

wird induktiv iiber die Struktur des ersten Parameters erklart.

Sei w E IN*, u E [Loc -fin IN] und m E IN.

1. DELAY [(v,0)](w,u,m):= LIT Vj falls V E USESO(E,S) UUdEDr(E,d).

2. DELAY [(IL, 0)](w, u, m) := MKNODE (IL,O)j falls IL E 0+ U r+ U {F E Fun I rg(F) > O}.

3. DELAY [(Xi, 0)D(w, u, m) := LOAD ij DELAY [(y,0)](w,u,m) := LOADLOC m - u(Y)j

4. DELAY [(F(eI, ... ,er),AN(F(eI, ... ,er))](w,u,m) := DELAY [(el, AN(et))](w.l, u,m)

DELAY [( er , AN( er ) )]( w.r, u, m) MKNODE (F, r)j

5. In allen anderen Fallen sei:

DELAY [(e,AN(e))](w,u,m) ARGNODE (w.l,w.2,w.3)j JMP w.4j

w.l: EVALRET[(e, AN(e))](6, w.l, u, m) w.2: EVALRET[(e, AN(e))](6, w.2, u, m) w.3: EVALRET[(e,AN(e))D(6,w.3,u,m) w.4:

ARGNODE (w.l,w.l,w.l)j JMP w.2j

w.l: EVALRET[(e, AN(e))](6, w.l, u, m) w.2 :

falls Xi E A1Y. falls y E Loc.

falls r = rg(F).

falls typ(e) ED,

sonst

Page 69: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

298 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Die iibliche Behandlung von nicht-strikten Argumenten ist die Erzeugung ei­nes Argumentknotens. In Abhangigkeit vom Typ des Ausdruckes werden zudem Codesequenzen fUr die Auswertung der Argumente mit den Auswertern ~1,6,6 bzw. nur 6 erzeugt, deren Codeadressen im Argumentknoten festgehalten werden.

Fiir Kombinatorapplikationen wird allerdings ein Taskknoten angelegt, so daB bei einer Aktivierung ein paralleler ProzeB erzeugt wird. Wie die Ubersetzung zeigt, verschenkt man dabei aber die Striktheitsinformationen, die durch den kontext­sensitiven 'evaluation transformer' der Kombinatorapplikation gegeben sind.

Eine Aktivierung des schlafenden Taskknoten kann nur indirekt erfolgen, so daB zur Auswertung der Argumente lediglich die Striktheitsinformationen des kon­textfreien 'evaluation transformer' des Kombinators benutzt werden. Eine alter­native Ubersetzung von Kombinatorapplikationen, die die Kenntnis des kontext­sensitiven 'evaluation transformer' beriicksichtigt, ware etwa die folgende:

Falls typ( F( el, ... ,er)) tf. D:

DELAY [(F(el" .. , er)), {(F(el,"" er), ETCS)} U Uj=l AN(ej )}]( w, 0", m) .- ARGNODE (w.l, w.l, w.l); JMP w.2;

w.l : INIT [(el, AN(el))](ET1S(6), w.l.l, 0", m)

INIT [(en AN( er) )](ET;S(6), w.l.r, 0", m) MKNODE (F,r); ACTIVATE 6; RET 6;

w.2: ...

und falls typ(F(el, ... ,er)) ED:

DELAY [(F(el, ... , er)), {(F(el"'" er), ETCS)} U Uj=l AN(ej)}]( w, 0", m) .- ARGNODE (w.l,w.2,w.3); JMP wA;

w.l : INIT [(el' AN(el))](ET1S(6), w.l.l, 0", m)

INIT [(en AN(er))](ET;S(~d, w.l.r,0", m) MKNODE (F,r); ACTIVATE ~l; RET 6;

w.2 : INIT [(el, AN(el))](ET1S(6), w.2.1, 0", m)

INIT [(er, AN(er))](ET;S(6), w.2.r, 0", m) MKNODE (F,r); ACTIVATE 6; RET 6;

w.3 : INIT [(el, AN(el))](ET1S(6), w.3.1, 0", m)

INIT [(e r , AN(er ))](ET;S(6), w.3.r, 0", m) MKNODE (F, r); ACTIVATE 6; RET 6;

wA: '" .

Page 70: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

lOA. CODEERZEUGUNG 299

Diese Compilation hat den Vorteil, daB kontextsensitive Informationen zur Ar­gumentauswertung nicht verloren gehen und daB somit alle parallelen Prozesse direkt (!), d.h. mittels ACTIVATE aktiviert werden. Nachteilig ist aber, daB die Erzeugung des parallelen Prozesses verzogert wird und ein zusatzlicher Argument­knot en angelegt wird, der bei Durchfiihrung des RET-Befehls durch einen lokalen Verweisknoten iiberschrieben wird.

Mit Verzogerung des parallelen Prozesses ist natiirlich nicht die geringfUgige Verzogerung durch die vorherige Aktivierung der Argumente gemeint, sondern die Zeit zwischen der Aktivierung des Argumentknotens und der Aktivierung des parallel en Prozesses. Bei der Aktivierung des Argumentknotens erfolgt ja i.a. keineswegs eine sofortige AusfUhrung des zugehorigen Codes, sondern die Adresse des aktivierten Knotens wird zur lokalen Taskwarteschlange hinzugefiigt. Zwischen Aktivierung und AusfUhrung liegt also ein unbestimmter Zeitraum.

Bei dem Ansatz, den wir in obiger Definition gewahlt haben, wird sogleich bei der Aktivierung des schlafenden Taskknoten ein paralleler ProzeB erzeugt. Die sofortige Aktivierung paralleler Prozesse erscheint uns so wiChtig, daB wir den Verlust kontextsensitiver Striktheitsinformationen in Kauf nehmen.

Die Ubersetzung parallelisierter Kombinatorsysteme ist damit vollstandig be­schrieben. Einige wichtige Optimierungen, wie etwa die gesonderte Behandlung von 'tail-rekursiven' Kombinatoren, wurden bereits in den Ubersetzungsfunktio­nen beriicksichtigt. Natiirlich kann der erzeugte Code in vielfacher Hinsicht wei­ter optimiert werden. So kann man z.B. bei mehreren Zugriffen auf eine Varia­ble beim zweitem Zugriff voraussetzen, daB die Aktivierung der Variable bereits erfolgt ist und weitere INITARG/LOC Befehle streichen. AuBerdem sind viele Optimierungstechniken, die von konventionellen Implementierungen bekannt sind, iibertragbar. Wir werden in dieser Arbeit auf diese Dinge nicht weiter eingehen.

Fiir die in Beispiel 7.2.3 angegebene parallelisierte Form PQSort des in unserem Quicksort-Beispielprogramm (5.2.6) auftretenden Kombinators QSort wird der in Bild 10.12 gezeigte Code fiir eine Auswertung mit Auswerter 6 erzeugt. Der Code ist in linearisierter Form angegeben.

AbschlieBend definieren wir die Organisation des Programmspeichers fUr ein iibersetztes Programm.

10.4.7 Definition Sei (n,e,AN(1?,e)) ein annotiertes parallelisiertes Kombina­torprogramm mit den Kombinatoren {FI , ... , Fk }.

Dann heiBt ps( (n, e, AN(R,e))) := (ca-co, ca-fo, rgo, c-evto; co) mit

Page 71: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

300 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

1: INITARG (1,6); 17: LOADLOC 1; 2: GETARG (1, ~d; 18: MKNODE( Tit,!); 3: LOAD 1; 19: INITLOC (2,6); 4: WAIT 1; 20: LOADLOC 2; 5: SPLIT; 21: MKNODE(Filter,2); 6: CASE (NIL,7),(CONS,9)}; 22: EVALUATE 6; 7: LIT NIL; 23: MKNODE(PQSort,I); 8: RET; 24: ACTIVATE 6; 9: LOADLOC 1; 25: STORE 2;

10: MKNODE( Tgeq, 1); 26: INITLOC (1,6); 11: INITLOC (2,6); 27: LOADLOC 1; 12: LOADLOC 2; 28: INITLOC (3,6); 13: MKNODE(Filter,2); 29: LOADLOC 3; 14: EVALUATE 6; 30: INITLOC (2,6); 15: MKNODE(PQSort,I); 31: LOADLOC 2; 16: ACTIVATE 6; 32: NODE (CONS, 6);

33: PUSH (Append,2);

Bild 10.12: PAM-Code fUr den Beispielkombinator PQSort (Beispiel 7.2.3)

• ca-co:

Fun x Evset x {dir, indir} ~ PAdr Lade2(i.j) falls F = Fi (1 :S i :S k),

~ = ~j (1 ~ j ~ k) und at = indir,

(F,~,at) 1-+ Lade2(i.j.l) falls F = Fi (1 :S i:S k), ~ = ~j (1 :S j :S k) und at = dir,

nicht def. sonst,

f. { 0+ = {fI""'/I} ~ PAdr • ca- . Ii 1-+ Lade2(0.0.i) (1:S i :S I), • rgo := rgR,

• c-evto : (c,~) 1-+ (il'~il)'" (ik'~ik)' { r x Evset ~ (IN x Evset)*

wobei ETiJ (c)(~) = ~iJ =1= ~o und ETl(C)(~) = ~o fUr aIle I ¢ {i l , ... , ik},

• und Co:= Ladel«(R,e,AN(R,e)})

der Programmspeicher zu (R,e,AN(R,e).).

Page 72: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.5. SPEZIFIKATION DER REDUKTIONSEINHEIT 301

10.5 Spezifikation der Reduktionseinheit

Nachdem wir in den beiden vorherigen Abschnitten die Maschinenbefehle mit den lokalen Zustandsraumveranderungen, die durch sie bewirkt werden, sowie die Ubersetzung von Kombinatorsystemen in Maschinencodesequenzen beschrieben haben, wenden wir uns in diesem Abschnitt dem Gesamtverhalten der Reduk­tionseinheiten zu. Dazu definieren wir zunachst den globalen Zustandsraum der Reduktionseinheiten, der aus dem lokalen Zustandsraum und den Komponenten des gemeinsamen Speichers von Reduktions- und Kommunikationseinheit besteht. Sodann beschreiben wir die Zustandstransitionen der Reduktionseinheiten im Re­duktionsmodus, im Aktivierungsmodus und im Wartemodus. Auf die Nachrichten­verarbeitung im Kommunikationsmodus werden wir im nachsten Kapitel gesondert eingehen.

Der gemeinsame Speicher von Reduktions- und Kommunikationseinheit enthalt zwei Warteschlangen, iiber die Nachrichten zwischen den Einheiten ausgetauscht werden und ein boolesches Flag, das von der Reduktionseinheit zur Anforderung eines neuen Prozesses gesetzt werden kann (vgl. Bild 10.3). Der Zugriff einer Ein­heit auf den gemeinsamen Speicher ist sehr beschrankt. Jede Einheit kann den erst en Eintrag der Warteschlage, die an sie gerichtete Nachrichten enthalt, lesen und loschen, sowie Nachrichten an das Ende der anderen Warteschlange schreiben. Die Reduktionseinheit kann das ProzeBanforderungsflag setzen, die Kommunikati­onseinheit kann dieses Flag zuriicksetzen. Auf diese Weise konnen keine Konflikte beim Zugriff auf den gemeinsamen Speicher auftreten. Die Menge der Nachrichten, die zwischen Reduktionseinheit und Kommunikationseinheit ausgetauscht werden konnen, wurde bereits in Definition 10.3.5 formalisiert.

10.5.1 Definition Der gemeinsame Speicher von Reduktions- und Kommunika­tionseinheiten wird definiert durch:

SM := Redqueue x Comqueue x Nexttask,

wobei

• Redqueue := Comqueue := RedMes* und

• Nexttask:= {true, false}.

Einen Zustand des gemeinsamen Speichers bezeichnen wir im allgemeinen wie folgt:

(red-q, com-q, next).

Die Nachrichtenwarteschlangen sind jeweils nach den Prozessoreinheiten be­nannt, an die die Nachrichten gerichtet sind.

Page 73: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

302 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Zur formalen Spezifikation einer Reduktionseinheit benutzen wir Transitions­systeme. Ein Transitionssystem besteht aus einer Menge von Zustanden, einer Ubergangsrelation zwischen den Zustanden und einer Menge von ausgezeichneten Anfangszustanden t .

Ein Transitionssystem heifit deterministisch, falls zu jedem Zustand durch die Ubergangsrelation hochstens ein Folgezustand gegeben ist. Wie wir sehen werden, ist das Transitionssystem einer Reduktionseinheit deterministisch.

10.5.2 Definition Sei j E {1, ... ,n}, wobei n wie bisher die Anzahl der Prozes­sorelemente der parallelen Maschine bezeichne.

Die j-te Reduktionseinheit REj wird als Transitionssystem

mit

der Zustandsmenge LStRE X SM,

der Ubergangsrelation rRE} ~ (LStRE X SM) X (LStRE X SM)

und

der Anfangszustandsmenge (initial states) IN RE} ~ LStRE X SM

definiert.

Die Ubergangsrelation werden wir in den folgenden Definitionen festlegen.

Als Anfangszustandsmenge definieren wir

INRE} .-

{((rm, 0, G0[0/(TASK,'ur',E, (6, 1, E, E, 0, E, E))], 1, E, E, ps), (E, E, false)) I ps E Pstore}

{((wm, nil, G0, 0, E, E, ps), (E,E,true)) Ips E Pstore}

falls j = 1,

falls j =1= 1.

Dabei bezeichne G0 die nirgends definierte Abbildung von lokalen Grapha­dressen in die Graphknoten.

tIn Transitionssystemen wird i.a. nur ein Anfangszustand ausgezeichnet. Wir lassen hier eine Menge von Anfangszustanden zu, da die Reduktionseinheiten programmierbar sind und somit verschiedene Anfangszustande moglich sind, die sich durch die Belegung des Programmspeichers unterscheiden.

Page 74: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.5. SPEZIFIKATION DER REDUKTIONSEINHEIT 303

Die Festlegung der AnJangszustande der Reduktionseinheiten zeigt, daB die Berechnung eines Programms von der Reduktionseinheit des erst en Prozessorele­mentes ausgeht. Diese Reduktionseinheit beginnt als einzige im Reduktionsmodus. Ihr 'active task pointer' zeigt auf die sogenannte 'Urtask', deren Taskknoten im Graphen an der Adresse 0 liegt. Diese 'Urtask' hat keine Argumente. Ihre Aus­wertung erfolgt immer mit Auswerter ~1' Der Instruktionszeiger wird mit der Programmadresse 1, unter der die Ubersetzung des Hauptprogrammausdruckes liegt, initialisiert. Die Keller und Adressenlisten sind leer. Der 'pending count' hat den Wert O. Da im Graphen eine Adresse belegt ist, hat der Graphzeiger den Wert 1. Die lokale Taskwarteschlange und die Aktivierungsliste sind ebenfalls leer. Der gemeinsame Speicher enthalt zunachst leere Nachrichtenschlangen. Da die Re­duktionseinheit eine Task zur Ausfiihrung hat, ist das Flag zur ProzeBanforderung nicht gesetzt.

Alle anderen Reduktionseinheiten beginnen im Wartemodus, d.h. ohne Arbeit mit "leeren" Komponenten. 1m gemeinsamen Speicher signalisiert das gesetzte ProzeBanforderungsfiag den Wartezustand der Reduktionseinheit.

Das Verhalten einer Reduktionseinheit ist durch die Ubergangsrelation

f-REJ ~ (L8tRE X 8M) X (LStRE X 8M)

bestimmt. Wir definieren diese Ubergangsrelation im folgenden jeweils fUr die verschiedenen Arbeitsmodi der Reduktionseinheiten.

1m Reduktionsmodus sind die Zustandsiibergange der Reduktionseinheiten haupt­sachlich durch die Maschinenbefehle bestimmt, die im letzten Abschnitt vorgestellt wurden. Die Semantik der Maschinenbefehle bestimmt die Veranderung des 10-kalen Zustandsraumes und die Nachrichten, die in die Nachrichtenschlange des gemeinsamen Speichers geschrieben werden sollen. Welcher Maschinenbefehl zur Ausfiihrung gelangt, ist jeweils durch den Befehlszahler im Taskknoten der gerade ausgefUhrten Task festgelegt.

1st der 'active task pointer' mit 'nil' belegt, so bedeutet dies, daB ein ProzeB­wechsel erfolgen muB, da eine Task suspendiert oder beendet wurde. Falls die Aktivierungsliste nicht leer ist, wird diese zunachst im Aktivierungsmodus abge­arbeitet, d.h. es erfolgt ein Ubergang in den Aktivierungsmodus. Anderenfalls wird die lokale Taskwarteschlange iiberpriift. 1st diese nicht-leer, so wird der 'ac­tive task pointer' auf das erste Element dieser Taskqueue gesetzt. Anderenfalls wird das ProzeBanforderungsfiag im gemeinsamen Speicher von Kommunikations­und Reduktionseinheit gesetzt und in den Wartemodus gewechselt.

Der Reduktionsmodus ist der Standardmodus jeder Reduktionseinheit, da die codegesteuerte Durchfiihrung von Reduktionen die Hauptaufgabe dieser Einheiten

Page 75: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

304 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

ist. Urn aber parallel erfolgende Teilberechnungen nicht unnotig zu verzogern, hat die Bearbeitung von Nachrichten in jeder Reduktioneinheit hochste Prioritat. So­bald im gemeinsamen Speicher eine Nachricht fur die Reduktionseinheit vorliegt, wird in den Kommunikationsmodus gewechselt, in dem die Nachricht bearbeitet und gegebenenfalls beantwortet wird. Alle ubrigen Ubergange im Reduktionsmo­dus sind also nur moglich, wenn die Komponente 'red-q' im gemeinsamen Speicher leer ist.

10.5.3 Definition 1m Reduktionsmodus sind fUr die Reduktionseinheit REj mit j E {I, ... , n} folgende Zustandsubergange moglich:

1. Ausfiihrung von Maschinenbefehlen

( (rm, atp, G[atp/(TASK, /1, arglist, (~, ip, ds, lv, 0, lq, gq ))], gp, ltq, aI, ( ca-c, ca-f, rg, c-evt, c )),

( E, com-q, false) ) I-REJ (proji (C [ c(ip)] j

(rm, atp, G, gp, ltq, aI, ( ca-c, ca-f, rg, c-evt, c ) )), (E, com-q . proj~ (C[c(ip)) j

(rm,atp,G,gp,ltq,al, (ca-c,ca-f,rg,c-evt,c) )), false) ),

falls atp '# 'nil'.

2. Prozepwechsel

( (rm,'nil', G, gp, ltq, al, ps), (E, com-q, false) ) ((am, 'nil', G, gp, ltq, aI, ps), (E, com-q, false))

falls al '# E

((rm, hd(1tq), G, gp, tl(ltq), E, ps), (E, com-q, false) ) I-REJ falls al = E

und ltq = hd(ltq):tl(ltq) '# E

mit hd (ltq) E LAdr ((wm, 'nil', G, gp, E, E, ps), (E, com-q, true) )

falls al = Itq = E.

3. Nachrichtenankunft

( (rm, atp, G, gp, ltq, al, ps), (red-q, com-q, next) ) I-REJ ( (em, atp, G, gp, ltq, aI, ps), (red-q, com-q, next) )

falls red-q '# E.

1m Aktivierungsmodus wird die weitere Auswertung von Datenstrukturen ver­anlafit, deren Auswerter nachtraglich erhoht wurde. Die Eintrage in der Akti-

Page 76: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.5. SPEZIFIKATION DER REDUKTIONSEINHEIT 305

vierungsliste bestehen jeweils aus einem Zeiger auf den Wurzelknoten der Daten­struktur und einer Liste von neuen A uswertern fiir die Komponenten der Daten­struktur, deren Auswerter erhoht werden mull. Da die Komponenten einer Da­tenstruktur von beliebiger Natur sind, d.h. als Wert, glob ale Adresse oder lokale Adresse auf Taskknoten, Argumentknoten, Terminalknoten oder Verweisknoten vorliegen konnen, entspricht die Erhohung des Auswerters der Durchfiihrung eines INITARG-Befehls fiir die entsprechende Komponente.

Nach vollstandiger Abarbeitung der Aktivierungsliste wird in den Reduktions­modus zuriickgekehrt. Auch im Aktivierungsmodus erfolgt, sobald eine Nachricht von der Kommunikationeinheit eintrifft, ein Ubergang in den Kommunikationsmo­dus zur Bearbeitung der eingetroffenen Nachricht.

10.5.4 Definition 1m Aktivierungsmodus sind fUr die j-te Reduktionseinheit REj folgende Zustandsiibergange moglich:

1. Aktivierung von Komponenten

( (am, nil, G[ladr / (SDATA, c, arg1 : ... : argk, ~)], gp, ltq, (ladr, (i, e): etl): aI, ps), (E, com-q, false) )

((am, nil, G[ ladr/(SDATA, c,arg1 : ... : argk>~)], gp, ltq, (ladr,etl):al, ps),

( E, com-q, false)) falls argi = (V, a) oder argi = (P, adr, e') mit ~" ~ e.

((am, nil, G[ ladr/(SDATA, C, argl : ... argi· .. : argk, 0], gp, ltq, (ladr,etl):al, ps),

(E, com-q:[INITIATE, gadr, e]' false) ) falls argi = (P, gadr, e') mit ~" < e und gadr = (pur, ladr) mit pur f:. j, wobei argi = (P, gadr, e).

((rm, atp, G[ ladr/(SDATA, c, arg1 : ... argi ... : argk, 0, ladr' /(lNDIRECTION, ?, e, E, E)],

gp, Itq, (ladr,etl):al, ps), (E, com-q:[PROCESS,F,arglist', e ,indir,(pur,ladr')] ,false))

falls argi = (P, (j, ladr'), ~o) mit G(ladr') = (TASK,F,arglist',~o),F E Fun, wobei argi = (P, (j, ladr'), e).

Page 77: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

306 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

((am, nil, G[ ladr/(SDATA, e, argl : ... argi ... : argk, ~), ladr' / (TASK,jL' ,arglist',

gp, ltq, (ladr,etl):al, ps), ( E, com-q, false))

(t' ,ip' ,ds' ,lv',pc' ,lq' ,gq') )]

falls argi = (P, (j, ladr'), t) mit G(1adr') = (TASK, jL', arglist',

(t, ip', ds', lv', pc', lq', gq')), wobei argi = (P, (j, ladr'), t') und t' := max{t',(}.

((am, nil, G[ ladr/(SDATA, e, arg1 : ... argi ... : argk' ~), ladr' /(TASK, 'arg' ,arglist', W, lj, E,lv' ,O,E, E) )],

gp, ltq: ladr', (ladr,etl):al, ps), (E, com-q, false))

falls argi = (P, (j, ladr'), ~o) mit G(ladr') =

(ARGUMENT, (arglist' ,Iv'), (11,12 ,13)),

wobei argi := (P, (j, ladr'), e ), und e = ~j mit j E {1,2,3}.

((am, nil, G[ ladr/ (SDATA, e, arg1 : ... argi ... : argk' ~), ladr' /(SDATA, e', arglist', t')],

gp, ltq, (ladr,etl):al', ps), ( E, com-q, false))

falls argi = (P, (j, ladr'), t) mit G(1adr') = (SDATA, e', arglist, t), wobei argi := (P, (j, ladr'), t'), t' := maxie, t} und aI' := { al:(ladr', c-evt (e', e)) falls e ~ t

al sonst

((am, nil, G[ ladr/(SDATA, e, arg1 : ... argi ... : argkl ~,)], gp, ltq, (ladr,etl):al, ps)

(E, com-q, false)) falls ( = 6 und argi := (P, (j, ladr'), ~o) mit G(ladr') = (SDATA, ... ) oder G(ladr') = (FUNCTION, ... ), wobei argi = (P, (j,ladr'),6).

Page 78: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.5. SPEZIFIKATION DER REDUKTIONSEINHEIT 307

((am, nil, G[ ladr/(SDATA, C, argl : ... arg~ ... : argk, ~), ladr' /(INDIRECTION, ?, t', lq', gq')],

gp, Itq, (ladr,etl):al, ps) ( f, eom-q, false))

falls argi := (P, (j, ladr'), ~) mit G(ladr') = (INDIRECTION, ?, t, lq', gq'), wobei argi = (P, (j, ladr') , t') und t' := max{t,e}

((am, nil, G[ ladr/(SDATA, C, argl : ... argi .. ·: argk'~)' ladr' /(INDIRECTION, gadr, t', lq', gq')]'

gp, Itq, (ladr,etl):al, ps), (f, com-q:mes, false))

falls argi := (P, (j, ladr'), ~) mit G(ladr') = (INDIRECTION, gadr, t, lq', gq'), wobei argi = (P, (j, ladr'),t'), t' := max{e,t} und

mes := { ~INITIATE, gadr, e] falls e > t " sonst.

((am, nil, G[ ladr/(SDATA, C, argl : ... argi.··: argk'~)], gp, ltq, (ladr,etl):al, ps),

(f,com-q, false)) falls argi := (P, (j, ladr') , ~) mit G(ladr') = (LOCAL-IND, ladr"), wobei argi = (P, (j,ladr"),~).

( (am, nil, G, gp, ltq, (ladr, f): al, ps), (€, eom-q, false) ) I-REJ ( (am, nil, G, gp, Itq, al, ps), (f, com-q, false) )

2. Rilckkehr in den Reduktionsmodus

( (am, nil, G, gp, ltq, f, ps), (f, eom-q, false) ) I-REJ ( (rm, nil, G, gp, Itq, f, ps), (f, com-q, false) )

3. Ankunft von Nachrichten

( (am, nil, G, gp, Itq, al, ps), (red-q, eom-q, false) ) I-REJ ( (em, nil, G, gp, Itq, al, ps), (red-q, eom-q, false) )

falls red-q =J f.

1m Wartemodus hat die Reduktionseinheit keine Arbeit. Sie wartet auf Nach­richten von der Kommunikationeinheit. Die einzige mogliche 'Iransition ist der Ubergang in den Kommunikationsmodus, sobald N achriehten eintreffen.

Page 79: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

308 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Anforderung von Arbeit

Reduktionsmodus

Wartemodus

Ankunft von Nachrichten

Ankunft von N achrichten

Kommunikations­modus

Ausfiihrung von Tasks

Ende der N achrichtenbearbeitung

Bearbeitung von

Proze:B-

Ende der Aktivierungen

wechsel Ak . . d bei nicht- tIvlerungsmo us 1-----

leerer Aktivierungsliste Aktivierung

von Datenstrukturkomponenten

N achrichten

Ankunft von N achrichten

Bild 10.13: Uberblick iiber Zustandsiibergange der Reduktionseinheiten

10.5.5 Definition 1m Wartemodus sind fUr die j-te Reduktionseinheit folgende Zustandsiibergange moglich.

( (wm, nil, G, gp, E, E, ps), (red-q, com-q, false)} I-REJ ( (cm, nil, G, gp, E, E, ps), (red-q, com-q, false) } falls red-q =F E.

Bis auf die Zustandsiibergange im Kommunikationsmodus, die wir im nach­sten Kapitel spezifizieren werden, sind die Reduktionseinheiten somit vollstandig definiert. Bild 10.13 zeigt eine Ubersicht iiber die Arbeitsmodi und die Aktionen, mit denen Ubergange zwischen den Arbeitsmodi erfolgen.

Page 80: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.6. BEISPIELAUSFUHRUNG 309

10.6 ErUiuterung einer Beispielausfiihrung

In dies em Abschnitt wird anhand des Quicksort-Beispielprogramms die Durchfuh­rung programmierter Graphreduktion in einer Reduktionseinheit beschrieben. Zu dem parallelisierten Kombinator PQSort (vgl. Beispiel 7.2.3):

PQSort(lintlist) := case 1 of NIL: NIL; CONS(Yl, Y2) :

esac

let par iiI = PQSort(Filter (Tlt(Yl)' Y2)) if 6 and i12 = PQSort( Filter ( Tgeq(Yd, Y2)) if 6 in Append (Yl, CONS(Yl, Y2))

ergibt sich der bereits in Bild 10.12 gezeigte Code:

1: INITARG (1,6); 17: LOADLOC 1; 2: GETARG (1,6); 18: MKNODE(Tlt,I); 3: LOAD 1; 19: INITLOC (2,6); 4: WAIT 1; 20: LOADLOC 2; 5: SPLIT; 21: MKNODE(Filter,2); 6: CASE ((NIL,7),(CONS,9)}; 22: EVALUATE 6; 7: LIT NIL; 23: MKNODE(PQSort,I); 8: RET; 24: ACTIVATE 6; 9: LOADLOC 1; 25: STORE 2;

10: MKNODE( Tgeq,I); 26: INITLOC (1,6); 11: INITLOC (2,6); 27: LOADLOC 1; 12: LOADLOC 2; 28: INITLOC (3,6); 13: MKNODE(Filter,2); 29: LOADLOC 3; 14: EVALUATE 6; 30: INITLOC (2,6); 15: MKNODE(PQSort,I); 31: LOADLOC 2; 16: ACTIVATE 6; 32: NODE (CONS, 6);

33: PUSH (Append,2);

Die Ausfiihrung dieser Maschinencodesequenz fuhrt im lokalen Speicher einer Reduktionseinheit zu den in den Bildern 10.14 (I-IX) graphisch verdeutlichten Zustandstransformationen.

Page 81: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

310 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

I. Bild I zeigt die Ausgangssituation:

Der 'active task pointer' im lokalen Speicherbereich der Reduktionseinheit zeigt auf einen Taskknoten, der einen Aufruf des Kombinators PQSort re­prasentiert. Das Argument dieses Aufrufes ist durch einen Zeiger auf einen lokalen Datenstrukturknoten, die Wurzel der zu sortierenden Liste, gegeben. Der Auswerter des aktiven Taskknoten ist 6. Der Instruktionszeiger zeigt bereits auf den dritten Befehl des Maschinen­codes von PQSort. Die AusfUhrung der erst en Befehle bewirkt lediglich die Inkrementation des Befehlszahlers, da fUr das Argument der Task bereits der Auswerter 6 vorliegt. Die lokalen Keller des Taskknoten sind leer. Der 'pending count' ist mit 0 initialisiert. Es wird angenommen, daB noch keine anderen Tasks auf das Ergebnis dieser Task warten. Die Adressenlisten des Taskknoten sind also ebenfalls leer.

II. Der LOAD-Befehl bewirkt das Laden des Argumentes der Task auf den Datenkeller. Da der Wurzelknoten der Argumentstruktur lokal vorliegt, verandert der WAIT-Befehl nur den Instruktionszeiger.

III. Der SPLIT -Befehlladt die Komponenten des Datenstrukturknoten auf den Variablenkeller. Der nachfolgende CASE-Befehl verandert den Instruktions­zeiger in Abhangigkeit von dem Konstruktor des Datenknoten und loscht die Adresse des Datenstrukturknoten yom Datenkeller.

IV. Mittels des Befehls LOADLOC 1 wird das oberste Element des Variablenkel­lers auf den Datenkeller geladen. Da der Kombinator Tgeq den Rang 2 hat, wird durch den Befehl MKNODE( Tgeq, 1) ein Funktionsknoten, der die par­tielle Applikation des Kombinators auf ein Argument reprasentiert, erzeugt. Zu der Adresse des neu erzeugten Funktionsknoten wird der Auswerter 6 vermerkt, da partielle Applikationen nicht weiter ausgewertet werden.

Page 82: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.6. BEISPIELAUSFUHRUNG

I

code:

GETARG (1,(3) LOAD 1 WAIT 1

311

II

SPLIT CASE ( (NIL,7),(CONS,9) )

llI------------------~v-------------------

code:

9: LOADLOC 1 MKNODE(Tgeq,l) INITLOC(2,h) MKNODE(Filter,2)

Bild lO.14a: BeispielausfUhrung

Page 83: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

312 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

V. Nachdem das zweite Element des Variablenkellers auf den Datenkeller ge­laden worden ist (LOADLOC 2), erzeugt der Befehl MKNODE(Filter,2) einen schlafenden Taskknoten (Auswerter ~o) mit zwei Argumenteintriigen, die yom Datenkeller genommen werden.

VI. Der Befehl EVALUATE 6 bewirkt eme lokale direkte Aktivierung dieses Taskknoten mit Auswerter 6:

- Der Taskknoten wird urn Statusinformationen (Instruktionsziihler, Da­ten- und Variablenkeller, 'pending count' und Adref31isten erweitert). Dabei wird der Instruktionsziihler mit der Codeanfangsadresse initiali­siert, die im Programmspeicher zu dem Kombinator Filter fiir den Fall einer direkten Aktivierung mit Auswerter 6 abgespeichert ist. Die Kel­ler und die AdreBlisten sind zuniichst leer, der 'pending count' ist auf 0 gesetzt.

- Die Adresse des Taskknoten wird zur lokalen Taskwarteschlange hinzu­gefiigt.

Die aktive Task bleibt weiterhin aktiv.

VII. Der Befehl MKNODE(PQSort,l) erzeugt wiederum einen schlafenden Task­knoten, der als Argumenteintrag die Adresse des zuvor aktivierten Taskkno­ten erhiilt.

VIII. Mittels ACTIVATE 6 erfolgt eine parallele Aktivierung des zuletzt erzeugten Taskknoten:

- Eine ProzeBnachricht, die neben den Informationen aus dem Taskkno­ten den Auswerter 6, die Aktivierungsart 'dir' und die Heimatadresse des neu erzeugten Prozesses enthalt wird erzeugt und in die Warte­schlange des gemeinsamen Speichers von Reduktions- und Kommuni­kationseinheit geschrieben.

- Der Taskknoten wird durch einen Verweisknoten iiberschrieben, in dem nur noch der Auswerter, mit dem die Aktivierung des Prozesses erfolgte, als Information iiber den ProzeB behalten wird.

Page 84: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.6. BEISPIELAUSFUHRUNG 313

V IVI

atp~ ... atp~ . .. Itq

TASK I PQSort I (P, (,6) 16 TASK I PQSort I (P, (,6) 16 '--

i Ii ~p'l>eo I Iv,Slp,la'~3~ 101- - 1 ~ P, 1>6 1 Iv ,Slp,la,es ~ 10 ) - l - -.- .- {~

I TASK I Filter I(p, ,~d:(p,la,6)1 eo I TASK I Filter I(p, '~1 ):(p,la,es)16

·1 ~ ~ 101- I -

code: I FUNCTION Tgeql (V,5):? 11 code: FUNCTION ITgeql (V,5):? 11 .. . ...

MKNODE(Filter,2) EVALUATE el EVALUATE e3 .... MKNODE(PQSort,l) MKNODE(PQSort,l) ACTIVATE e3 .. . ...

--------------------T--------------------VII atp~ Itq IVIII atp~ Itq .. . I ...

!-- I--

TASKI PQSort I (P,r,6) 16 i I TASK I PQSort I (p,r,6) 16 i I I ~ P, ,eo 1 Iv ,Slp,la,es ~ 10 I - I - - I Ii ~P, ,61 Iv,Slp,la'~3~ 101- I - r--~ {~ I ~ If=--

TASK I Filter I(p, ,6 ):(P,la,es) 6 I TASK I Filter I(p, ,~d:(P,la,~3)16 I

ol~ ~ 101- - I ·1 ~ ~JOI-J -I

FUNCTION ITgeql (V,5):? 11 I FUNCTION ITgeql (V,5):? 11 I I

" I --.jTASK IpQSortl (P\~3) eo I --.j INDIRECTION I ? l ~31 - J -

I I

& die Nachricht: I I [PROCESS, PQSort, (P, ,~3), ~3,dir, 1

code: I code: wird an die Kommunika-.. . I ... tionseinheit weitergelei-

MKNODE(PQSort,l) I ACTIVATE e3 tet. '+ ACTIVATE e3 I .... LOADLOC 1

LOADLOC 1 I MKNODE(Tlt,l)

.. . 1 ... I

Bild lO.14b: Beispielausfiihrung - Fortsetzung

Page 85: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

314 KAPITEL 10. PROGRAMMIERTE GRAPHREDUKTION

Die Ausfiihrung der nun folgenden Befehle (Programmadressen 17 - 24) erfolgt vollkommen analog zu den Befehlen mit den Programmadressen 9 - 23, deren Auswirkungen auf den Zustandsraum der Reduktionseinheit in den Bildern III -VIII (Bild 10.14ajb) veranschaulicht sind. Insbesondere erfolgt die Aktivierung eines weiteren parallelen Prozesses fiir den zweiten rekursiven Aufruf des Kombi­nators PQSort. Mittels des STORE-Befehls werden dann die Zeiger auf die Verweisknoten der parallelen Prozesse auf den Variablenkeller geschoben. Dann wird der Code, der fur den Rumpf des letpar-Konstruktes generiert wurde, ausgefUhrt. Die aktuellen Bindungen der in diesem Rumpf auftretenden lokalen Variablen liegen auf dem Variablenkeller in der Reihenfolge

Yl : Y2 : Yl : Y2,

konnen also durch die Befehle LOADLOC 1-4 referenziert werden. Vor den La­debefehlen wird jeweils entsprechend den Striktheitsinformationen die Auswer­tung der Variablenbindungen durch INITLOC-Befehle angestoBen. Da fUr alle Variablenwerte allerdings bereits der maximale Auswerter vorliegt, fiihren die INITLOC-Befehle in diesem Beispiel nur zur Erhohung des Befehlszahlers der ak­tiven Task. Der Code fuhrt schlieBlich zu der Erzeugung eines Konstruktorknoten (Befehl NODE cONs,6)), in dem das Kopfelement der Argumentliste - nun gegeben durch das dritte Element des Variablenkellers (lokale Variable Yl) - die erste Komponente bildet. Bild 10.14c (IX) zeigt den Zustand der Reduktionseinheit nach der Erzeugung des Konstruktorknotens. Der nachfolgende Befehl wird die Uberschreibung des aktiven Taskknoten durch einen Taskknoten zur Berechnung des Aufrufes des Kombinators Append bewirken. Inzwischen konnen von den parallelen Prozessen Anfragenachrichten an die lokalen Tasks mit Kombinator Filter eingetroffen sein, die in den globalen Adressenlisten dieser Tasks vermerkt wurden, da die Ausfiihrung dieser Tasks noch nicht be­gonnen wurde. Formal werden wir die Bearbeitung von Nachrichten durch die Reduktionseinheit im folgenden Kapitel beschreiben. Die neue Task mit Kombinator Append erhalt als Argumente die beiden Datenkel­lereintrage. Da der Code von Append (bei direkter Aktivierung) mit den Befehlen GETARG(1,6);LOAD l;WAIT 1 beginnt, das erste Argument aber durch einen Verweisknoten reprasentiert, also nicht lokal vorhanden ist, fiihrt der WAIT-Befehl zur Suspendierung der aktiven Task, was dann einen ProzeBwechsel ermoglicht (siehe Bild 1O.14c (X)).

Page 86: [Informatik-Fachberichte] Parallele Implementierung funktionaler Programmiersprachen Volume 232 || Organisation der programmierten Graphreduktion

10.6. BEISPIELAUSFUHRUNG 315

IX atp~ ... /

TASK I PQSort I (P, (,6) 16 ~

d~p, ,61P, ,61 P, ,61P, ,61+'~ 101-1 - ltq i '\.... \ /' ~ f--

"'---... I ~ TASK I Filter I(p, '~1 ):(P,la,~3) 6 TASK I Filter [(P, ,6 ):(P,la,6) 6

·1 ~ ~ 101- I" ·1 ~ ~ 101- I"

FUNCTION TIt I (V,5):? 11 FUNCTION Tgeql (V,5):? 11

INDIRECTION I ? I ~31 - I - r- L:::t INDIRECTION.I ? 16 I - I -

t ISDATA CONSI (V,5):(p,I,6) l6J

code: ... PUSH(Append,2)

X atp I nil I

TASK I Append [ (P, ,6):(P, ,6) 16 >-----

I [ijP,I,61 ~ 111- I -

Itq i '\.... /' =--

I' I r---

TASK I Filter I(p, ,6 ):(P,la,6) 6 TASK I Filter I(p, ,6 ):(P,la,€J) 6

·1 ~ ~ 101- .. ·1 ~ ~ 101- ..

FUNCTION Tlt I (V,5):? 11 FUNCTION Tgeql (V,5):? 11

"-INDIRECTION I ? I ~31- I - '--~ INDIRECTION I ? 16 I J I-

i ./

ISDATA CONSI (V,5):(p,I,6) 6 code: ., .

LOAD I WAIT I --.. ...

Bild lO.14c: Beispielausfiihrung - Fortsetzung