I have the following very simple kernel in OpenCL
void kernel simple_add(global const int* A, global const int* B, global int* C){
C[get_global_id(0)]=A[get_global_id(0)]+B[get_global_id(0)];
};
I created a C++ program to load the kernel from a binary created from its source. The binary loads correctly (CL_SUCCESS), but does not display the correct result for the input. It displays changing garbage values like so
result: 538976310 538976288 538976288 538976288 538976288 790634528 796160111 1702129257 1886334828 1818455653
inline cl::Program CreateProgramFromBinary(cl::Context context,const std::vector<cl::Device> devices, const char* fileName)
{
std::ifstream file(fileName, std::ios::binary | std::ios::in | std::ios::ate);
uint32_t size = file.tellg();
file.seekg(0, std::ios::beg);
char* buffer = new char[size];
file.read(buffer, size);
file.close();
cl::Program::Binaries bin{{buffer, size}};
std::vector<cl_int> binaryStatus;
cl_int err = 0;
cl::Program program = cl::Program{context, devices, bin, &binaryStatus, &err};
if(err != CL_SUCCESS) {
std::cout<<" Error loading"<< err<< "\n";
exit(1);
}
for (std::vector<cl_int>::const_iterator bE = binaryStatus.begin(); bE != binaryStatus.end(); bE++) {
std::cout<< *bE <<std::endl;
}
std::cout<<"No Error loading"<< err<< "\n";
delete[] buffer;
return program;
}
int main(int argc, char** argv)
{
std::vector<cl::Device> devices= loadDevices();
cl::Context context{devices};
std::cout << "Save program binary for future run..." << std::endl;
//cl::Program program = CreateBinaryFromProgram(context, devices, "HelloWorld.cl", "HelloWorld.cl.bin");
//CreateBinaryFromProgram(context, devices, "HelloWorld.cl", "HelloWorld.cl.bin");
std::cout << "Reading from binary..." << std::endl;
cl::Program program = CreateProgramFromBinary(context, devices, "HelloWorld.cl.bin");
std::cout << "Running Program..." << std::endl;
cl::Buffer buffer_A(context,CL_MEM_READ_WRITE,sizeof(int)*10);
cl::Buffer buffer_B(context,CL_MEM_READ_WRITE,sizeof(int)*10);
cl::Buffer buffer_C(context,CL_MEM_READ_WRITE,sizeof(int)*10);
int A[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int B[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
//create queue to which we will push commands for the device.
cl::CommandQueue queue(context,devices[0]);
//write arrays A and B to the device
queue.enqueueWriteBuffer(buffer_A,CL_TRUE,0,sizeof(int)*10,A);
queue.enqueueWriteBuffer(buffer_B,CL_TRUE,0,sizeof(int)*10,B);
//run the kernel
cl::Kernel kernel_add=cl::Kernel(program,"simple_add");
kernel_add.setArg(0,buffer_A);
kernel_add.setArg(1,buffer_B);
kernel_add.setArg(2,buffer_C);
queue.enqueueNDRangeKernel(kernel_add,cl::NullRange,cl::NDRange(10),cl::NullRange);
queue.finish();
int C[10];
//read result C from the device to array C
queue.enqueueReadBuffer(buffer_C,CL_TRUE,0,sizeof(int)*10,C);
std::cout<<" result: \n";
for(int i=0;i<10;i++)
std::cout<<C[i]<<" ";
std::cout << "\n";
return 0;
}
Loading this program directly from the CL file however, results in the correct output of the program. Is the binary I've loaded somehow different from the CL file?
EDIT:
How I created the Binary
inline cl::Program CreateBinaryFromProgram(const cl::Context context,const std::vector<cl::Device> devices, const char* readFileName, const char* writeFileName)
{
std::ifstream file(readFileName, std::ios::binary| std::ios::ate | std::ios::in);
uint32_t size = file.tellg();
file.seekg(0, std::ios::beg);
char* buffer = new char[size];
file.read(buffer, size);
file.close();
cl::Program::Sources sources;
// kernel calculates for each element C=A+B
std::string kernel_code(buffer);
sources.push_back({kernel_code.c_str(),kernel_code.length()});
cl::Program program{context,sources};
if(program.build(devices)!=CL_SUCCESS){
std::cout<<" Error building: "<<program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0])<<"\n";
exit(1);
}
std::vector<size_t> output_sizes = program.getInfo<CL_PROGRAM_BINARY_SIZES>();
std::vector<char*> output = program.getInfo<CL_PROGRAM_BINARIES>();
std::cout << sizeof(output[0]) << std::endl;
std::cout << output_sizes[0] << std::endl;
const std::vector<unsigned long> binSizes = program.getInfo<CL_PROGRAM_BINARY_SIZES>();
std::vector<char> binData (std::accumulate(binSizes.begin(),binSizes.end(),0));
char* binChunk = &binData[0] ;
//A list of pointers to the binary data
std::vector<char*> binaries;
for(unsigned int i = 0; i<binSizes.size(); ++i) {
binaries.push_back(binChunk) ;
binChunk += binSizes[i] ;
}
program.getInfo(CL_PROGRAM_BINARIES , &binaries[0] ) ;
std::ofstream binaryfile(writeFileName, std::ios::binary);
for (unsigned int i = 0; i < binaries.size(); ++i)
binaryfile.write(binaries[i], binSizes[i]);
delete[] buffer;
return program;
}
clBuildProgram
must be called even for a program created by clCreateProgramWithBinary
, according to the OpenCL Specification s5.6.2 "Building Program Executables" :
OpenCL allows program executables to be built using the source or the binary.
clBuildProgram
must be called for program created using eitherclCreateProgramWithSource
orclCreateProgramWithBinary
to build the program executable for one or more devices associated with program. If program is created withclCreateProgramWithBinary
, then the program binary must be an executable binary (not a compiled binary or library).
The reason for this is that a "device binary" is not necessary a fully compiled/linked machine code for a target device: it can be an intermediate representation in some form (eg LLVM IR), that requires further compilation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.