Ich bin ziemlich neu zu OpenCL und ich betreibe OS X 10.6, die die Nvidia 330 Grafikkarte. Ich arbeite an einer Stoffsimulation in C++, die es mir ermöglicht hat, einen Kernel zu schreiben, der kompiliert und ausgeführt wird. Das Problem ist, dass es langsamer läuft als auf der CPU ohne OpenCL. Ich glaube der Grund dafür ist, dass jedes Mal, wenn ich die update() -Methode aufruft, um einige Berechnungen durchzuführen, ich den Kontext und das Gerät setze und dann den Kernel aus der Quelle neu kompiliere.Problem mit OpenCL Kernel rekompilieren Verlangsamung Programm und mögliche Speicherprobleme wegen der
Um dies zu lösen, habe ich versucht, die verschiedenen OpenCL-Typen, die ich brauchte, in die Stoffsimulationsklasse zu kapseln und zu versuchen, sie dort zu speichern, und dann ein initCL() erstellt, um diese Werte einzurichten. Ich habe dann eine runCL() erstellt, um den Kernel auszuführen. Seltsamerweise gibt mir das nur ein Speicherproblem, wenn ich die OpenCL-Sachen in zwei Methoden unterteile. Es funktioniert gut, wenn die initCL() und runCL() beide in einer Methode kombiniert werden, weshalb ich ein wenig fest bin.
Das Programm kompiliert und läuft, aber ich bekomme dann eine SIGABRT oder EXC BAD ACCESS an der Stelle im RunCL() - Code markiert. Wenn ich ein SIGABRT bekomme, bekomme ich den Fehler CL_INVALID_COMMAND_QUEUE, aber ich kann nicht für das Leben von mir herausfinden, warum dies nur passiert, wenn ich die zwei Methoden aufspalte. Ich bekomme manchmal ein SIGABRT, wenn die Assertion fehlschlägt, was zu erwarten ist, aber manchmal bekomme ich nur den schlechten Speicherzugriffsfehler, wenn ich versuche, in den Puffer zu schreiben.
Auch wenn mir jemand einen besseren Weg/das Recht dazu sagen kann oder wenn das JIT-Re-Compilieren nicht das ist, was meinen Code verlangsamt, dann wäre ich sehr dankbar, weil ich das auch schon lange angestarrt habe lange!
Danke,
Jon
Die Initialisierung von OpenCL Variablen 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);
}
Verfahren den Kernel Code auszuführen:
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;
}
Frage auch hier gepostet http://www.khronos.org/message_boards/viewtopic.php?f=37&t=3296 –