[Beignet] [PATCH V3] add binary type support for compiled object and library.

Zhigang Gong zhigang.gong at linux.intel.com
Tue Jun 17 02:11:39 PDT 2014


This patch causes utest regression:

enqueue_copy_buf()different index is 0
    [FAILED]
    Error: 0
  at file /home/gongzg/git/fdo/beignet/utests/enqueue_copy_buf.cpp, function test_copy_buf, line 41

Before reproduce this bug, please rebase your tree with latest git master.

On Tue, Jun 17, 2014 at 05:28:09AM +0800, xionghu.luo at intel.com wrote:
> From: Luo <xionghu.luo at intel.com>
> 
> save the llvm bitcode to program->binary: insert a byte in front of the
> bitcode stands for binary type(0 means GEN binary, 1 means COMPILED_OBJECT, 2 means LIBRARY);
> load the binary to module by ParseIR.
> 
> create random directory to save compile header files.
> use strncpy and strncat to replace strcpy and strcat.
> 
> Signed-off-by: Luo <xionghu.luo at intel.com>
> ---
>  backend/src/backend/gen_program.cpp | 71 +++++++++++++++++++++++++++++++-----
>  backend/src/backend/program.cpp     |  1 +
>  backend/src/backend/program.h       |  8 +++--
>  src/cl_api.c                        | 25 +++++++++++--
>  src/cl_gbe_loader.cpp               | 11 ++++--
>  src/cl_gbe_loader.h                 | 10 +++---
>  src/cl_program.c                    | 72 +++++++++++++++++++++++++++++++++----
>  src/cl_program.h                    |  1 +
>  8 files changed, 172 insertions(+), 27 deletions(-)
> 
> diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp
> index 300741e..8897dbb 100644
> --- a/backend/src/backend/gen_program.cpp
> +++ b/backend/src/backend/gen_program.cpp
> @@ -35,6 +35,12 @@
>  
>  #include "llvm/Linker.h"
>  #include "llvm/Transforms/Utils/Cloning.h"
> +#include "llvm/Bitcode/ReaderWriter.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include "llvm/Support/SourceMgr.h"
> +#include "llvm/IRReader/IRReader.h"
>  
>  #include "backend/program.h"
>  #include "backend/gen_program.h"
> @@ -55,6 +61,7 @@
>  #include <iostream>
>  #include <fstream>
>  #include <mutex>
> +#include <unistd.h>
>  
>  namespace gbe {
>  
> @@ -188,7 +195,8 @@ namespace gbe {
>    static gbe_program genProgramNewFromBinary(uint32_t deviceID, const char *binary, size_t size) {
>      using namespace gbe;
>      std::string binary_content;
> -    binary_content.assign(binary, size);
> +    //the first 5 bytes are header to differentiate from llvm bitcode binary.
> +    binary_content.assign(binary+5, size-5);
>      GenProgram *program = GBE_NEW(GenProgram, deviceID);
>      std::istringstream ifs(binary_content, std::ostringstream::binary);
>      // FIXME we need to check the whether the current device ID match the binary file's.
> @@ -203,20 +211,66 @@ namespace gbe {
>      return reinterpret_cast<gbe_program>(program);
>    }
>  
> -  static size_t genProgramSerializeToBinary(gbe_program program, char **binary) {
> +  static gbe_program genProgramNewFromLLVMBinary(uint32_t deviceID, const char *binary, size_t size) {
> +#ifdef GBE_COMPILER_AVAILABLE
> +    using namespace gbe;
> +    std::string binary_content;
> +    //the first byte stands for binary_type.
> +    binary_content.assign(binary+1, size-1);
> +    llvm::StringRef llvm_bin_str(binary_content);
> +    llvm::LLVMContext& c = llvm::getGlobalContext();
> +    llvm::SMDiagnostic Err;
> +    llvm::MemoryBuffer* memory_buffer = llvm::MemoryBuffer::getMemBuffer(llvm_bin_str, "llvm_bin_str");
> +    acquireLLVMContextLock();
> +    llvm::Module* module = llvm::ParseIR(memory_buffer, Err, c);
> +    releaseLLVMContextLock();
> +    if(module == NULL){
> +      GBE_ASSERT(0);
> +    }
> +
> +    GenProgram *program = GBE_NEW(GenProgram, deviceID, module);
> +
> +    //program->printStatus(0, std::cout);
> +    return reinterpret_cast<gbe_program>(program);
> +#else
> +      return NULL;
> +#endif
> +  }
> +
> +  static size_t genProgramSerializeToBinary(gbe_program program, char **binary, int binary_type) {
>      using namespace gbe;
>      size_t sz;
>      std::ostringstream oss;
>      GenProgram *prog = (GenProgram*)program;
>  
> -    if ((sz = prog->serializeToBin(oss)) == 0) {
> -      *binary = 0;
> +    //0 means GEN binary, 1 means LLVM bitcode compiled object, 2 means LLVM bitcode library
> +    if(binary_type == 0){
> +      if ((sz = prog->serializeToBin(oss)) == 0) {
> +        *binary = NULL;
> +        return 0;
> +      }
> +
> +      //add header to differetiate from llvm bitcode binary.
> +      //the header length is 5 bytes: 1 binary type, 4 bitcode header.
> +      *binary = (char *)malloc(sizeof(char) * (sz+5) );
> +      memset(*binary, 0, sizeof(char) * (sz+5) );
> +      memcpy(*binary+5, oss.str().c_str(), sz*sizeof(char));
> +      return sz+5;
> +    }else{
> +#ifdef GBE_COMPILER_AVAILABLE
> +      std::string str;
> +      llvm::raw_string_ostream OS(str);
> +      llvm::WriteBitcodeToFile((llvm::Module*)prog->module, OS);
> +      std::string& bin_str = OS.str();
> +      int llsz = bin_str.size();
> +      *binary = (char *)malloc(sizeof(char) * (llsz+1) );
> +      *(*binary) = binary_type;
> +      memcpy(*binary+1, bin_str.c_str(), llsz);
> +      return llsz+1;
> +#else
>        return 0;
> +#endif
>      }
> -
> -    *binary = (char *)malloc(sizeof(char) * sz);
> -    memcpy(*binary, oss.str().c_str(), sz*sizeof(char));
> -    return sz;
>    }
>  
>    static gbe_program genProgramNewFromLLVM(uint32_t deviceID,
> @@ -337,6 +391,7 @@ namespace gbe {
>  void genSetupCallBacks(void)
>  {
>    gbe_program_new_from_binary = gbe::genProgramNewFromBinary;
> +  gbe_program_new_from_llvm_binary = gbe::genProgramNewFromLLVMBinary;
>    gbe_program_serialize_to_binary = gbe::genProgramSerializeToBinary;
>    gbe_program_new_from_llvm = gbe::genProgramNewFromLLVM;
>    gbe_program_new_gen_program = gbe::genProgramNewGenProgram;
> diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
> index 45983fd..98e7ab7 100644
> --- a/backend/src/backend/program.cpp
> +++ b/backend/src/backend/program.cpp
> @@ -1158,6 +1158,7 @@ GBE_EXPORT_SYMBOL gbe_program_new_from_source_cb *gbe_program_new_from_source =
>  GBE_EXPORT_SYMBOL gbe_program_compile_from_source_cb *gbe_program_compile_from_source = NULL;
>  GBE_EXPORT_SYMBOL gbe_program_link_program_cb *gbe_program_link_program = NULL;
>  GBE_EXPORT_SYMBOL gbe_program_new_from_binary_cb *gbe_program_new_from_binary = NULL;
> +GBE_EXPORT_SYMBOL gbe_program_new_from_llvm_binary_cb *gbe_program_new_from_llvm_binary = NULL;
>  GBE_EXPORT_SYMBOL gbe_program_serialize_to_binary_cb *gbe_program_serialize_to_binary = NULL;
>  GBE_EXPORT_SYMBOL gbe_program_new_from_llvm_cb *gbe_program_new_from_llvm = NULL;
>  GBE_EXPORT_SYMBOL gbe_program_new_gen_program_cb *gbe_program_new_gen_program = NULL;
> diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h
> index 508fe64..c56b94a 100644
> --- a/backend/src/backend/program.h
> +++ b/backend/src/backend/program.h
> @@ -179,8 +179,12 @@ extern gbe_program_new_gen_program_cb *gbe_program_new_gen_program;
>  typedef gbe_program (gbe_program_new_from_binary_cb)(uint32_t deviceID, const char *binary, size_t size);
>  extern gbe_program_new_from_binary_cb *gbe_program_new_from_binary;
>  
> -/*! Serialize a program to a bin */
> -typedef size_t (gbe_program_serialize_to_binary_cb)(gbe_program program, char **binary);
> +/*! Create a new program from the llvm bitcode*/
> +typedef gbe_program (gbe_program_new_from_llvm_binary_cb)(uint32_t deviceID, const char *binary, size_t size);
> +extern gbe_program_new_from_llvm_binary_cb *gbe_program_new_from_llvm_binary;
> +
> +/*! Serialize a program to a bin, 0 means executable, 1 means llvm bitcode*/
> +typedef size_t (gbe_program_serialize_to_binary_cb)(gbe_program program, char **binary, int binary_type);
>  extern gbe_program_serialize_to_binary_cb *gbe_program_serialize_to_binary;
>  
>  /*! Create a new program from the given LLVM file */
> diff --git a/src/cl_api.c b/src/cl_api.c
> index 73447c4..2f287e3 100644
> --- a/src/cl_api.c
> +++ b/src/cl_api.c
> @@ -1065,8 +1065,16 @@ clGetProgramInfo(cl_program       program,
>      FILL_GETINFO_RET (char, (strlen(program->source) + 1),
>                     program->source, CL_SUCCESS);
>    } else if (param_name == CL_PROGRAM_BINARY_SIZES) {
> -    if (program->binary == NULL) {
> -      program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary);
> +    if (program->binary == NULL){
> +      if( program->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE) {
> +        program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 0);
> +      }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT) {
> +        program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 1);
> +      }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_LIBRARY) {
> +        program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 2);
> +      }else{
> +        return CL_INVALID_BINARY;
> +      }
>      }
>  
>      if (program->binary == NULL || program->binary_sz == 0) {
> @@ -1082,7 +1090,15 @@ clGetProgramInfo(cl_program       program,
>      /* param_value points to an array of n
>         pointers allocated by the caller */
>      if (program->binary == NULL) {
> -      program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary);
> +      if( program->binary_type == CL_PROGRAM_BINARY_TYPE_EXECUTABLE) {
> +        program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 0);
> +      }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT) {
> +        program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 1);
> +      }else if( program->binary_type == CL_PROGRAM_BINARY_TYPE_LIBRARY) {
> +        program->binary_sz = compiler_program_serialize_to_binary(program->opaque, &program->binary, 2);
> +      }else{
> +        return CL_INVALID_BINARY;
> +      }
>      }
>  
>      if (program->binary == NULL || program->binary_sz == 0) {
> @@ -1134,6 +1150,9 @@ clGetProgramBuildInfo(cl_program             program,
>      FILL_GETINFO_RET (char, program->build_log_sz + 1, program->build_log, CL_SUCCESS);
>      if (param_value_size_ret)
>        *param_value_size_ret = program->build_log_sz + 1;
> +  }else if (param_name == CL_PROGRAM_BINARY_TYPE){
> +
> +    FILL_GETINFO_RET (cl_uint, 1, &program->binary_type, CL_SUCCESS);
>    } else {
>      return CL_INVALID_VALUE;
>    }
> diff --git a/src/cl_gbe_loader.cpp b/src/cl_gbe_loader.cpp
> index 470299b..2fda50c 100644
> --- a/src/cl_gbe_loader.cpp
> +++ b/src/cl_gbe_loader.cpp
> @@ -24,13 +24,14 @@
>  
>  //function pointer from libgbe.so
>  gbe_program_new_from_source_cb *compiler_program_new_from_source = NULL;
> -gbe_program_serialize_to_binary_cb *compiler_program_serialize_to_binary = NULL;
> -gbe_program_new_from_llvm_cb *compiler_program_new_from_llvm = NULL;
> -gbe_set_image_base_index_cb *compiler_set_image_base_index = NULL;
>  gbe_program_compile_from_source_cb *compiler_program_compile_from_source = NULL;
>  gbe_program_new_gen_program_cb *compiler_program_new_gen_program = NULL;
>  gbe_program_link_program_cb *compiler_program_link_program = NULL;
>  gbe_program_build_from_llvm_cb *compiler_program_build_from_llvm = NULL;
> +gbe_program_new_from_llvm_binary_cb *compiler_program_new_from_llvm_binary = NULL;
> +gbe_program_serialize_to_binary_cb *compiler_program_serialize_to_binary = NULL;
> +gbe_program_new_from_llvm_cb *compiler_program_new_from_llvm = NULL;
> +gbe_set_image_base_index_cb *compiler_set_image_base_index = NULL;
>  
>  //function pointer from libgbeinterp.so
>  gbe_program_new_from_binary_cb *interp_program_new_from_binary = NULL;
> @@ -272,6 +273,10 @@ struct GbeLoaderInitializer
>        if (compiler_program_build_from_llvm == NULL)
>          return;
>  
> +      compiler_program_new_from_llvm_binary = *(gbe_program_new_from_llvm_binary_cb **)dlsym(dlhCompiler, "gbe_program_new_from_llvm_binary");
> +      if (compiler_program_new_from_llvm_binary == NULL)
> +        return;
> +
>        compiler_program_serialize_to_binary = *(gbe_program_serialize_to_binary_cb **)dlsym(dlhCompiler, "gbe_program_serialize_to_binary");
>        if (compiler_program_serialize_to_binary == NULL)
>          return;
> diff --git a/src/cl_gbe_loader.h b/src/cl_gbe_loader.h
> index bd6afe6..632163b 100644
> --- a/src/cl_gbe_loader.h
> +++ b/src/cl_gbe_loader.h
> @@ -25,9 +25,15 @@
>  extern "C" {
>  #endif
>  extern gbe_program_new_from_source_cb *compiler_program_new_from_source;
> +extern gbe_program_compile_from_source_cb *compiler_program_compile_from_source;
> +extern gbe_program_new_gen_program_cb *compiler_program_new_gen_program;
> +extern gbe_program_link_program_cb *compiler_program_link_program;
> +extern gbe_program_build_from_llvm_cb *compiler_program_build_from_llvm;
> +extern gbe_program_new_from_llvm_binary_cb *compiler_program_new_from_llvm_binary;
>  extern gbe_program_serialize_to_binary_cb *compiler_program_serialize_to_binary;
>  extern gbe_program_new_from_llvm_cb *compiler_program_new_from_llvm;
>  extern gbe_set_image_base_index_cb *compiler_set_image_base_index;
> +
>  extern gbe_program_new_from_binary_cb *interp_program_new_from_binary;
>  extern gbe_program_get_global_constant_size_cb *interp_program_get_global_constant_size;
>  extern gbe_program_get_global_constant_data_cb *interp_program_get_global_constant_data;
> @@ -63,10 +69,6 @@ extern gbe_get_printf_sizeof_size_cb* interp_get_printf_sizeof_size;
>  extern gbe_release_printf_info_cb* interp_release_printf_info;
>  extern gbe_output_printf_cb* interp_output_printf;
>  //extern gbe_set_image_base_index_cb *gbe_set_image_base_index_interp;
> -extern gbe_program_compile_from_source_cb *compiler_program_compile_from_source;
> -extern gbe_program_new_gen_program_cb *compiler_program_new_gen_program;
> -extern gbe_program_link_program_cb *compiler_program_link_program;
> -extern gbe_program_build_from_llvm_cb *compiler_program_build_from_llvm;
>  extern gbe_kernel_get_arg_info_cb *interp_kernel_get_arg_info;
>  
>  int CompilerSupported();
> diff --git a/src/cl_program.c b/src/cl_program.c
> index 240453c..0dcc59a 100644
> --- a/src/cl_program.c
> +++ b/src/cl_program.c
> @@ -156,6 +156,30 @@ error:
>    return err;
>  }
>  
> +inline cl_bool isBitcodeWrapper(const unsigned char *BufPtr, const unsigned char *BufEnd)
> +{
> +  // See if you can find the hidden message in the magic bytes :-).
> +  // (Hint: it's a little-endian encoding.)
> +  return BufPtr != BufEnd &&
> +    BufPtr[0] == 0xDE &&
> +    BufPtr[1] == 0xC0 &&
> +    BufPtr[2] == 0x17 &&
> +    BufPtr[3] == 0x0B;
> +}
> +
> +inline cl_bool isRawBitcode(const unsigned char *BufPtr, const unsigned char *BufEnd)
> +{
> +  // These bytes sort of have a hidden message, but it's not in
> +  // little-endian this time, and it's a little redundant.
> +  return BufPtr != BufEnd &&
> +    BufPtr[0] == 'B' &&
> +    BufPtr[1] == 'C' &&
> +    BufPtr[2] == 0xc0 &&
> +    BufPtr[3] == 0xde;
> +}
> +
> +#define isBitcode(BufPtr,BufEnd)  (isBitcodeWrapper(BufPtr, BufEnd) || isRawBitcode(BufPtr, BufEnd))
> +
>  LOCAL cl_program
>  cl_program_create_from_binary(cl_context             ctx,
>                                cl_uint                num_devices,
> @@ -197,6 +221,23 @@ cl_program_create_from_binary(cl_context             ctx,
>    program->binary_sz = lengths[0];
>    program->source_type = FROM_BINARY;
>  
> +  if(isBitcode((unsigned char*)program->binary+1, (unsigned char*)program->binary+program->binary_sz)) {
> +    if(*program->binary == 1){
> +      program->binary_type = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT;
> +    }else if(*program->binary == 2){
> +      program->binary_type = CL_PROGRAM_BINARY_TYPE_LIBRARY;
> +    }else{
> +      err= CL_INVALID_BINARY;
> +      goto error;
> +    }
> +    program->opaque = compiler_program_new_from_llvm_binary(program->ctx->device->vendor_id, program->binary, program->binary_sz);
> +
> +    if (UNLIKELY(program->opaque == NULL)) {
> +      err = CL_INVALID_PROGRAM;
> +      goto error;
> +    }
> +  }
> +
>    if (binary_status)
>      binary_status[0] = CL_SUCCESS;
>  
> @@ -360,6 +401,7 @@ cl_program_create_from_source(cl_context ctx,
>    *p = '\0';
>  
>    program->source_type = FROM_SOURCE;
> +  program->binary_type = CL_PROGRAM_BINARY_TYPE_NONE;
>  
>  exit:
>    cl_free(lens);
> @@ -432,6 +474,7 @@ cl_program_build(cl_program p, const char *options)
>      TRY (cl_program_load_gen_program, p);
>      p->source_type = FROM_LLVM;
>    }
> +  p->binary_type = CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
>  
>    for (i = 0; i < p->ker_n; i ++) {
>      const gbe_kernel opaque = interp_program_get_kernel(p->opaque, i);
> @@ -468,6 +511,7 @@ cl_program_link(cl_context            context,
>    p->opaque = compiler_program_new_gen_program(context->device->vendor_id, NULL, NULL);
>  
>    for(i = 0; i < num_input_programs; i++) {
> +    // if program create with llvm binary, need deserilize first to get module.
>      if(input_programs[i])
>        compiler_program_link_program(p->opaque, input_programs[i]->opaque,
>          p->build_log_max_sz, p->build_log, &p->build_log_sz);
> @@ -477,6 +521,13 @@ cl_program_link(cl_context            context,
>      }
>    }
>  
> +  if(options && strstr(options, "-create-library")){
> +    p->binary_type = CL_PROGRAM_BINARY_TYPE_LIBRARY;
> +    return p;
> +  }else{
> +    p->binary_type = CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
> +  }
> +
>    compiler_program_build_from_llvm(p->opaque, p->build_log_max_sz, p->build_log, &p->build_log_sz, options);
>  
>    /* Create all the kernels */
> @@ -534,7 +585,9 @@ cl_program_compile(cl_program            p,
>      p->build_opts = NULL;
>    }
>  
> -  const char* temp_header_path = "/tmp/beignet_header/";
> +  char temp_header_template[]= "/tmp/beignet.XXXXXX";
> +  char* temp_header_path = mkdtemp(temp_header_template);
> +
>    if (p->source_type == FROM_SOURCE) {
>  
>      if (!CompilerSupported()) {
> @@ -542,14 +595,15 @@ cl_program_compile(cl_program            p,
>        goto error;
>      }
>  
> -    //write the headers to /tmp/beignet_header for include.
> +    //write the headers to /tmp/beignet.XXXXXX for include.
>      for (i = 0; i < num_input_headers; i++) {
>        if(header_include_names[i] == NULL || input_headers[i] == NULL)
>          continue;
>  
> -      char temp_path[255];
> -      strcpy(temp_path, temp_header_path);
> -      strcat(temp_path, header_include_names[i]);
> +      char temp_path[255]="";
> +      strncpy(temp_path, temp_header_path, strlen(temp_header_path));
> +      strncat(temp_path, "/", 1);
> +      strncat(temp_path, header_include_names[i], strlen(header_include_names[i]));
>        char* dirc = strdup(temp_path);
>        char* dir = dirname(dirc);
>        mkdir(dir, 0755);
> @@ -572,9 +626,12 @@ cl_program_compile(cl_program            p,
>      p->opaque = compiler_program_compile_from_source(p->ctx->device->vendor_id, p->source, temp_header_path,
>          p->build_log_max_sz, options, p->build_log, &p->build_log_sz);
>  
> -    int rm_ret = system("rm /tmp/beignet_header/* -rf");
> +    char rm_path[255]="rm ";
> +    strncat(rm_path, temp_header_path, strlen(temp_header_path));
> +    strncat(rm_path, " -rf", 4);
> +    int temp = system(rm_path);
>  
> -    if(rm_ret){
> +    if(temp){
>        assert(0);
>      }
>  
> @@ -588,6 +645,7 @@ cl_program_compile(cl_program            p,
>  
>      /* Create all the kernels */
>      p->source_type = FROM_LLVM;
> +    p->binary_type = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT;
>    }
>    p->is_built = 1;
>    return CL_SUCCESS;
> diff --git a/src/cl_program.h b/src/cl_program.h
> index 49a4f48..52d1ac1 100644
> --- a/src/cl_program.h
> +++ b/src/cl_program.h
> @@ -50,6 +50,7 @@ struct _cl_program {
>    char *source;           /* Program sources */
>    char *binary;           /* Program binary. */
>    size_t binary_sz;       /* The binary size. */
> +  uint32_t binary_type;   /* binary type: COMPILED_OBJECT(LLVM IR), LIBRARY(LLVM IR with option "-create-library"), or EXECUTABLE(GEN binary). */
>    uint32_t ker_n;         /* Number of declared kernels */
>    uint32_t source_type:2; /* Built from binary, source or LLVM */
>    uint32_t is_built:1;    /* Did we call clBuildProgram on it? */
> -- 
> 1.8.1.2
> 
> _______________________________________________
> Beignet mailing list
> Beignet at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/beignet


More information about the Beignet mailing list