Je suis assez nouveau à OpenCL et je cours sous OS X 10.6 que la carte graphique Nvidia 330. Je travaille sur une simulation de tissu en C++ que j'ai réussi à écrire un noyau pour compiler et exécuter. Le problème est qu'il fonctionne plus lentement que sur le CPU sans OpenCL. Je crois que la raison en est que chaque fois que j'appelle la méthode update() pour faire des calculs, je suis en train de configurer le contexte et le périphérique, puis de recompiler le noyau à partir de la source. Pour résoudre ce problème, j'ai essayé d'encapsuler les différents types d'OpenCL dont j'avais besoin dans la classe de simulation de chiffon pour essayer de les stocker, puis j'ai créé un initCL() pour configurer ces valeurs. J'ai alors créé un runCL() pour exécuter le noyau. Etrangement, cela ne me pose un problème de mémoire que lorsque je sépare le contenu OpenCL en deux méthodes. Cela fonctionne bien si les initCL() et runCL() sont tous deux combinés en une seule méthode, ce qui explique pourquoi je suis un peu coincé.Problème avec la recompilation du noyau OpenCL ralentissant le programme et les problèmes de mémoire possibles à cause de cela
Le programme compile et s'exécute mais je reçois alors un SIGABRT ou EXC BAD ACCESS au point marqué dans le code runCL(). Quand je reçois un SIGABRT, j'obtiens l'erreur CL_INVALID_COMMAND_QUEUE mais je ne peux pas m'expliquer pour la vie de moi pourquoi cela ne se produit que lorsque je divise les deux méthodes. Je reçois parfois un SIGABRT quand l'assertion échoue ce qui est à prévoir mais d'autres fois je reçois juste l'erreur d'accès de mémoire mauvaise en essayant d'écrire dans le tampon.
Aussi si quelqu'un peut me dire un meilleur moyen/le droit de le faire ou si la recompilation JIT n'est pas ce qui ralentit mon code, alors je serais très reconnaissant parce que je regarde cela depuis trop longtemps longue!
Merci,
Jon
L'initialisation des variables OpenCL code:
int VPESimulationCloth::initCL(){
// Find the CPU CL device, as a fallback
err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 1, &device, NULL);
assert(err == CL_SUCCESS);
// Find the GPU CL device, this is what we really want
// If there is no GPU device is CL capable, fall back to CPU
err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device, NULL);
if (err != CL_SUCCESS) err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 1, &device, NULL);
assert(device);
// Get some information about the returned device
cl_char vendor_name[1024] = {0};
cl_char device_name[1024] = {0};
err = clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(vendor_name),
vendor_name, &returned_size);
err |= clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name),
device_name, &returned_size);
assert(err == CL_SUCCESS);
//printf("Connecting to %s %s...\n", vendor_name, device_name);
// Now create a context to perform our calculation with the
// specified device
context = clCreateContext(0, 1, &device, NULL, NULL, &err);
assert(err == CL_SUCCESS);
// And also a command queue for the context
cmd_queue = clCreateCommandQueue(context, device, 0, NULL);
// Load the program source from disk
// The kernel/program should be in the resource directory
const char * filename = "clothSimKernel.cl";
char *program_source = load_program_source(filename);
program[0] = clCreateProgramWithSource(context, 1, (const char**)&program_source,
NULL, &err);
if (!program[0])
{
printf("Error: Failed to create compute program!\n");
return EXIT_FAILURE;
}
assert(err == CL_SUCCESS);
err = clBuildProgram(program[0], 0, NULL, NULL, NULL, NULL);
if (err != CL_SUCCESS)
{
char build[2048];
clGetProgramBuildInfo(program[0], device, CL_PROGRAM_BUILD_LOG, 2048, build, NULL);
printf("Build Log:\n%s\n",build);
if (err == CL_BUILD_PROGRAM_FAILURE) {
printf("CL_BUILD_PROGRAM_FAILURE\n");
}
}
if (err != CL_SUCCESS) {
cout<<getErrorDesc(err)<<endl;
}
assert(err == CL_SUCCESS);
//writeBinaries();
// Now create the kernel "objects" that we want to use in the example file
kernel[0] = clCreateKernel(program[0], "clothSimulation", &err);
}
La méthode pour exécuter le noyau code:
int VPESimulationCloth::runCL(){
// Find the GPU CL device, this is what we really want
// If there is no GPU device is CL capable, fall back to CPU
err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device, NULL);
if (err != CL_SUCCESS) err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 1, &device, NULL);
assert(device);
// Get some information about the returned device
cl_char vendor_name[1024] = {0};
cl_char device_name[1024] = {0};
err = clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(vendor_name),
vendor_name, &returned_size);
err |= clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name),
device_name, &returned_size);
assert(err == CL_SUCCESS);
//printf("Connecting to %s %s...\n", vendor_name, device_name);
// Now create a context to perform our calculation with the
// specified device
//cmd_queue = clCreateCommandQueue(context, device, 0, NULL);
//memory allocation
cl_mem nowPos_mem, prevPos_mem, rForce_mem, mass_mem, passive_mem, canMove_mem,numPart_mem, theForces_mem, numForces_mem, drag_mem, answerPos_mem;
// Allocate memory on the device to hold our data and store the results into
buffer_size = sizeof(float4) * numParts;
// Input arrays
//------------------------------------
// This is where the error occurs
nowPos_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, nowPos_mem, CL_TRUE, 0, buffer_size,
(void*)nowPos, 0, NULL, NULL);
if (err != CL_SUCCESS) {
cout<<getErrorDesc(err)<<endl;
}
assert(err == CL_SUCCESS);
//------------------------------------
prevPos_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, prevPos_mem, CL_TRUE, 0, buffer_size,
(void*)prevPos, 0, NULL, NULL);
assert(err == CL_SUCCESS);
rForce_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, rForce_mem, CL_TRUE, 0, buffer_size,
(void*)rForce, 0, NULL, NULL);
assert(err == CL_SUCCESS);
mass_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, mass_mem, CL_TRUE, 0, buffer_size,
(void*)mass, 0, NULL, NULL);
assert(err == CL_SUCCESS);
answerPos_mem = clCreateBuffer(context, CL_MEM_READ_WRITE, buffer_size, NULL, NULL);
//uint buffer
buffer_size = sizeof(uint) * numParts;
passive_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, passive_mem, CL_TRUE, 0, buffer_size,
(void*)passive, 0, NULL, NULL);
assert(err == CL_SUCCESS);
canMove_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, canMove_mem, CL_TRUE, 0, buffer_size,
(void*)canMove, 0, NULL, NULL);
assert(err == CL_SUCCESS);
buffer_size = sizeof(float4) * numForces;
theForces_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err = clEnqueueWriteBuffer(cmd_queue, theForces_mem, CL_TRUE, 0, buffer_size,
(void*)theForces, 0, NULL, NULL);
assert(err == CL_SUCCESS);
//drag float
buffer_size = sizeof(float);
drag_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL);
err |= clEnqueueWriteBuffer(cmd_queue, drag_mem, CL_TRUE, 0, buffer_size,
(void*)drag, 0, NULL, NULL);
assert(err == CL_SUCCESS);
// Now setup the arguments to our kernel
err = clSetKernelArg(kernel[0], 0, sizeof(cl_mem), &nowPos_mem);
err |= clSetKernelArg(kernel[0], 1, sizeof(cl_mem), &prevPos_mem);
err |= clSetKernelArg(kernel[0], 2, sizeof(cl_mem), &rForce_mem);
err |= clSetKernelArg(kernel[0], 3, sizeof(cl_mem), &mass_mem);
err |= clSetKernelArg(kernel[0], 4, sizeof(cl_mem), &passive_mem);
err |= clSetKernelArg(kernel[0], 5, sizeof(cl_mem), &canMove_mem);
err |= clSetKernelArg(kernel[0], 6, sizeof(cl_mem), &numParts);
err |= clSetKernelArg(kernel[0], 7, sizeof(cl_mem), &theForces_mem);
err |= clSetKernelArg(kernel[0], 8, sizeof(cl_mem), &numForces);
err |= clSetKernelArg(kernel[0], 9, sizeof(cl_mem), &drag_mem);
err |= clSetKernelArg(kernel[0], 10, sizeof(cl_mem), &answerPos_mem);
if (err != CL_SUCCESS) {
cout<<getErrorDesc(err)<<endl;
}
assert(err == CL_SUCCESS);
// Run the calculation by enqueuing it and forcing the
// command queue to complete the task
size_t global_work_size = numParts;
size_t local_work_size = global_work_size/8;
err = clEnqueueNDRangeKernel(cmd_queue, kernel[0], 1, NULL,
&global_work_size, &local_work_size, 0, NULL, NULL);
if (err != CL_SUCCESS) {
cout<<getErrorDesc(err)<<endl;
}
assert(err == CL_SUCCESS);
//clFinish(cmd_queue);
// Once finished read back the results from the answer
// array into the results array
//reset the buffer first
buffer_size = sizeof(float4) * numParts;
err = clEnqueueReadBuffer(cmd_queue, answerPos_mem, CL_TRUE, 0, buffer_size,
answerPos, 0, NULL, NULL);
if (err != CL_SUCCESS) {
cout<<getErrorDesc(err)<<endl;
}
//cl mem
clReleaseMemObject(nowPos_mem);
clReleaseMemObject(prevPos_mem);
clReleaseMemObject(rForce_mem);
clReleaseMemObject(mass_mem);
clReleaseMemObject(passive_mem);
clReleaseMemObject(canMove_mem);
clReleaseMemObject(theForces_mem);
clReleaseMemObject(drag_mem);
clReleaseMemObject(answerPos_mem);
clReleaseCommandQueue(cmd_queue);
clReleaseContext(context);
assert(err == CL_SUCCESS);
return err;
}
Question également publié ici http://www.khronos.org/message_boards/viewtopic.php?f=37&t=3296 –