Warum ist Rekursion in OpenCL verboten?


19

Ich möchte OpenCL verwenden, um das Rendern von Raytrace-Bildern zu beschleunigen, aber ich stelle fest, dass auf der Wikipedia-Seite behauptet wird, dass die Rekursion in Open CL verboten ist. Ist das wahr? Da ich beim Raytracing weitgehend von Rekursion Gebrauch mache, ist eine erhebliche Neugestaltung erforderlich, um von der Beschleunigung zu profitieren. Was ist die zugrunde liegende Einschränkung, die eine Rekursion verhindert? Gibt es einen Ausweg?


2
GPUs funktionieren anders. (Einige Architekturen) haben nicht das Konzept eines globalen "Programmstacks", so dass rekursive Funktionsaufrufe in diesen nicht möglich sind. OpenCL nimmt wahrscheinlich den kleinsten gemeinsamen Nenner an, sodass es nicht mehr vollständig auf GPUs portierbar ist. Neuere CUDA-Hardware scheint irgendwann Unterstützung für die Rekursion eingeführt zu haben: stackoverflow.com/q/3644809/1198654
glampert

Antworten:


27

Dies liegt im Wesentlichen daran, dass nicht alle GPUs Funktionsaufrufe unterstützen können - und selbst wenn dies möglich ist, können Funktionsaufrufe sehr langsam sein oder Einschränkungen aufweisen, z. B. eine sehr geringe Stapeltiefe.

Shader-Code und GPU-Computing-Code scheinen überall Funktionsaufrufe zu haben, aber unter normalen Umständen sind sie alle zu 100% vom Compiler eingebettet. Der von der GPU ausgeführte Maschinencode enthält Verzweigungen und Schleifen, jedoch keine Funktionsaufrufe. Rekursive Funktionsaufrufe können jedoch aus offensichtlichen Gründen nicht eingebunden werden. (Es sei denn, einige der Argumente sind Konstanten für die Kompilierungszeit, sodass der Compiler sie falten und den gesamten Aufrufbaum einbinden kann.)

Um echte Funktionsaufrufe zu implementieren, benötigen Sie einen Stack. In den meisten Fällen wird für Shader-Code überhaupt kein Stapel verwendet. GPUs verfügen über große Registerdateien, und Shader können alle ihre Daten die ganze Zeit über in Registern speichern. Es ist schwierig, einen Stapel zum Laufen zu bringen, weil (a) Sie viel Stapelplatz benötigen würden, um all die vielen Verzerrungen, die gleichzeitig im Flug sein können, unterzubringen, und (b) das GPU-Speichersystem für das Zusammenfügen vieler Stapel optimiert ist von Speicher-Transaktionen, um einen hohen Durchsatz zu erzielen, aber dies geht zu Lasten der Latenz, so dass ich vermute, dass Stapeloperationen wie das Speichern / Wiederherstellen lokaler Variablen furchtbar langsam wären.

In der Vergangenheit waren Funktionsaufrufe auf Hardwareebene auf der GPU nicht besonders nützlich, da es sinnvoller war, alles im Compiler zu integrieren. GPU-Architekten haben sich also nicht darauf konzentriert, sie schnell zu machen. Wahrscheinlich könnten einige andere Kompromisse eingegangen werden, wenn in Zukunft effiziente Hardware-Level-Aufrufe erforderlich sind, aber (wie bei allem im Engineering) werden die Kosten woanders anfallen.

Was Raytracing anbelangt, besteht die Art und Weise, wie Menschen normalerweise mit solchen Dingen umgehen, darin, Warteschlangen von Strahlen zu erstellen, die gerade verfolgt werden. Anstatt sich zu wiederholen, fügen Sie einen Strahl zu einer Warteschlange hinzu, und auf der oberen Ebene befindet sich irgendwo eine Schleife, die so lange verarbeitet wird, bis alle Warteschlangen leer sind. Wenn Sie jedoch von einem klassischen rekursiven Raytracer ausgehen, muss Ihr Rendering-Code erheblich umstrukturiert werden. Weitere Informationen finden Sie in folgendem Artikel: Wavefront Path Tracing .


6
Ich teile diese geheime Sauce nur ungern, aber ich hatte ziemlich viel Glück damit, eine feste maximale Sprungzahl und einen Stapel fester Größe (und eine Schleife mit einer festen Anzahl von Iterationen) zu haben. Auch (und dies ist die wahre geheime Sauce imo!) Ich habe meine Materialien entweder reflektierend oder brechend, aber niemals beides, was es so macht, dass Strahlen sich nicht teilen, wenn sie aufprallen. Das Endergebnis all dessen ist ein Raytrace-Rendering vom rekursiven Typ, jedoch durch Iteration mit fester Größe und nicht durch Rekursion.
Alan Wolfe

Wie Schwanzrekursion?
Tanmay Patil

Sie benötigen keinen Stack, um die Schwanzrekursion durchzuführen, da Schwanzrekursive Funktionen in iterative Funktionen konvertiert werden können. Tut der OpenCL-Compiler dies nicht automatisch?
Anderson Green
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.