OpenCL : Exécution de notre première function

Cet article a pour but de montrer comment appeler notre première fonction OpenCL avec un paramètre.

Afin de mieux comprendre cet article, je vous conseille de lire l’article précédent : http://software.intel.com/fr-fr/blogs/2013/12/10/premier-pas-sur-opencl-mon-pc-est-il-compatible

Objectif du tutoriel

Dans cet exemple nous allons créer une variable et appeler la fonction OpenCL suivante, qui prend un paramètre et retourne la valeur de celui-ci + 1.

__kernel void HostDeviceExchangeSample (__global const float* src, __global float* res)
{
    *res = *src + 1;
}

Code

Nous déclarons une variable et l’affectons :

float* h_src = new float;
*h_src = 5.0f;

La fonction OpenCL est définit dans un fichier à part (nommé HostDeviceExchange.cl), et pour l’utiliser nous devons lire ce fichier :

size_t src_size = 0;
const char* path = "./HostDeviceExchange.cl";

std::ostringstream ostream;
std::ifstream my_file(path);
ostream << my_file.rdbuf();
my_file.close();
std::string fileContent = ostream.str();

const char* source = fileContent.c_str();

Nous créons ensuite le cl::Program, qui va permettre de compiler et exécuter le programme OpenCL, ainsi que le cl::Context, qui sera le contexte utilisé par la mémoire, le programme, etc.

Le cl::Program doit récupérer les sources que nous venons le lire, afin de pouvoir les compiler et par la suite les exécuter :

cl::Program::Sources sources;
sources.push_back(std::pair<const char*, ::size_t>(source, src_size));

cl::Context context(device, NULL, NULL);

cl::Program program(context, sources);
program.build();

Une fois le programme compilé nous récupérons la function afin de pouvoir l’exécuter par la suite :

cl::Kernel hostDeviceExchange(program, "HostDeviceExchangeSample");

Nous voulons passer la variable h_src en paramètre à la fonction OpenCL HostDeviceExchange. Les souci est que l’exécution se passera sur carte graphique, et donc dans un espace mémoire totalement différent. Nous ne pouvons donc pas passer directement cette variable en argument.

Nous devons créer de la mémoire côté OpenCL dans laquelle nous allons copier notre variable.

Idem pour récupérer le retour de la fonction, nous devons créer un emplacement mémoire que nous pourrons interroger une fois la fonction OpenCL appelée.

cl::Buffer d_src(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float), h_src, &error);
cl::Buffer d_res(context, CL_MEM_WRITE_ONLY, sizeof(float), NULL, &error);

Dernière étape avant d’appeler la fonction, nous devons pousser les arguments de notre fonction. Pour cela nous allons pousser d_src, mais aussi d_res afin d’avoir le résultat :

error = hostDeviceExchange.setArg<cl::Buffer>(0, d_src);
error = hostDeviceExchange.setArg<cl::Buffer>(1, d_res);

Nous pouvons enfin lancer notre programme OpenCL, pour cela on créer une cl::Queue nous permettant d’ajouter le programme à la file d’exécution :

cl::CommandQueue queue(context, device, 0);

error = queue.enqueueNDRangeKernel(hostDeviceExchange, cl::NullRange, cl::NDRange(1), cl::NDRange(1));

Une fois le programme exécuté nous récupérons notre résultat:

float* result = new float;
queue.enqueueReadBuffer(d_res, CL_TRUE, 0, sizeof(float), (void*)result);

Téléchargement sources et références

Sources : https://github.com/littlebigben/OpenCL_call_first_function

Intel SDK for OpenCL* Applications 2013 : http://software.intel.com/en-us/vcsource/tools/opencl-sdk

Documentation OpenCL : http://khronos.org/OpenCL

Intel SDK for OpenCL* Applications 2012 Release Notes : http://software.intel.com/en-us/articles/opencl-release-notes/

Prochain article

Pour le prochain article nous verrons en détail comment fonctionne la mémoire OpenCL et de cela découlera une explication des mots clés __kernel, __global, etc.

Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.