Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:24:59

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_SYSTEM_HPP
0012 #define BOOST_COMPUTE_SYSTEM_HPP
0013 
0014 #include <string>
0015 #include <vector>
0016 #include <cstdlib>
0017 
0018 #include <boost/throw_exception.hpp>
0019 
0020 #if defined(BOOST_COMPUTE_THREAD_SAFE) 
0021 #  if defined(BOOST_COMPUTE_USE_CPP11)
0022 #    include <mutex>
0023 #    include <thread>
0024 #    include <atomic>
0025 #  else
0026 #    include <boost/thread/mutex.hpp>
0027 #    include <boost/thread/lock_guard.hpp>
0028 #    include <boost/atomic.hpp>
0029 #  endif
0030 #endif 
0031 
0032 #include <boost/compute/cl.hpp>
0033 #include <boost/compute/device.hpp>
0034 #include <boost/compute/context.hpp>
0035 #include <boost/compute/platform.hpp>
0036 #include <boost/compute/command_queue.hpp>
0037 #include <boost/compute/detail/getenv.hpp>
0038 #include <boost/compute/exception/no_device_found.hpp>
0039 #include <boost/compute/exception/context_error.hpp>
0040 
0041 namespace boost {
0042 namespace compute {
0043 
0044 /// \class system
0045 /// \brief Provides access to platforms and devices on the system.
0046 ///
0047 /// The system class contains a set of static functions which provide access to
0048 /// the OpenCL platforms and compute devices on the host system.
0049 ///
0050 /// The default_device() convenience method automatically selects and returns
0051 /// the "best" compute device for the system following a set of heuristics and
0052 /// environment variables. This simplifies setup of the OpenCL enviornment.
0053 ///
0054 /// \see platform, device, context
0055 class system
0056 {
0057 public:
0058     /// Returns the default compute device for the system.
0059     ///
0060     /// The default device is selected based on a set of heuristics and can be
0061     /// influenced using one of the following environment variables:
0062     ///
0063     /// \li \c BOOST_COMPUTE_DEFAULT_DEVICE -
0064     ///        name of the compute device (e.g. "GTX TITAN")
0065     /// \li \c BOOST_COMPUTE_DEFAULT_DEVICE_TYPE
0066     ///        type of the compute device (e.g. "GPU" or "CPU")
0067     /// \li \c BOOST_COMPUTE_DEFAULT_PLATFORM -
0068     ///        name of the platform (e.g. "NVIDIA CUDA")
0069     /// \li \c BOOST_COMPUTE_DEFAULT_VENDOR -
0070     ///        name of the device vendor (e.g. "NVIDIA")
0071     /// \li \c BOOST_COMPUTE_DEFAULT_ENFORCE -
0072     ///        If this is set to "1", then throw a no_device_found() exception
0073     ///        if any of the above environment variables is set, but a matching
0074     ///        device was not found.
0075     ///
0076     /// The default device is determined once on the first time this function
0077     /// is called. Calling this function multiple times will always result in
0078     /// the same device being returned.
0079     ///
0080     /// If no OpenCL device is found on the system, a no_device_found exception
0081     /// is thrown.
0082     ///
0083     /// For example, to print the name of the default compute device on the
0084     /// system:
0085     /// \code
0086     /// // get the default compute device
0087     /// boost::compute::device device = boost::compute::system::default_device();
0088     ///
0089     /// // print the name of the device
0090     /// std::cout << "default device: " << device.name() << std::endl;
0091     /// \endcode
0092     static device default_device()
0093     {
0094         return init_default_device();
0095     }
0096 
0097     /// Returns the device with \p name.
0098     ///
0099     /// \throws no_device_found if no device with \p name is found.
0100     static device find_device(const std::string &name)
0101     {
0102         const std::vector<device> devices = system::devices();
0103         for(size_t i = 0; i < devices.size(); i++){
0104             const device& device = devices[i];
0105 
0106             if(device.name() == name){
0107                 return device;
0108             }
0109         }
0110 
0111         BOOST_THROW_EXCEPTION(no_device_found());
0112     }
0113 
0114     /// Returns a vector containing all of the compute devices on
0115     /// the system.
0116     ///
0117     /// For example, to print out the name of each OpenCL-capable device
0118     /// available on the system:
0119     /// \code
0120     /// for(const auto &device : boost::compute::system::devices()){
0121     ///     std::cout << device.name() << std::endl;
0122     /// }
0123     /// \endcode
0124     static std::vector<device> devices()
0125     {
0126         std::vector<device> devices;
0127 
0128         const std::vector<platform> platforms = system::platforms();
0129         for(size_t i = 0; i < platforms.size(); i++){
0130             const std::vector<device> platform_devices = platforms[i].devices();
0131 
0132             devices.insert(
0133                 devices.end(), platform_devices.begin(), platform_devices.end()
0134             );
0135         }
0136 
0137         return devices;
0138     }
0139 
0140     /// Returns the number of compute devices on the system.
0141     static size_t device_count()
0142     {
0143         size_t count = 0;
0144 
0145         const std::vector<platform> platforms = system::platforms();
0146         for(size_t i = 0; i < platforms.size(); i++){
0147             count += platforms[i].device_count();
0148         }
0149 
0150         return count;
0151     }
0152 
0153     /// Returns the default context for the system.
0154     ///
0155     /// The default context is created for the default device on the system
0156     /// (as returned by default_device()).
0157     ///
0158     /// The default context is created once on the first time this function is
0159     /// called. Calling this function multiple times will always result in the
0160     /// same context object being returned.
0161     static context default_context()
0162     {
0163         return init_default_context();
0164     }
0165 
0166     /// Returns the default command queue for the system.
0167     ///
0168     /// If user-provided command queue is given, the system-wide default context
0169     /// and default device will be set up appropriately so that the default queue
0170     /// matches the default context and device.
0171     ///
0172     /// If the OpenCL context and device associated with user-provided command queue 
0173     /// does not match the default context and device that have already been set,
0174     /// a set_default_queue_error exception is thrown. For example:
0175     ///
0176     /// \snippet test/test_attach_user_queue_error.cpp queue_mismatch
0177     ///
0178     /// The default queue is created once on the first time this function is
0179     /// called. Calling this function multiple times will always result in the
0180     /// same command queue object being returned.
0181     static command_queue& default_queue(const command_queue &user_queue = command_queue())
0182     {
0183         return init_default_queue(user_queue);
0184     }
0185 
0186     /// Blocks until all outstanding computations on the default
0187     /// command queue are complete.
0188     ///
0189     /// This is equivalent to:
0190     /// \code
0191     /// system::default_queue().finish();
0192     /// \endcode
0193     static void finish()
0194     {
0195         default_queue().finish();
0196     }
0197 
0198     /// Returns a vector containing each of the OpenCL platforms on the system.
0199     ///
0200     /// For example, to print out the name of each OpenCL platform present on
0201     /// the system:
0202     /// \code
0203     /// for(const auto &platform : boost::compute::system::platforms()){
0204     ///     std::cout << platform.name() << std::endl;
0205     /// }
0206     /// \endcode
0207     static std::vector<platform> platforms()
0208     {
0209         cl_uint count = 0;
0210         clGetPlatformIDs(0, 0, &count);
0211 
0212         std::vector<platform> platforms;
0213         if(count > 0)
0214         {
0215             std::vector<cl_platform_id> platform_ids(count);
0216             clGetPlatformIDs(count, &platform_ids[0], 0);
0217 
0218             for(size_t i = 0; i < platform_ids.size(); i++){
0219                 platforms.push_back(platform(platform_ids[i]));
0220             }
0221         }
0222         return platforms;
0223     }
0224 
0225     /// Returns the number of compute platforms on the system.
0226     static size_t platform_count()
0227     {
0228         cl_uint count = 0;
0229         clGetPlatformIDs(0, 0, &count);
0230         return static_cast<size_t>(count);
0231     }
0232 
0233 private:
0234     /// \internal_
0235     static device find_default_device()
0236     {
0237         // get a list of all devices on the system
0238         const std::vector<device> devices_ = devices();
0239         if(devices_.empty()){
0240             BOOST_THROW_EXCEPTION(no_device_found());
0241         }
0242 
0243         // check for device from environment variable
0244         const char *name     = detail::getenv("BOOST_COMPUTE_DEFAULT_DEVICE");
0245         const char *type     = detail::getenv("BOOST_COMPUTE_DEFAULT_DEVICE_TYPE");
0246         const char *platform = detail::getenv("BOOST_COMPUTE_DEFAULT_PLATFORM");
0247         const char *vendor   = detail::getenv("BOOST_COMPUTE_DEFAULT_VENDOR");
0248         const char *enforce  = detail::getenv("BOOST_COMPUTE_DEFAULT_ENFORCE");
0249 
0250         if(name || type || platform || vendor){
0251             for(size_t i = 0; i < devices_.size(); i++){
0252                 const device& device = devices_[i];
0253                 if (name && !matches(device.name(), name))
0254                     continue;
0255 
0256                 if (type && matches(std::string("GPU"), type))
0257                     if (!(device.type() & device::gpu))
0258                         continue;
0259 
0260                 if (type && matches(std::string("CPU"), type))
0261                     if (!(device.type() & device::cpu))
0262                         continue;
0263 
0264                 if (platform && !matches(device.platform().name(), platform))
0265                     continue;
0266 
0267                 if (vendor && !matches(device.vendor(), vendor))
0268                     continue;
0269 
0270                 return device;
0271             }
0272 
0273             if(enforce && enforce[0] == '1')
0274                 BOOST_THROW_EXCEPTION(no_device_found());
0275         }
0276 
0277         // find the first gpu device
0278         for(size_t i = 0; i < devices_.size(); i++){
0279             const device& device = devices_[i];
0280 
0281             if(device.type() & device::gpu){
0282                 return device;
0283             }
0284         }
0285 
0286         // find the first cpu device
0287         for(size_t i = 0; i < devices_.size(); i++){
0288             const device& device = devices_[i];
0289 
0290             if(device.type() & device::cpu){
0291                 return device;
0292             }
0293         }
0294 
0295         // return the first device found
0296         return devices_[0];
0297     }
0298 
0299     /// \internal_
0300     static bool matches(const std::string &str, const std::string &pattern)
0301     {
0302         return str.find(pattern) != std::string::npos;
0303     }
0304 
0305     /// \internal_
0306     static device init_default_device(const device &user_device = device())
0307     {
0308         static device default_device;
0309 
0310 #ifdef BOOST_COMPUTE_THREAD_SAFE
0311     #ifdef BOOST_COMPUTE_USE_CPP11
0312         using namespace std;
0313     #else 
0314         using namespace boost;
0315     #endif 
0316         static atomic<bool> is_init;
0317         static mutex init_mutex;
0318 
0319         bool is_init_value = is_init.load(memory_order_consume);
0320         if (!is_init_value)
0321         {
0322             lock_guard<mutex> lock(init_mutex);
0323             is_init_value = is_init.load(memory_order_consume);
0324             if (!is_init_value)
0325             {
0326                 default_device = user_device.get() ? 
0327                     user_device : find_default_device();
0328 
0329                 is_init.store(true, memory_order_release);
0330             }
0331         }
0332 #else // BOOST_COMPUTE_THREAD_SAFE
0333         if (!default_device.get())
0334         {
0335             default_device = user_device.get() ? 
0336                 user_device : find_default_device();
0337         }
0338 #endif // BOOST_COMPUTE_THREAD_SAFE   
0339         return default_device;
0340     }
0341 
0342     /// \internal_
0343     static context init_default_context(const context &user_context = context())
0344     {
0345         static context default_context;
0346 
0347 #ifdef BOOST_COMPUTE_THREAD_SAFE
0348     #ifdef BOOST_COMPUTE_USE_CPP11
0349         using namespace std;
0350     #else 
0351         using namespace boost;
0352     #endif 
0353         static atomic<bool> is_init;
0354         static mutex init_mutex;
0355 
0356         bool is_init_value = is_init.load(memory_order_consume);
0357         if (!is_init_value)
0358         {
0359             lock_guard<mutex> lock(init_mutex);
0360             is_init_value = is_init.load(memory_order_consume);
0361             if (!is_init_value)
0362             {
0363                 default_context = user_context.get() ? 
0364                     user_context : context(default_device());
0365 
0366                 is_init.store(true, memory_order_release);
0367             }
0368         }
0369 #else // BOOST_COMPUTE_THREAD_SAFE
0370         if (!default_context.get())
0371         {
0372             default_context = user_context.get() ?
0373                 user_context : context(default_device());
0374         }
0375 #endif // BOOST_COMPUTE_THREAD_SAFE
0376         return default_context;
0377     }
0378 
0379     /// \internal_
0380     static void init_default_device_and_context(const command_queue &user_queue)
0381     {
0382         device user_device = user_queue.get_device();
0383         context user_context = user_queue.get_context();
0384 
0385         if ( (user_device != init_default_device(user_device)) ||
0386              (user_context != init_default_context(user_context)) )
0387         {
0388             // Try invoking default_queue() before anything else
0389             BOOST_THROW_EXCEPTION(set_default_queue_error());  
0390         }
0391     }
0392     
0393     /// \internal_
0394     static command_queue& init_default_queue(const command_queue &user_queue = command_queue())
0395     {
0396         static command_queue default_queue;
0397 
0398 #ifdef BOOST_COMPUTE_THREAD_SAFE
0399     #ifdef BOOST_COMPUTE_USE_CPP11
0400         using namespace std;
0401     #else 
0402         using namespace boost;
0403     #endif 
0404         static atomic<bool> is_init;
0405         static mutex init_mutex;
0406 
0407         bool is_init_value = is_init.load(memory_order_consume);
0408         if (!is_init_value)
0409         {
0410             lock_guard<mutex> lock(init_mutex);
0411             is_init_value = is_init.load(memory_order_consume);
0412             if (!is_init_value)
0413             {
0414                 if (user_queue.get())
0415                     init_default_device_and_context(user_queue);
0416 
0417                 default_queue = user_queue.get() ? 
0418                     user_queue : 
0419                     command_queue(default_context(), default_device());
0420 
0421                 is_init.store(true, memory_order_release);
0422             }
0423         }
0424 #else // BOOST_COMPUTE_THREAD_SAFE
0425         if (!default_queue.get())
0426         {
0427             if (user_queue.get())
0428                 init_default_device_and_context(user_queue);
0429 
0430             default_queue = user_queue.get() ? 
0431                 user_queue :
0432                 command_queue(default_context(), default_device());
0433         }
0434 #endif // BOOST_COMPUTE_THREAD_SAFE
0435         else
0436         {
0437             BOOST_ASSERT_MSG(user_queue.get() == 0, 
0438                 "Default command queue has already been set.");
0439         }
0440         return default_queue;
0441     }
0442 };
0443 
0444 } // end compute namespace
0445 } // end boost namespace
0446 
0447 #endif // BOOST_COMPUTE_SYSTEM_HPP