/// Tries to read program binaries from file cache. inline boost::optional<cl::Program> load_program_binaries( const std::string &hash, const cl::Context &context, const std::vector<cl::Device> &device, const std::string &options = "" ) { std::ifstream bfile(program_binaries_path(hash) + "kernel", std::ios::binary); if (!bfile) return boost::optional<cl::Program>(); size_t n; std::vector<char> buf; bfile.read((char*)&n, sizeof(size_t)); buf.resize(n); bfile.read(buf.data(), n); cl::Program program(context, device, cl::Program::Binaries( 1, std::make_pair(static_cast<const void*>(buf.data()), n))); try { program.build(device, options.c_str()); } catch(const cl::Error&) { std::cerr << "Loading binaries failed:" << std::endl << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0]) << std::endl; return boost::optional<cl::Program>(); } return boost::optional<cl::Program>(program); }
/// Compile and load a program from source string. inline vex::backend::program build_sources(const command_queue &q, const std::string &source, const std::string &options = "" ) { #ifdef VEXCL_SHOW_KERNELS std::cout << source << std::endl; #else if (getenv("VEXCL_SHOW_KERNELS")) std::cout << source << std::endl; #endif std::string compile_options = options + " " + get_compile_options(q); sha1_hasher sha1; sha1.process(source) .process(compile_options) .process(VEXCL_JIT_COMPILER) .process(VEXCL_JIT_COMPILER_OPTIONS); std::string hash = static_cast<std::string>(sha1); // Write source to a .cpp file std::string basename = program_binaries_path(hash, true) + "kernel"; std::string sofile = basename + ".so"; if ( !boost::filesystem::exists(sofile) ) { std::string cppfile = basename + ".cpp"; { std::ofstream f(cppfile); f << source; } // Compile the source. std::ostringstream cmdline; cmdline << VEXCL_JIT_COMPILER << " -o " << sofile << " " << cppfile << " " << VEXCL_JIT_COMPILER_OPTIONS << " " << compile_options; if (0 != system(cmdline.str().c_str()) ) { #ifndef VEXCL_SHOW_KERNELS std::cerr << source << std::endl; #endif vex::detail::print_backtrace(); throw std::runtime_error("Kernel compilation failed"); } } // Load the compiled shared library. return boost::dll::shared_library(sofile); }
/// Saves program binaries for future reuse. inline void save_program_binaries( const std::string &hash, const cl::Program &program, const std::string &source ) { std::ofstream bfile(program_binaries_path(hash, true) + "kernel", std::ios::binary); if (!bfile) return; std::vector<size_t> sizes = program.getInfo<CL_PROGRAM_BINARY_SIZES>(); std::vector<char*> binaries = program.getInfo<CL_PROGRAM_BINARIES>(); assert(sizes.size() == 1); bfile.write((char*)&sizes[0], sizeof(size_t)); bfile.write(binaries[0], sizes[0]); delete[] binaries[0]; bfile << "\n" << source << "\n"; }
/// Saves program binaries for future reuse. inline void save_program_binaries( const std::string &hash, const cl::Program &program ) { // Prevent writing to the same file by several threads at the same time. static boost::mutex mx; boost::lock_guard<boost::mutex> lock(mx); std::ofstream bfile(program_binaries_path(hash, true) + "kernel", std::ios::binary); if (!bfile) return; std::vector<size_t> sizes = program.getInfo<CL_PROGRAM_BINARY_SIZES>(); std::vector<char*> binaries = program.getInfo<CL_PROGRAM_BINARIES>(); assert(sizes.size() == 1); bfile.write((char*)&sizes[0], sizeof(size_t)); bfile.write(binaries[0], sizes[0]); delete[] binaries[0]; }
/// Create and build a program from source string. inline vex::backend::program build_sources( const command_queue &queue, const std::string &source, const std::string &options = "" ) { #ifdef VEXCL_SHOW_KERNELS std::cout << source << std::endl; #else if (getenv("VEXCL_SHOW_KERNELS")) std::cout << source << std::endl; #endif std::string compile_options = options + " " + get_compile_options(queue); queue.context().set_current(); auto cc = queue.device().compute_capability(); std::ostringstream ccstr; ccstr << std::get<0>(cc) << std::get<1>(cc); sha1_hasher sha1; sha1.process(source) .process(queue.device().name()) .process(compile_options) .process(ccstr.str()) ; std::string hash = static_cast<std::string>(sha1); // Write source to a .cu file std::string basename = program_binaries_path(hash, true) + "kernel"; std::string ptxfile = basename + ".ptx"; if ( !boost::filesystem::exists(ptxfile) ) { std::string cufile = basename + ".cu"; { std::ofstream f(cufile); f << source; } // Compile the source to ptx. std::ostringstream cmdline; cmdline << "nvcc -ptx -O3" << " -arch=sm_" << std::get<0>(cc) << std::get<1>(cc) << " " << compile_options << " -o " << ptxfile << " " << cufile; if (0 != system(cmdline.str().c_str()) ) { #ifndef VEXCL_SHOW_KERNELS std::cerr << source << std::endl; #endif vex::detail::print_backtrace(); throw std::runtime_error("nvcc invocation failed"); } } // Load the compiled ptx. CUmodule prg; cuda_check( cuModuleLoad(&prg, ptxfile.c_str()) ); return program(queue.context(), prg); }