如何收集二进制内核以分发专有代码

时间:2016-12-14 18:34:21

标签: opencl

我有一个代码,其中包含我不想在源代码中分发的专有技术。解决方案之一是提供一堆预编译的内核,并根据用户的硬件选择正确的二进制文件。

如何用最少的二进制文件覆盖大多数用户(AMD和Intel,因为Nvidia可以使用CUDA代码),而且我必须运行离线编译器的机器最少?是否有可以使用相同二进制文件的GPU系列? CUDA编译器可以针对不同的架构进行编译,那么OpenCL呢?二进制兼容性数据似乎没有很好地记录,但也许有人为自己收集了这些数据。

我知道有SPIR,但较旧的硬件不支持它。

如果有人发现了这个问题并且做得比我少,那么我的实施细节如下。我创建了一个将内核编译到文件的工具,然后我将所有这些二进制文件收集到一个C数组中,以包含在主应用程序中:

const char* binaries[] = { //kernels/HD Graphics 4000 "\x62\x70\x6c\x69\x73\x74\x30\x30\xd4\x01\x02\x03" "\x04\x05\x06\x07\x08\x5f\x10\x0f\x63\x6c\x42\x69" "\x6e\x61\x72\x79\x56\x65\x72\x73\x69\x6f\x6e\x5c" ... "\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x47\xe0" , //here more kernels }; size_t binaries_sizes[] = { 204998, 205907, ... };

然后我使用以下代码迭代所有内核(我没有发明任何比试错更聪明的东西,选择第一个成功构建的内核,可能有更好的解决方案):

int e3 = -1; int i = 0; while (e3 != CL_SUCCESS) { if (i == lenof(binaries)) { throw Error(); } program = clCreateProgramWithBinary(context, 1, &deviceIds[devIdx], &binaries_sizes[i], (const unsigned char**)&binaries[i], nullptr, &e3); if (e3 != CL_SUCCESS) { ++i; continue; } int e4 = clBuildProgram(program, 1, &deviceIds[devIdx], "", nullptr, nullptr); e3 = e4; ++i; }

1 个答案:

答案 0 :(得分:2)

不幸的是,您的问题没有标准的解决方案。 OpenCL与平台无关,并且没有标准方法(除了SPIR)来处理这个问题。每个供应商在内部决定不同的编译器工具链,甚至可以在同一驱动程序的多个版本或不同设备上进行更改。

您可以向内核添加一些元数据以确定您为其编译了哪个平台,这将为您节省试用和错误部分(即,不仅可以存储二进制文件和二进制文件,还可以存储binary_platform和binary_device,然后迭代这些数组,看看你应该加载哪个二进制文件。

最好的解决方案是SPIR(或新的SPIRV),它们是中间表示,然后可以由OpenCL驱动程序“重新编译”到实际的体系结构指令集。 如果您将二进制文件存储在SPIRV中,并且可以访问/了解某些编译器魔法,则可以使用转换器工具取回LLVM-IR,然后使用LLVM基础结构编译到其他平台,例如AMD或PTX。 (见https://github.com/KhronosGroup/SPIRV-LLVM