| //TODO: copyrights |
| |
| #ifndef __COMMANDQUEUE_H__ |
| #define __COMMANDQUEUE_H__ |
| |
| #include "object.h" |
| #include "opencl.h" |
| #include "Resource.hpp" |
| |
| #include <mutex> |
| #include <map> |
| #include <list> |
| |
| namespace Devices |
| { |
| |
| class Context; |
| class DeviceInterface; |
| class Event; |
| |
| /** |
| * \brief Command queue |
| * |
| * This class holds a list of events that will be pushed on a given device. |
| * |
| * More details are given on the \ref events page. |
| */ |
| class CommandQueue : public Object |
| { |
| public: |
| CommandQueue(Context *ctx, |
| DeviceInterface *device, |
| cl_command_queue_properties properties, |
| cl_int *errcode_ret); |
| ~CommandQueue(); |
| |
| /** |
| * \brief Queue an event |
| * \param event event to be queued |
| * \return \c CL_SUCCESS if success, otherwise an error code |
| */ |
| cl_int queueEvent(Event *event); |
| |
| /** |
| * \brief Information about the command queue |
| * \copydetails Coal::DeviceInterface::info |
| */ |
| cl_int info(cl_command_queue_info param_name, |
| size_t param_value_size, |
| void *param_value, |
| size_t *param_value_size_ret) const; |
| |
| /** |
| * \brief Set properties of the command queue |
| * \note This function is deprecated and only there for OpenCL 1.0 |
| * compatibility |
| * \param properties property to enable or disable |
| * \param enable true to enable the property, false to disable it |
| * \param old_properties old value of the properties, ignored if NULL |
| * \return \c CL_SUCCESS if all is good, an error code if \p properties is |
| * invalid |
| */ |
| cl_int setProperty(cl_command_queue_properties properties, |
| cl_bool enable, |
| cl_command_queue_properties *old_properties); |
| |
| /** |
| * \brief Check the properties given |
| * \return \c CL_SUCCESS if they are valid, an error code otherwise |
| */ |
| cl_int checkProperties() const; |
| |
| /** |
| * \brief Push events on the device |
| * |
| * This function implements a big part of what is described in |
| * \ref events . |
| * |
| * It is called by \c Coal::Event::setStatus() when an event is |
| * completed, or by \c queueEvent(). Its purpose is to explore the list |
| * of queued events (\c p_events) and to call |
| * \c Coal::DeviceInterface::pushEvent() for each event meeting its push |
| * conditions. |
| * |
| * \section conditions Conditions |
| * |
| * If the command queue has the \c CL_OUT_OF_ORDER_EXEC_MODE_ENABLE |
| * property disabled, an event can be pushed only if all the previous |
| * ones in the list are completed with success. This way, an event |
| * must be completed before any other can be pushed. This ensures |
| * in-order execution. |
| * |
| * If this property is enable, more complex heuristics are used. |
| * |
| * The event list \c p_events is explored from top to bottom. At each |
| * loop iteration, checks are performed to see if the event can be pushed. |
| * |
| * - When a \c Coal::BarrierEvent is encountered, no more events can be |
| * pushed, except if the \c Coal::BarrierEvent is the first in the list, |
| * as that means there are no other events that can be pushed, so the |
| * barrier can go away |
| * - All events that are already pushed or finished are skipped |
| * - The wait list of the event is then explored to ensure that all its |
| * dependencies are met. |
| * - Finally, if the events passes all the tests, it is either pushed on |
| * the device, or simply set to \c Coal::Event::Complete if it's a |
| * dummy event (see \c Coal::Event::isDummy()). |
| */ |
| void pushEventsOnDevice(); |
| |
| /** |
| * \brief Remove from the event list completed events |
| * |
| * This function is called periodically to clean the event list from |
| * completed events. |
| * |
| * It is needed to do that out of \c pushEventsOnDevice() as deleting |
| * event may \c dereference() this command queue, and also delete it. It |
| * would produce crashes. |
| */ |
| void cleanEvents(); |
| |
| /** |
| * \brief Flush the command queue |
| * |
| * Pushes all the events on the device, and then return. The event |
| * don't need to be completed after this call. |
| */ |
| void flush(); |
| |
| /** |
| * \brief Finish the command queue |
| * |
| * Pushes the events like \c flush() but also wait for them to be |
| * completed before returning. |
| */ |
| void finish(); |
| |
| /** |
| * \brief Return all the events in the command queue |
| * \note Retains all the events |
| * \param count number of events in the event queue |
| * \return events currently in the event queue |
| */ |
| Event **events(unsigned int &count); |
| |
| private: |
| DeviceInterface *p_device; |
| cl_command_queue_properties p_properties; |
| |
| std::list<Event *> p_events; |
| std::mutex p_event_list_mutex; |
| sw::Event *p_event_list_cond; |
| bool p_flushed; |
| }; |
| |
| /** |
| * \brief Base class for all events |
| * |
| * This class contains logic common to all the events. |
| * |
| * Beside handling OpenCL-specific stuff, \c Coal::Event objects do nothing |
| * implementation-wise. They do not compile kernels, copy data around, etc. |
| * They only contain static and immutable data that is then used by the devices |
| * to actually implement the event. |
| */ |
| class Event : public Object |
| { |
| public: |
| /** |
| * \brief Event type |
| * |
| * The allows objects using \c Coal::Event to know which event it is, |
| * and to cast it to the correct sub-class. |
| */ |
| enum Type |
| { |
| NDRangeKernel = CL_COMMAND_NDRANGE_KERNEL, |
| TaskKernel = CL_COMMAND_TASK, |
| NativeKernel = CL_COMMAND_NATIVE_KERNEL, |
| ReadBuffer = CL_COMMAND_READ_BUFFER, |
| WriteBuffer = CL_COMMAND_WRITE_BUFFER, |
| CopyBuffer = CL_COMMAND_COPY_BUFFER, |
| ReadImage = CL_COMMAND_READ_IMAGE, |
| WriteImage = CL_COMMAND_WRITE_IMAGE, |
| CopyImage = CL_COMMAND_COPY_IMAGE, |
| CopyImageToBuffer = CL_COMMAND_COPY_IMAGE_TO_BUFFER, |
| CopyBufferToImage = CL_COMMAND_COPY_BUFFER_TO_IMAGE, |
| MapBuffer = CL_COMMAND_MAP_BUFFER, |
| MapImage = CL_COMMAND_MAP_IMAGE, |
| UnmapMemObject = CL_COMMAND_UNMAP_MEM_OBJECT, |
| Marker = CL_COMMAND_MARKER, |
| AcquireGLObjects = CL_COMMAND_ACQUIRE_GL_OBJECTS, |
| ReleaseGLObjects = CL_COMMAND_RELEASE_GL_OBJECTS, |
| ReadBufferRect = CL_COMMAND_READ_BUFFER_RECT, |
| WriteBufferRect = CL_COMMAND_WRITE_BUFFER_RECT, |
| CopyBufferRect = CL_COMMAND_COPY_BUFFER_RECT, |
| User = CL_COMMAND_USER, |
| Barrier, |
| WaitForEvents |
| }; |
| |
| /** |
| * \brief Event status |
| */ |
| enum Status |
| { |
| Queued = CL_QUEUED, /*!< \brief Simply queued in a command queue */ |
| Submitted = CL_SUBMITTED, /*!< \brief Submitted to a device */ |
| Running = CL_RUNNING, /*!< \brief Running on the device */ |
| Complete = CL_COMPLETE /*!< \brief Completed */ |
| }; |
| |
| /** |
| * \brief Function that can be called when an event change status |
| */ |
| typedef void (CL_CALLBACK *event_callback)(cl_event, cl_int, void *); |
| |
| /** |
| * Structure used internally by \c Coal::Event to store for each event |
| * status the callbacks to call with the corresponding \c user_data. |
| */ |
| struct CallbackData |
| { |
| event_callback callback; /*!< Function to call */ |
| void *user_data; /*!< Pointer to pass as its third argument */ |
| }; |
| |
| /** |
| * \brief Timing counters of an event |
| */ |
| enum Timing |
| { |
| Queue, /*!< Time when the event was queued */ |
| Submit, /*!< Time when the event was submitted to the device */ |
| Start, /*!< Time when its execution began on the device */ |
| End, /*!< Time when its execution finished */ |
| Max /*!< Number of items in this enum */ |
| }; |
| |
| public: |
| /** |
| * \brief Constructor |
| * \param parent parent \c Coal::CommandQueue |
| * \param status \c Status the event has when it is created |
| * \param num_events_in_wait_list number of events to wait on |
| * \param event_wait_list list of events to wait on |
| * \param errcode_ret return value |
| */ |
| Event(CommandQueue *parent, |
| Status status, |
| cl_uint num_events_in_wait_list, |
| const Event **event_wait_list, |
| cl_int *errcode_ret); |
| |
| void freeDeviceData(); /*!< \brief Call \c Coal::DeviceInterface::freeEventDeviceData() */ |
| virtual ~Event(); /*!< \brief Destructor */ |
| |
| /** |
| * \brief Type of the event |
| * \return type of the event |
| */ |
| virtual Type type() const = 0; |
| |
| /** |
| * \brief Dummy event |
| * |
| * A dummy event is an event that doesn't have to be pushed on a device, |
| * it is only a hint for \c Coal::CommandQueue |
| * |
| * \return true if the event is dummy |
| */ |
| bool isDummy() const; |
| |
| /** |
| * \brief Set the event status |
| * |
| * This function calls the event callbacks, and |
| * \c Coal::CommandQueue::pushEventsOnDevice() if \p status is |
| * \c Complete . |
| * |
| * \param status new status of the event |
| */ |
| void setStatus(Status status); |
| |
| /** |
| * \brief Set device-specific data |
| * \param data device-specific data |
| */ |
| void setDeviceData(void *data); |
| |
| /** |
| * \brief Update timing info |
| * |
| * This function reads current system time and puts it in \c p_timing |
| * |
| * \param timing timing event having just finished |
| */ |
| void updateTiming(Timing timing); |
| |
| /** |
| * \brief Status |
| * \return status of the event |
| */ |
| Status status() const; |
| |
| /** |
| * \brief Wait for a specified status |
| * |
| * This function blocks until the event's status is set to \p status |
| * by another thread. |
| * |
| * \param status the status the event must have for the function to return |
| */ |
| void waitForStatus(Status status); |
| |
| /** |
| * \brief Device-specific data |
| * \return data set using \c setDeviceData() |
| */ |
| void *deviceData(); |
| |
| /** |
| * \brief List of events on which this event depends on |
| * \param count number of events in the list |
| * \return list of the events |
| * \warning the data is not copied, it's a simple pointer to internal data |
| */ |
| const Event **waitEvents(cl_uint &count) const; |
| |
| /** |
| * \brief Add a callback for this event |
| * \param command_exec_callback_type status the event must have in order |
| * to have the callback called |
| * \param callback callback function |
| * \param user_data user data given to the callback |
| */ |
| void setCallback(cl_int command_exec_callback_type, |
| event_callback callback, |
| void *user_data); |
| |
| /** |
| * \brief Info about the event |
| * \copydetails Coal::DeviceInterface::info |
| */ |
| cl_int info(cl_event_info param_name, |
| size_t param_value_size, |
| void *param_value, |
| size_t *param_value_size_ret) const; |
| |
| /** |
| * \brief Profiling info |
| * \copydetails Coal::DeviceInterface::info |
| */ |
| cl_int profilingInfo(cl_profiling_info param_name, |
| size_t param_value_size, |
| void *param_value, |
| size_t *param_value_size_ret) const; |
| private: |
| cl_uint p_num_events_in_wait_list; |
| const Event **p_event_wait_list; |
| |
| sw::Event *p_state_change_cond; |
| std::mutex p_state_mutex; |
| |
| Status p_status; |
| void *p_device_data; |
| std::multimap<Status, CallbackData> p_callbacks; |
| |
| cl_uint p_timing[Max]; |
| }; |
| |
| } |
| |
| struct _cl_command_queue : public Devices::CommandQueue |
| {}; |
| |
| struct _cl_event : public Devices::Event |
| {}; |
| |
| #endif |