opencl build机器码程序
来源:互联网 发布:华为光伏数据采集器 编辑:程序博客网 时间:2024/06/02 05:29
在前一篇介绍 program
等术语时,提到创建 program
对象有两种方式:clCreateProgramWithSource
和 clCreateProgramWithBinary
。区别仅在于 opencl 程序在用户面前的展现形式,前者是源代码形式,后者是二进制形式。二进制形式的数据格式是不透明的,不同的实现可以有不同的标准。使用二进制形式的好处有二:一是由于二进制码已经经过编译(部分编译为中间件或全部编译为可执行文件),所以加载速度更快,需要的内存更少;二是可以保护 opencl 代码,保护知识产权。
下面我们就来看看如何利用二进制形式:
- 存储 opencl 程序为二进制
- 读入二进制版 opencl 程序
存储 opencl 程序为二进制
我们的第一个问题是:二进制版的 opencl 程序从哪里来?前文说过,所有的 cl
代码都要经过加载并创建 program
对象,然后由 program
对象在 device
上面编译并执行。难道还有其他方式编译 opencl 代码?答案是:NO!
意味着我们还是需要将代码送到 device
里面编译。你会说,这不是多此一举吗?看起来确实有点,不过一般的做法是在软件安装的时候就进行编译保存二进制形式,然后真正运行时才加载二进制。这样分成两个步骤的话,倒也说的过去。
省去前面那些与 platform
、device
和 context
的代码,我们直接进入创建 program
的地方。首先还是利用 clCreateProgramWithSource
函数读取源代码文件并用 clBuildProgram
函数编译。示例代码如下:
cl_int status;cl_program program;ifstream kernelFile("binary_kernel.ocl", ios::in);if(!kernelFile.is_open()) return;ostringstream oss;oss << kernelFile.rdbuf();string srcStdStr = oss.str();const char *srcStr = srcStdStr.c_str();program = clCreateProgramWithSource(context, 1, (const char **)&srcStr, NULL, NULL);if(program ==NULL) return;status = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);if(status != CL_SUCCESS) return;
代码可能不完整,完整示例请看文末。
现在我们已经将 opencl 代码在 device
编译完成了。接下来要做的就是将编译好的二进制取出来存在磁盘上。使用的 API 就是 clGetProgramInfo
:
cl_int clGetProgramInfo(cl_program program, cl_program_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)
使用方法见如下代码片段(为使逻辑清晰,省略了错误检测,实际开发可不要省啊):
cl_uint numDevices = 0;// 获取 program 绑定过的 device 数量clGetProgramInfo(program, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &numDevices, NULL);// 获取所有的 device IDcl_device_id *devices = new cl_device_id[numDevices];clGetProgramInfo(program, CL_PROGRAM_DEVICES, sizeof(cl_device_id) * numDevices, devices, NULL);// 决定每个 program 二进制的大小size_t *programBinarySizes = new size_t[numDevices];clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t) * numDevices, programBinarySizes, NULL);unsigned char **programBinaries = new unsigned char *[numDevices];for(cl_uint i = 0; i < numDevices; ++i) programBinaries[i] = new unsigned char[programBinarySizes[i]];// 获取所有的 program 二进制clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(unsigned char *) * numDevices, programBinaries, NULL);// 存储 device 所需要的二进制for(cl_uint i = 0; i < numDevices; ++i){ // 只存储 device 需要的二进制,多个 device 需要存储多个二进制 if(devices[i] == device){ FILE *fp = fopen("kernel_binary_ocl.bin", "wb"); fwrite(programBinaries[i], 1, programBinarySizes[i], fp); fclose(fp); break; }}// 清理delete[] devices;delete [] programBinarySizes;for(cl_uint i = 0; i < numDevices; ++i) delete [] programBinaries[i];delete[] programBinaries;
要注意的是,可能有很多个 device
都编译了 program
,所以将二进制提取出来时,我们是遍历了所有编译了 program
的 device
。
读取二进制版opencl程序
经过上面一系列的操作,我们的磁盘上应该存在一个二进制版的 opencl 程序了。里面的内容可能是可读的,也可能是不可读的。这个视不同厂商实现而不同。
相对于存储,读取看起来就清爽的多,无非是打开二进制文件,然后调用clCreateProgramWithBinary
函数。示例如下:
FILE *fp= fopen("kernel_binary_ocl.bin", "rb");// 获取二进制的大小size_t binarySize;fseek(fp, 0, SEEK_END);binarySize = ftell(fp);rewind(fp);// 加载二进制文件unsigned char *programBinary = new unsigned char[binarySize];fread(programBinary, 1, binarySize, fp);fclose(fp);cl_program program;program = clCreateProgramWithBinary(context, 1, &device, &binarySize, (const unsigned char**)&programBinary, NULL, NULL);delete [] programBinary;clBildProgram(program 0, NULL, NULL, NULL, NULL);
这里要注意,即使加载是二进制版,我们在之后还是要对其进行 clBuildProgram
。原因在于,我们无法保证所谓的二进制一定是可执行码。因为每个厂商的实现不一,有的可能就是最终执行码,而有的却是中间码。所以无论是从源代码还是二进制创建program
,之后都需要 clBuildProgram
。
这样兜了一圈,发现要使用二进制版还是用了一遍源代码方式,感觉代码复杂好多,有点多余。其实换个角度来看,我们完全可以写成两个程序,一个专门用来读取源代码并编译生成二进制,另一个才是读取二进制运行软件。前者开发人员使用,后者才是给用户使用的。只有这样才能体现二进制版的优势。
- opencl build机器码程序
- 机器码
- 机器码
- 机器码
- 机器码
- OpenCL程序框架
- opencl程序架构
- opencl入门程序
- OpenCL入门程序
- OpenCL程序实例
- opencl的c++程序
- 一个简单的OpenCL程序
- intel opencl hello程序实例
- 使用CodeBlocks编写OpenCL程序
- OpenCL程序编程基本流程
- No.2 OpenCL 程序构建
- OpenCL
- OpenCL
- explicit关键字
- 第十一周项目6-1-反序数
- 按钮不可用,按钮至灰做法
- Debug Multithread DLL 与 Debug Multithread
- redhat下ngnix安装
- opencl build机器码程序
- 2015互联网校招总结—一路走来(转载)
- Debian Linux 下获得Root权限以及使用Root登入图像界面的办法
- Android 向右滑动销毁(finish)Activity, 随着手势的滑动而滑动的效果 .
- 第11周项目6-1000以内素数
- Laplacian Meshes
- Dll的分析与编写(二)
- Math.atan与Math.atan2
- C# 委托和事件(续)