一旦创建、编译了一个程序对象,可以使用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为需要查询的程序对象的属性名称。可设置的值如吓表中所示:
对于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为需要查询的编译信息的属性名称。可设置的值如下表所示:
表格中,笔者经常使用的一个属性类型是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,就会使编译器自动重新加载。