저는 OpenCL 1.1 EP를 지원하는 i.MX6q 보드로 실행하기위한 샘플 코드를 개발하기 위해 현재 임베디드 및 OpenCL에 대한 새로운 지식을 보유하고 있습니다.OpenCL 1.1에서 CL_MEM_USE_HOST_PTR을 사용하여 간단히 복사/붙여 넣기 값을 만들려고하는데 왜 작동하지 않습니까?
처음부터 시작해야하므로 these tutorials, the OpenCL 1.1 Reference pages 및 this OpenCL example을 수행하여 첫 번째 OpenCL 구현/응용 프로그램을 만들었습니다.
기본적으로 내가하고 싶은 것은 보드에서 실행되는 "성능 테스트"를 개발하는 것입니다. 이것은 두 개의 int 배열 (입출력)을 가지며 첫 번째 배열을 임의의 값으로 채우고 OpenCL 작업 항목을 사용하여 출력 배열에 붙여 넣습니다.
clEnqueue (읽기/쓰기) 버퍼 함수와 clCreateBuffer 플래그 (특히 CL_MEM_USE_HOST_PTR) 사이에 혼란스러워 보였으므로 살펴보고 연습 해보기로했습니다.
내 코드가 제대로 컴파일 내가 출력 배열 값을 읽고있을 때, 그들은 여전히 여기에 0숙박 그러나 제대로 실행
내 코드 (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);
}
그리고 여기에 내 OpenCL 커널이 있습니다 :
__kernel void buffer_copy(__global int* input, __global int* output)
{
int id = get_global_id(0);
output[id] = input[id];
}
지금 당장은 그것을 최적화하지 않고 작동 시키려고합니다. 그리고 나는 여기 저기에 좋은 점을 놓치고 있다고 생각하지만 나는 그들을 잡을 수 없다. 제 생각에는 clCreateBuffer 플래그를 혼동하고 있습니다.
여러분이 저에게 계몽하고 도와 주시겠습니까?
편집 : 업데이트 된 코드 + 새로운 정보를 정기적으로!
이 값이 잘 붙여 넣은 것 같다,하지만 커널 작업 그룹 크기에있어서, 상기 CL_DEVICE_MAX_WORK_GROUP_SIZE 1024 반환하고 CL_KERNEL_WORK_GROUP_SIZE는 1024을 반환 (도 이상이다). 따라서 내 배열의 처음 1024 개의 정수는 잘 복사/붙여 넣기는되지만 더 이상 작동하지 않습니다. 이를 확인하기 위해 global_work_group_size를 수동으로 32로 설정하고 프로그램을 다시 실행 한 다음 처음 32 개의 정수 만 올바르게 붙여 넣습니다. 나는 정말로 여기서 무슨 일이 일어나고 있는지 이해하지 못한다.
예, 잘못된 전체 크기 및 로컬 작업 그룹 크기를 사용하고있는 것에 동의합니다. 전역 크기는 실행할 총 스레드 수입니다. 로컬 작업 그룹 크기는 공유 로컬 메모리 또는 기타 작업 그룹 개념을 사용하는 경우를위한 것입니다. 초보자라면 무시하고 NULL을 전달하고 런타임에서 하나를 선택하도록 할 수 있습니다 (2의 거듭 제곱 또는 적어도 CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE의 배수와 같은 비 프라임 전역 크기를 사용하면 더 좋을 것입니다). – Dithermaster