Welche Zwischendarstellungen können verwendet werden, um über Parallelität zu urteilen?

12

Ich versuche besser zu verstehen, was erforderlich wäre, damit ein Compiler im Namen des Programmierers intelligente Entscheidungen in Bezug auf die Parallelität treffen kann. Mir ist klar, dass es bei diesem Problem viele schwierige Aspekte gibt, zum Beispiel:

  • Sicherstellen, dass keine Rennbedingungen vorliegen
  • Sicherstellen, dass der gleichzeitig auszuführende Code keine Nebenwirkungen hat, die sich auf die semantische Bedeutung des Codes auswirken

  • Die Entscheidung, ob sich der Overhead durch das Hochfahren von Threads lohnt, ist angesichts des im Code verfügbaren Grads an Parallelität sinnvoll

Ich verstehe, dass die beiden in modernen Compilern verwendeten Hauptzwischenrepräsentationen statische Einzelzuweisungen für prozedurale und objektorientierte Sprachen und Fortsetzungsstile für funktionale Sprachen sind. Mit diesen Zwischenformen scheint es schwierig zu sein, über eines der oben aufgeführten Probleme nachzudenken. Sogar Sprachen, die theoretisch die besten Chancen auf automatische Parallelisierung haben sollten (reine Funktionssprachen wie Haskell mit der Garantie, dass keine Nebenwirkungen auftreten), haben diesbezüglich nur begrenzte Fortschritte erzielt.

Meine Frage ist also wirklich, welche Zwischenrepräsentationen verwendet wurden, um dieses Problem anzugehen? Gibt es andere Darstellungen, die in der akademischen Forschung verwendet wurden, von denen ich nichts weiß, und die besser für diese Aufgabe geeignet sind? Ist dieses Problem eines, das vom Compiler-Frontend durch Manipulieren des abstrakten Syntaxbaums grundlegend gelöst werden muss, bevor die Kompilierung eine Zwischendarstellung erreicht?


quelle
Wenn Sie Ihren Code funktional schreiben, müssen Sie sich keine Gedanken über die Rennbedingungen oder Nebenwirkungen machen.
Robert Harvey
4
Dies beantwortet Ihre Frage nicht ganz, aber möglicherweise interessiert Sie Process Calculi, mit dessen Hilfe Sie über gleichzeitigen Code urteilen können. Das bekannteste Beispiel könnte der Pi-Kalkül sein . Die automatische Parallelisierung ist jedoch nach wie vor ein weitgehend ungelöstes Problem und wird am besten dadurch gelöst, dass Sprachen speziell entwickelt werden, um dem Compiler bestimmte Garantien zu bieten, oder indem spezielle Anmerkungen verwendet werden.
Am
4
Das Papier, das als Hintergrund für Intel Concurrent Collections (CnC) dient, listet acht grundlegende gleichzeitige Muster auf, z. B. Producer-Consumer. Diese gleichzeitigen Muster hängen wiederum von einer Reihe von Eigenschaften ab, z. B. Unveränderlichkeit und nebenwirkungsfrei. (Ich würde mich
freuen,
Eines der theoretischen Tools heißt "Dynamic Single Assignment (DSA)", das auf SSA aufbaut.
rwong
@rwong: Kannst du einen expliziten Verweis geben?
Ira Baxter

Antworten:

5

Man würde annehmen, dass die explizite Modellierung der Parallelität in der Zwischendarstellung (Intermediate Representation, IR) eine notwendige Voraussetzung ist. Eine Antwort wäre also "jede IR, die für sequentielle Programme mit einigen Paralleloperationen verwendet wird", z. B. "fork and join", "parallel x y". Wenn Sie diese hinzufügen, können Sie über einige Arten von Parallelität nachdenken, was jedoch nicht unbedingt einfach ist. Es ist auch nicht klar, wie bestimmte Eigenschaften (Datenrassenfreiheit) sichergestellt werden können, ohne dass eine voll funktionsfähige Darstellung erforderlich ist (was es schwierig macht, Parallelität sinnvoll zu modellieren).

Wohl farbige Petri-Netze (CPNs) sind eine gute Wahl für die Darstellung von Programmen mit Parallelität. (Token in CPNs sind "farbig" [haben einen Typ] und können Werte tragen; "Übergänge" in Zustände können bei eingehenden Token eine willkürliche Arithmetik ausführen, um ein möglicherweise andersfarbiges Token mit berechnetem Wert an der "Stelle" zu erzeugen.) Wenn Sie sich Orte als berechnete Ergebnisse und Übergänge als Modellierungsoperatoren vorstellen (einschließlich eines speziellen Operators für den Speicherzugriff), erhalten Sie einen Datenflussgraphen, mit dem Sie Programme modellieren können. Sie können dies leicht verwenden, um klassischen Compiler-Darstellungen wie Tripeln [Operator, Eingabe1, Eingabe2, Ausgabe] eine formale Interpretation zu geben.

Es gibt viele Tools zum Analysieren solcher CPN-Diagramme, einschließlich der Berechnungseigenschaften wie Deadlock-Freiheit, Beschränkung der Anzahl der Token an bestimmten Stellen usw. Mit heirarchischen CPNs können Sie Funktionen und Prozeduren sowie den Begriff "Aufrufe" modellieren.

Was diese Darstellungen nicht eindeutig machen, ist es einfach zu überlegen, wo man eine Anwendung parallelisieren könnte. Trivialerweise können zwei Teilberechnungen parallel sein, wenn sie keine gemeinsam genutzten Operanden beeinflussen (weshalb manche Leute funktionale Programme / Darstellungen lieben). Wenn Ihre Programmdarstellung einen gemeinsam genutzten Speicher modelliert, können Sie ihn als Monolith modellieren und die üblichen Probleme beim Überlegen von Interaktionen auf dem gemeinsam genutzten Speicher, einschließlich Alias-Adressierung usw., beheben der größere Programmzustand ist eine (baumartige) Assemblierung von diesen; Sie können diese Stücke wohl in Ihrer Zwischendarstellung herumreichen. Es gibt keine Interaktion zwischen zwei parallelen Berechnungen, wenn diese keine Chunks gemeinsam nutzen (z. B. Speicher-Teilbäume).

Ira Baxter
quelle