event.hpp 10 KB

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