Загрузка OpenCL из двоичного файла - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть следующее очень простое ядро ​​в 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)];
};

Я создал программу на C ++ для загрузки ядра из двоичного файла, созданного из его источника.Двоичный файл загружается правильно (CL_SUCCESS), но не отображает правильный результат для ввода.Он отображает изменяющиеся значения мусора следующим образом:

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 Ответ

0 голосов
/ 29 декабря 2018

clBuildProgram должен вызываться даже для программы, созданной clCreateProgramWithBinary, в соответствии со спецификацией OpenCL s5.6.2 «Создание исполняемых программ» :

OpenCL позволяетисполняемые файлы программы должны быть собраны с использованием исходного кода или двоичного файла.clBuildProgram должен вызываться для программы, созданной с использованием clCreateProgramWithSource или clCreateProgramWithBinary для создания исполняемого файла программы для одного или нескольких устройств, связанных с программой.Если программа создается с clCreateProgramWithBinary, то двоичный файл программы должен быть исполняемым двоичным файлом (не скомпилированный двоичный файл или библиотека).

Причина этого в том, что «двоичный файл устройства» не требуетсяполностью скомпилированный / связанный машинный код для целевого устройства: это может быть промежуточное представление в некоторой форме (например, LLVM IR), которое требует дальнейшей компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...