boost/compute/event.hpp
//---------------------------------------------------------------------------//
// 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