You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
9.2 KiB
288 lines
9.2 KiB
//---------------------------------------------------------------------------// |
|
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> |
|
// |
|
// Distributed under the Boost Software License, Version 1.0 |
|
// See accompanying file LICENSE_1_0.txt or copy at |
|
// http://www.boost.org/LICENSE_1_0.txt |
|
// |
|
// See http://boostorg.github.com/compute for more information. |
|
//---------------------------------------------------------------------------// |
|
|
|
#ifndef BOOST_COMPUTE_SYSTEM_HPP |
|
#define BOOST_COMPUTE_SYSTEM_HPP |
|
|
|
#include <string> |
|
#include <vector> |
|
#include <cstdlib> |
|
|
|
#include <boost/throw_exception.hpp> |
|
|
|
#include <boost/compute/cl.hpp> |
|
#include <boost/compute/device.hpp> |
|
#include <boost/compute/context.hpp> |
|
#include <boost/compute/platform.hpp> |
|
#include <boost/compute/command_queue.hpp> |
|
#include <boost/compute/detail/getenv.hpp> |
|
#include <boost/compute/exception/no_device_found.hpp> |
|
|
|
namespace boost { |
|
namespace compute { |
|
|
|
/// \class system |
|
/// \brief Provides access to platforms and devices on the system. |
|
/// |
|
/// The system class contains a set of static functions which provide access to |
|
/// the OpenCL platforms and compute devices on the host system. |
|
/// |
|
/// The default_device() convenience method automatically selects and returns |
|
/// the "best" compute device for the system following a set of heuristics and |
|
/// environment variables. This simplifies setup of the OpenCL enviornment. |
|
/// |
|
/// \see platform, device, context |
|
class system |
|
{ |
|
public: |
|
/// Returns the default compute device for the system. |
|
/// |
|
/// The default device is selected based on a set of heuristics and can be |
|
/// influenced using one of the following environment variables: |
|
/// |
|
/// \li \c BOOST_COMPUTE_DEFAULT_DEVICE - |
|
/// name of the compute device (e.g. "GTX TITAN") |
|
/// \li \c BOOST_COMPUTE_DEFAULT_DEVICE_TYPE |
|
/// type of the compute device (e.g. "GPU" or "CPU") |
|
/// \li \c BOOST_COMPUTE_DEFAULT_PLATFORM - |
|
/// name of the platform (e.g. "NVIDIA CUDA") |
|
/// \li \c BOOST_COMPUTE_DEFAULT_VENDOR - |
|
/// name of the device vendor (e.g. "NVIDIA") |
|
/// \li \c BOOST_COMPUTE_DEFAULT_ENFORCE - |
|
/// If this is set to "1", then throw a no_device_found() exception |
|
/// if any of the above environment variables is set, but a matching |
|
/// device was not found. |
|
/// |
|
/// The default device is determined once on the first time this function |
|
/// is called. Calling this function multiple times will always result in |
|
/// the same device being returned. |
|
/// |
|
/// If no OpenCL device is found on the system, a no_device_found exception |
|
/// is thrown. |
|
/// |
|
/// For example, to print the name of the default compute device on the |
|
/// system: |
|
/// \code |
|
/// // get the default compute device |
|
/// boost::compute::device device = boost::compute::system::default_device(); |
|
/// |
|
/// // print the name of the device |
|
/// std::cout << "default device: " << device.name() << std::endl; |
|
/// \endcode |
|
static device default_device() |
|
{ |
|
static device default_device = find_default_device(); |
|
|
|
return default_device; |
|
} |
|
|
|
/// Returns the device with \p name. |
|
/// |
|
/// \throws no_device_found if no device with \p name is found. |
|
static device find_device(const std::string &name) |
|
{ |
|
const std::vector<device> devices = system::devices(); |
|
for(size_t i = 0; i < devices.size(); i++){ |
|
const device& device = devices[i]; |
|
|
|
if(device.name() == name){ |
|
return device; |
|
} |
|
} |
|
|
|
BOOST_THROW_EXCEPTION(no_device_found()); |
|
} |
|
|
|
/// Returns a vector containing all of the compute devices on |
|
/// the system. |
|
/// |
|
/// For example, to print out the name of each OpenCL-capable device |
|
/// available on the system: |
|
/// \code |
|
/// for(const auto &device : boost::compute::system::devices()){ |
|
/// std::cout << device.name() << std::endl; |
|
/// } |
|
/// \endcode |
|
static std::vector<device> devices() |
|
{ |
|
std::vector<device> devices; |
|
|
|
const std::vector<platform> platforms = system::platforms(); |
|
for(size_t i = 0; i < platforms.size(); i++){ |
|
const std::vector<device> platform_devices = platforms[i].devices(); |
|
|
|
devices.insert( |
|
devices.end(), platform_devices.begin(), platform_devices.end() |
|
); |
|
} |
|
|
|
return devices; |
|
} |
|
|
|
/// Returns the number of compute devices on the system. |
|
static size_t device_count() |
|
{ |
|
size_t count = 0; |
|
|
|
const std::vector<platform> platforms = system::platforms(); |
|
for(size_t i = 0; i < platforms.size(); i++){ |
|
count += platforms[i].device_count(); |
|
} |
|
|
|
return count; |
|
} |
|
|
|
/// Returns the default context for the system. |
|
/// |
|
/// The default context is created for the default device on the system |
|
/// (as returned by default_device()). |
|
/// |
|
/// The default context is created once on the first time this function is |
|
/// called. Calling this function multiple times will always result in the |
|
/// same context object being returned. |
|
static context default_context() |
|
{ |
|
static context default_context(default_device()); |
|
|
|
return default_context; |
|
} |
|
|
|
/// Returns the default command queue for the system. |
|
static command_queue& default_queue() |
|
{ |
|
static command_queue queue(default_context(), default_device()); |
|
|
|
return queue; |
|
} |
|
|
|
/// Blocks until all outstanding computations on the default |
|
/// command queue are complete. |
|
/// |
|
/// This is equivalent to: |
|
/// \code |
|
/// system::default_queue().finish(); |
|
/// \endcode |
|
static void finish() |
|
{ |
|
default_queue().finish(); |
|
} |
|
|
|
/// Returns a vector containing each of the OpenCL platforms on the system. |
|
/// |
|
/// For example, to print out the name of each OpenCL platform present on |
|
/// the system: |
|
/// \code |
|
/// for(const auto &platform : boost::compute::system::platforms()){ |
|
/// std::cout << platform.name() << std::endl; |
|
/// } |
|
/// \endcode |
|
static std::vector<platform> platforms() |
|
{ |
|
cl_uint count = 0; |
|
clGetPlatformIDs(0, 0, &count); |
|
|
|
std::vector<platform> platforms; |
|
if(count > 0) |
|
{ |
|
std::vector<cl_platform_id> platform_ids(count); |
|
clGetPlatformIDs(count, &platform_ids[0], 0); |
|
|
|
for(size_t i = 0; i < platform_ids.size(); i++){ |
|
platforms.push_back(platform(platform_ids[i])); |
|
} |
|
} |
|
return platforms; |
|
} |
|
|
|
/// Returns the number of compute platforms on the system. |
|
static size_t platform_count() |
|
{ |
|
cl_uint count = 0; |
|
clGetPlatformIDs(0, 0, &count); |
|
return static_cast<size_t>(count); |
|
} |
|
|
|
private: |
|
/// \internal_ |
|
static device find_default_device() |
|
{ |
|
// get a list of all devices on the system |
|
const std::vector<device> devices_ = devices(); |
|
if(devices_.empty()){ |
|
BOOST_THROW_EXCEPTION(no_device_found()); |
|
} |
|
|
|
// check for device from environment variable |
|
const char *name = detail::getenv("BOOST_COMPUTE_DEFAULT_DEVICE"); |
|
const char *type = detail::getenv("BOOST_COMPUTE_DEFAULT_DEVICE_TYPE"); |
|
const char *platform = detail::getenv("BOOST_COMPUTE_DEFAULT_PLATFORM"); |
|
const char *vendor = detail::getenv("BOOST_COMPUTE_DEFAULT_VENDOR"); |
|
const char *enforce = detail::getenv("BOOST_COMPUTE_DEFAULT_ENFORCE"); |
|
|
|
if(name || type || platform || vendor){ |
|
for(size_t i = 0; i < devices_.size(); i++){ |
|
const device& device = devices_[i]; |
|
if (name && !matches(device.name(), name)) |
|
continue; |
|
|
|
if (type && matches(std::string("GPU"), type)) |
|
if (!(device.type() & device::gpu)) |
|
continue; |
|
|
|
if (type && matches(std::string("CPU"), type)) |
|
if (!(device.type() & device::cpu)) |
|
continue; |
|
|
|
if (platform && !matches(device.platform().name(), platform)) |
|
continue; |
|
|
|
if (vendor && !matches(device.vendor(), vendor)) |
|
continue; |
|
|
|
return device; |
|
} |
|
|
|
if(enforce && enforce[0] == '1') |
|
BOOST_THROW_EXCEPTION(no_device_found()); |
|
} |
|
|
|
// find the first gpu device |
|
for(size_t i = 0; i < devices_.size(); i++){ |
|
const device& device = devices_[i]; |
|
|
|
if(device.type() & device::gpu){ |
|
return device; |
|
} |
|
} |
|
|
|
// find the first cpu device |
|
for(size_t i = 0; i < devices_.size(); i++){ |
|
const device& device = devices_[i]; |
|
|
|
if(device.type() & device::cpu){ |
|
return device; |
|
} |
|
} |
|
|
|
// return the first device found |
|
return devices_[0]; |
|
} |
|
|
|
/// \internal_ |
|
static bool matches(const std::string &str, const std::string &pattern) |
|
{ |
|
return str.find(pattern) != std::string::npos; |
|
} |
|
}; |
|
|
|
} // end compute namespace |
|
} // end boost namespace |
|
|
|
#endif // BOOST_COMPUTE_SYSTEM_HPP
|
|
|