OpenCL 查询和管理Program对象

一旦创建、编译了一个程序对象,可以使用clGetProgramInfo和clGetProgramBuildInfo来查询程序对象的信息。clGetProgramInfo返回程序对象的属性信息,如它关联的上下文、设备。clGetProgramBuildInfo返回的是程序对象编译信息。

clGetProgramInfo

clGetProgramInfo定义如下

cl_int clGetProgramInfo(cl_progpram program,
                            cl_program_info param_name,
                            size_t param_value_size,
                            void *param_value,
                            size_t *param_value_size_ret)

参数param_name为需要查询的程序对象的属性名称。可设置的值如吓表中所示:

clGetProgramInfo参数查询

对于CL_PROGRAM_SOURCE,把包含所有内核函数的程序源码合并为一个字符串。

clGetProgramBuildInfo

clGetProgramBuildInfo定义如下

cl_int   clGetProgramBuildInfo(cl_program program,
                                    cl_device_id device,
                                    cl_program_build_info param_name,
                                    size_t param_value_size,
                                    void *param_value,
                                    size_t *param_value_size_ret)

参数param_name为需要查询的编译信息的属性名称。可设置的值如下表所示:

clGetProgramBuildInfo参数查询

表格中,笔者经常使用的一个属性类型是CL_PROGRAM_BUILD_LOG。通过查询编译日志,我们可以方便地找出源码中的语法错误。

在下面的例子中,用源码创建、构建程序对象,把程序对象中的内容保存到二进制文件中。再从二进制文件中创建程序对象,并构建程序对象。

……
//从源码创建和构建程序对象
program = rclCreateProgramWithSource(context, 1,
                                            (const char **) &file_context,
                                            & file_length, &err);
err = clBuildProgram(program, num_device, &devices, NULL, NULL,
                        NULL)
//保存程序对象到二进制文件中
SaveProgramToBinary(program, "HelloWorld.bin");
……
cl_int binary_status;
program_handle = fopen("HelloWorld.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),
err = clBuildProgram(program, 1, &device, NULL, NULL, NULL);
if(CL_SUCCESS != err)
{
    printf("Error: Failed to build program executable!");
    char *buffer;
    size_t logsize;
    //查看构建日志
    err = clGetProgramBuildInfo(program, device,
        CL_PROGRAM_BUILD_LOG, 0, NULL,
        &logsize);
    buffer = (char *)malloc(logsize * sizeof(char));
    err = clGetProgramBuildInfo(program, device,
    CL_PROGRAM_BUILD_LOG, logsize,
    buffer, NULL);
    printf("log:%s\n", buffer);
    free(buffer);
}

上述代码,首先从源码创建和构建程序对象,调用函数SaveProgramToBinary()把程序对象内容保存到HelloWorld.bin二进制文件中。最后读取二进制文件来创建和构建程序对象,在构建程序对象时,通过函数返回值来判断构建是否成功,如果不成功则查看构建日志,找出程序对象构建失败的原因。函数SaveProgramToBinary代码如下:

int SaveProgramToBinary(cl_program program, const char *fileName)
{
    //查询与程序对象关联的设备数
    cl_uint numDevices = 0;
    err = clGetProgramInfo(program, CL_PROGRAM_NUM_DEVICES,
                                sizeof(cl_uint), &numDevices, NULL);
    //获得所有设备IDs
    cl_device_id *devices = (cl_device_id *)malloc(sizeof(
                                      cl_device_id) * numDevices);
    err = clGetProgramInfo(program, CL_PROGRAM_DEVICES,
                                sizeof(cl_device_id) * numDevices,
                                devices, NULL);
    //确定每个程序二进制大小
    size_t *programBinarySize = (size_t *)malloc(sizeof(
                                          size_t) * numDevices);
    err = clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES,
                                sizeof(size_t) * numDevices,
programBinarySize, NULL);
    unsigned char **programBinaries = (unsigned char **)malloc(
                                      sizeof(unsigned char) * numDevices);
    for(cl_uint i = 0; i 〈 numDevices; i++)
    {
        programBinaries[i] = (unsigned char **)malloc(
                        sizeof(unsigned char) * programBinarySize[i]);
    }
    //获得所有程序对象二进制内容
    err = clGetProgram(program, CL_PROGRAM_BINARIES,
                            sizeof(unsigned char *)*numDevices,
                            programBinaries, NULL);
    //保存所有程序对象二进制内容到文本中
    for(cl_uint i = 0; i 〈 numDevices; i++)
        FILE *fp = fopen(fileName, "a + ");
    fwrite(programBinaries[i], 1, programBinarySize[i], fp);
fclose(fp);
}

SaveProgramToBinary()首先查询与程序关联的设备数。接下来获得与各个设备关联的设备ID。得到设备列表后,这个函数再获得对应各个设备的各个程序目标二进制码及其大小,并把这些数据保存至HelloWorld.bin文件中。

对于创建的程序对象,可以使用如下参数操作程序对象的引用计数值:

cl_int clRetainProgram(cl_program program)
cl_int clReleaseProgram(cl_program program)

clRetainProgram增加程序对象引用计数(引用计数+1),clReleaseProgram减少程序对象引用计数(引用计数-1)。当引用计数值为0时,则释放程序对象。

应用程序完成程序的构建后,可以调用如下函数来告诉OpenCL实现编译器的工作完成:

cl_int clUnloadPlatformCompiler(cl_platform_id platform)

OpenCL实现会释放编译器分配的资源,这样做可能会释放实现使用的一些内存。如果应用调用该函数后,再次调用clBuildProgram、clCompilerProgram或clLinkProgram,就会使编译器自动重新加载。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程