281 lines
9.0 KiB
C++
281 lines
9.0 KiB
C++
|
//---------------------------------------------------------------------------//
|
||
|
// 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")
|
||
|
///
|
||
|
/// 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");
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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
|