#第四章 内核模型
在OpenCL中,程序是由多个内核构成的,而内核就是在设备上运行的一个个功能函数,内核函数用__kernel字符标记,表示该函数用于在设备上运行,实现某种特定的功能,OpenCL程序就是将这些特定的功能模块组合在一起,从而实现整个系统功能。内核的调用由主机完成,主机通过命令队列指示设备调用内核,完成任务。
我们要从程序中将内核分离出来,放在特定的内核对象中,用于后面的调用。
创建内核对象的方法有两种:
cl_kernel clCreateKernel (cl_program program, //内核所在的程序对象
const char *kernel_name, //内核函数的名称
cl_int *errcode_ret) //错误指示标记
该接口将会返回一个根据特定名称而创建的内核对象。
cl_int clCreateKernelsInProgram (cl_program program, //内核所在的程序对象
cl_uint num_kernels, //该程序中所包含的内核数量
cl_kernel *kernels, //创建的内核对象列表
cl_uint *num_kernels_ret) //返回的该程序中所包含的内核数量
该接口需要调用两次,第一次确定该程序中包含的内核个数,第二次将所有的内核对象创建完成并存放在内核对象列表中。
在内核对象创建完成后可以查询该内核的信息:
cl_int clGetKernelInfo (cl_kernel kernel, //查询的内核对象
cl_kernel_info param_name, //查询的参数名称
size_t param_value_size, //参数内容大小
void *param_value, //参数内容列表
size_t *param_value_size_ret) //返回的参数内容大小
可查询信息参数:
与上下文以及队列对象等相同,内核对象也可以通过引用计数来管理:
cl_int clRetainKernel (cl_kernel kernel) //增加引用计数
cl_int clReleaseKernel (cl_kernel kernel) //减少引用计数
实验代码:
#include"opencl.h"
#define filesname "hello_world.cl"
char *readKernelSourceFile(const char *filename, size_t *filelength){
FILE *file = NULL;
size_t source_length;
char *source_string;
int ret;
file = fopen(filename, "rb");
if (file == NULL){
//printf("%s at %d :Can't open %s\n", __FILE__, __LINE__ - 2, filename);
return NULL;
}
fseek(file, 0, SEEK_END);
source_length = ftell(file);
fseek(file, 0, SEEK_SET);
source_string = (char *)malloc(source_length + 1);
//source_string[source_length] = '\0';
ret = fread(source_string, source_length, 1, file);
if (ret == 0){
printf("%s at %d :Can't read source %s \n", __FILE__, __LINE__ - 2, filename);
return NULL;
}
fclose(file);
if (source_length != 0){
*filelength = source_length;
}
source_string[source_length] = '\0';
return source_string;
}
int main(){
cl_uint platform_num;
clGetPlatformIDs(0, NULL, &platform_num);
cl_platform_id *platforms = new cl_platform_id[platform_num];
clGetPlatformIDs(platform_num, platforms, NULL);
cl_uint device_num;
clGetDeviceIDs(platforms[1], CL_DEVICE_TYPE_ALL, 0, NULL, &device_num);
cl_device_id *devices = new cl_device_id[device_num];
clGetDeviceIDs(platforms[1], CL_DEVICE_TYPE_ALL, device_num, devices, NULL);
cl_int err;
cl_context context = clCreateContext(NULL, device_num, devices, NULL, NULL, &err);
checkError(err, "Can't create context");
cl_command_queue *queues = new cl_command_queue[device_num];
for (cl_uint i = 0; i < device_num; i++){
queues[i] = clCreateCommandQueue(context, devices[i], CL_QUEUE_PROFILING_ENABLE, &err);
checkError(err, "Can't create queue");
}
size_t file_length;
char * files_string = readKernelSourceFile(filesname, &file_length);
cl_program program = clCreateProgramWithSource(context, 1, (const char **)&files_string, &file_length, &err);
checkError(err, "Failed to create program with source");
err = clBuildProgram(program, device_num, devices, NULL, NULL, NULL);
checkError(err, "Can't build the program");
cl_kernel kernel_one = clCreateKernel(program, "hello_world", &err);
size_t value_size;
clGetKernelInfo(kernel_one, CL_KERNEL_FUNCTION_NAME, NULL, NULL, &value_size);
char *kernel_name = new char[value_size];
clGetKernelInfo(kernel_one, CL_KERNEL_FUNCTION_NAME, value_size, kernel_name, NULL);
cout <<"The name of kernel_one is :" <<string(kernel_name) << endl;
return 0;
}
实验结果: