所以我正在编写一个在CPU + GPU上运行的openCL程序,我正在尝试使用clCreateProgramWithSource()创建程序后保存/缓存二进制文件。我使用CL_DEVICE_TYPE_ALL创建clContext和clProgram,并使用这些规范构建源代码。
然后我接受二进制文件并将它们存储到磁盘(每个设备有一个二进制文件),以便在后续启动时我的程序自动调用clBuildProgramWithBinary。问题是,如果我将二进制文件保存到使用设置CL_DEVICE_TYPE_ALL创建的磁盘,则CPU的二进制文件会被破坏,并且clBuildProgramWithBinary会抛出错误。
为了将所有二进制文件正确保存到磁盘,我必须编辑我的代码,首先使用CL_DEVICE_TYPE_CPU运行并自行保存CPU二进制文件,然后再次编辑我的代码以使用CL_DEVICE_TYPE_GPU运行,保存gpu二进制文件然后最终将其切换回CL_DEVICE_TYPE_ALL。如果我这样做,clBuildProgramWithBinary能够为每种设备类型准确地构建二进制文件并执行我的程序。
这只是openCL的一个怪癖,我不能一起为GPU和CPU构建二进制文件吗?或者我只是做错了吗?
我的代码基于在此处找到的二进制保存的实现:https://code.google.com/p/opencl-book-samples/source/browse/trunk/src/Chapter_6/HelloBinaryWorld/HelloBinaryWorld.cpp?r=42并且已经进行了修改以处理多个设备。
以下是我的代码的一些部分:
/*----Initial setup of platform, context and devices---*/
cl_int err, deviceCount;
cl_device_id *devices;
cl_platform_id platform;
cl_context context;
cl_program program;
err = clGetPlatformIDs(1, &platform, NULL);
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &deviceCount);
devices = new cl_device_id[deviceCount];
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, deviceCount, devices, NULL);
context = clCreateContext(NULL, deviceCount, devices, NULL, NULL, &err);
/*---Build Program---*/
int numFiles = 2;
const char *sourceFiles[] =
{
"File1.cl",
"File2.cl",
};
char *sourceStrings[numFiles];
for(int i = 0; i < numFiles; i++)
{
sourceStrings[i] = ReadFile(sourceFiles[i]);
}
/*---Create the compute program from the source buffer---*/
program = clCreateProgramWithSource(context, numFiles, (const char **)sourceStrings, NULL, &err);
/*---Build the program executable---*/
err = clBuildProgram(program, deviceCount, devices, NULL, NULL, NULL);
/*----Save binary to disk---*/
//Determine the size of each program binary
size_t *programBinarySizes = new size_t[deviceCount];
err = clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t) * deviceCount, programBinarySizes, NULL);
if(err != CL_SUCCESS)
{
delete [] devices;
delete [] programBinarySizes;
return false;
}
unsigned char **programBinaries = new unsigned char*[deviceCount];
for(cl_uint i = 0; i < deviceCount; i++)
{
programBinaries[i] = new unsigned char[programBinarySizes[i]];
}
//Get all of the program binaries
err = clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(unsigned char *) * deviceCount, programBinaries, NULL);
if (err != CL_SUCCESS)
{
delete [] devices;
delete [] programBinarySizes;
for (cl_uint i = 0; i < deviceCount; i++)
{
delete [] programBinaries[i];
}
delete [] programBinaries;
}
//Store the binaries
for(cl_uint i = 0; i < deviceCount; i++)
{
// Store the binary for all devices
std::string currFile = binaryFile + to_string(i) + ".txt";
FILE *fp = fopen(currFile.c_str(), "wb");
fwrite(programBinaries[i], 1, programBinarySizes[i], fp);
fclose(fp);
}
// Cleanup
delete [] programBinarySizes;
for (cl_uint i = 0; i < deviceCount; i++)
{
delete [] programBinaries[i];
}
delete [] programBinaries;
然后在接下来的代码中调用此函数从二进制文件创建程序:
unsigned char **programBinaries = new unsigned char *[deviceCount];
size_t sizes[deviceCount];
for(int i = 0; i < deviceCount; i++)
{
string currFile = binaryFile + to_string(i) + ".txt";
FILE *fp = fopen(currFile.c_str(), "rb");
if(!fp) return NULL;
size_t binarySize;
fseek(fp, 0, SEEK_END);
binarySize = ftell(fp);
sizes[i] = binarySize;
rewind(fp);
programBinaries[i] = new unsigned char[binarySize];
fread(programBinaries[i], 1, binarySize, fp);
fclose(fp);
}
cl_int errNum = 0;
cl_program program;
cl_int binaryStatus;
program = clCreateProgramWithBinary(context,
deviceCount,
devices,
sizes,
(const unsigned char **)programBinaries,
&binaryStatus,
&errNum);
delete [] programBinaries;
errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
答案 0 :(得分:3)
我有一个rmbp,它只在一个苹果平台上有三个设备。我在上面运行你的代码并遇到了同样的问题。实际上我不知道解决方案,但我可以给你一些调试提示。
我修改了您的代码段,如下所示:
#include <sys/stat.h>
unsigned char **programBinaries = new unsigned char *[deviceCount];
size_t sizes[deviceCount];
int fd;
struct stat st;
for(cl_uint i = 0; i < deviceCount; i++)
{
string currFile = binaryFile + to_string(i) + ".txt";
fd = open(currFile.c_str(), O_RDONLY);
if (fd == -1) {
return -1;
}
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
return -2;
}
size_t binarySize;
FILE *fp = fdopen(fd, "rb");
if (fseeko(fp, 0 , SEEK_END) != 0) {
return -3;
}
binarySize = ftello(fp);
cout << "device " << i << ": " << binarySize << endl;
sizes[i] = binarySize;
rewind(fp);
programBinaries[i] = new unsigned char[binarySize];
fread(programBinaries[i], 1, binarySize, fp);
fclose(fp);
close(fd);
}
但是,在我的系统上,我得到了与原始代码相同的结果。
cl_program clCreateProgramWithBinary(cl_context context, cl_uint num_devices, const cl_device_id * device_list, const size_t *个长度, const unsigned char **二进制文件, cl_int * binary_status, cl_int * errcode_ret)
binary_status:返回device_list中指定的每个设备的程序二进制文件是否已成功加载。它是一个num_devices条目数组,如果二进制文件已成功加载到device_list [i]指定的设备,则返回binary_status [i]中的CL_SUCCESS;如果length [i]为零或者如果binaryaries [i]为NULL值,则返回CL_INVALID_VALUE;如果程序二进制文件不是指定设备的有效二进制文件,则返回binary_status [i]中的CL_INVALID_BINARY。如果binary_status为NULL,则忽略它。
如果您修改代码如下:
cl_int binaryStatus[deviceCount];
program = clCreateProgramWithBinary(context,
deviceCount,
devices,
sizes,
(const unsigned char **)programBinaries,
binaryStatus,
&errNum);
for (cl_uint i = 0; i < deviceCount; ++i)
{
cout << "device: " << i << ": " << binaryStatus[i] << endl;
}
通常,您将获得以下结果:
device: 0: 0
device: 1: -42
第一行表示第一个二进制程序(用于CPU)已成功加载。第二行中的-42对应CL_INVALID_BINARY
,这意味着它无法加载二进制程序。
我也尝试从程序中检索构建选项,但什么都没有。
//set device_id to 0,1,3...
cl_uint device_id = 0;
cl_build_status status;
// Determine the reason for the error
char buildOptions[16384];
char buildLog[16384];
clGetProgramBuildInfo(program, devices[device_id], CL_PROGRAM_BUILD_STATUS,
sizeof(cl_build_status), &status, NULL);
std::cout << "status: " << status << endl;
clGetProgramBuildInfo(program, devices[device_id], CL_PROGRAM_BUILD_OPTIONS,
sizeof(buildOptions), buildOptions, NULL);
std::cout << "build options: " << endl;
std::cout << buildOptions;
clGetProgramBuildInfo(program, devices[device_id], CL_PROGRAM_BUILD_LOG,
sizeof(buildLog), buildLog, NULL);
std::cout << "build log: " << endl;
std::cout << buildLog;
我猜这是opencl驱动程序的一个bug。希望上面的内容对你有所帮助。