wiki:OpenCL
Please look at the new OpenCL Cheat Sheet attached ;-)

Was ist OpenCL?

OpenCL ist eine standardisierte, generische Programmiersprache zur Programmierung von massiv parallelen Systemen. Die Sprache orientiert sich dabei v. a. an den Bedürfnissen von Grafikkarten, aber nicht nur! Der OpenCL Standard ist wesentlich breiter gefasst. Es lassen sich sowohl datenparallele (SIMD|SIMT) als auch aufgabenparallele (Tasks|Threads) Probleme mit OpenCL beschreiben. Auch ganz normale Multi-Core Prozessoren können von OpenCL profitieren :-)

Der enum-Datentyp cl_device_type zeigt, für welche Geräte OpenCL gedacht ist:

CL_DEVICE_TYPE_DEFAULT   
CL_DEVICE_TYPE_CPU                     
CL_DEVICE_TYPE_GPU                      
CL_DEVICE_TYPE_ACCELERATOR // z. B. Cell 
CL_DEVICE_TYPE_ALL

Spezifikationen und Header-Dateien

Alle Spezifikationen und Header-Dateien, die im Zusammenhang mit OpenCL wichtig sind, findet man auf der Seite der Khronos-Gruppe, die neben OpenCL auch OpenGL verwaltet.

OpenCL bei Khronos
http://www.khronos.org/registry/cl/ (Stand: 29.05.11)

für C++:

Davon braucht man vor allem die Spezifikationen für die C++-Bindings

http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.1.pdf (Stand: 29.05.11)

und evtl. je nach OpenCL-Implementation noch das Header-File:

http://www.khronos.org/registry/cl/api/1.1/cl.hpp (Stand: 29.05.11)

für C:
http://www.khronos.org/registry/cl/specs/opencl-1.1.pdf (Stand: 29.05.11)

Die C-Spezifikation liest sich auch gut, wenn man etwas bei der C++-Spezifikation nicht versteht.

Nützlich und interaktiver als die PDF-Dateien ist die Reference Page
http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/ (Stand: 02.06.11)

OpenCL Fehlercodes

Fehlercodes muss man sehr häufig übersetzen:

/* Error Codes */
#define CL_SUCCESS                                  0
#define CL_DEVICE_NOT_FOUND                         -1
#define CL_DEVICE_NOT_AVAILABLE                     -2
#define CL_COMPILER_NOT_AVAILABLE                   -3
#define CL_MEM_OBJECT_ALLOCATION_FAILURE            -4
#define CL_OUT_OF_RESOURCES                         -5
#define CL_OUT_OF_HOST_MEMORY                       -6
#define CL_PROFILING_INFO_NOT_AVAILABLE             -7
#define CL_MEM_COPY_OVERLAP                         -8
#define CL_IMAGE_FORMAT_MISMATCH                    -9
#define CL_IMAGE_FORMAT_NOT_SUPPORTED               -10
#define CL_BUILD_PROGRAM_FAILURE                    -11
#define CL_MAP_FAILURE                              -12
#define CL_MISALIGNED_SUB_BUFFER_OFFSET             -13
#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14

#define CL_INVALID_VALUE                            -30
#define CL_INVALID_DEVICE_TYPE                      -31
#define CL_INVALID_PLATFORM                         -32
#define CL_INVALID_DEVICE                           -33
#define CL_INVALID_CONTEXT                          -34
#define CL_INVALID_QUEUE_PROPERTIES                 -35
#define CL_INVALID_COMMAND_QUEUE                    -36
#define CL_INVALID_HOST_PTR                         -37
#define CL_INVALID_MEM_OBJECT                       -38
#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR          -39
#define CL_INVALID_IMAGE_SIZE                       -40
#define CL_INVALID_SAMPLER                          -41
#define CL_INVALID_BINARY                           -42
#define CL_INVALID_BUILD_OPTIONS                    -43
#define CL_INVALID_PROGRAM                          -44
#define CL_INVALID_PROGRAM_EXECUTABLE               -45
#define CL_INVALID_KERNEL_NAME                      -46
#define CL_INVALID_KERNEL_DEFINITION                -47
#define CL_INVALID_KERNEL                           -48
#define CL_INVALID_ARG_INDEX                        -49
#define CL_INVALID_ARG_VALUE                        -50
#define CL_INVALID_ARG_SIZE                         -51
#define CL_INVALID_KERNEL_ARGS                      -52
#define CL_INVALID_WORK_DIMENSION                   -53
#define CL_INVALID_WORK_GROUP_SIZE                  -54
#define CL_INVALID_WORK_ITEM_SIZE                   -55
#define CL_INVALID_GLOBAL_OFFSET                    -56
#define CL_INVALID_EVENT_WAIT_LIST                  -57
#define CL_INVALID_EVENT                            -58
#define CL_INVALID_OPERATION                        -59
#define CL_INVALID_GL_OBJECT                        -60
#define CL_INVALID_BUFFER_SIZE                      -61
#define CL_INVALID_MIP_LEVEL                        -62
#define CL_INVALID_GLOBAL_WORK_SIZE                 -63
#define CL_INVALID_PROPERTY                         -64

aus http://www.khronos.org/registry/cl/api/1.1/cl.h (Stand 02.06.11) betrifft OpenCL 1.1

Jetzt habe ich einen C++ ähnlichen Code, der für andere Programmiersprachen sicherlich leicht modifiziert werden kann, angehängt (--> ocl_strerror.txt).

Tutorials

Eine gute Übersicht bekommt man durch den Podcast von macresearch.org. Es gibt die Folien als PDF und den Vortrag als Video. Der Autor vergleicht OpenCL am Anfang mit CUDA. Wer direkt mit dem coden anfangen will, sollte allerdings ein anderes Tutorial wählen. Der Autor verwendent die Programmiersprache C.
http://macresearch.org/opencl (Stand 02.06.11)

Ebenfalls eine gute Übersicht bekommt man, wenn man sich das OpenCL Skript des 10. Lehrstuhls der Universität Erlangen anschaut. Leider habe ich dieses Skript erst sehr spät entdeckt. Tobias Preclik arbeitet mit C++.
http://www10.informatik.uni-erlangen.de/Teaching/Courses/SS2010/SiWiR2/teaching/siwir2-lecture07.pdf (Stand 02.06.11)

Eine tolle Einführung in OpenCL für C-Programmierer gibt's hier:
http://enja.org/2010/07/13/adventures-in-opencl-part-1-getting-started/ (Stand 02.06.11)

Wer lieber mit den C++-Bindings arbeitet, dem seien folgende Webseiten wärmstens empfohlen:
http://enja.org/2010/07/20/adventures-in-opencl-part-1-5-cpp-bindings/ (Stand 02.06.11)
http://www.thebigblob.com/using-the-cpp-bindings-for-opencl/ (Stand 02.06.11)


Eine sehr detaillierte Vorlesung zum Thema OpenCL kommt vom Institute for Multiscale Simulation das zur FAU gehört: Supercomputing on Graphics Cards: An Introduction to OpenCL and the C++ Bindings:

In der ersten Vorlesung wird OpenCL nur angerissen:
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/419/Lecture1.pdf (Stand 03.06.11)

In der zweiten Vorlesung geht es kurz um (OpenCL) Platforms, Devices, Contexts und Command Queues. Ein ausführlicher Teil wird den Buffers gewidmet. Es geht unter anderem um das mappen von dem Speicher des Buffer-Objekts und dem Host-Speicher. Weitere Details:
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/423/Lecture2.pdf (Stand 03.06.11)

Die dritte Vorlesung beschäftig sich fast ausschließlich mit Kernels. Lesenswert v. a. wg. Kernel Functors:
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/442/Lecture3.pdf (Stand 03.06.11)
Eine gute Übersicht zur API der Kernel Functors gibt es hier:
http://www10.informatik.uni-erlangen.de/Teaching/Courses/SS2011/HESP/exercises/doc-opencl-cpp-1.0/html/classcl_1_1KernelFunctor.html (Stand 07.06.11)

In der vierten Vorlesung geht es am Anfang um Extensions. Hier wird besonders die Extension cl_khr_icd hervorgehoben. Sie ermöglicht die Nutzung von mehreren Plattformen auf einem Host. Später geht es noch um's Debugging mit OpenCL. Hierbei wird auf die AMD-Extension cl_amd_printf verwiesen. Weiterhin wird eine Möglichkeit gezeigt, OpenCL-Code mit dem gdb zu debuggen. Sehr lesenswert. Am Ende geht es noch darum, wie man den vom OpenCL Compiler erzeugten PTX-Code (nVidia) bzw. CAL-Code (AMD) gewinnt.
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/449/Lecture4.pdf (Stand 03.06.11)

kurzes Cheatsheet:
==================

printf-Debugging:
-----------------

#pragma OPENCL EXTENSION cl_amd_printf : enable
Beispiel: printf("%d\n", x);
Restriktion: nur auf CPUs und nur mit der AMD-Implementierung möglich

GDB-Debugging:
--------------
1) in der Shell: 
export CPU_COMPILER_OPTIONS="-g"
[export CPU_MAX_COMPUTE_UNITS=1]
(reduziert die Threads auf 1, man verpasst Synchronisierungsfehler...)
2) Compiler:
-pthread
3) GDB Starten

Die fünfte Vorlesung behandelt die unterschiedlichen Arten von Speicher, die zur Verfügung stehen (private, local, global, constant). Außerdem geht sie auf die Architektur von nVidias Multiprozessoren ein. Ferner werden Optimierungen besprochen. Dazu gehört coalescing und das optimieren von if-Abfragen auf aktueller Standardgrafikhardware. Zuletzt wird auf atomic functions eingegangen. Diese sichern die Synchronisation von gemeinsamen Zählvariablen, machen die Berechnungen aber u. U. sehr langsam.
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/469/Lecture5.pdf (Stand 03.06.11)

In der sechsten Vorlesung geht es am Anfang wieder um Speichersynchronisation. Es wird der Begriff der Barriere eingeführt (barrier(CLK_LOCAL_MEM_FENCE)). Außerdem wird auf Bankkonflikte eingegangen. Thematisch werden Reduktions- und Prefixscankernel besprochen.
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/486/Lecture6.pdf (Stand 03.06.11)

Ingesamt ist diese Vorlesungsserie sehr zu empfehlen.

Es gibt auch vier Übungsblätter zur Vorlesung:
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/422/Ex1.pdf (Stand 03.06.11)
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/441/Ex2.pdf (Stand 03.06.11)
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/462/Ex3.pdf (Stand 03.06.11)
http://www.mss.cbi.uni-erlangen.de/KkuDatabase/files/files/487/Ex4.pdf (Stand 03.06.11)


Interessante Dinge zu OpenCL

Vektordatentypen
OpenCL unterstützt auch Vektordatentypen wie double2, ..., double16. So lässt sich so die Performance je nach Applikation steigern:
http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/vectorDataTypes.html (Stand 02.06.11)

Extra OpenCL Compiler Optionen auf der nVidia-Plattform
Besonders interessant für Tuner:

-cl-nv-verbose
        Passed on to ptxas as --verbose
        Enable verbose mode.
        Output will be reported in the build log (accessible through the
        callback parameter to clBuildProgram).

Ansonsten gibt es noch -cl-nv-opt-level=<N> und -cl-nv-maxrregcount=<N>. Ich rate generell davon ab, die Optionen zu verwenden, denn der Sinn von OpenCL besteht eigentlich in plattformunabhängigen Code. Für Tuner eben...
http://developer.download.nvidia.com/compute/cuda/3_2/toolkit/docs/OpenCL_Extensions/cl_nv_compiler_options.txt (Stand 02.06.11)

WebCL
Mit WebCL kann man über eine Website via Javascript auf die Grafikkarten des Rechners zugreifen.
http://www.golem.de/1107/84688.html (Stand 09.07.11)

Code-Beispiel

var cl = new WebCLComputeContext();

var context = cl.createContext(null, device_id, null, null);
var queue = cl.createCommandQueue(context, device_id, null);
var program = cl.createProgramWithSource(context, kernelSource);
cl.buildProgram(program, null, null, null);

var kernel = cl.createKernel(program, kernelName);
var input = cl.createBuffer(context,  cl.MEM_READ_ONLY,
  Float32Array.BYTES_PER_ELEMENT * count, null);

cl.enqueueWriteBuffer(queue, input, true, 0,
  Float32Array.BYTES_PER_ELEMENT * count, data, null);
    
cl.setKernelArgGlobal(kernel, 0, input);
cl.enqueueNDRangeKernel(queue, kernel, 1, 0,
  globalWorkSize, localWorkSize, null);

cl.finish(queue, null, null);

Quelle:
http://code.google.com/p/webcl/ (Stand 09.07.11)

PyOpenCL
Hierbei handelt es sich um eine Python Bibliothek für OpenCL. Wenn jemand eine Idee hat und die mal eben ausprobieren will, ist dass sicher einer der interessantesten Wege.
http://documen.tician.de/pyopencl/ (Stand 02.06.11)
http://www.bu.edu/pasi/files/2011/01/AndreasKloeckner2-05-0900.pdf (Stand 02.06.11)

clUtil
Ziel des Projekts ist es, OpenCL so zu kapseln, dass man es genauso einfach wie CUDA verwenden kann.
http://code.google.com/p/clutil/ (Stand 02.06.11)
http://code.google.com/p/clutil/wiki/Documentation (Stand 02.06.11)
http://forums.nvidia.com/index.php?showtopic=188713 (Stand 02.06.11)

CMake
Wer CMake verwendet braucht ein Skript, das im sagt, wo die Header und Libraries sind:
http://forums.nvidia.com/index.php?showtopic=97795 (Stand 04.06.11)
Eine kurze Einführung zu CMake gibt's hier:
http://mathnathan.com/2010/07/11/getting-started-with-cmake/ (Stand 04.06.11)
und hier:
http://www.linux-magazin.de/Heft-Abo/Ausgaben/2007/02/Mal-ausspannen (Stand 04.06.11)
Die beste CMake-Einführung, die ich bis jetzt gelesen habe, ist diese:
http://glt07.linuxtage.at/slides/cmake.pdf (Stand 06.06.11)

Bugs und Pitfalls

Double Precision plattform übergreifend
Für Double Precision muss man unter OpenCL normalerweise die Extension cl_khr_fp64 aktivieren. Die AMD Implementierung ist hier leider nicht standardkonform und geht einen Sonderweg. Die Extension heißt dort cl_amd_fp64. Bei den OpenCL-Dateien (*.cl), bei denen man Double-Precision braucht, sollte man deshalb den folgenden Code oben einfügen:

#if defined(cl_khr_fp64)  // Khronos extension available?
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#elif defined(cl_amd_fp64)  // AMD extension available?
#pragma OPENCL EXTENSION cl_amd_fp64 : enable
#endif

Den Präprozessorcode habe ich auf dieser Seite gefunden:
http://www.bealto.com/gpu-fft2_real-type.html (Stand 02.06.11)

#includes im OpenCL-Kernel
http://www.marix.org/content/opencl-und-include (Stand 04.06.11)

OpenCL Compiler Option -cl-nv-verbose
Mit der Option kann man den nVidia-Plattform Compiler dazu anweisen, die Register- und Speichernutzung aufzulisten. Das ist ein sehr interessantes Feature, das einem hilft, wenn man effiziente Kernel entwickeln will.
Ich habe die Option dem OpenCL-Compiler übergeben und beim darauffolgendem Start des Programms bekam ich eine schöne Ausgabe:

Build Log: 
ptxas info    : Compiling entry function 'jacobi' for 'sm_20'
ptxas info    : Function properties for jacobi
0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Used 21 registers, 56 bytes cmem[0]

Beim nächsten Start bekam ich leider keine Ausgabe zu Gesicht. Ich habe sehr lange nach dem Grund gesucht. Es scheint so zu sein, dass der nVidia-Compiler für OpenCL Dateien, die sich nicht geändert haben, entweder cacht oder nicht neu compiliert. Das verwirrende daran war, dass ich die OpenCL-Sources jedes Mal neu eingelesen habe und davon ausgegangen bin, dass sie vom Compiler dann auch neu übersetzt werden.

Weitere Informationen gibt dieser Forumseintrag:
http://forums.nvidia.com/index.php?showtopic=175839 (Stand: 16.05.11)

Abseits von OpenCL

Vergleich von CUDA und STREAM
http://ra.ziti.uni-heidelberg.de/pages/student_work/seminar/hws08/Erich_Marth/praesentation.pdf (Stand 02.06.11)

Tutorial zu CUDA
http://heim.ifi.uio.no/~knutm/geilo2008/seland.pdf (Stand 02.06.11)

Einführung in Boost's Multidimensional Array
http://pinyotae.blogspot.com/2009/06/note-on-boost-multidimensional-array.html (Stand 09.07.11)

Core Dumps analysiseren

gcc -g -o mycode mycode.c
gdb mycode core

Cheatsheet wichtiger Kommandozeilenbefehle

Scheduling von GPU-Jobs (Sun Grid Engine):

qlogin -q gpu.q -l gpu_host=true,geforce_gtx480=1
oder
qlogin -q gpu.q -l gpu_host=true,tesla_c2050=1
export JOB_ID=...
alloc geforce_gtx480/tesla_c2050 1

mehr dazu hier im Wiki: SgeIntroduction

Kopieren mit rSync:

Zielverzeichnis muss existieren
rsync -avze ssh Quellverzeichnis user@computer:~/Zielverzeichnis

rSync/scp CMake Problem
CMake erstellt nachdem ersten Aufruf eine Datei namens CMakeCache.txt. Diese Datei enhält Pfade des Computers auf dem sie erstellt wurde. Kopiert man das Verzeichnis auf einen anderen Rechner muss man die Datei erst löschen, damit der Aufruf von cmake . nicht fehlgeleitet wird.

touch CMakeCache.txt && rm CMakeCache.txt && cmake . && make && ./mycode
Last modified 18 months ago Last modified on Dec 15, 2011 8:43:08 AM

Attachments (2)

Download all attachments as: .zip