]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | //---------------------------------------------------------------------------// |
2 | // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0 | |
5 | // See accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt | |
7 | // | |
8 | // See http://boostorg.github.com/compute for more information. | |
9 | //---------------------------------------------------------------------------// | |
10 | ||
11 | #ifndef BOOST_COMPUTE_SYSTEM_HPP | |
12 | #define BOOST_COMPUTE_SYSTEM_HPP | |
13 | ||
14 | #include <string> | |
15 | #include <vector> | |
16 | #include <cstdlib> | |
17 | ||
18 | #include <boost/throw_exception.hpp> | |
19 | ||
20 | #include <boost/compute/cl.hpp> | |
21 | #include <boost/compute/device.hpp> | |
22 | #include <boost/compute/context.hpp> | |
23 | #include <boost/compute/platform.hpp> | |
24 | #include <boost/compute/command_queue.hpp> | |
25 | #include <boost/compute/detail/getenv.hpp> | |
26 | #include <boost/compute/exception/no_device_found.hpp> | |
27 | ||
28 | namespace boost { | |
29 | namespace compute { | |
30 | ||
31 | /// \class system | |
32 | /// \brief Provides access to platforms and devices on the system. | |
33 | /// | |
34 | /// The system class contains a set of static functions which provide access to | |
35 | /// the OpenCL platforms and compute devices on the host system. | |
36 | /// | |
37 | /// The default_device() convenience method automatically selects and returns | |
38 | /// the "best" compute device for the system following a set of heuristics and | |
39 | /// environment variables. This simplifies setup of the OpenCL enviornment. | |
40 | /// | |
41 | /// \see platform, device, context | |
42 | class system | |
43 | { | |
44 | public: | |
45 | /// Returns the default compute device for the system. | |
46 | /// | |
47 | /// The default device is selected based on a set of heuristics and can be | |
48 | /// influenced using one of the following environment variables: | |
49 | /// | |
50 | /// \li \c BOOST_COMPUTE_DEFAULT_DEVICE - | |
51 | /// name of the compute device (e.g. "GTX TITAN") | |
52 | /// \li \c BOOST_COMPUTE_DEFAULT_DEVICE_TYPE | |
53 | /// type of the compute device (e.g. "GPU" or "CPU") | |
54 | /// \li \c BOOST_COMPUTE_DEFAULT_PLATFORM - | |
55 | /// name of the platform (e.g. "NVIDIA CUDA") | |
56 | /// \li \c BOOST_COMPUTE_DEFAULT_VENDOR - | |
57 | /// name of the device vendor (e.g. "NVIDIA") | |
58 | /// | |
59 | /// The default device is determined once on the first time this function | |
60 | /// is called. Calling this function multiple times will always result in | |
61 | /// the same device being returned. | |
62 | /// | |
63 | /// If no OpenCL device is found on the system, a no_device_found exception | |
64 | /// is thrown. | |
65 | /// | |
66 | /// For example, to print the name of the default compute device on the | |
67 | /// system: | |
68 | /// \code | |
69 | /// // get the default compute device | |
70 | /// boost::compute::device device = boost::compute::system::default_device(); | |
71 | /// | |
72 | /// // print the name of the device | |
73 | /// std::cout << "default device: " << device.name() << std::endl; | |
74 | /// \endcode | |
75 | static device default_device() | |
76 | { | |
77 | static device default_device = find_default_device(); | |
78 | ||
79 | return default_device; | |
80 | } | |
81 | ||
82 | /// Returns the device with \p name. | |
83 | /// | |
84 | /// \throws no_device_found if no device with \p name is found. | |
85 | static device find_device(const std::string &name) | |
86 | { | |
87 | const std::vector<device> devices = system::devices(); | |
88 | for(size_t i = 0; i < devices.size(); i++){ | |
89 | const device& device = devices[i]; | |
90 | ||
91 | if(device.name() == name){ | |
92 | return device; | |
93 | } | |
94 | } | |
95 | ||
96 | BOOST_THROW_EXCEPTION(no_device_found()); | |
97 | } | |
98 | ||
99 | /// Returns a vector containing all of the compute devices on | |
100 | /// the system. | |
101 | /// | |
102 | /// For example, to print out the name of each OpenCL-capable device | |
103 | /// available on the system: | |
104 | /// \code | |
105 | /// for(const auto &device : boost::compute::system::devices()){ | |
106 | /// std::cout << device.name() << std::endl; | |
107 | /// } | |
108 | /// \endcode | |
109 | static std::vector<device> devices() | |
110 | { | |
111 | std::vector<device> devices; | |
112 | ||
113 | const std::vector<platform> platforms = system::platforms(); | |
114 | for(size_t i = 0; i < platforms.size(); i++){ | |
115 | const std::vector<device> platform_devices = platforms[i].devices(); | |
116 | ||
117 | devices.insert( | |
118 | devices.end(), platform_devices.begin(), platform_devices.end() | |
119 | ); | |
120 | } | |
121 | ||
122 | return devices; | |
123 | } | |
124 | ||
125 | /// Returns the number of compute devices on the system. | |
126 | static size_t device_count() | |
127 | { | |
128 | size_t count = 0; | |
129 | ||
130 | const std::vector<platform> platforms = system::platforms(); | |
131 | for(size_t i = 0; i < platforms.size(); i++){ | |
132 | count += platforms[i].device_count(); | |
133 | } | |
134 | ||
135 | return count; | |
136 | } | |
137 | ||
138 | /// Returns the default context for the system. | |
139 | /// | |
140 | /// The default context is created for the default device on the system | |
141 | /// (as returned by default_device()). | |
142 | /// | |
143 | /// The default context is created once on the first time this function is | |
144 | /// called. Calling this function multiple times will always result in the | |
145 | /// same context object being returned. | |
146 | static context default_context() | |
147 | { | |
148 | static context default_context(default_device()); | |
149 | ||
150 | return default_context; | |
151 | } | |
152 | ||
153 | /// Returns the default command queue for the system. | |
154 | static command_queue& default_queue() | |
155 | { | |
156 | static command_queue queue(default_context(), default_device()); | |
157 | ||
158 | return queue; | |
159 | } | |
160 | ||
161 | /// Blocks until all outstanding computations on the default | |
162 | /// command queue are complete. | |
163 | /// | |
164 | /// This is equivalent to: | |
165 | /// \code | |
166 | /// system::default_queue().finish(); | |
167 | /// \endcode | |
168 | static void finish() | |
169 | { | |
170 | default_queue().finish(); | |
171 | } | |
172 | ||
173 | /// Returns a vector containing each of the OpenCL platforms on the system. | |
174 | /// | |
175 | /// For example, to print out the name of each OpenCL platform present on | |
176 | /// the system: | |
177 | /// \code | |
178 | /// for(const auto &platform : boost::compute::system::platforms()){ | |
179 | /// std::cout << platform.name() << std::endl; | |
180 | /// } | |
181 | /// \endcode | |
182 | static std::vector<platform> platforms() | |
183 | { | |
184 | cl_uint count = 0; | |
185 | clGetPlatformIDs(0, 0, &count); | |
186 | ||
187 | std::vector<platform> platforms; | |
188 | if(count > 0) | |
189 | { | |
190 | std::vector<cl_platform_id> platform_ids(count); | |
191 | clGetPlatformIDs(count, &platform_ids[0], 0); | |
192 | ||
193 | for(size_t i = 0; i < platform_ids.size(); i++){ | |
194 | platforms.push_back(platform(platform_ids[i])); | |
195 | } | |
196 | } | |
197 | return platforms; | |
198 | } | |
199 | ||
200 | /// Returns the number of compute platforms on the system. | |
201 | static size_t platform_count() | |
202 | { | |
203 | cl_uint count = 0; | |
204 | clGetPlatformIDs(0, 0, &count); | |
205 | return static_cast<size_t>(count); | |
206 | } | |
207 | ||
208 | private: | |
209 | /// \internal_ | |
210 | static device find_default_device() | |
211 | { | |
212 | // get a list of all devices on the system | |
213 | const std::vector<device> devices_ = devices(); | |
214 | if(devices_.empty()){ | |
215 | BOOST_THROW_EXCEPTION(no_device_found()); | |
216 | } | |
217 | ||
218 | // check for device from environment variable | |
219 | const char *name = detail::getenv("BOOST_COMPUTE_DEFAULT_DEVICE"); | |
220 | const char *type = detail::getenv("BOOST_COMPUTE_DEFAULT_DEVICE_TYPE"); | |
221 | const char *platform = detail::getenv("BOOST_COMPUTE_DEFAULT_PLATFORM"); | |
222 | const char *vendor = detail::getenv("BOOST_COMPUTE_DEFAULT_VENDOR"); | |
223 | ||
224 | if(name || type || platform || vendor){ | |
225 | for(size_t i = 0; i < devices_.size(); i++){ | |
226 | const device& device = devices_[i]; | |
227 | if (name && !matches(device.name(), name)) | |
228 | continue; | |
229 | ||
230 | if (type && matches(std::string("GPU"), type)) | |
231 | if (!(device.type() & device::gpu)) | |
232 | continue; | |
233 | ||
234 | if (type && matches(std::string("CPU"), type)) | |
235 | if (!(device.type() & device::cpu)) | |
236 | continue; | |
237 | ||
238 | if (platform && !matches(device.platform().name(), platform)) | |
239 | continue; | |
240 | ||
241 | if (vendor && !matches(device.vendor(), vendor)) | |
242 | continue; | |
243 | ||
244 | return device; | |
245 | } | |
246 | } | |
247 | ||
248 | // find the first gpu device | |
249 | for(size_t i = 0; i < devices_.size(); i++){ | |
250 | const device& device = devices_[i]; | |
251 | ||
252 | if(device.type() & device::gpu){ | |
253 | return device; | |
254 | } | |
255 | } | |
256 | ||
257 | // find the first cpu device | |
258 | for(size_t i = 0; i < devices_.size(); i++){ | |
259 | const device& device = devices_[i]; | |
260 | ||
261 | if(device.type() & device::cpu){ | |
262 | return device; | |
263 | } | |
264 | } | |
265 | ||
266 | // return the first device found | |
267 | return devices_[0]; | |
268 | } | |
269 | ||
270 | /// \internal_ | |
271 | static bool matches(const std::string &str, const std::string &pattern) | |
272 | { | |
273 | return str.find(pattern) != std::string::npos; | |
274 | } | |
275 | }; | |
276 | ||
277 | } // end compute namespace | |
278 | } // end boost namespace | |
279 | ||
280 | #endif // BOOST_COMPUTE_SYSTEM_HPP |