Ich bin ziemlich neu in der Embedded und OpenCL, ich versuche derzeit, einen Beispielcode zu einer i.MX6q-Platine, die OpenCL 1.1 EP unterstützt ausführen zu entwickeln.Versuchen Sie, in OpenCL 1.1 mit CL_MEM_USE_HOST_PTR einfach Werte zu kopieren/einfügen, warum funktioniert das nicht?
Ich musste von vorne anfangen, also folgte ich these tutorials, the OpenCL 1.1 Reference pages und auch this OpenCL example, um meine erste OpenCL-Implementierung/Anwendung zu machen.
Grundsätzlich möchte ich einen "Performance Test" entwickeln, der auf der Platine läuft. Es besteht darin, zwei int-Arrays (Eingabe und Ausgabe) zu haben, die erste mit zufälligen Werten zu füllen und sie mit OpenCL-Workitems in das Ausgabe-Array einzufügen.
Ich war ziemlich verwirrt zwischen clEnqueue (Lesen/Schreiben) Pufferfunktionen und den clCreateBuffer Flags (besonders CL_MEM_USE_HOST_PTR), also beschloss ich, einen Blick darauf zu werfen und damit zu üben.
Mein Code kompiliert korrekt und läuft jedoch richtig, wenn ich die Ausgabe-Array Werte gerade lese, sie bleiben immer noch auf 0
Hier ist mein Code (das ist C++):
void buffer_copy(char* kernelfile)
{
cl_platform_id platform_id;
cl_device_id device_id;
cl_context context;
cl_command_queue cmd_queue;
cl_program program;
// Retrieving all the OpenCL data needed
// to start the performance test
platform_id = get_platform();
device_id = get_device(platform_id);
context = get_context(platform_id, device_id);
cmd_queue = get_command_queue(context, device_id);
program = get_program(context, kernelfile);
cl_mem buffer_input, buffer_output;
size_t buffer_width = 640, buffer_height = 480;
size_t buffer_size = buffer_width * buffer_height;
cl_kernel kernel;
cl_int err = 0;
char* options = "-Werror -cl-std=CL1.1";
int data_input[buffer_size];
int data_output[buffer_size];
// Assigning random values in the data_input array and
// initializing the data_output array to zero-values
srand(time(NULL));
for (size_t index = 0; index < buffer_size; ++index)
{
data_input[index] = rand();
data_output[index] = 0;
}
// Creating OpenCL buffers
buffer_input = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, buffer_size * sizeof(int), data_input, &err);
assert(err == CL_SUCCESS);
buffer_output = clCreateBuffer(context, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, buffer_size * sizeof(int), data_output, &err);
assert(err == CL_SUCCESS);
err = clBuildProgram(program, 1, &device_id, options, NULL, NULL);
assert(err == CL_SUCCESS);
kernel = clCreateKernel(program, "buffer_copy", &err);
assert(err == CL_SUCCESS);
clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer_input);
clSetKernelArg(kernel, 1, sizeof(cl_mem), &buffer_output);
size_t device_max_work_group_size;
size_t global_work_size, local_work_size;
size_t preferred_work_group_size_multiple;
cl_ulong global_mem_size, max_mem_alloc_size;
clGetDeviceInfo(device_id, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &global_mem_size, NULL);
clGetDeviceInfo(device_id, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &max_mem_alloc_size, NULL);
clGetDeviceInfo(device_id, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &device_max_work_group_size, NULL);
std::cout << "Global device memory size: " << global_mem_size << " bytes" << std::endl;
std::cout << "Device max memory allocation size: " << max_mem_alloc_size << " bytes" << std::endl;
std::cout << "Device max work group size: " << device_max_work_group_size << std::endl;
clGetKernelWorkGroupInfo(kernel, device_id, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &global_work_size, NULL);
std::cout << "global_work_size value: " << global_work_size << std::endl;
clGetKernelWorkGroupInfo(kernel, device_id, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, sizeof(size_t), &preferred_work_group_size_multiple, NULL);
local_work_size = global_work_size/preferred_work_group_size_multiple;
std::cout << "local_work_size value: " << local_work_size << std::endl;
cl_event events[2];
err = clEnqueueNDRangeKernel(cmd_queue, kernel, 1, NULL, &global_work_size, &local_work_size, 0, 0, &events[0]);
assert (err == CL_SUCCESS);
err = clEnqueueReadBuffer(cmd_queue, buffer_output, CL_TRUE, 0, buffer_size * sizeof(int), data_output, 0, NULL, &events[1]);
assert (err == CL_SUCCESS);
err = clWaitForEvents(2, events);
assert (err == CL_SUCCESS);
for (size_t index = 0; index < buffer_size; ++index)
{
if (data_input[index] != data_output[index])
{
std::cerr << "Error, values differ (at index " << index << ")." << std::endl;
break;
}
else
{
//std::cout << "data_input[index] =\t" << data_input[index] << std::endl;
//std::cout << "data_output[index] =\t" << data_output[index] << std::endl;
}
}
cl_ulong time_start, time_end;
double total_time;
clGetEventProfilingInfo(events[0], CL_PROFILING_COMMAND_START, sizeof(time_start), &time_start, NULL);
clGetEventProfilingInfo(events[1], CL_PROFILING_COMMAND_END, sizeof(time_end), &time_end, NULL);
total_time = time_end - time_start;
std::cout << "Execution time in milliseconds: " << (total_time/1000000.0) << " ms" << std::endl;
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseMemObject(buffer_input);
clReleaseMemObject(buffer_output);
clReleaseCommandQueue(cmd_queue);
clReleaseContext(context);
}
Und hier ist mein OpenCL-Kernel:
__kernel void buffer_copy(__global int* input, __global int* output)
{
int id = get_global_id(0);
output[id] = input[id];
}
Im Moment bin ich nur zu machen versucht, es funktioniert, nicht es zu optimieren. Und ich denke, ich vermisse hier und da gute Punkte, aber ich kann sie nicht fangen. Meiner Meinung nach verwechsle ich die clCreateBuffer Flags.
Könnt ihr mich aufklären und mir dabei helfen?
EDIT: aktualisierten Code + neue Infos!
Es scheint, dass Werte gut eingefügt werden, aber nur entsprechend der Größe der Kernel-Arbeitsgruppe: CL_DEVICE_MAX_WORK_GROUP_SIZE gibt 1024 zurück und CL_KERNEL_WORK_GROUP_SIZE gibt auch 1024 zurück (was auch merkwürdig ist). Also die ersten 1024 ganzen Zahlen meines Arrays werden gut kopiert/eingefügt, aber danach funktioniert es nicht mehr. Um dies zu überprüfen, setze ich global_work_group_size manuell auf 32, führe mein Programm erneut aus und dann werden die ersten 32 ganzen Zahlen korrekt eingefügt. Ich verstehe wirklich nicht, was hier vor sich geht.
Ja, ich stimme zu, dass Sie falsche globale Größe und lokale Arbeitsgruppengrößen verwendet haben. Ihre globale Größe gibt an, wie viele Threads insgesamt ausgeführt werden sollen. Die Größe Ihrer lokalen Arbeitsgruppe wird verwendet, wenn Sie gemeinsam genutzten lokalen Speicher oder andere Arbeitsgruppenkonzepte verwenden. Wenn Sie ein Anfänger sind, können Sie es ignorieren und NULL übergeben, und lassen Sie die Laufzeit eine für Sie wählen (es wird besser, wenn Sie globale Nicht-Prime-Größe verwenden, wie Potenzen von zwei oder mindestens ein Vielfaches von CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE). – Dithermaster