Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:05

0001 //---------------------------------------------------------------------------//
0002 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 // See http://boostorg.github.com/compute for more information.
0009 //---------------------------------------------------------------------------//
0010 
0011 #ifndef BOOST_COMPUTE_PROGRAM_HPP
0012 #define BOOST_COMPUTE_PROGRAM_HPP
0013 
0014 #include <string>
0015 #include <vector>
0016 #include <fstream>
0017 #include <streambuf>
0018 
0019 #ifdef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
0020 #include <iostream>
0021 #endif
0022 
0023 #include <boost/compute/config.hpp>
0024 #include <boost/compute/context.hpp>
0025 #include <boost/compute/exception.hpp>
0026 #include <boost/compute/exception/program_build_failure.hpp>
0027 #include <boost/compute/detail/assert_cl_success.hpp>
0028 
0029 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0030 #include <sstream>
0031 #include <boost/optional.hpp>
0032 #include <boost/compute/platform.hpp>
0033 #include <boost/compute/detail/getenv.hpp>
0034 #include <boost/compute/detail/path.hpp>
0035 #include <boost/compute/detail/sha1.hpp>
0036 #endif
0037 
0038 namespace boost {
0039 namespace compute {
0040 
0041 class kernel;
0042 
0043 /// \class program
0044 /// \brief A compute program.
0045 ///
0046 /// The program class represents an OpenCL program.
0047 ///
0048 /// Program objects are created with one of the static \c create_with_*
0049 /// functions. For example, to create a program from a source string:
0050 ///
0051 /// \snippet test/test_program.cpp create_with_source
0052 ///
0053 /// And to create a program from a source file:
0054 /// \code
0055 /// boost::compute::program bar_program =
0056 ///     boost::compute::program::create_with_source_file("/path/to/bar.cl", context);
0057 /// \endcode
0058 ///
0059 /// Once a program object has been successfully created, it can be compiled
0060 /// using the \c build() method:
0061 /// \code
0062 /// // build the program
0063 /// foo_program.build();
0064 /// \endcode
0065 ///
0066 /// Once the program is built, \ref kernel objects can be created using the
0067 /// \c create_kernel() method by passing their name:
0068 /// \code
0069 /// // create a kernel from the compiled program
0070 /// boost::compute::kernel foo_kernel = foo_program.create_kernel("foo");
0071 /// \endcode
0072 ///
0073 /// \see kernel
0074 class program
0075 {
0076 public:
0077     /// Creates a null program object.
0078     program()
0079         : m_program(0)
0080     {
0081     }
0082 
0083     /// Creates a program object for \p program. If \p retain is \c true,
0084     /// the reference count for \p program will be incremented.
0085     explicit program(cl_program program, bool retain = true)
0086         : m_program(program)
0087     {
0088         if(m_program && retain){
0089             clRetainProgram(m_program);
0090         }
0091     }
0092 
0093     /// Creates a new program object as a copy of \p other.
0094     program(const program &other)
0095         : m_program(other.m_program)
0096     {
0097         if(m_program){
0098             clRetainProgram(m_program);
0099         }
0100     }
0101 
0102     /// Copies the program object from \p other to \c *this.
0103     program& operator=(const program &other)
0104     {
0105         if(this != &other){
0106             if(m_program){
0107                 clReleaseProgram(m_program);
0108             }
0109 
0110             m_program = other.m_program;
0111 
0112             if(m_program){
0113                 clRetainProgram(m_program);
0114             }
0115         }
0116 
0117         return *this;
0118     }
0119 
0120     #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
0121     /// Move-constructs a new program object from \p other.
0122     program(program&& other) BOOST_NOEXCEPT
0123         : m_program(other.m_program)
0124     {
0125         other.m_program = 0;
0126     }
0127 
0128     /// Move-assigns the program from \p other to \c *this.
0129     program& operator=(program&& other) BOOST_NOEXCEPT
0130     {
0131         if(m_program){
0132             clReleaseProgram(m_program);
0133         }
0134 
0135         m_program = other.m_program;
0136         other.m_program = 0;
0137 
0138         return *this;
0139     }
0140     #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
0141 
0142     /// Destroys the program object.
0143     ~program()
0144     {
0145         if(m_program){
0146             BOOST_COMPUTE_ASSERT_CL_SUCCESS(
0147                 clReleaseProgram(m_program)
0148             );
0149         }
0150     }
0151 
0152     /// Returns the underlying OpenCL program.
0153     cl_program& get() const
0154     {
0155         return const_cast<cl_program &>(m_program);
0156     }
0157 
0158     /// Returns the source code for the program.
0159     std::string source() const
0160     {
0161         return get_info<std::string>(CL_PROGRAM_SOURCE);
0162     }
0163 
0164     /// Returns the binary for the program.
0165     std::vector<unsigned char> binary() const
0166     {
0167         size_t binary_size = get_info<size_t>(CL_PROGRAM_BINARY_SIZES);
0168         std::vector<unsigned char> binary(binary_size);
0169 
0170         unsigned char *binary_ptr = &binary[0];
0171         cl_int error = clGetProgramInfo(m_program,
0172                                         CL_PROGRAM_BINARIES,
0173                                         sizeof(unsigned char **),
0174                                         &binary_ptr,
0175                                         0);
0176         if(error != CL_SUCCESS){
0177             BOOST_THROW_EXCEPTION(opencl_error(error));
0178         }
0179 
0180         return binary;
0181     }
0182 
0183     #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0184     /// Returns the SPIR-V binary for the program.
0185     std::vector<unsigned char> il_binary() const
0186     {
0187         return get_info<std::vector<unsigned char> >(CL_PROGRAM_IL);
0188     }
0189     #endif // BOOST_COMPUTE_CL_VERSION_2_1
0190 
0191     std::vector<device> get_devices() const
0192     {
0193         std::vector<cl_device_id> device_ids =
0194             get_info<std::vector<cl_device_id> >(CL_PROGRAM_DEVICES);
0195 
0196         std::vector<device> devices;
0197         for(size_t i = 0; i < device_ids.size(); i++){
0198             devices.push_back(device(device_ids[i]));
0199         }
0200 
0201         return devices;
0202     }
0203 
0204     /// Returns the context for the program.
0205     context get_context() const
0206     {
0207         return context(get_info<cl_context>(CL_PROGRAM_CONTEXT));
0208     }
0209 
0210     /// Returns information about the program.
0211     ///
0212     /// \see_opencl_ref{clGetProgramInfo}
0213     template<class T>
0214     T get_info(cl_program_info info) const
0215     {
0216         return detail::get_object_info<T>(clGetProgramInfo, m_program, info);
0217     }
0218 
0219     /// \overload
0220     template<int Enum>
0221     typename detail::get_object_info_type<program, Enum>::type
0222     get_info() const;
0223 
0224     /// Returns build information about the program.
0225     ///
0226     /// For example, this function can be used to retreive the options used
0227     /// to build the program:
0228     /// \code
0229     /// std::string build_options =
0230     ///     program.get_build_info<std::string>(CL_PROGRAM_BUILD_OPTIONS);
0231     /// \endcode
0232     ///
0233     /// \see_opencl_ref{clGetProgramInfo}
0234     template<class T>
0235     T get_build_info(cl_program_build_info info, const device &device) const
0236     {
0237         return detail::get_object_info<T>(clGetProgramBuildInfo, m_program, info, device.id());
0238     }
0239 
0240     /// Builds the program with \p options.
0241     ///
0242     /// If the program fails to compile, this function will throw an
0243     /// opencl_error exception.
0244     /// \code
0245     /// try {
0246     ///     // attempt to compile to program
0247     ///     program.build();
0248     /// }
0249     /// catch(boost::compute::opencl_error &e){
0250     ///     // program failed to compile, print out the build log
0251     ///     std::cout << program.build_log() << std::endl;
0252     /// }
0253     /// \endcode
0254     ///
0255     /// \see_opencl_ref{clBuildProgram}
0256     void build(const std::string &options = std::string())
0257     {
0258         const char *options_string = 0;
0259 
0260         if(!options.empty()){
0261             options_string = options.c_str();
0262         }
0263 
0264         cl_int ret = clBuildProgram(m_program, 0, 0, options_string, 0, 0);
0265 
0266         #ifdef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
0267         if(ret != CL_SUCCESS){
0268             // print the error, source code and build log
0269             std::cerr << "Boost.Compute: "
0270                       << "kernel compilation failed (" << ret << ")\n"
0271                       << "--- source ---\n"
0272                       << source()
0273                       << "\n--- build log ---\n"
0274                       << build_log()
0275                       << std::endl;
0276         }
0277         #endif
0278 
0279         if(ret != CL_SUCCESS){
0280             BOOST_THROW_EXCEPTION(program_build_failure(ret, build_log()));
0281         }
0282     }
0283 
0284     #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0285     /// Compiles the program with \p options.
0286     ///
0287     /// \opencl_version_warning{1,2}
0288     ///
0289     /// \see_opencl_ref{clCompileProgram}
0290     void compile(const std::string &options = std::string(),
0291                  const std::vector<std::pair<std::string, program> > &headers =
0292                     std::vector<std::pair<std::string, program> >())
0293     {
0294         const char *options_string = 0;
0295 
0296         if(!options.empty()){
0297             options_string = options.c_str();
0298         }
0299 
0300         cl_int ret;
0301         if (headers.empty())
0302         {
0303             ret = clCompileProgram(
0304                 m_program, 0, 0, options_string, 0, 0, 0, 0, 0
0305             );
0306         }
0307         else
0308         {
0309             std::vector<const char*> header_names(headers.size());
0310             std::vector<cl_program> header_programs(headers.size());
0311             for (size_t i = 0; i < headers.size(); ++i)
0312             {
0313                 header_names[i] = headers[i].first.c_str();
0314                 header_programs[i] = headers[i].second.m_program;
0315             }
0316 
0317             ret = clCompileProgram(
0318                 m_program,
0319                 0,
0320                 0,
0321                 options_string,
0322                 static_cast<cl_uint>(headers.size()),
0323                 header_programs.data(),
0324                 header_names.data(),
0325                 0,
0326                 0
0327             );
0328         }
0329 
0330         if(ret != CL_SUCCESS){
0331             BOOST_THROW_EXCEPTION(opencl_error(ret));
0332         }
0333     }
0334 
0335     /// Links the programs in \p programs with \p options in \p context.
0336     ///
0337     /// \opencl_version_warning{1,2}
0338     ///
0339     /// \see_opencl_ref{clLinkProgram}
0340     static program link(const std::vector<program> &programs,
0341                         const context &context,
0342                         const std::string &options = std::string())
0343     {
0344         const char *options_string = 0;
0345 
0346         if(!options.empty()){
0347             options_string = options.c_str();
0348         }
0349 
0350         cl_int ret;
0351         cl_program program_ = clLinkProgram(
0352             context.get(),
0353             0,
0354             0,
0355             options_string,
0356             static_cast<uint_>(programs.size()),
0357             reinterpret_cast<const cl_program*>(&programs[0]),
0358             0,
0359             0,
0360             &ret
0361         );
0362 
0363         if(!program_){
0364             BOOST_THROW_EXCEPTION(opencl_error(ret));
0365         }
0366 
0367         return program(program_, false);
0368     }
0369     #endif // BOOST_COMPUTE_CL_VERSION_1_2
0370 
0371     /// Returns the build log.
0372     std::string build_log() const
0373     {
0374         return get_build_info<std::string>(CL_PROGRAM_BUILD_LOG, get_devices().front());
0375     }
0376 
0377     /// Creates and returns a new kernel object for \p name.
0378     ///
0379     /// For example, to create the \c "foo" kernel (after the program has been
0380     /// created and built):
0381     /// \code
0382     /// boost::compute::kernel foo_kernel = foo_program.create_kernel("foo");
0383     /// \endcode
0384     kernel create_kernel(const std::string &name) const;
0385 
0386     /// Returns \c true if the program is the same at \p other.
0387     bool operator==(const program &other) const
0388     {
0389         return m_program == other.m_program;
0390     }
0391 
0392     /// Returns \c true if the program is different from \p other.
0393     bool operator!=(const program &other) const
0394     {
0395         return m_program != other.m_program;
0396     }
0397 
0398     /// \internal_
0399     operator cl_program() const
0400     {
0401         return m_program;
0402     }
0403 
0404     /// Creates a new program with \p source in \p context.
0405     ///
0406     /// \see_opencl_ref{clCreateProgramWithSource}
0407     static program create_with_source(const std::string &source,
0408                                       const context &context)
0409     {
0410         const char *source_string = source.c_str();
0411 
0412         cl_int error = 0;
0413         cl_program program_ = clCreateProgramWithSource(context,
0414                                                         uint_(1),
0415                                                         &source_string,
0416                                                         0,
0417                                                         &error);
0418         if(!program_){
0419             BOOST_THROW_EXCEPTION(opencl_error(error));
0420         }
0421 
0422         return program(program_, false);
0423     }
0424 
0425     /// Creates a new program with \p sources in \p context.
0426     ///
0427     /// \see_opencl_ref{clCreateProgramWithSource}
0428     static program create_with_source(const std::vector<std::string> &sources,
0429                                       const context &context)
0430     {
0431         std::vector<const char*> source_strings(sources.size());
0432         for(size_t i = 0; i < sources.size(); i++){
0433             source_strings[i] = sources[i].c_str();
0434         }
0435 
0436         cl_int error = 0;
0437         cl_program program_ = clCreateProgramWithSource(context,
0438                                                         uint_(sources.size()),
0439                                                         &source_strings[0],
0440                                                         0,
0441                                                         &error);
0442         if(!program_){
0443             BOOST_THROW_EXCEPTION(opencl_error(error));
0444         }
0445 
0446         return program(program_, false);
0447     }
0448 
0449     /// Creates a new program with \p file in \p context.
0450     ///
0451     /// \see_opencl_ref{clCreateProgramWithSource}
0452     static program create_with_source_file(const std::string &file,
0453                                            const context &context)
0454     {
0455         // create program
0456         return create_with_source(read_source_file(file), context);
0457     }
0458 
0459     /// Creates a new program with \p files in \p context.
0460     ///
0461     /// \see_opencl_ref{clCreateProgramWithSource}
0462     static program create_with_source_file(const std::vector<std::string> &files,
0463                                            const context &context)
0464     {
0465         std::vector<std::string> sources(files.size());
0466 
0467         for(size_t i = 0; i < files.size(); ++i) {
0468             // open file stream
0469             std::ifstream stream(files[i].c_str());
0470 
0471             if(stream.fail()){
0472                 BOOST_THROW_EXCEPTION(std::ios_base::failure("failed to create stream."));
0473             }
0474 
0475             // read source
0476             sources[i] = std::string(
0477                     (std::istreambuf_iterator<char>(stream)),
0478                     std::istreambuf_iterator<char>()
0479             );
0480         }
0481 
0482         // create program
0483         return create_with_source(sources, context);
0484     }
0485 
0486     /// Creates a new program with \p binary of \p binary_size in
0487     /// \p context.
0488     ///
0489     /// \see_opencl_ref{clCreateProgramWithBinary}
0490     static program create_with_binary(const unsigned char *binary,
0491                                       size_t binary_size,
0492                                       const context &context)
0493     {
0494         const cl_device_id device = context.get_device().id();
0495 
0496         cl_int error = 0;
0497         cl_int binary_status = 0;
0498         cl_program program_ = clCreateProgramWithBinary(context,
0499                                                         uint_(1),
0500                                                         &device,
0501                                                         &binary_size,
0502                                                         &binary,
0503                                                         &binary_status,
0504                                                         &error);
0505         if(!program_){
0506             BOOST_THROW_EXCEPTION(opencl_error(error));
0507         }
0508         if(binary_status != CL_SUCCESS){
0509             BOOST_THROW_EXCEPTION(opencl_error(binary_status));
0510         }
0511 
0512         return program(program_, false);
0513     }
0514 
0515     /// Creates a new program with \p binary in \p context.
0516     ///
0517     /// \see_opencl_ref{clCreateProgramWithBinary}
0518     static program create_with_binary(const std::vector<unsigned char> &binary,
0519                                       const context &context)
0520     {
0521         return create_with_binary(&binary[0], binary.size(), context);
0522     }
0523 
0524     /// Creates a new program with \p file in \p context.
0525     ///
0526     /// \see_opencl_ref{clCreateProgramWithBinary}
0527     static program create_with_binary_file(const std::string &file,
0528                                            const context &context)
0529     {
0530         // open file stream
0531         std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary);
0532 
0533         // read binary
0534         std::vector<unsigned char> binary(
0535             (std::istreambuf_iterator<char>(stream)),
0536             std::istreambuf_iterator<char>()
0537         );
0538 
0539         // create program
0540         return create_with_binary(&binary[0], binary.size(), context);
0541     }
0542 
0543     #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0544     /// Creates a new program with the built-in kernels listed in
0545     /// \p kernel_names for \p devices in \p context.
0546     ///
0547     /// \opencl_version_warning{1,2}
0548     ///
0549     /// \see_opencl_ref{clCreateProgramWithBuiltInKernels}
0550     static program create_with_builtin_kernels(const context &context,
0551                                                const std::vector<device> &devices,
0552                                                const std::string &kernel_names)
0553     {
0554         cl_int error = 0;
0555 
0556         cl_program program_ = clCreateProgramWithBuiltInKernels(
0557             context.get(),
0558             static_cast<uint_>(devices.size()),
0559             reinterpret_cast<const cl_device_id *>(&devices[0]),
0560             kernel_names.c_str(),
0561             &error
0562         );
0563 
0564         if(!program_){
0565             BOOST_THROW_EXCEPTION(opencl_error(error));
0566         }
0567 
0568         return program(program_, false);
0569     }
0570     #endif // BOOST_COMPUTE_CL_VERSION_1_2
0571 
0572     #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
0573     /// Creates a new program with \p il_binary (SPIR-V binary)
0574     /// of \p il_size size in \p context.
0575     ///
0576     /// \opencl_version_warning{2,1}
0577     ///
0578     /// \see_opencl21_ref{clCreateProgramWithIL}
0579     static program create_with_il(const void * il_binary,
0580                                   const size_t il_size,
0581                                   const context &context)
0582     {
0583         cl_int error = 0;
0584 
0585         cl_program program_ = clCreateProgramWithIL(
0586             context.get(), il_binary, il_size, &error
0587         );
0588 
0589         if(!program_){
0590             BOOST_THROW_EXCEPTION(opencl_error(error));
0591         }
0592 
0593         return program(program_, false);
0594     }
0595 
0596     /// Creates a new program with \p il_binary (SPIR-V binary)
0597     /// in \p context.
0598     ///
0599     /// \opencl_version_warning{2,1}
0600     ///
0601     /// \see_opencl_ref{clCreateProgramWithIL}
0602     static program create_with_il(const std::vector<unsigned char> &il_binary,
0603                                   const context &context)
0604     {
0605         return create_with_il(&il_binary[0], il_binary.size(), context);
0606     }
0607 
0608     /// Creates a new program in \p context using SPIR-V
0609     /// binary \p file.
0610     ///
0611     /// \opencl_version_warning{2,1}
0612     ///
0613     /// \see_opencl_ref{clCreateProgramWithIL}
0614     static program create_with_il_file(const std::string &file,
0615                                        const context &context)
0616     {
0617         // open file stream
0618         std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary);
0619 
0620         // read binary
0621         std::vector<unsigned char> il(
0622             (std::istreambuf_iterator<char>(stream)),
0623             std::istreambuf_iterator<char>()
0624         );
0625 
0626         // create program
0627         return create_with_il(&il[0], il.size(), context);
0628     }
0629     #endif // BOOST_COMPUTE_CL_VERSION_2_1
0630 
0631     /// Create a new program with \p source in \p context and builds it with \p options.
0632     /**
0633      * In case BOOST_COMPUTE_USE_OFFLINE_CACHE macro is defined,
0634      * the compiled binary is stored for reuse in the offline cache located in
0635      * $HOME/.boost_compute on UNIX-like systems and in %APPDATA%/boost_compute
0636      * on Windows.
0637      */
0638     static program build_with_source(
0639             const std::string &source,
0640             const context     &context,
0641             const std::string &options = std::string()
0642             )
0643     {
0644 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0645         // Get hash string for the kernel.
0646         device   d = context.get_device();
0647         platform p = d.platform();
0648 
0649         detail::sha1 hash;
0650         hash.process( p.name()    )
0651             .process( p.version() )
0652             .process( d.name()    )
0653             .process( options     )
0654             .process( source      )
0655             ;
0656         std::string hash_string = hash;
0657 
0658         // Try to get cached program binaries:
0659         try {
0660             boost::optional<program> prog = load_program_binary(hash_string, context);
0661 
0662             if (prog) {
0663                 prog->build(options);
0664                 return *prog;
0665             }
0666         } catch (...) {
0667             // Something bad happened. Fallback to normal compilation.
0668         }
0669 
0670         // Cache is apparently not available. Just compile the sources.
0671 #endif
0672         const char *source_string = source.c_str();
0673 
0674         cl_int error = 0;
0675         cl_program program_ = clCreateProgramWithSource(context,
0676                                                         uint_(1),
0677                                                         &source_string,
0678                                                         0,
0679                                                         &error);
0680         if(!program_){
0681             BOOST_THROW_EXCEPTION(opencl_error(error));
0682         }
0683 
0684         program prog(program_, false);
0685         prog.build(options);
0686 
0687 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0688         // Save program binaries for future reuse.
0689         save_program_binary(hash_string, prog);
0690 #endif
0691 
0692         return prog;
0693     }
0694 
0695     /// Create a new program with \p file in \p context and builds it with \p options.
0696     /**
0697      * In case BOOST_COMPUTE_USE_OFFLINE_CACHE macro is defined,
0698      * the compiled binary is stored for reuse in the offline cache located in
0699      * $HOME/.boost_compute on UNIX-like systems and in %APPDATA%/boost_compute
0700      * on Windows.
0701      */
0702     static program build_with_source_file(
0703             const std::string &file,
0704             const context     &context,
0705             const std::string &options = std::string()
0706             )
0707     {
0708         return build_with_source(read_source_file(file), context, options);
0709     }
0710 
0711 private:
0712 #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
0713     // Saves program binaries for future reuse.
0714     static void save_program_binary(const std::string &hash, const program &prog)
0715     {
0716         std::string fname = detail::program_binary_path(hash, true) + "kernel";
0717         std::ofstream bfile(fname.c_str(), std::ios::binary);
0718         if (!bfile) return;
0719 
0720         std::vector<unsigned char> binary = prog.binary();
0721 
0722         size_t binary_size = binary.size();
0723         bfile.write((char*)&binary_size, sizeof(size_t));
0724         bfile.write((char*)binary.data(), binary_size);
0725     }
0726 
0727     // Tries to read program binaries from file cache.
0728     static boost::optional<program> load_program_binary(
0729             const std::string &hash, const context &ctx
0730             )
0731     {
0732         std::string fname = detail::program_binary_path(hash) + "kernel";
0733         std::ifstream bfile(fname.c_str(), std::ios::binary);
0734         if (!bfile) return boost::optional<program>();
0735 
0736         size_t binary_size;
0737         std::vector<unsigned char> binary;
0738 
0739         bfile.read((char*)&binary_size, sizeof(size_t));
0740 
0741         binary.resize(binary_size);
0742         bfile.read((char*)binary.data(), binary_size);
0743 
0744         return boost::optional<program>(
0745                 program::create_with_binary(
0746                     binary.data(), binary_size, ctx
0747                     )
0748                 );
0749     }
0750 #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
0751 
0752     static std::string read_source_file(const std::string &file)
0753     {
0754         // open file stream
0755         std::ifstream stream(file.c_str());
0756 
0757         if(stream.fail()){
0758           BOOST_THROW_EXCEPTION(std::ios_base::failure("failed to create stream."));
0759         }
0760 
0761         // read source
0762         return std::string(
0763             (std::istreambuf_iterator<char>(stream)),
0764             std::istreambuf_iterator<char>()
0765         );
0766     }
0767 
0768 private:
0769     cl_program m_program;
0770 };
0771 
0772 /// \internal_ define get_info() specializations for program
0773 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
0774     ((cl_uint, CL_PROGRAM_REFERENCE_COUNT))
0775     ((cl_context, CL_PROGRAM_CONTEXT))
0776     ((cl_uint, CL_PROGRAM_NUM_DEVICES))
0777     ((std::vector<cl_device_id>, CL_PROGRAM_DEVICES))
0778     ((std::string, CL_PROGRAM_SOURCE))
0779     ((std::vector<size_t>, CL_PROGRAM_BINARY_SIZES))
0780     ((std::vector<unsigned char *>, CL_PROGRAM_BINARIES))
0781 )
0782 
0783 #ifdef BOOST_COMPUTE_CL_VERSION_1_2
0784 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
0785     ((size_t, CL_PROGRAM_NUM_KERNELS))
0786     ((std::string, CL_PROGRAM_KERNEL_NAMES))
0787 )
0788 #endif // BOOST_COMPUTE_CL_VERSION_1_2
0789 
0790 #ifdef BOOST_COMPUTE_CL_VERSION_2_1
0791 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
0792     ((std::vector<unsigned char>, CL_PROGRAM_IL))
0793 )
0794 #endif // BOOST_COMPUTE_CL_VERSION_2_1
0795 
0796 } // end compute namespace
0797 } // end boost namespace
0798 
0799 #endif // BOOST_COMPUTE_PROGRAM_HPP