diff options
Diffstat (limited to 'boost/compute/event.hpp')
-rw-r--r-- | boost/compute/event.hpp | 338 |
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 |