Compiler-Direktiven zur Parallelisierung

Das Beispielprogramm linalg zeigt, daß ein globales Übersetzen aller Routinen mit der Option ''-O3'' nicht sinnvoll ist: Der Parallelisierungsgewinn liegt für viele Schleifen unter 1, d.h. sie arbeiten mit vier CPUs langsamer als mit einer! Man sollte die Option ''-O3'' also zunächst nur bei den Routinen einsetzen, die dadurch insgesamt schneller werden, und alle anderen nur vektorisieren. Weitergehende Schritte erfordern die Verwendung von Compiler-Direktiven, die mit ''C$DIR DIREKTIVE'' in Fortran- bzw. mit ''#pragma_CNX direktive'' in C-Programme eingebaut werden.
Möchte man auch solche Routinen parallelisieren, bei denen nur einige Schleifen davon profitieren, kann man den Compiler durch die Direktive
     NO_PARALLEL
vor einer schlecht parallelisierenden Schleife anweisen, diese nicht zu parallelisieren.
Es gibt eine ganze Reihe von Direktiven, mit denen man den Compiler dazu bringen kann, eine Schleife zu parallelisieren: Natürlich sind diese Anweisungen - vor allem FORCE_PARALLEL - mit Vorsicht zu benutzen; man sollte sich hinterher immer davon überzeugen, daß das Programm für verschiedene Eingabewerte noch richtige Ergebnisse produziert. Da aber das genaue Verhalten eines parallelisierten Programms lastabhängig ist, kann ein Fehler u.U. lange verborgen bleiben.
Ein typischer Anwendungsfall für diese Direktiven sind Schleifen, in denen Routinen aufgerufen werden. Solche Schleifen werden vom Compiler grundsätzlich nicht parallelisiert, da Seiteneffekte der Funktion, z.B. über globale Variable, möglicherweise eine Synchronisation der Iterationen erfordern, ohne daß der Compiler dies feststellen kann. Wenn man weiß, daß die Routine in der Schleife keine Seiteneffekte hat, kann man die Parallelisierung der Schleife durch eine der obigen Direktiven erzwingen. Außerdem muß man die Funktion mit der Compiler-Option ''-re'' (''reentrant'') übersetzen, damit bei gleichzeitiger mehrfacher Ausführung der Funktion jedes Exemplar seinen eigenen Datenbereich bekommt. Ohne diese Option würde der Compiler nur einen Text- und Stackbereich für die Funktion anlegen, so daß alle parallelen Versionen auf dieselben lokalen Variablen zugreifen, was natürlich zu einem vollständigen Durcheinander führen könnte.
Man kann auch über die Parallelisierung von Schleifen hinausgehen, indem man eigenständige ''Tasks'' definiert, also Programmteile, die bei der Ausführung verschiedenen Threads zugeordnet werden können. Dazu dienen die Anweisungen
        BEGIN_TASKS, NEXT_TASK, END_TASKS .
Schließlich gibt es Direktiven, mit denen man die Synchronisation von Threads explizit steuern kann, indem man kritische Bereiche mit Hilfe von Sperr-Variablen (''Locks'') sichert. Näheres dazu kann man dem ''FORTRAN/C Optimization Guide'' von Convex entnehmen.

previous    contents     next

Peter Junglas 18.10.1993