I'm very new to OpenCL. I created a simple working code to perform A = AB + C, and used that to get to my actual task, which is to read in a raw image file and do debayering on it. But the modified code fails at clCreateProgramWithSource sometimes with error code -6. There's minimal changes, and I compared with a diff but for the life of me I can't figure out why I'm getting error in the failed code. So here's the working code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <CL/cl.h>
#define LIST_SIZE 1024
int main()
{
// We need an object to hold the program
cl_program prog = NULL;
// First step is to load the kernel in a local memory
FILE *kfile;
char *kfilename = "./src/mad_kernel.cl";
kfile = fopen(kfilename, "r");
fseek(kfile, 0L, SEEK_END);
int kfilesize = ftell(kfile) + 1;
rewind(kfile);
char *kernel = malloc(kfilesize);
memset(kernel, 0, kfilesize);
fread(kernel, 1, kfilesize, kfile);
fclose(kfile);
// printf("%s", kernel); // Test passed
// We want to get the platform ID
cl_platform_id pid = NULL;
// We need some variables for holding the returned values
cl_uint num_platforms;
cl_int ret = clGetPlatformIDs(1, &pid, &num_platforms);
printf("Line %d err = %d\n", __LINE__, ret);
// We need a cl device ID
cl_device_id dev_id = NULL;
cl_uint num_devices;
ret = clGetDeviceIDs(pid, CL_DEVICE_TYPE_ALL, 1, &dev_id, &num_devices);
printf("Line %d err = %d\n", __LINE__, ret);
// Creating a queue to pass our tasks
// ------------------------------------------------------------------------
// We need a context for the cl application to run in
cl_context context = clCreateContext(NULL, 1, &dev_id, NULL, NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// We need a command queue to send our commands to
cl_command_queue cmd_queue = clCreateCommandQueue(context, dev_id, 0, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// ------------------------------------------------------------------------
// We need objects to hold the data
// We are going to perform A = A*B + C
int *A = malloc(LIST_SIZE * sizeof(int));
int *B = malloc(LIST_SIZE * sizeof(int));
int *C = malloc(LIST_SIZE * sizeof(int));
for (int i = 0; i < LIST_SIZE; i++) {
A[i] = 2;
B[i] = 3;
C[i] = 5;
}
cl_mem vec_A = clCreateBuffer(context, CL_MEM_READ_WRITE, LIST_SIZE*sizeof(int),
NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
cl_mem vec_B = clCreateBuffer(context, CL_MEM_READ_ONLY, LIST_SIZE*sizeof(int),
NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
cl_mem vec_C = clCreateBuffer(context, CL_MEM_READ_ONLY, LIST_SIZE*sizeof(int),
NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// Pass A, B and C to the CL memory
ret = clEnqueueWriteBuffer(cmd_queue, vec_A, CL_TRUE,
0, LIST_SIZE*sizeof(int), A, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clEnqueueWriteBuffer(cmd_queue, vec_B, CL_TRUE,
0, LIST_SIZE*sizeof(int), B, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clEnqueueWriteBuffer(cmd_queue, vec_C, CL_TRUE,
0, LIST_SIZE*sizeof(int), C, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
// We're ready to create the kernel now
prog = clCreateProgramWithSource(context, 1, (const char **)&kernel,
(const size_t *)&kfilesize, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clBuildProgram(prog, 1, &dev_id, NULL, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
cl_kernel kern = clCreateKernel(prog, "vector_mad", &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// Set the created memory as arguments to the kernel
ret = clSetKernelArg(kern, 0, sizeof(cl_mem), &vec_A);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clSetKernelArg(kern, 1, sizeof(cl_mem), &vec_B);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clSetKernelArg(kern, 2, sizeof(cl_mem), &vec_C);
printf("Line %d err = %d\n", __LINE__, ret);
// Tell the program size of the entire object
size_t global_item_size = LIST_SIZE;
// Each chunk size
size_t local_item_size = 64;
ret = clEnqueueNDRangeKernel(cmd_queue, kern, 1, NULL, &global_item_size,
&local_item_size, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
// Read memory back from CL
ret = clEnqueueReadBuffer(cmd_queue, vec_A, CL_TRUE, 0, LIST_SIZE * sizeof(int), A,
0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
int flag = 1;
for (int i = 0; i < LIST_SIZE; i++) {
// printf("%d\n", A[i]);
flag &= A[i] == 11;
}
if (flag) {
printf("Pass\n");
} else {
printf("Fail\n");
}
// Clean up
ret = clFlush(cmd_queue);
ret = clFinish(cmd_queue);
ret = clReleaseKernel(kern);
ret = clReleaseProgram(prog);
ret = clReleaseMemObject(vec_A);
ret = clReleaseMemObject(vec_B);
ret = clReleaseMemObject(vec_C);
ret = clReleaseCommandQueue(cmd_queue);
ret = clReleaseContext(context);
free(A);
free(B);
free(C);
return 0;
}
with the kernel:
__kernel void vector_mad(__global int *A, __global int *B, __global int *C)
{
int i = get_global_id(0);
A[i] = A[i] * B[i] + C[i];
}
Now, I wanted to read in a raw image in one of the buffer and for initial test, just output a constant value to the output RGBA right, so I modified this program to:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <CL/cl.h>
int main()
{
// We need an object to hold the program
cl_program prog = NULL;
// First step is to load the kernel in a local memory
FILE *kfile;
char *kfilename = "./src/mad_kernel.cl";
kfile = fopen(kfilename, "r");
fseek(kfile, 0L, SEEK_END);
int kfilesize = ftell(kfile) + 1;
rewind(kfile);
char *kernel = malloc(kfilesize);
memset(kernel, 0, kfilesize);
fread(kernel, 1, kfilesize, kfile);
fclose(kfile);
// printf("%s", kernel); // Test passed
// We want to get the platform ID
cl_platform_id pid = NULL;
// We need some variables for holding the returned values
cl_uint num_platforms;
cl_int ret = clGetPlatformIDs(1, &pid, &num_platforms);
printf("Line %d err = %d\n", __LINE__, ret);
// We need a cl device ID
cl_device_id dev_id = NULL;
cl_uint num_devices;
ret = clGetDeviceIDs(pid, CL_DEVICE_TYPE_ALL, 1, &dev_id, &num_devices);
printf("Line %d err = %d\n", __LINE__, ret);
// Creating a queue to pass our tasks
// ------------------------------------------------------------------------
// We need a context for the cl application to run in
cl_context context = clCreateContext(NULL, 1, &dev_id, NULL, NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// We need a command queue to send our commands to
cl_command_queue cmd_queue = clCreateCommandQueue(context, dev_id, 0, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// ------------------------------------------------------------------------
size_t imgsize = 16*16;
// We need objects to hold the data
// We are going to perform A = A*B + C
int *A = malloc(imgsize * sizeof(int));
int *B = malloc(imgsize * sizeof(int));
//FILE *img = fopen("./data/testimage.raw", "rb");
//fread(A, sizeof(cl_ushort), imgsize, img);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
printf("%x ", *(A + (16*i) + j));
}
printf("\n");
}
cl_mem vec_A = clCreateBuffer(context, CL_MEM_READ_ONLY, imgsize*sizeof(int),
NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
cl_mem vec_B = clCreateBuffer(context, CL_MEM_WRITE_ONLY, imgsize*sizeof(int),
NULL, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// Pass A, B and C to the CL memory
ret = clEnqueueWriteBuffer(cmd_queue, vec_A, CL_TRUE,
0, imgsize * sizeof(int), A, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clEnqueueWriteBuffer(cmd_queue, vec_B, CL_TRUE,
0, imgsize * sizeof(int), B, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
// We're ready to create the kernel now
prog = clCreateProgramWithSource(context, 1, (const char **)&kernel,
(const size_t *)&kfilesize, &ret);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clBuildProgram(prog, 1, &dev_id, NULL, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
cl_kernel kern = clCreateKernel(prog, "vector_mad", &ret);
printf("Line %d err = %d\n", __LINE__, ret);
// Set the created memory as arguments to the kernel
ret = clSetKernelArg(kern, 0, sizeof(cl_mem), &vec_A);
printf("Line %d err = %d\n", __LINE__, ret);
ret = clSetKernelArg(kern, 1, sizeof(cl_mem), &vec_B);
printf("Line %d err = %d\n", __LINE__, ret);
// Tell the program size of the entire object
size_t global_item_size = imgsize;
// Each chunk size
size_t local_item_size = 64;
ret = clEnqueueNDRangeKernel(cmd_queue, kern, 1, NULL, &global_item_size,
&local_item_size, 0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
// Read memory back from CL
cl_uint *C = malloc(imgsize * sizeof(int));
ret = clEnqueueReadBuffer(cmd_queue, vec_B, CL_TRUE, 0, imgsize * sizeof(int), C,
0, NULL, NULL);
printf("Line %d err = %d\n", __LINE__, ret);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
printf("%x", *(C + (16*i) + j));
}
printf("\n");
}
// Clean up
ret = clFlush(cmd_queue);
ret = clFinish(cmd_queue);
ret = clReleaseKernel(kern);
ret = clReleaseProgram(prog);
ret = clReleaseMemObject(vec_A);
ret = clReleaseMemObject(vec_B);
ret = clReleaseCommandQueue(cmd_queue);
ret = clReleaseContext(context);
free(A);
free(B);
free(C);
return 0;
}
But it did not work, so I even commented out the file read and the vector A now contains only garbage. But the code is failing at the line:
prog = clCreateProgramWithSource(context, 1, (const char **)&kernel,
(const size_t *)&kfilesize, &ret);
I have an Intel CPU and NVidia GPU, so I've tried compiling on both platforms: On intel:
PS E:\OpenCL_SoftISP\image_proc\ocldemo> gcc -g2 -I"C:\Program Files (x86)\IntelSWTools\system_studio_2020\OpenCL\sdk\include" -L"C:\Program Files (x86)\IntelSWTools\system_studio_2020\OpenCL\sdk\lib\x64" -DCL_TARGET_OPENCL_VERSION=120 src/improc.c -o improc -lOpenCL
PS E:\OpenCL_SoftISP\image_proc\ocldemo> .\improc.exe
When I run with gdb it fails at:
Thread 1 hit Breakpoint 1, main () at src\improc.c:81
81 prog = clCreateProgramWithSource(context, 1, (const char **)&kernel,
(gdb) c
Continuing.
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ffcd81699ca in nvopencl64!cuGetExportTable () from C:\Windows\System32\DriverStore\FileRepository\nvamui.inf_amd64_5f5d5675b52c555b\nvopencl64.dll
On Nvidia:
PS E:\OpenCL_SoftISP\image_proc\ocldemo> gcc -g2 -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\include" -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\lib\x64" -DCL_TARGET_OPENCL_VERSION=120 src/improc.c -o improc -lOpenCL
PS E:\OpenCL_SoftISP\image_proc\ocldemo> .\improc.exe
When I run with GDB, it breaks at:
Thread 1 hit Breakpoint 2, main () at src\improc.c:81
81 prog = clCreateProgramWithSource(context, 1, (const char **)&kernel,
(gdb) s
[New Thread 16688.0x4918]
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ffcd81699ca in nvopencl64!cuGetExportTable () from C:\Windows\System32\DriverStore\FileRepository\nvamui.inf_amd64_5f5d5675b52c555b\nvopencl64.dll
Now the interesting part is, that if I actually do the file read:
FILE *img = fopen("./data/testimage.raw", "rb");
fread(A, sizeof(cl_ushort), imgsize, img);
I actually get a different output
Line 67 err = 0
Line 70 err = 0
Line 75 err = 0
Line 78 err = 0
Line 83 err = -6
Line 85 err = -44
Line 87 err = -44
Line 91 err = -48
Line 93 err = -48
Line 102 err = -48
Line 108 err = 0
Where the error -6 I can see is:
CL_OUT_OF_HOST_MEMORY -6
Which still points to the fact that some illegal memory access I must be doing. But I am going crazy because where is it happening?