¿Cómo pasar y acceder a los vectores C ++ al kernel de OpenCL?

Soy nuevo en C, C ++ y OpenCL y hago todo lo posible por aprenderlos en este momento. Aquí hay una función de C ++ preexistente que estoy tratando de averiguar cómo migrar a OpenCL usando los enlaces C o C ++.

#include  using namespace std; class Test { private: double a; vector b; vector c; vector<vector > d; public: double foo(long x, double y) { // mathematical operations // using x, y, a, b, c, d // and also b.size() // to calculate return value return 0.0; } }; 

En términos generales, mi pregunta es cómo pasar a todos los miembros de la clase a los que esta función accede al enlace y al núcleo. Entiendo cómo pasar los valores escalares pero los valores vectoriales de los que no estoy seguro. ¿Hay tal vez una forma de pasar los punteros a cada uno de los miembros anteriores o asignarles un mapa de memoria para que la vista de OpenCL de ellos esté sincronizada con la memoria del host? Desglosado mis preguntas son las siguientes

  1. ¿Cómo paso el miembro b y c al enlace y al kernel dado que estos son de tamaño variable?
  2. ¿Cómo paso en el miembro d dado que es bidimensional?
  3. ¿Cómo accedo a estos miembros desde dentro del kernel y qué tipos serán declarados como en los argumentos del kernel? ¿El simple uso de la notación de índice de matriz, es decir, b [0], funcionará para el acceso?
  4. ¿Cómo invoco una operación equivalente a b.size () dentro de la función del kernel o no lo hago y en su lugar pasa el tamaño del enlace al kernel como un argumento adicional? ¿Qué pasa si cambia?

Realmente apreciaría el código fuente del código de kernel y el enlace de C o C ++ en las respuestas.

Muchas gracias.

  1. Debe asignar un búfer OpenCL y copiar los datos de la CPU en él. Un búfer OpenCL tiene un tamaño fijo, por lo que debe recrearlo si cambia el tamaño de sus datos o hacerlo “lo suficientemente grande” y usar solo una subsección si se necesita menos memoria. Por ejemplo, para crear un búfer para b y al mismo tiempo copiar todos sus datos en el dispositivo:

     cl_mem buffer_b = clCreateBuffer( context, // OpenCL context CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, // Only read access from kernel, // copy data from host sizeof(cl_double) * b.size(), // Buffer size in bytes &b[0], // Pointer to data to copy &errorcode); // Return code 

    También es posible asignar directamente la memoria del host ( CL_MEM_USE_HOST_PTR ), pero esto impone algunas restricciones en la alineación y el acceso a la memoria del host después de crear el búfer. Básicamente, la memoria del host puede contener basura cuando no la está asignando actualmente.

  2. Depende. ¿Los tamaños de los vectores en la segunda dimensión son consistentemente iguales? Luego simplemente aplastarlos al cargarlos en el dispositivo OpenCL. De lo contrario se vuelve más complicado.

  3. Usted declara los argumentos del búfer como __global punteros __global en su kernel. Por ejemplo, __global double *b sería apropiado para el búfer creado en 1. Simplemente puede usar la notación de matriz en el kernel para acceder a los elementos individuales en el búfer.

  4. No puede consultar el tamaño del búfer desde el núcleo, por lo que debe pasarlo manualmente. Esto también puede suceder implícitamente, por ejemplo, si el número de elementos de trabajo coincide con el tamaño de b .

Un kernel que puede acceder a todos los datos para el cálculo podría tener este aspecto:

 __kernel void foo(long x, double y, double a, __global double* b, int b_size, __global long* c, __global double* d, __global double* result) { // Here be dragons *result = 0.0; } 

Tenga en cuenta que también tiene que asignar memoria para el resultado. Podría ser necesario pasar argumentos de tamaño adicional si los necesita. Usted llamaría al kernel de la siguiente manera:

 // Create/fill buffers // ... // Set arguments clSetKernelArg(kernel, 0, sizeof(cl_long), &x); clSetKernelArg(kernel, 1, sizeof(cl_double), &y); clSetKernelArg(kernel, 2, sizeof(cl_double), &a); clSetKernelArg(kernel, 3, sizeof(cl_mem), &b_buffer); cl_int b_size = b.size(); clSetKernelArg(kernel, 4, sizeof(cl_int), &b_size); clSetKernelArg(kernel, 5, sizeof(cl_mem), &c_buffer); clSetKernelArg(kernel, 6, sizeof(cl_mem), &d_buffer); clSetKernelArg(kernel, 7, sizeof(cl_mem), &result_buffer); // Enqueue kernel clEnqueueNDRangeKernel(queue, kernel, /* ... depends on your domain */); // Read back result cl_double result; clEnqueueReadBuffer(queue, result_buffer, CL_TRUE, 0, sizeof(cl_double), &result, 0, NULL, NULL);