代码之家  ›  专栏  ›  技术社区  ›  cjds

OpenCL从二进制文件加载程序

  •  0
  • cjds  · 技术社区  · 6 年前

    我在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)];
    };
    

    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;
    }
    

    但是,直接从CL文件加载此程序会导致程序的正确输出。我加载的二进制文件是否与CL文件有所不同?


    编辑:

    我是如何创建二进制文件的

    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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Andrew Savonichev    6 年前

    clBuildProgram 即使对于由创建的程序,也必须调用 clCreateProgramWithBinary ,根据 OpenCL Specification s5.6.2 "Building Program Executables"

    OpenCL允许使用源代码或二进制代码构建程序可执行文件。 clBuildProgram 必须为使用以下任一方法创建的程序调用 clCreateProgramWithSource 为与程序关联的一个或多个设备构建程序可执行文件。如果程序是用 ,则程序二进制文件必须是可执行二进制文件(而不是已编译的二进制文件或库)。

    这是因为“设备二进制文件”不是目标设备完全编译/链接的机器代码所必需的:它可以是某种形式的中间表示(例如LLVM IR),需要进一步编译。