summaryrefslogtreecommitdiff
path: root/boost/compute/event.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/compute/event.hpp')
-rw-r--r--boost/compute/event.hpp338
1 files changed, 338 insertions, 0 deletions
diff --git a/boost/compute/event.hpp b/boost/compute/event.hpp
new file mode 100644
index 0000000000..2f53d87650
--- /dev/null
+++ b/boost/compute/event.hpp
@@ -0,0 +1,338 @@
+//---------------------------------------------------------------------------//
+// 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_EVENT_HPP
+#define BOOST_COMPUTE_EVENT_HPP
+
+#include <boost/function.hpp>
+
+#include <boost/compute/config.hpp>
+#include <boost/compute/exception.hpp>
+#include <boost/compute/detail/duration.hpp>
+#include <boost/compute/detail/get_object_info.hpp>
+#include <boost/compute/detail/assert_cl_success.hpp>
+#include <boost/compute/types/fundamental.hpp>
+
+namespace boost {
+namespace compute {
+
+/// \class event
+/// \brief An event corresponding to an operation on a compute device
+///
+/// Event objects are used to track operations running on the device (such as
+/// kernel executions and memory transfers). Event objects are returned by the
+/// various \c enqueue_* methods of the command_queue class.
+///
+/// Events can be used to synchronize operations between the host and the
+/// device. The \c wait() method will block execution on the host until the
+/// operation corresponding to the event on the device has completed. The
+/// status of the operation can also be polled with the \c status() method.
+///
+/// Event objects can also be used for performance profiling. In order to use
+/// events for profiling, the command queue must be constructed with the
+/// \c CL_QUEUE_PROFILING_ENABLE flag. Then the \c duration() method can be
+/// used to retrieve the total duration of the operation on the device:
+/// \code
+/// std::cout << "time = " << e.duration<std::chrono::milliseconds>().count() << "ms\n";
+/// \endcode
+///
+/// \see \ref future "future<T>", wait_list
+class event
+{
+public:
+ /// \internal_
+ enum execution_status {
+ complete = CL_COMPLETE,
+ running = CL_RUNNING,
+ submitted = CL_SUBMITTED,
+ queued = CL_QUEUED
+ };
+
+ /// \internal_
+ enum command_type {
+ ndrange_kernel = CL_COMMAND_NDRANGE_KERNEL,
+ task = CL_COMMAND_TASK,
+ native_kernel = CL_COMMAND_NATIVE_KERNEL,
+ read_buffer = CL_COMMAND_READ_BUFFER,
+ write_buffer = CL_COMMAND_WRITE_BUFFER,
+ copy_buffer = CL_COMMAND_COPY_BUFFER,
+ read_image = CL_COMMAND_READ_IMAGE,
+ write_image = CL_COMMAND_WRITE_IMAGE,
+ copy_image = CL_COMMAND_COPY_IMAGE,
+ copy_image_to_buffer = CL_COMMAND_COPY_IMAGE_TO_BUFFER,
+ copy_buffer_to_image = CL_COMMAND_COPY_BUFFER_TO_IMAGE,
+ map_buffer = CL_COMMAND_MAP_BUFFER,
+ map_image = CL_COMMAND_MAP_IMAGE,
+ unmap_mem_object = CL_COMMAND_UNMAP_MEM_OBJECT,
+ marker = CL_COMMAND_MARKER,
+ aquire_gl_objects = CL_COMMAND_ACQUIRE_GL_OBJECTS,
+ release_gl_object = CL_COMMAND_RELEASE_GL_OBJECTS
+ #if defined(CL_VERSION_1_1)
+ ,
+ read_buffer_rect = CL_COMMAND_READ_BUFFER_RECT,
+ write_buffer_rect = CL_COMMAND_WRITE_BUFFER_RECT,
+ copy_buffer_rect = CL_COMMAND_COPY_BUFFER_RECT
+ #endif
+ };
+
+ /// \internal_
+ enum profiling_info {
+ profiling_command_queued = CL_PROFILING_COMMAND_QUEUED,
+ profiling_command_submit = CL_PROFILING_COMMAND_SUBMIT,
+ profiling_command_start = CL_PROFILING_COMMAND_START,
+ profiling_command_end = CL_PROFILING_COMMAND_END
+ };
+
+ /// Creates a null event object.
+ event()
+ : m_event(0)
+ {
+ }
+
+ explicit event(cl_event event, bool retain = true)
+ : m_event(event)
+ {
+ if(m_event && retain){
+ clRetainEvent(event);
+ }
+ }
+
+ /// Makes a new event as a copy of \p other.
+ event(const event &other)
+ : m_event(other.m_event)
+ {
+ if(m_event){
+ clRetainEvent(m_event);
+ }
+ }
+
+ /// Copies the event object from \p other to \c *this.
+ event& operator=(const event &other)
+ {
+ if(this != &other){
+ if(m_event){
+ clReleaseEvent(m_event);
+ }
+
+ m_event = other.m_event;
+
+ if(m_event){
+ clRetainEvent(m_event);
+ }
+ }
+
+ return *this;
+ }
+
+ #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
+ /// Move-constructs a new event object from \p other.
+ event(event&& other) BOOST_NOEXCEPT
+ : m_event(other.m_event)
+ {
+ other.m_event = 0;
+ }
+
+ /// Move-assigns the event from \p other to \c *this.
+ event& operator=(event&& other) BOOST_NOEXCEPT
+ {
+ if(m_event){
+ clReleaseEvent(m_event);
+ }
+
+ m_event = other.m_event;
+ other.m_event = 0;
+
+ return *this;
+ }
+ #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
+
+ /// Destroys the event object.
+ ~event()
+ {
+ if(m_event){
+ BOOST_COMPUTE_ASSERT_CL_SUCCESS(
+ clReleaseEvent(m_event)
+ );
+ }
+ }
+
+ /// Returns a reference to the underlying OpenCL event object.
+ cl_event& get() const
+ {
+ return const_cast<cl_event &>(m_event);
+ }
+
+ /// Returns the status of the event.
+ cl_int status() const
+ {
+ return get_info<cl_int>(CL_EVENT_COMMAND_EXECUTION_STATUS);
+ }
+
+ /// Returns the command type for the event.
+ cl_command_type get_command_type() const
+ {
+ return get_info<cl_command_type>(CL_EVENT_COMMAND_TYPE);
+ }
+
+ /// Returns information about the event.
+ ///
+ /// \see_opencl_ref{clGetEventInfo}
+ template<class T>
+ T get_info(cl_event_info info) const
+ {
+ return detail::get_object_info<T>(clGetEventInfo, m_event, info);
+ }
+
+ /// \overload
+ template<int Enum>
+ typename detail::get_object_info_type<event, Enum>::type
+ get_info() const;
+
+ /// Returns profiling information for the event.
+ ///
+ /// \see event::duration()
+ ///
+ /// \see_opencl_ref{clGetEventProfilingInfo}
+ template<class T>
+ T get_profiling_info(cl_profiling_info info) const
+ {
+ return detail::get_object_info<T>(clGetEventProfilingInfo,
+ m_event,
+ info);
+ }
+
+ /// Blocks until the actions corresponding to the event have
+ /// completed.
+ void wait() const
+ {
+ cl_int ret = clWaitForEvents(1, &m_event);
+ if(ret != CL_SUCCESS){
+ BOOST_THROW_EXCEPTION(opencl_error(ret));
+ }
+ }
+
+ #if defined(CL_VERSION_1_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
+ /// Registers a function to be called when the event status changes to
+ /// \p status (by default CL_COMPLETE). The callback is passed the OpenCL
+ /// event object, the event status, and a pointer to arbitrary user data.
+ ///
+ /// \see_opencl_ref{clSetEventCallback}
+ ///
+ /// \opencl_version_warning{1,1}
+ void 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)
+ {
+ cl_int ret = clSetEventCallback(m_event, status, callback, user_data);
+ if(ret != CL_SUCCESS){
+ BOOST_THROW_EXCEPTION(opencl_error(ret));
+ }
+ }
+
+ /// Registers a generic function to be called when the event status
+ /// changes to \p status (by default \c CL_COMPLETE).
+ ///
+ /// The function specified by \p callback must be invokable with zero
+ /// arguments (e.g. \c callback()).
+ ///
+ /// \opencl_version_warning{1,1}
+ template<class Function>
+ void set_callback(Function callback, cl_int status = CL_COMPLETE)
+ {
+ set_callback(
+ event_callback_invoker,
+ status,
+ new boost::function<void()>(callback)
+ );
+ }
+ #endif // CL_VERSION_1_1
+
+ /// Returns the total duration of the event from \p start to \p end.
+ ///
+ /// For example, to print the number of milliseconds the event took to
+ /// execute:
+ /// \code
+ /// std::cout << event.duration<std::chrono::milliseconds>().count() << " ms" << std::endl;
+ /// \endcode
+ ///
+ /// \see event::get_profiling_info()
+ template<class Duration>
+ Duration duration(cl_profiling_info start = CL_PROFILING_COMMAND_START,
+ cl_profiling_info end = CL_PROFILING_COMMAND_END) const
+ {
+ const ulong_ nanoseconds =
+ get_profiling_info<ulong_>(end) - get_profiling_info<ulong_>(start);
+
+ return detail::make_duration_from_nanoseconds(Duration(), nanoseconds);
+ }
+
+ /// Returns \c true if the event is the same as \p other.
+ bool operator==(const event &other) const
+ {
+ return m_event == other.m_event;
+ }
+
+ /// Returns \c true if the event is different from \p other.
+ bool operator!=(const event &other) const
+ {
+ return m_event != other.m_event;
+ }
+
+ /// \internal_
+ operator cl_event() const
+ {
+ return m_event;
+ }
+
+ /// \internal_ (deprecated)
+ cl_int get_status() const
+ {
+ return status();
+ }
+
+private:
+ #ifdef CL_VERSION_1_1
+ /// \internal_
+ static void BOOST_COMPUTE_CL_CALLBACK
+ event_callback_invoker(cl_event, cl_int, void *user_data)
+ {
+ boost::function<void()> *callback =
+ static_cast<boost::function<void()> *>(user_data);
+
+ (*callback)();
+
+ delete callback;
+ }
+ #endif // CL_VERSION_1_1
+
+protected:
+ cl_event m_event;
+};
+
+/// \internal_ define get_info() specializations for event
+BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(event,
+ ((cl_command_queue, CL_EVENT_COMMAND_QUEUE))
+ ((cl_command_type, CL_EVENT_COMMAND_TYPE))
+ ((cl_int, CL_EVENT_COMMAND_EXECUTION_STATUS))
+ ((cl_uint, CL_EVENT_REFERENCE_COUNT))
+)
+
+#ifdef CL_VERSION_1_1
+BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(event,
+ ((cl_context, CL_EVENT_CONTEXT))
+)
+#endif
+
+} // end compute namespace
+} // end boost namespace
+
+#endif // BOOST_COMPUTE_EVENT_HPP