很久没来了,一直在忙毕设的东西。这篇博文整理下OpenCL内核参数设置的问题。资源摘自OpenCL实战
首先,说一下kernel中的几种地址空间限定符:
(1)__global
该参数的数据会保存在全局数据空间,在内核中的参数使用例子如下:
__kernel void kernel_func(__global float *f)
{
}
(2)__constant
该参数的数据会保存在全局,只读内存中,该参数使用前必须初始化
(3)__local
该参数数据保存在局部内存中,需要注意的是,不论主机还是设备都不能直接初始化内核中的局部变量。
__local float x=4.0; //编译出错
改成下面方式:
__local float x;
x=4.0;
(4)__private
默认限定符,也就是说所有未标明限定的都是该限定符。私有地址空间仅每个工作项自己可见。
然后,是每一个kernel中数据的设置方式
(1)__global使用clSetKernelArg()设定
clSetKernelArg(kernel,0,sizeof(cl_mem),&cl_mem_instance);
(2)__local以及__private
clSetKernelArg(kernel,0,16*sizeof(float),NULL)
对应内核:
__kernel void proc_data(__local float *nums,...)
{
}
私有内存的设置
int num_iterations=4;
clSetKernelArg(kernel,0,sizeof(num_iterations),&num_iterations);
也就是说最后一个参数设置成基本的int*,float*,char*等类型
对于向量型数据可以采用如下方式:
float nums[4] = {0.0f,1.0f,2.0f,3.0f};
cl_kernelArg(kernel,0,sizeof(nums),nums);
__kernel void proc_data(float4 values,...)
{
}
在OpenCL Parallel Programming Developement Cookbook中还提到了使用用户定义的struct类型的方法
在宿主机端和设备内核中都进行如下定义:
typedef struct UserData{
int x;
int y;
int z;
int w;
};
宿主机端程序:
#define DATA_SIZE 1048576
userData *ud_in =(UserData *)malloc(sizeof(UserData)*DATA_SIZE);
//initialization omitted
cl_mem UDObj = clCreateBuffer(context,CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PRT,sizeof(UserData)*DATA_SIZE,ud_in,&error);
if(error != CL_SUCCESS)
{
perror("Unable to create buffer object");
exit(1);
}
//内核参数设置
error = clSetKernelArg(kernels[i],0,sizeof(cl_mem),&UDObj);
另外需要注意的是,整个OpenCL API是线程安全的,只有一个例外clSetKernelArg()。
线程安全意味着可以有多个宿主机线程同时调用这个函数,而无需提供互斥机制。也就是说,除了clSetKernelArg()之外,应用程序可以从宿主机上的多个线程调用同样的OpenCL函数,OpenCL可以保证其内部状态保持一致。
原因有两点:
1)该函数是最常调用的函数,规范的作者要确保这个函数尽可能是轻量级的。由于线程安全意味着固有开销,所以在保证速度的情况下,没将其定义成线程安全的。
2)除了性能方面的原因,实际应用中很难找到两个线程同时给同一个内核对象设置内核参数的理由。
有了这些基本内核参数设置就应该不成问题了。