]>
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_EVENT_HPP | |
12 | #define BOOST_COMPUTE_EVENT_HPP | |
13 | ||
14 | #include <boost/function.hpp> | |
15 | ||
16 | #include <boost/compute/config.hpp> | |
17 | #include <boost/compute/exception.hpp> | |
18 | #include <boost/compute/detail/duration.hpp> | |
19 | #include <boost/compute/detail/get_object_info.hpp> | |
20 | #include <boost/compute/detail/assert_cl_success.hpp> | |
21 | #include <boost/compute/types/fundamental.hpp> | |
22 | ||
23 | namespace boost { | |
24 | namespace compute { | |
25 | ||
26 | /// \class event | |
27 | /// \brief An event corresponding to an operation on a compute device | |
28 | /// | |
29 | /// Event objects are used to track operations running on the device (such as | |
30 | /// kernel executions and memory transfers). Event objects are returned by the | |
31 | /// various \c enqueue_* methods of the command_queue class. | |
32 | /// | |
33 | /// Events can be used to synchronize operations between the host and the | |
34 | /// device. The \c wait() method will block execution on the host until the | |
35 | /// operation corresponding to the event on the device has completed. The | |
36 | /// status of the operation can also be polled with the \c status() method. | |
37 | /// | |
38 | /// Event objects can also be used for performance profiling. In order to use | |
39 | /// events for profiling, the command queue must be constructed with the | |
40 | /// \c CL_QUEUE_PROFILING_ENABLE flag. Then the \c duration() method can be | |
41 | /// used to retrieve the total duration of the operation on the device: | |
42 | /// \code | |
43 | /// std::cout << "time = " << e.duration<std::chrono::milliseconds>().count() << "ms\n"; | |
44 | /// \endcode | |
45 | /// | |
46 | /// \see \ref future "future<T>", wait_list | |
47 | class event | |
48 | { | |
49 | public: | |
50 | /// \internal_ | |
51 | enum execution_status { | |
52 | complete = CL_COMPLETE, | |
53 | running = CL_RUNNING, | |
54 | submitted = CL_SUBMITTED, | |
55 | queued = CL_QUEUED | |
56 | }; | |
57 | ||
58 | /// \internal_ | |
59 | enum command_type { | |
60 | ndrange_kernel = CL_COMMAND_NDRANGE_KERNEL, | |
61 | task = CL_COMMAND_TASK, | |
62 | native_kernel = CL_COMMAND_NATIVE_KERNEL, | |
63 | read_buffer = CL_COMMAND_READ_BUFFER, | |
64 | write_buffer = CL_COMMAND_WRITE_BUFFER, | |
65 | copy_buffer = CL_COMMAND_COPY_BUFFER, | |
66 | read_image = CL_COMMAND_READ_IMAGE, | |
67 | write_image = CL_COMMAND_WRITE_IMAGE, | |
68 | copy_image = CL_COMMAND_COPY_IMAGE, | |
69 | copy_image_to_buffer = CL_COMMAND_COPY_IMAGE_TO_BUFFER, | |
70 | copy_buffer_to_image = CL_COMMAND_COPY_BUFFER_TO_IMAGE, | |
71 | map_buffer = CL_COMMAND_MAP_BUFFER, | |
72 | map_image = CL_COMMAND_MAP_IMAGE, | |
73 | unmap_mem_object = CL_COMMAND_UNMAP_MEM_OBJECT, | |
74 | marker = CL_COMMAND_MARKER, | |
75 | aquire_gl_objects = CL_COMMAND_ACQUIRE_GL_OBJECTS, | |
76 | release_gl_object = CL_COMMAND_RELEASE_GL_OBJECTS | |
77 | #if defined(CL_VERSION_1_1) | |
78 | , | |
79 | read_buffer_rect = CL_COMMAND_READ_BUFFER_RECT, | |
80 | write_buffer_rect = CL_COMMAND_WRITE_BUFFER_RECT, | |
81 | copy_buffer_rect = CL_COMMAND_COPY_BUFFER_RECT | |
82 | #endif | |
83 | }; | |
84 | ||
85 | /// \internal_ | |
86 | enum profiling_info { | |
87 | profiling_command_queued = CL_PROFILING_COMMAND_QUEUED, | |
88 | profiling_command_submit = CL_PROFILING_COMMAND_SUBMIT, | |
89 | profiling_command_start = CL_PROFILING_COMMAND_START, | |
90 | profiling_command_end = CL_PROFILING_COMMAND_END | |
91 | }; | |
92 | ||
93 | /// Creates a null event object. | |
94 | event() | |
95 | : m_event(0) | |
96 | { | |
97 | } | |
98 | ||
99 | explicit event(cl_event event, bool retain = true) | |
100 | : m_event(event) | |
101 | { | |
102 | if(m_event && retain){ | |
103 | clRetainEvent(event); | |
104 | } | |
105 | } | |
106 | ||
107 | /// Makes a new event as a copy of \p other. | |
108 | event(const event &other) | |
109 | : m_event(other.m_event) | |
110 | { | |
111 | if(m_event){ | |
112 | clRetainEvent(m_event); | |
113 | } | |
114 | } | |
115 | ||
116 | /// Copies the event object from \p other to \c *this. | |
117 | event& operator=(const event &other) | |
118 | { | |
119 | if(this != &other){ | |
120 | if(m_event){ | |
121 | clReleaseEvent(m_event); | |
122 | } | |
123 | ||
124 | m_event = other.m_event; | |
125 | ||
126 | if(m_event){ | |
127 | clRetainEvent(m_event); | |
128 | } | |
129 | } | |
130 | ||
131 | return *this; | |
132 | } | |
133 | ||
134 | #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES | |
135 | /// Move-constructs a new event object from \p other. | |
136 | event(event&& other) BOOST_NOEXCEPT | |
137 | : m_event(other.m_event) | |
138 | { | |
139 | other.m_event = 0; | |
140 | } | |
141 | ||
142 | /// Move-assigns the event from \p other to \c *this. | |
143 | event& operator=(event&& other) BOOST_NOEXCEPT | |
144 | { | |
145 | if(m_event){ | |
146 | clReleaseEvent(m_event); | |
147 | } | |
148 | ||
149 | m_event = other.m_event; | |
150 | other.m_event = 0; | |
151 | ||
152 | return *this; | |
153 | } | |
154 | #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES | |
155 | ||
156 | /// Destroys the event object. | |
157 | ~event() | |
158 | { | |
159 | if(m_event){ | |
160 | BOOST_COMPUTE_ASSERT_CL_SUCCESS( | |
161 | clReleaseEvent(m_event) | |
162 | ); | |
163 | } | |
164 | } | |
165 | ||
166 | /// Returns a reference to the underlying OpenCL event object. | |
167 | cl_event& get() const | |
168 | { | |
169 | return const_cast<cl_event &>(m_event); | |
170 | } | |
171 | ||
172 | /// Returns the status of the event. | |
173 | cl_int status() const | |
174 | { | |
175 | return get_info<cl_int>(CL_EVENT_COMMAND_EXECUTION_STATUS); | |
176 | } | |
177 | ||
178 | /// Returns the command type for the event. | |
179 | cl_command_type get_command_type() const | |
180 | { | |
181 | return get_info<cl_command_type>(CL_EVENT_COMMAND_TYPE); | |
182 | } | |
183 | ||
184 | /// Returns information about the event. | |
185 | /// | |
186 | /// \see_opencl_ref{clGetEventInfo} | |
187 | template<class T> | |
188 | T get_info(cl_event_info info) const | |
189 | { | |
190 | return detail::get_object_info<T>(clGetEventInfo, m_event, info); | |
191 | } | |
192 | ||
193 | /// \overload | |
194 | template<int Enum> | |
195 | typename detail::get_object_info_type<event, Enum>::type | |
196 | get_info() const; | |
197 | ||
198 | /// Returns profiling information for the event. | |
199 | /// | |
200 | /// \see event::duration() | |
201 | /// | |
202 | /// \see_opencl_ref{clGetEventProfilingInfo} | |
203 | template<class T> | |
204 | T get_profiling_info(cl_profiling_info info) const | |
205 | { | |
206 | return detail::get_object_info<T>(clGetEventProfilingInfo, | |
207 | m_event, | |
208 | info); | |
209 | } | |
210 | ||
211 | /// Blocks until the actions corresponding to the event have | |
212 | /// completed. | |
213 | void wait() const | |
214 | { | |
215 | cl_int ret = clWaitForEvents(1, &m_event); | |
216 | if(ret != CL_SUCCESS){ | |
217 | BOOST_THROW_EXCEPTION(opencl_error(ret)); | |
218 | } | |
219 | } | |
220 | ||
221 | #if defined(CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED) | |
222 | /// Registers a function to be called when the event status changes to | |
223 | /// \p status (by default CL_COMPLETE). The callback is passed the OpenCL | |
224 | /// event object, the event status, and a pointer to arbitrary user data. | |
225 | /// | |
226 | /// \see_opencl_ref{clSetEventCallback} | |
227 | /// | |
228 | /// \opencl_version_warning{1,1} | |
229 | void set_callback(void (BOOST_COMPUTE_CL_CALLBACK *callback)( | |
230 | cl_event event, cl_int status, void *user_data | |
231 | ), | |
232 | cl_int status = CL_COMPLETE, | |
233 | void *user_data = 0) | |
234 | { | |
235 | cl_int ret = clSetEventCallback(m_event, status, callback, user_data); | |
236 | if(ret != CL_SUCCESS){ | |
237 | BOOST_THROW_EXCEPTION(opencl_error(ret)); | |
238 | } | |
239 | } | |
240 | ||
241 | /// Registers a generic function to be called when the event status | |
242 | /// changes to \p status (by default \c CL_COMPLETE). | |
243 | /// | |
244 | /// The function specified by \p callback must be invokable with zero | |
245 | /// arguments (e.g. \c callback()). | |
246 | /// | |
247 | /// \opencl_version_warning{1,1} | |
248 | template<class Function> | |
249 | void set_callback(Function callback, cl_int status = CL_COMPLETE) | |
250 | { | |
251 | set_callback( | |
252 | event_callback_invoker, | |
253 | status, | |
254 | new boost::function<void()>(callback) | |
255 | ); | |
256 | } | |
257 | #endif // CL_VERSION_1_1 | |
258 | ||
259 | /// Returns the total duration of the event from \p start to \p end. | |
260 | /// | |
261 | /// For example, to print the number of milliseconds the event took to | |
262 | /// execute: | |
263 | /// \code | |
264 | /// std::cout << event.duration<std::chrono::milliseconds>().count() << " ms" << std::endl; | |
265 | /// \endcode | |
266 | /// | |
267 | /// \see event::get_profiling_info() | |
268 | template<class Duration> | |
269 | Duration duration(cl_profiling_info start = CL_PROFILING_COMMAND_START, | |
270 | cl_profiling_info end = CL_PROFILING_COMMAND_END) const | |
271 | { | |
272 | const ulong_ nanoseconds = | |
273 | get_profiling_info<ulong_>(end) - get_profiling_info<ulong_>(start); | |
274 | ||
275 | return detail::make_duration_from_nanoseconds(Duration(), nanoseconds); | |
276 | } | |
277 | ||
278 | /// Returns \c true if the event is the same as \p other. | |
279 | bool operator==(const event &other) const | |
280 | { | |
281 | return m_event == other.m_event; | |
282 | } | |
283 | ||
284 | /// Returns \c true if the event is different from \p other. | |
285 | bool operator!=(const event &other) const | |
286 | { | |
287 | return m_event != other.m_event; | |
288 | } | |
289 | ||
290 | /// \internal_ | |
291 | operator cl_event() const | |
292 | { | |
293 | return m_event; | |
294 | } | |
295 | ||
296 | /// \internal_ (deprecated) | |
297 | cl_int get_status() const | |
298 | { | |
299 | return status(); | |
300 | } | |
301 | ||
302 | private: | |
303 | #ifdef CL_VERSION_1_1 | |
304 | /// \internal_ | |
305 | static void BOOST_COMPUTE_CL_CALLBACK | |
306 | event_callback_invoker(cl_event, cl_int, void *user_data) | |
307 | { | |
308 | boost::function<void()> *callback = | |
309 | static_cast<boost::function<void()> *>(user_data); | |
310 | ||
311 | (*callback)(); | |
312 | ||
313 | delete callback; | |
314 | } | |
315 | #endif // CL_VERSION_1_1 | |
316 | ||
317 | protected: | |
318 | cl_event m_event; | |
319 | }; | |
320 | ||
321 | /// \internal_ define get_info() specializations for event | |
322 | BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(event, | |
323 | ((cl_command_queue, CL_EVENT_COMMAND_QUEUE)) | |
324 | ((cl_command_type, CL_EVENT_COMMAND_TYPE)) | |
325 | ((cl_int, CL_EVENT_COMMAND_EXECUTION_STATUS)) | |
326 | ((cl_uint, CL_EVENT_REFERENCE_COUNT)) | |
327 | ) | |
328 | ||
329 | #ifdef CL_VERSION_1_1 | |
330 | BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(event, | |
331 | ((cl_context, CL_EVENT_CONTEXT)) | |
332 | ) | |
333 | #endif | |
334 | ||
335 | } // end compute namespace | |
336 | } // end boost namespace | |
337 | ||
338 | #endif // BOOST_COMPUTE_EVENT_HPP |