在 OpenCL 的内核中设置参数会导致错误
Setting arguments in a kernel in OpenCL causes error
我是 OpenCL 的初学者,因此编写了一个简单的程序来将数组的元素加倍。
内核代码为:-
__kernel void dataParallel(__global int* A, __global int* B)
{
int base = get_local_id(0);
B[base]=A[base]+A[base];
}
local_work_size=32 因为我正在对 32 个元素求平方。
在我的程序中,我声明了一个整数数组,其中包含要平方的元素。
int *A;
A=(int*)malloc(sizeof(int)*64);
for (i=0; i < 32; i++) { A[i] = i; }
platforms[i]
存放的是平台id,devices[j]
存放的是对应的设备id。他们的类型:
cl_platform_id* platforms;
cl_device_id* devices;
创建上下文
cl_context context=clCreateContext(NULL,1,&devices[j],NULL,NULL,NULL);
接下来是命令队列
cl_command_queue cmdqueue=cmdqueue=clCreateCommandQueue(context,devices[j],NULL,&err);
接下来我创建了 2 个内存缓冲区,一个用于保存输入数据,另一个用于保存结果。
cl_mem Abuffer,Bbuffer;
Abuffer=clCreateBuffer(context, CL_MEM_READ_WRITE ,32*sizeof(int),NULL,&err);
Bbuffer=clCreateBuffer(context, CL_MEM_READ_WRITE ,32*sizeof(int),NULL,&err);
然后我把数组A的数据复制到Abuffer
ret=clEnqueueWriteBuffer(cmdqueue, Abuffer, CL_TRUE, 0, 32*sizeof(int), A, 0, NULL, NULL);
printf("%d",ret);//output is 0 thus data written successfully into the buffer
然后将内核代码读入字符串source_str
并创建程序。
kernelprgrm=clCreateProgramWithSource(context,1,(const char **)&source_str,(const size_t *)&source_size,&err);
if(!err)
{
printf("\nKernel program created successfully\n");
}//Outputs -Kernel program created successfully
然后我使用以下方法构建程序:
ret=clBuildProgram(kernelprgrm,1,&devices[j],NULL,NULL,NULL);//returns CL_SUCCESS
下一步获取构建信息
ret=clGetProgramBuildInfo(kernelprgrm,devices[j], CL_PROGRAM_BUILD_STATUS ,0,NULL,&size);//Returns success
正在创建内核
kernel = clCreateKernel(kernelprgrm, "dataParallel", &ret);
printf("\nReturn kernel program=%d",ret);
if(!ret)
{
printf("\nProgram created successfully!\n");
}
//Outputs -Program created successfully!
现在魔鬼来了:-
ret=clSetKernelArg(kernel,0,sizeof(cl_mem),(void *) Abuffer);
printf("\nKernel argument 1 ret=%d",ret);
ret=clSetKernelArg(kernel,1,sizeof(cl_mem),(void *) Bbuffer);
printf("\nKernel argument 2 ret=%d",ret);
两个return-38意思是CL_INVALID_MEM_OBJECT
.
P.S.:根据指出的错误,即在参数中使用 &Abuffer 而不是 Abuffer 并在进行必要的更改后,return 0
size_t global_item_size = 32;
size_t local_item_size = 32;
还有ret = clEnqueueNDRangeKernel(cmdqueue, kernel, 1, NULL,&global_item_size, &local_item_size, 0, NULL, NULL);
returns 0.
正在尝试获取结果
ret = clEnqueueReadBuffer(cmdqueue, Bbuffer, CL_TRUE, 0, 32*sizeof(int), B, 0, NULL, NULL);`
printf("\nB:-\n");
for (t=0; t < 32; t++) {
printf("%d\t ", B[t]);
}
这个 returns buildstatus=0 核心被转储到我的 AMD GPU(运行 AMD 加速并行处理平台)和 NVIDIA GPU 而它工作 如果所选设备 CPU 使用 Intel(R) OpenCL 平台。
我还尝试使用以下方法获取构建日志:
cl_build_status *status=(cl_build_status *)malloc(sizeof(cl_build_status )*size);
clGetProgramBuildInfo(kernelprgrm,devices[j], CL_PROGRAM_BUILD_STATUS ,size,status,NULL);
printf("\nBuild status=%d\n",*status);
//如果不成功获取构建信息
clGetProgramBuildInfo(kernelprgrm,devices[i], CL_PROGRAM_BUILD_LOG ,0,NULL,&size);
char *buildlog=(char*)malloc(size);
clGetProgramBuildInfo(kernelprgrm,devices[i], CL_PROGRAM_BUILD_LOG ,size,buildlog,NULL);
printf("\n!!!!!!!!!!!!!!!!!!!!!Program ended!!!!!!!!!!!\n");
printf("\n\nBuildlog: %s\n\n",buildlog);
但它 returns Buildlog: Compilation started
Compilation done
Linking started
Linking done
Device build started
Device build done
Kernel <dataParallel> was successfully vectorized (4)
Done.
以下是 OpenCL 1.2 规范关于将缓冲区设置为内核参数的内容:
If the argument is a memory object (buffer, image or image array), the arg_value entry will be a pointer to the appropriate buffer, image or image array object.
因此,您需要将 指针 传递给 cl_mem
对象:
ret=clSetKernelArg(kernel,0,sizeof(cl_mem),(void *) &Abuffer);
为什么要使用 clEnqueueTask?如果您有并行工作要做,我认为您应该使用 clEnqueueNDRangeKernel。另外,只需设置全局工作大小;为本地工作组大小传递 NULL。 32x32 大于某些设备的尺寸。
我是 OpenCL 的初学者,因此编写了一个简单的程序来将数组的元素加倍。 内核代码为:-
__kernel void dataParallel(__global int* A, __global int* B)
{
int base = get_local_id(0);
B[base]=A[base]+A[base];
}
local_work_size=32 因为我正在对 32 个元素求平方。
在我的程序中,我声明了一个整数数组,其中包含要平方的元素。
int *A;
A=(int*)malloc(sizeof(int)*64);
for (i=0; i < 32; i++) { A[i] = i; }
platforms[i]
存放的是平台id,devices[j]
存放的是对应的设备id。他们的类型:
cl_platform_id* platforms;
cl_device_id* devices;
创建上下文
cl_context context=clCreateContext(NULL,1,&devices[j],NULL,NULL,NULL);
接下来是命令队列
cl_command_queue cmdqueue=cmdqueue=clCreateCommandQueue(context,devices[j],NULL,&err);
接下来我创建了 2 个内存缓冲区,一个用于保存输入数据,另一个用于保存结果。
cl_mem Abuffer,Bbuffer;
Abuffer=clCreateBuffer(context, CL_MEM_READ_WRITE ,32*sizeof(int),NULL,&err);
Bbuffer=clCreateBuffer(context, CL_MEM_READ_WRITE ,32*sizeof(int),NULL,&err);
然后我把数组A的数据复制到Abuffer
ret=clEnqueueWriteBuffer(cmdqueue, Abuffer, CL_TRUE, 0, 32*sizeof(int), A, 0, NULL, NULL);
printf("%d",ret);//output is 0 thus data written successfully into the buffer
然后将内核代码读入字符串source_str
并创建程序。
kernelprgrm=clCreateProgramWithSource(context,1,(const char **)&source_str,(const size_t *)&source_size,&err);
if(!err)
{
printf("\nKernel program created successfully\n");
}//Outputs -Kernel program created successfully
然后我使用以下方法构建程序:
ret=clBuildProgram(kernelprgrm,1,&devices[j],NULL,NULL,NULL);//returns CL_SUCCESS
下一步获取构建信息
ret=clGetProgramBuildInfo(kernelprgrm,devices[j], CL_PROGRAM_BUILD_STATUS ,0,NULL,&size);//Returns success
正在创建内核
kernel = clCreateKernel(kernelprgrm, "dataParallel", &ret);
printf("\nReturn kernel program=%d",ret);
if(!ret)
{
printf("\nProgram created successfully!\n");
}
//Outputs -Program created successfully!
现在魔鬼来了:-
ret=clSetKernelArg(kernel,0,sizeof(cl_mem),(void *) Abuffer);
printf("\nKernel argument 1 ret=%d",ret);
ret=clSetKernelArg(kernel,1,sizeof(cl_mem),(void *) Bbuffer);
printf("\nKernel argument 2 ret=%d",ret);
两个return-38意思是CL_INVALID_MEM_OBJECT
.
P.S.:根据指出的错误,即在参数中使用 &Abuffer 而不是 Abuffer 并在进行必要的更改后,return 0
size_t global_item_size = 32;
size_t local_item_size = 32;
还有ret = clEnqueueNDRangeKernel(cmdqueue, kernel, 1, NULL,&global_item_size, &local_item_size, 0, NULL, NULL);
returns 0.
正在尝试获取结果
ret = clEnqueueReadBuffer(cmdqueue, Bbuffer, CL_TRUE, 0, 32*sizeof(int), B, 0, NULL, NULL);`
printf("\nB:-\n");
for (t=0; t < 32; t++) {
printf("%d\t ", B[t]);
}
这个 returns buildstatus=0 核心被转储到我的 AMD GPU(运行 AMD 加速并行处理平台)和 NVIDIA GPU 而它工作 如果所选设备 CPU 使用 Intel(R) OpenCL 平台。
我还尝试使用以下方法获取构建日志:
cl_build_status *status=(cl_build_status *)malloc(sizeof(cl_build_status )*size);
clGetProgramBuildInfo(kernelprgrm,devices[j], CL_PROGRAM_BUILD_STATUS ,size,status,NULL);
printf("\nBuild status=%d\n",*status);
//如果不成功获取构建信息
clGetProgramBuildInfo(kernelprgrm,devices[i], CL_PROGRAM_BUILD_LOG ,0,NULL,&size);
char *buildlog=(char*)malloc(size);
clGetProgramBuildInfo(kernelprgrm,devices[i], CL_PROGRAM_BUILD_LOG ,size,buildlog,NULL);
printf("\n!!!!!!!!!!!!!!!!!!!!!Program ended!!!!!!!!!!!\n");
printf("\n\nBuildlog: %s\n\n",buildlog);
但它 returns Buildlog: Compilation started
Compilation done
Linking started
Linking done
Device build started
Device build done
Kernel <dataParallel> was successfully vectorized (4)
Done.
以下是 OpenCL 1.2 规范关于将缓冲区设置为内核参数的内容:
If the argument is a memory object (buffer, image or image array), the arg_value entry will be a pointer to the appropriate buffer, image or image array object.
因此,您需要将 指针 传递给 cl_mem
对象:
ret=clSetKernelArg(kernel,0,sizeof(cl_mem),(void *) &Abuffer);
为什么要使用 clEnqueueTask?如果您有并行工作要做,我认为您应该使用 clEnqueueNDRangeKernel。另外,只需设置全局工作大小;为本地工作组大小传递 NULL。 32x32 大于某些设备的尺寸。