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(BOOST_COMPUTE_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. event()94 event() 95 : m_event(0) 96 { 97 } 98 event(cl_event event,bool retain=true)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. event(const event & 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. operator =(const event & other)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. event(event && 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. operator =(event && other)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. ~event()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. get() const167 cl_event& get() const 168 { 169 return const_cast<cl_event &>(m_event); 170 } 171 172 /// Returns the status of the event. status() const173 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. get_command_type() const179 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> get_info(cl_event_info info) const188 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> get_profiling_info(cl_profiling_info info) const204 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. wait() const213 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(BOOST_COMPUTE_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} set_callback(void (BOOST_COMPUTE_CL_CALLBACK * callback)(cl_event event,cl_int status,void * user_data),cl_int status=CL_COMPLETE,void * user_data=0)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> set_callback(Function callback,cl_int status=CL_COMPLETE)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 // BOOST_COMPUTE_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> duration(cl_profiling_info start=CL_PROFILING_COMMAND_START,cl_profiling_info end=CL_PROFILING_COMMAND_END) const269 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. operator ==(const event & other) const279 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. operator !=(const event & other) const285 bool operator!=(const event &other) const 286 { 287 return m_event != other.m_event; 288 } 289 290 /// \internal_ operator cl_event() const291 operator cl_event() const 292 { 293 return m_event; 294 } 295 296 /// \internal_ (deprecated) get_status() const297 cl_int get_status() const 298 { 299 return status(); 300 } 301 302 private: 303 #ifdef BOOST_COMPUTE_CL_VERSION_1_1 304 /// \internal_ 305 static void BOOST_COMPUTE_CL_CALLBACK event_callback_invoker(cl_event,cl_int,void * user_data)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 // BOOST_COMPUTE_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 BOOST_COMPUTE_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 339