OpenCL 创建Program对象

Program对象与Kernel对象是OpenCL中两个最重要的对象,这两个对象关系到在设备上执行的代码,以及代码执行所实现的功能。对于初学者,可能区分不出程序对象和内核对象的区别。对于内核对象而言,一个内核对象代表的就是一个在设备上执行的函数;而对于程序对象而言,一个程序对象就是内核的一个容器。打个比方:程序对象就好比一个集群系统,内核对象就好比在这个集群系统中的节点,多个节点组成了这个集群系统,同时对于每个节点而言可以执行不同的任务(程序对象里的每个内核函数实现功能不同)。换句话说,我们通常会在一个.cl文件里写上多个内核函数(被kernel关键字所修饰的函数),甚至写上多个.cl文件,包含多个内核函数。一个程序对象包含了对所有指定cl源文件编译、构建后的一个二进制目标对象。而一个内核对象则表示其中某一个内核执行函数。

程序对象包含多个在设备上执行的内核函数,是内核对象的集合。在OpenCL中用cl_program类型来表示程序对象。

OpenCL 创建Program对象

要创建程序对象,可以传入OpenCL C源代码文本,或者利用程序二进制来创建。为此OpenCL提供了两个对应的函数来创建程序:clCreateProgramWithSourceclCreateProgramWithBinary。两个函数都是把源码转变为cl_program。需要注意的是,两个函数都不接受文件名或文件处理,因此如果文件中包含内核代码,在创建程序之前需要把文件读取到一个字符串数组中。如果有多个文件来创建程序,则需要指定源文件个数或二进制目标的个数。

cl_program clCreateProgramWithSource(cl_context context,
                                            cl_uint count,
                                            const char **strings,
                                            const size_t *lengths,
                                            cl_int *errcode_ret)
cl_program clCreateProgramWithBinary(cl_context context,
                                            cl_uint num_devices,
                                            const cl_device_id *device_list,
                                            const size_t *lengths;
                                            const unsigned char **binaries,
                                            cl_int *binary_status,
                                            cl_int *errcode_ret)

clCreateProgramWithSrouce函数,是从源代码创建程序对象,内核代码存放在第三个参数strings字符串数组中。对于第二个参数count指的是第三个参数字符串数组中的内核代码个数。第四个参数lengths指示strings中所包含的对应每个内核代码字节个数。例如,strings[0]含有300个字节,stirngs[1]含有200个字节,那么lengths[0]就应该为300, lengths[1]就应该为200。最后一个参数errcode_ret为输出参数,用于存放函数执行的错误码。

clCreateProgramWithBinary函数,是利用程序二进制来创建程序对象,二进制内容在第五个参数binaries中,第四个参数为二进制内容大小。第二个参数num_devices为设备个数,第三个参数device_list为设备列表,这两个参数用来告诉程序对象有多少设备会执行程序函数。第六个参数binary_status返回在device_list中的每个设备对应的二进制程序是否成功加载,对于每一个由device_list[i]指定的设备,若成功加载,则binary_status[i]返回CL_SUCCESS,返回的错误码有两种情况,第一种是当length[i]为0,或者binary[i]是NULL时返回CL_INVALID_VALUE;第二种是当传入的二进制程序无效时,返回CL_INVALID_BINARY。最后一个参数errcode_ret为函数执行的错误代码。

下面来看从文件读取源代码创建程序对象的例子:

……
program_handle = fopen("kernel.cl", "r");
fseek(program_handle, 0, SEEK_END);
//确定文件内容大小
program_size = ftell(program_handle);
rewind(program_handle);
program_buffer = (char *)malloc(program_size + 1);
//读取文件内容,获得源代码
fread(program_buffer, sizeof(char), program_size,
      program_handle);
program_buffer[program_size] = '\0';
fclose(program_handle);
//从代码创建程序对象
program = clCreateProgramWidthSource(context, 1,
                                          (const cahr **)&program_buffer,
                                          &program_sizes, &err);
……

上述代码,从文件kernel.cl中读取源代码内容,利用源代码创建程序对象。例子中,源代码是在一个文件中。如果源代码来自于多个文件,那该如何处理呢?下面的代码就展示了从多个文件读取源代码创建程序对象:

……
#define FILE_NUM 2
……
cl_program program;
FILE *program_handle;
char *program_buffer[FILE_NUM];
const char *file_name[] = {"kernel_one.cl", "kernel_two.cl"};
size_t program_size[FILE_NUM];
……
//读取两个文件源代码
for(i = 0; i 〈 FILE_NUM; i++)
{
    program_handle = fopen(file_name[i], "r");
    fseek(progpram_handle, 0, SEEK_END);
    program_size[i] = ftell(program_handle);
    rewind(program_handle);
    program_buffer[i] = (char *)malloc(program_size[i] + 1);
    fread(program_buffer[i], sizeof(char), program_size[i],
            program_handle);
    fclose(program_handle);
}
//两个源代码创建程序对象
program = clCreateProgamWithSource(context, FILE_NUM,
                                        (const char **)program_buffer,
                                          program_size, &err);

上述代码,从FILE_NUM个文件中读取源代码保存到字符串数组program_buffer中。因program_buffer元素个数为FILE_NUM,故创建程序对象时clCreateProgamWithSource第2个参数为FILE_NUM。

前两个例子都是根据源代码创建程序对象,接下来就用另一个例子来展示如何用二进制创建一个程序:

……
cl_int binary_status;
program_handle = fopen("kernel.bin", "r");
fseek(program_handle, 0, SEEK_END);
program_size = ftell(program_handle);
rewind(program_handle);
binary_buffer = (char *)malloc(program_size + 1);
//读取二进制
fread(program_buffer, sizeof(char), binary _size,
      program_handle);
binary _buffer[program_size] = '\0';
fclose(program_handle);
//二进制创建程序对象
program = clCreateProgramWidthSource(context, 1, device, & binary_buffer,
                    (const unsgined char **)&binary_buf, &binary_status, &err);

上述代码,从kernel.bin的二进制文件中读取二进制内容到binary_buf字符串中,利用二进制创建程序对象。但有个问题一直没有提:二进制内容是如何生成的呢?在后面的教程中,我们将会用一个例子来说明。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程