You are here

OpenCL: Buffer vs. mehrere Devices

Da OpenCL sowohl auf CPUs als auch auf GPUs funktioniert kommt man recht schnell in die Situation in der mehr als ein OpenCL-Device verwendet werden will. Doch was passiert in diesem Fall mit dem kostbaren, weil wenigem, Grafikkartenspeicher? Die Funktion clCreateBuffer bietet ja leider keine Möglichkeit anzugeben auf welchem Device der Speicher allokiert werden soll.

Die einfachste Variante mit mehreren OpenCL-Devices zu arbeiten ist alle in einem Context zu verwalten. In diesem Fall wird ein Buffer aber immer für alle Devices angelegt. Wird ein Speicher also nur auf einem Device benötigt muss man befürchten, dass dieser auch auf anderen Devices kostbaren Speicher verbraucht.

Glücklicherweise sollte dies sowohl auf AMD, als auch auf NVIDIA-Hardware kein Problem darstellen. Beide teilen einem Buffer immer erst dann Speicher auf der Grafikkarte zu wenn dieser dort das erste mal verwendet wird. AMD dokumentiert dies explizit in seinem AMD APP Programming Guide. NVIDIA geht in seiner GPU Computing Documentation zwar nicht explizit auf diese Problematik ein, Beiträge in den Foren von NVIDIA und Khronos dokumentieren aber dieses Verhalten. Bedenken sollte man allerdings, dass man, um von diesem Verhalten zu profitieren, CL_MEM_COPY_HOST_PTR nicht verwenden darf.

AMDs Programming Guide empfiehlt explizit einen gemeinsamen Context für alle Devices zu verwenden, da dies programmiertechnisch die einfacherere Lösung ist. Es wird aber auch eingestanden, dass ein Context pro Device deutlich flexibler ist. Dies ist beispielsweise die einzige Möglichkeit CPUs mit NVIDIA-Grafikkarten zu kombinieren.

Die Flexibilität mehrere Contexte hat allerdings ihren Preis. So ist es nicht möglich die Ausführung zwischen mehreren Contexten über Events zu synchronisieren. Die OpenCL-Spezifikation weist explizit darauf hin, dass ein Befehl in einer Workqueue immer nur auf Events welche zum gleichen Context gehören warten kann. Prinzipiel kann diese Beschränkung mithilfe von Event Callbacks und User Events umgangen werden, dies ist aber auch mit einem höheren Aufwand verbunden.

Außerdem sollte man auch immer bedenken, dass Buffer welche ausschließlich auf der CPU verwendet werden mit CL_MEM_ALLOC_HOST_PTR oder CL_MEM_USE_HOST_PTR initialisiert werden sollten um unnötiges kopieren der Daten zu vermeiden.

Da OpenCL sowohl auf CPUs als auch auf GPUs funktioniert kommt man recht schnell in die Situation in der mehr als ein OpenCL-Device verwendet werden will. Doch was passiert in diesem Fall mit dem kostbaren, weil wenigem, Grafikkartenspeicher? Die Funktion clCreateBuffer bietet ja leider keine Möglichkeit anzugeben auf welchem Device der Speicher allokiert werden soll. Die einfachste Variante mit mehreren OpenCL-Devices zu arbeiten ist alle in einem Context zu verwalten. In diesem Fall wird ein Buffer aber immer für alle Devices angelegt. Wird ein Speicher also nur auf einem Device benötigt muss man befürchten, dass dieser auch auf anderen Devices kostbaren Speicher verbraucht. Glücklicherweise sollte dies sowohl auf AMD, als auch auf NVIDIA-Hardware kein Problem darstellen. Beide teilen einem Buffer immer erst dann Speicher auf der Grafikkarte zu wenn dieser dort das erste mal verwendet wird. AMD dokumentiert dies explizit in seinem AMD APP Programming Guide. NVIDIA geht in seiner GPU Computing Documentation zwar nicht explizit auf diese Problematik ein, Beiträge in den Foren von NVIDIA und Khronos dokumentieren aber dieses Verhalten. Bedenken sollte man allerdings, dass man, um von diesem Verhalten zu profitieren, CL_MEM_COPY_HOST_PTR nicht verwenden darf. AMDs Programming Guide empfiehlt explizit einen gemeinsamen Context für alle Devices zu verwenden, da dies programmiertechnisch die einfacherere Lösung ist. Es wird aber auch eingestanden, dass ein Context pro Device deutlich flexibler ist. Dies ist beispielsweise die einzige Möglichkeit CPUs mit NVIDIA-Grafikkarten zu kombinieren. Die Flexibilität mehrere Contexte hat allerdings ihren Preis. So ist es nicht möglich die Ausführung zwischen mehreren Contexten über Events zu synchronisieren. Die OpenCL-Spezifikation weist explizit darauf hin, dass ein Befehl in einer Workqueue immer nur auf Events welche zum gleichen Context gehören warten kann. Prinzipiel kann diese Beschränkung mithilfe von Event Callbacks und User Events umgangen werden, dies ist aber auch mit einem höheren Aufwand verbunden. Außerdem sollte man auch immer bedenken, dass Buffer welche ausschließlich auf der CPU verwendet werden mit CL_MEM_ALLOC_HOST_PTR oder CL_MEM_USE_HOST_PTR initialisiert werden sollten um unnötiges kopieren der Daten zu vermeiden.

Sollten dir die Artikel auf dieser Seite gefallen und du Bitcoin für ein interessantes Experiment halten, so schicke doch eine kleine Spende an 14pQyjx5EFQCwPBkXMTz5nTcfPsnjHmWqA.