diff options
author | Denis Steckelmacher <steckdenis@yahoo.fr> | 2011-08-19 20:46:38 +0200 |
---|---|---|
committer | Denis Steckelmacher <steckdenis@yahoo.fr> | 2011-08-19 20:46:38 +0200 |
commit | 8e6b9328430a38de49026d5ef79e88de9476673d (patch) | |
tree | 37faf5c7d838e729d1217cab527c841978899bc8 | |
parent | c8829488fd5d46d8cf5a35f9aa9dc5820bd89abb (diff) |
Document some classes in src/core.
-rw-r--r-- | src/core/commandqueue.h | 245 | ||||
-rw-r--r-- | src/core/compiler.h | 53 | ||||
-rw-r--r-- | src/core/context.h | 31 | ||||
-rw-r--r-- | src/core/events.h | 301 | ||||
-rw-r--r-- | src/core/kernel.h | 201 | ||||
-rw-r--r-- | src/core/memobject.h | 166 |
6 files changed, 856 insertions, 141 deletions
diff --git a/src/core/commandqueue.h b/src/core/commandqueue.h index 5832093..eb1de34 100644 --- a/src/core/commandqueue.h +++ b/src/core/commandqueue.h @@ -25,6 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \file commandqueue.h + * \brief Command queue and base class for events + */ + #ifndef __COMMANDQUEUE_H__ #define __COMMANDQUEUE_H__ @@ -43,6 +48,11 @@ class Context; class DeviceInterface; class Event; +/** + * \brief Command queue + * + * This class holds a list of events that will be pushed on a given device + */ class CommandQueue : public Object { public: @@ -52,25 +62,115 @@ class CommandQueue : public Object 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(); - Event **events(unsigned int &count); /*!< @note Retains all the events */ + /** + * \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; @@ -82,9 +182,25 @@ class CommandQueue : public Object 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, @@ -112,61 +228,158 @@ class Event : public Object WaitForEvents }; + /** + * \brief Event status + */ enum Status { - Queued = CL_QUEUED, - Submitted = CL_SUBMITTED, - Running = CL_RUNNING, - Complete = CL_COMPLETE + 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; - void *user_data; + 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, - Submit, - Start, - End, - Max + 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(); - virtual ~Event(); + 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; - bool isDummy() const; /*!< Doesn't do anything, it's just an event type */ - + + /** + * \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, diff --git a/src/core/compiler.h b/src/core/compiler.h index b5af89d..3308bd8 100644 --- a/src/core/compiler.h +++ b/src/core/compiler.h @@ -25,6 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \file compiler.h + * \brief Compiler wrapped around Clang + */ + #ifndef __COMPILER_H__ #define __COMPILER_H__ @@ -49,19 +54,67 @@ namespace Coal class DeviceInterface; +/** + * \brief Compiler using Clang + * + * This class builds a Clang instance, runs it and then retains compilation logs + * and produced data. + */ class Compiler { public: + /** + * \brief Constructor + * \param device \c Coal::DeviceInterface for which code will be compiled + */ Compiler(DeviceInterface *device); ~Compiler(); + /** + * \brief Compile \p source to produce a LLVM module + * \param options options given to the compiler, described in the OpenCL spec + * \param source source to be compiled + * \return true if the compilation is successful, false otherwise + * \sa module() + * \sa log() + */ bool compile(const std::string &options, llvm::MemoryBuffer *source); + /** + * \brief Compilation log + * \note \c appendLog() can also be used to append custom info at the end + * of the log, for instance to keep compilation and linking logs + * in the same place + * \return log + */ const std::string &log() const; + + /** + * \brief Options given at \c compile() + * \return options used during compilation + */ const std::string &options() const; + + /** + * \brief Optimization enabled + * \return true if -cl-opt-disable was given in the options, false otherwise + */ bool optimize() const; + + /** + * \brief LLVM module generated + * \return LLVM module generated by the compilation, 0 if an error occured + */ llvm::Module *module() const; + /** + * \brief Append a string to the log + * + * This function can be used to append linking or code-gen logs to the + * internal compilation log kept by this class + * + * \param log log to be appended + */ void appendLog(const std::string &log); private: diff --git a/src/core/context.h b/src/core/context.h index cd2834d..82d9070 100644 --- a/src/core/context.h +++ b/src/core/context.h @@ -25,6 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \file context.h + * \brief OpenCL context + */ + #ifndef __CONTEXT_H__ #define __CONTEXT_H__ @@ -37,9 +42,24 @@ namespace Coal class DeviceInterface; +/** + * \brief OpenCL context + * + * This class is the root of all OpenCL objects, except \c Coal::DeviceInterface. + */ class Context : public Object { public: + /** + * \brief Constructor + * \param properties properties of the context + * \param num_devices number of devices that will be used + * \param devices \c Coal::DeviceInterface to be used + * \param pfn_notify function to call when an error arises, to give + * more detail + * \param user_data user data to pass to \p pfn_notify + * \param errcode_ret return code + */ Context(const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, @@ -49,11 +69,20 @@ class Context : public Object cl_int *errcode_ret); ~Context(); + /** + * \brief Info about the context + * \copydetails Coal::DeviceInterface::info + */ cl_int info(cl_context_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) const; + /** + * \brief Check that this context contains a given \p device + * \param device device to check + * \return whether this context contains \p device + */ bool hasDevice(DeviceInterface *device) const; private: @@ -72,4 +101,4 @@ class Context : public Object struct _cl_context : public Coal::Context {}; -#endif
\ No newline at end of file +#endif diff --git a/src/core/events.h b/src/core/events.h index d9cb651..cfcf4e4 100644 --- a/src/core/events.h +++ b/src/core/events.h @@ -25,6 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \file events.h + * \brief All the event-related classes + */ + #ifndef __EVENTS_H__ #define __EVENTS_H__ @@ -42,6 +47,9 @@ class Kernel; class DeviceKernel; class DeviceInterface; +/** + * \brief Buffer-related event + */ class BufferEvent : public Event { public: @@ -51,8 +59,20 @@ class BufferEvent : public Event const Event **event_wait_list, cl_int *errcode_ret); - MemObject *buffer() const; - + MemObject *buffer() const; /*!< \brief Buffer on which to operate */ + + /** + * \brief Check that a buffer is correctly aligned for a device + * + * OpenCL supports sub-buffers of buffers (\c Coal::SubBuffer). They + * have to be aligned on a certain device-dependent boundary. + * + * This function checks that \p buffer is correctly aligned for + * \p device. If \p buffer is not a \c Coal::SubBuffer, this function + * returns true. + * + * \return true if the buffer is aligned or not a \c Coal::SubBuffer + */ static bool isSubBufferAligned(const MemObject *buffer, const DeviceInterface *device); @@ -60,6 +80,9 @@ class BufferEvent : public Event MemObject *p_buffer; }; +/** + * \brief Reading or writing to a buffer + */ class ReadWriteBufferEvent : public BufferEvent { public: @@ -72,15 +95,18 @@ class ReadWriteBufferEvent : public BufferEvent const Event **event_wait_list, cl_int *errcode_ret); - size_t offset() const; - size_t cb() const; - void *ptr() const; + size_t offset() const; /*!< \brief Offset in the buffer of the operation, in bytes */ + size_t cb() const; /*!< \brief Number of bytes to read or write */ + void *ptr() const; /*!< \brief Pointer in host memory at which to put the data */ private: size_t p_offset, p_cb; void *p_ptr; }; +/** + * \brief Reading a buffer + */ class ReadBufferEvent : public ReadWriteBufferEvent { public: @@ -93,9 +119,12 @@ class ReadBufferEvent : public ReadWriteBufferEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::ReadBuffer one */ }; +/** + * \brief Writing a buffer + */ class WriteBufferEvent : public ReadWriteBufferEvent { public: @@ -108,9 +137,12 @@ class WriteBufferEvent : public ReadWriteBufferEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::WriteBuffer one */ }; +/** + * \brief Mapping a buffer + */ class MapBufferEvent : public BufferEvent { public: @@ -123,12 +155,22 @@ class MapBufferEvent : public BufferEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; - - size_t offset() const; - size_t cb() const; - cl_map_flags flags() const; - void *ptr() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::MapBuffer one */ + + size_t offset() const; /*!< \brief Offset in the buffer at which the mapping begins, in bytes */ + size_t cb() const; /*!< \brief Number of bytes to map */ + cl_map_flags flags() const; /*!< \brief Flags of the mapping */ + void *ptr() const; /*!< \brief Pointer at which the data has been mapped */ + + /** + * \brief Set the memory location at which the data has been mapped + * + * This function is called by the device when it has successfully mapped + * the buffer. It must be called inside + * \c Coal::DeviceInterface::initEventDeviceData(). + * + * \param ptr the address at which the buffer has been mapped + */ void setPtr(void *ptr); private: @@ -137,6 +179,9 @@ class MapBufferEvent : public BufferEvent void *p_ptr; }; +/** + * \brief Mapping an image + */ class MapImageEvent : public BufferEvent { public: @@ -149,19 +194,40 @@ class MapImageEvent : public BufferEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::MapImage one */ + /** + * \brief Origin of the mapping, in pixels, for the given dimension + * \param index dimension for which the origin is retrieved + * \return origin of the mapping for the given dimension + */ size_t origin(unsigned int index) const; - size_t region(unsigned int index) const; - cl_map_flags flags() const; - - void *ptr() const; - size_t row_pitch() const; - size_t slice_pitch() const; + /** + * \brief Region of the mapping, in pixels, for the given dimension + * \param index dimension for which the region is retrieved + * \return region of the mapping for the given dimension + */ + size_t region(unsigned int index) const; + cl_map_flags flags() const; /*!< \brief Flags of the mapping */ + + void *ptr() const; /*!< \brief Pointer at which the data is mapped */ + size_t row_pitch() const; /*!< \brief Row pitch of the mapped data */ + size_t slice_pitch() const; /*!< \brief Slice pitch of the mapped data */ + + /** + * \brief Set the memory location at which the image is mapped + * + * This function must be called by + * \c Coal::DeviceInterface::initEventDeviceData(). Row and slice pitches + * must also be set by this function by calling \c setRowPitch() and + * \c setSlicePitch(). + * + * \param ptr pointer at which the data is available + */ void setPtr(void *ptr); - void setRowPitch(size_t row_pitch); - void setSlicePitch(size_t slice_pitch); + void setRowPitch(size_t row_pitch); /*!< \brief Set row pitch */ + void setSlicePitch(size_t slice_pitch); /*!< \brief Set slice pitch */ private: cl_map_flags p_map_flags; @@ -170,6 +236,9 @@ class MapImageEvent : public BufferEvent size_t p_slice_pitch, p_row_pitch; }; +/** + * \brief Unmapping a memory object + */ class UnmapBufferEvent : public BufferEvent { public: @@ -180,14 +249,17 @@ class UnmapBufferEvent : public BufferEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::UnmapBuffer one */ - void *mapping() const; + void *mapping() const; /*!< \brief Mapped address to unmap */ private: void *p_mapping; }; +/** + * \brief Copying between two buffers + */ class CopyBufferEvent : public BufferEvent { public: @@ -201,19 +273,24 @@ class CopyBufferEvent : public BufferEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::CopyBuffer one */ - MemObject *source() const; - MemObject *destination() const; - size_t src_offset() const; - size_t dst_offset() const; - size_t cb() const; + MemObject *source() const; /*!< \brief Source buffer, equivalent to \c Coal::BufferEvent::buffer() */ + MemObject *destination() const; /*!< \brief Destination buffer */ + size_t src_offset() const; /*!< \brief Offset in the source buffer, in bytes */ + size_t dst_offset() const; /*!< \brief Offset in the destination buffer, in bytes */ + size_t cb() const; /*!< \brief Number of bytes to copy */ private: MemObject *p_destination; size_t p_src_offset, p_dst_offset, p_cb; }; +/** + * \brief Events related to rectangular (or cubic) memory regions + * + * This event is the base for all the *BufferRect events, and the Image ones. + */ class ReadWriteCopyBufferRectEvent : public BufferEvent { public: @@ -231,14 +308,14 @@ class ReadWriteCopyBufferRectEvent : public BufferEvent const Event **event_wait_list, cl_int *errcode_ret); - size_t src_origin(unsigned int index) const; - size_t dst_origin(unsigned int index) const; - size_t region(unsigned int index) const; - size_t src_row_pitch() const; - size_t src_slice_pitch() const; - size_t dst_row_pitch() const; - size_t dst_slice_pitch() const; - MemObject *source() const; + size_t src_origin(unsigned int index) const; /*!< \brief Source origin for the \p index dimension */ + size_t dst_origin(unsigned int index) const; /*!< \brief Destination origin for the \p index dimension */ + size_t region(unsigned int index) const; /*!< \brief Region to copy for the \p index dimension */ + size_t src_row_pitch() const; /*!< \brief Source row pitch */ + size_t src_slice_pitch() const; /*!< \brief Source slice pitch */ + size_t dst_row_pitch() const; /*!< \brief Destination row pitch */ + size_t dst_slice_pitch() const; /*!< \brief Destination slice pitch */ + MemObject *source() const; /*!< \brief Source of the copy, for readability. Calls \c Coal::BufferEvent::buffer(). */ protected: size_t p_src_origin[3], p_dst_origin[3], p_region[3]; @@ -246,6 +323,9 @@ class ReadWriteCopyBufferRectEvent : public BufferEvent size_t p_dst_row_pitch, p_dst_slice_pitch; }; +/** + * \brief Copying between two buffers + */ class CopyBufferRectEvent : public ReadWriteCopyBufferRectEvent { public: @@ -264,13 +344,16 @@ class CopyBufferRectEvent : public ReadWriteCopyBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - virtual Type type() const; - MemObject *destination() const; + virtual Type type() const; /*!< \brief Say the event is a \c Coal::Event::CopyBufferRect one */ + MemObject *destination() const; /*!< \brief Destination buffer */ private: MemObject *p_destination; }; +/** + * \brief Reading or writing to a buffer + */ class ReadWriteBufferRectEvent : public ReadWriteCopyBufferRectEvent { public: @@ -289,12 +372,15 @@ class ReadWriteBufferRectEvent : public ReadWriteCopyBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - void *ptr() const; + void *ptr() const; /*!< \brief Pointer in host memory in which to put the data */ private: void *p_ptr; }; +/** + * \brief Reading a buffer + */ class ReadBufferRectEvent : public ReadWriteBufferRectEvent { public: @@ -312,9 +398,12 @@ class ReadBufferRectEvent : public ReadWriteBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::ReadBufferRect one */ }; +/** + * \brief Writing a buffer + */ class WriteBufferRectEvent : public ReadWriteBufferRectEvent { public: @@ -332,9 +421,16 @@ class WriteBufferRectEvent : public ReadWriteBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::WriteBufferRect one */ }; +/** + * \brief Reading or writing images + * + * This class only converts some of the arguments given to its constructor + * to the one of \c Coal::ReadWriteBufferRectEvent. For example, the source row + * and slice pitches are read from the \c Coal::Image2D object. + */ class ReadWriteImageEvent : public ReadWriteBufferRectEvent { public: @@ -350,6 +446,9 @@ class ReadWriteImageEvent : public ReadWriteBufferRectEvent cl_int *errcode_ret); }; +/** + * \brief Reading an image + */ class ReadImageEvent : public ReadWriteImageEvent { public: @@ -364,9 +463,12 @@ class ReadImageEvent : public ReadWriteImageEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::ReadImage one */ }; +/** + * \brief Writing to an image + */ class WriteImageEvent : public ReadWriteImageEvent { public: @@ -381,9 +483,12 @@ class WriteImageEvent : public ReadWriteImageEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::WriteImage one */ }; +/** + * \brief Copying between two images + */ class CopyImageEvent : public CopyBufferRectEvent { public: @@ -397,9 +502,12 @@ class CopyImageEvent : public CopyBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::CopyImage one */ }; +/** + * \brief Copying an image to a buffer + */ class CopyImageToBufferEvent : public CopyBufferRectEvent { public: @@ -413,13 +521,16 @@ class CopyImageToBufferEvent : public CopyBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - size_t offset() const; - Type type() const; + size_t offset() const; /*!< \brief Offset in the buffer at which writing the image */ + Type type() const; /*!< \brief Say the event is a \c Coal::Event::CopyImageToBuffer one */ private: size_t p_offset; }; +/** + * \brief Copying a buffer to an image + */ class CopyBufferToImageEvent : public CopyBufferRectEvent { public: @@ -433,13 +544,21 @@ class CopyBufferToImageEvent : public CopyBufferRectEvent const Event **event_wait_list, cl_int *errcode_ret); - size_t offset() const; - Type type() const; + size_t offset() const; /*!< \brief Offset in the buffer at which the copy starts */ + Type type() const; /*!< \brief Say the event is a \c Coal::Event::CopyBufferToImage one */ private: size_t p_offset; }; +/** + * \brief Executing a native function as a kernel + * + * This event builds an argument list to give to the native function. It needs + * for example to replace all occurence of a \c Coal::MemObject by a pointer + * to data the host CPU can actually access, using + * \c Coal::DeviceBuffer::nativeGlobalPointer(). + */ class NativeKernelEvent : public Event { public: @@ -455,16 +574,19 @@ class NativeKernelEvent : public Event cl_int *errcode_ret); ~NativeKernelEvent(); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::NativeKernel one */ - void *function() const; - void *args() const; + void *function() const; /*!< \brief Host function to call */ + void *args() const; /*!< \brief Args to give to the host function */ private: void *p_user_func; void *p_args; }; +/** + * \brief Executing a compiled kernel + */ class KernelEvent : public Event { public: @@ -479,14 +601,14 @@ class KernelEvent : public Event cl_int *errcode_ret); ~KernelEvent(); - cl_uint work_dim() const; - size_t global_work_offset(cl_uint dim) const; - size_t global_work_size(cl_uint dim) const; - size_t local_work_size(cl_uint dim) const; - Kernel *kernel() const; - DeviceKernel *deviceKernel() const; + cl_uint work_dim() const; /*!< \brief Number of working dimensions */ + size_t global_work_offset(cl_uint dim) const; /*!< \brief Global work offset for the \p dim dimension */ + size_t global_work_size(cl_uint dim) const; /*!< \brief Global work size for the \p dim dimension */ + size_t local_work_size(cl_uint dim) const; /*!< \brief Number of work-items per work-group for the \p dim dimension */ + Kernel *kernel() const; /*!< \brief \c Coal::Kernel object to run */ + DeviceKernel *deviceKernel() const; /*!< \brief \c Coal::DeviceKernel for the kernel and device of this event */ - virtual Type type() const; + virtual Type type() const; /*!< \brief Say the event is a \c Coal::Event::NDRangeKernel one */ private: cl_uint p_work_dim; @@ -498,6 +620,18 @@ class KernelEvent : public Event DeviceKernel *p_dev_kernel; }; +/** + * \brief Executing a task kernel + * + * This event is simple a \c Coal::KernelEvent with: + * + * - \c work_dim() set to 1 + * - \c global_work_offset() set to {0} + * - \c global_work_size() set to {1} + * - \c local_work_size() set to {1} + * + * It's in fact a \c Coal::KernelEvent containing only one single work-item. + */ class TaskEvent : public KernelEvent { public: @@ -507,33 +641,61 @@ class TaskEvent : public KernelEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::TaskKernel one */ }; +/** + * \brief User event + * + * This event is a bit special as it is created by a call to + * \c clCreateUserEvent() and doesn't belong to an event queue. Thus, a mean had + * to be found for all to work. + * + * The solution is the \c addDependentCommandQueue() function, called every time + * the user event is added to a command queue. When this event becomes completed, + * \c flushQueues() is called to allow all the \c Coal::CommandQueue objects + * containing this event to push more events on their device. + * + * This way, command queues are not blocked by user events. + */ class UserEvent : public Event { public: UserEvent(Context *context, cl_int *errcode_ret); - Type type() const; - Context *context() const; - void addDependentCommandQueue(CommandQueue *queue); // We need to call pushOnDevice somewhere - void flushQueues(); + Type type() const; /*!< \brief Say the event is a \c Coal::Event::User one */ + Context *context() const; /*!< \brief Context of this event */ + void flushQueues(); /*!< \brief Call \c Coal::CommandQueue::pushEventsOnDevice() for each command queue in which this event is queued */ + + /** + * \brief Add a \c Coal::CommandQueue that will have to be flushed when this event becomes completed + * + * See the long description of this class for a complete explanation + * + * \param queue \c Coal::CommandQueue to add in the list of queues to flush + */ + void addDependentCommandQueue(CommandQueue *queue); private: Context *p_context; std::vector<CommandQueue *> p_dependent_queues; }; +/** + * \brief Barrier event + */ class BarrierEvent : public Event { public: BarrierEvent(CommandQueue *parent, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::Barrier one */ }; +/** + * \brief Event waiting for others to complete before being completed + */ class WaitForEventsEvent : public Event { public: @@ -542,9 +704,12 @@ class WaitForEventsEvent : public Event const Event **event_wait_list, cl_int *errcode_ret); - virtual Type type() const; + virtual Type type() const; /*!< \brief Say the event is a \c Coal::Event::WaitForEvents one */ }; +/** + * \brief Marker event + */ class MarkerEvent : public WaitForEventsEvent { public: @@ -553,7 +718,7 @@ class MarkerEvent : public WaitForEventsEvent const Event **event_wait_list, cl_int *errcode_ret); - Type type() const; + Type type() const; /*!< \brief Say the event is a \c Coal::Event::Marker one */ }; } diff --git a/src/core/kernel.h b/src/core/kernel.h index 043e640..98c6d58 100644 --- a/src/core/kernel.h +++ b/src/core/kernel.h @@ -25,6 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \file core/kernel.h + * \brief Kernel + */ + #ifndef __KERNEL_H__ #define __KERNEL_H__ @@ -48,55 +53,141 @@ class Program; class DeviceInterface; class DeviceKernel; +/** + * \brief Kernel + * + * A kernel represents a LLVM function that can be run on a device. As + * \c Coal::Kernel objects are device-independent, they in fact represent only + * the name of a kernel and the arguments the application wants to pass to it, + * but it also contains a list of LLVM functions for each device for which its + * parent \c Coal::Program has been built + */ class Kernel : public Object { public: + /** + * \brief Constructor + * \param program Parent \c Coal::Program + */ Kernel(Program *program); ~Kernel(); + /** + * \brief Kernel argument + * + * This class holds OpenCL-related information about the arguments of + * a kernel. It is also used to check that a kernel takes the same + * arguments on every device on which it has been built. + */ class Arg { public: + /** + * \brief Memory address space qualifier + */ enum File { - Private = 0, - Global = 1, - Local = 2, - Constant = 3 + Private = 0, /*!< \brief __private */ + Global = 1, /*!< \brief __global */ + Local = 2, /*!< \brief __local */ + Constant = 3 /*!< \brief __constant */ }; + + /** + * \brief Kind of argument (its datatype) + */ enum Kind { - Invalid, - Int8, - Int16, - Int32, - Int64, - Float, - Double, - Buffer, - Image2D, - Image3D, - Sampler + Invalid, /*!< \brief Invalid argument */ + Int8, /*!< \brief \c uchar or \c char, \c i8 in LLVM */ + Int16, /*!< \brief \c ushort or \c short, \c i16 in LLVM */ + Int32, /*!< \brief \c uint or \c int, \c i32 in LLVM */ + Int64, /*!< \brief \c ulong or \c long, \c i64 in LLVM */ + Float, /*!< \brief \c float, \c float in LLVM */ + Double, /*!< \brief \c double, \c double in LLVM */ + Buffer, /*!< \brief \c Coal::Buffer or \c Coal::SubBuffer, <tt>type*</tt> in LLVM */ + Image2D, /*!< \brief \c Coal::Image2D, <tt>\%struct.image2d*</tt> in LLVM */ + Image3D, /*!< \brief \c Coal::Image3D, <tt>\%struct.image3d*</tt> in LLVM */ + Sampler /*!< \brief \c Coal::Sampler::bitfield(), \c i32 in LLVM, see \c Coal::Kernel::setArg() */ }; + /** + * \brief Constructor + * \param vec_dim vector dimension of the argument, 1 if not a vector + * \param file \c File of the argument + * \param kind \c Kind of the argument + */ Arg(unsigned short vec_dim, File file, Kind kind); ~Arg(); + /** + * \brief Allocate the argument + * + * This function must be called before \c loadData(). It + * allocates a buffer in which the argument value can be stored. + * + * \sa valueSize() + */ void alloc(); + + /** + * \brief Load a value into the argument + * \note \c alloc() must have been called before this function. + * \sa valueSize() + */ void loadData(const void *data); + + /** + * \brief Set the number of bytes that must be allocated at run-time + * + * \c __local arguments don't take a value given by the host + * application, but take pointers allocated on the device + * for each work-group. + * + * This function allows to set the size of the device-allocated + * memory buffer used by this argument. + * + * \param size size in byte of the buffer the device has to + * allocate for each work-group of this kernel + */ void setAllocAtKernelRuntime(size_t size); + + /** + * \brief Changes the \c Kind of this argument + * \param kind new \c Kind + */ void refineKind(Kind kind); + /** + * \brief Compares this argument with another + * + * They are different if they \c vec_dim, \c file or \c kind are + * not the same. + * + * \param b other argument to compare + * \return true if the this arguments doesn't match \p b + */ bool operator !=(const Arg &b); + /** + * \brief Size of a field of this arg + * + * This function returns the size of this argument based on its + * \c Kind + * + * \note This size is not multiplied by \c vecDim(), you must do + * this by yourself to find the total space taken by this + * arg. + * \return the size of this argument, in bytes, without any padding + */ size_t valueSize() const; - unsigned short vecDim() const; - File file() const; - Kind kind() const; - bool defined() const; - size_t allocAtKernelRuntime() const; - const void *value(unsigned short index) const; - const void *data() const; + unsigned short vecDim() const; /*!< \brief Vector dimension */ + File file() const; /*!< \brief File */ + Kind kind() const; /*!< \brief Kind */ + bool defined() const; /*!< \brief Has the value of this argument already beed loaded by the host application ? */ + size_t allocAtKernelRuntime() const; /*!< \brief Size of the \c __local buffer to allocate at kernel runtime */ + const void *value(unsigned short index) const; /*!< \brief Pointer to the value of this argument, for the \p index vector element */ + const void *data() const; /*!< \brief Pointer to the data of this arg, equivalent to <tt>value(0)</tt> */ private: unsigned short p_vec_dim; @@ -107,22 +198,80 @@ class Kernel : public Object size_t p_runtime_alloc; }; + /** + * \brief Add a \c llvm::Function to this kernel + * + * This function adds a \c llvm::Function to this kernel for the + * specified \p device. It also has the responsibility to find the + * \c Arg::Kind of each of the function's arguments. + * + * LLVM provides a \c llvm::Type for each argument: + * + * - If it is a pointer, the kind of the argument is \c Arg::Buffer and + * its field is a simple cast from a LLVM \c addrspace to \c Arg::File. + * - If it is a pointer to a struct whose name is either + * <tt>\%struct.image2d</tt> or <tt>\%struct.image3d</tt>, kind is set + * to \c Arg::Image2D or \c Arg::Image3D, respectively. + * - If it is a vector, \c vec_dim is set to the vector size, and the + * rest of the computations are done on the element type + * - Then we translate the LLVM type to an \c Arg::Kind. For instance, + * \c i32 becomes \c Arg::Int32 + * + * Samplers aren't detected at this stage because they are plain \c i32 + * types on the LLVM side. They are detected in \c setArg() when the + * value being set to the argument appears to be a \c Coal::Sampler. + * + * \param device device for which the function is added + * \param function function to add + * \param module LLVM module of this function + */ cl_int addFunction(DeviceInterface *device, llvm::Function *function, llvm::Module *module); + + /** + * \brief Get the LLVM function for a specified \p device + * \param device the device for which a LLVM function is needed + * \return the LLVM function for the given \p device + */ llvm::Function *function(DeviceInterface *device) const; + + /** + * \brief Set the value of an argument + * + * See the constructor's documentation for a note on the + * \c Coal::Sampler objects + * + * \param index index of the argument + * \param size size of the value being stored in the argument, must match + * <tt>Arg::valueSize() * Arg::vecDim()</tt> + * \param value pointer to the data that will be copied in the argument + * \return \c CL_SUCCESS if success, an error code otherwise + */ cl_int setArg(cl_uint index, size_t size, const void *value); - unsigned int numArgs() const; - const Arg &arg(unsigned int index) const; + unsigned int numArgs() const; /*!< \brief Number of arguments of this kernel */ + const Arg &arg(unsigned int index) const; /*!< \brief \c Arg at the given \p index */ + + /*! \brief \c Coal::DeviceKernel for the specified \p device */ DeviceKernel *deviceDependentKernel(DeviceInterface *device) const; - bool argsSpecified() const; - bool hasLocals() const; + bool argsSpecified() const; /*!< \brief true if all the arguments have been set through \c setArg() */ + bool hasLocals() const; /*!< \brief true if one or more argument is in file \c Arg::Local */ + /** + * \brief Get information about this kernel + * \copydetails Coal::DeviceInterface::info + */ cl_int info(cl_kernel_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) const; + + /** + * \brief Get performance hints and device-specific data about this kernel + * \copydetails Coal::DeviceInterface::info + * \param device \c Coal::DeviceInterface on which the kernel will be run + */ cl_int workGroupInfo(DeviceInterface *device, cl_kernel_work_group_info param_name, size_t param_value_size, diff --git a/src/core/memobject.h b/src/core/memobject.h index 44d669f..2a81a03 100644 --- a/src/core/memobject.h +++ b/src/core/memobject.h @@ -25,6 +25,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * \file memobject.h + * \brief Memory objects + */ + #ifndef __MEMOBJECT_H__ #define __MEMOBJECT_H__ @@ -39,9 +44,15 @@ class DeviceBuffer; class Context; class DeviceInterface; +/** + * \brief Base class for all the memory objects + */ class MemObject : public Object { public: + /** + * \brief Type of memory object + */ enum Type { Buffer, @@ -51,28 +62,63 @@ class MemObject : public Object }; /** - * @note Doesn't do any initialization here, but in init. We only fill + * \brief Constructor + * \param ctx parent \c Coal::Context + * \param flags memory object flags + * \param host_ptr host pointer used by some flags (see the OpenCL spec) + * \param errcode_ret return value + * \note Don't do any initialization here, but in \c init(). We only fill * the private variables and check the values passed in argument. - * @sa init + * \sa init */ MemObject(Context *ctx, cl_mem_flags flags, void *host_ptr, cl_int *errcode_ret); ~MemObject(); + /** + * \brief Initialize the memory object + * + * Memory objects are device-independent classes. This function creates + * one \c Coal::DeviceBuffer per device present in the context by + * calling \c Coal::DeviceInterface::createDeviceBuffer(). + * + * If there is only one device, its \c Coal::DeviceBuffer is directly + * allocated. If there are more than one device, the allocation is + * deferred until a \c Coal::Event is pushed for this device. + * + * \return \c CL_SUCCESS if success, an error code otherwise + */ virtual cl_int init(); - virtual bool allocate(DeviceInterface *device); - virtual size_t size() const = 0; /*!< @warning this is a device-independent size */ - virtual Type type() const = 0; + virtual bool allocate(DeviceInterface *device); /*!< \brief Allocate this memory object on the given \p device */ + virtual size_t size() const = 0; /*!< \brief Device-independent size of the memory object */ + virtual Type type() const = 0; /*!< \brief Type of the memory object */ - cl_mem_flags flags() const; - void *host_ptr() const; - DeviceBuffer *deviceBuffer(DeviceInterface *device) const; + cl_mem_flags flags() const; /*!< \brief Flags */ + void *host_ptr() const; /*!< \brief Host pointer */ + DeviceBuffer *deviceBuffer(DeviceInterface *device) const; /*!< \brief \c Coal::DeviceBuffer for the given \p device */ - void deviceAllocated(DeviceBuffer *buffer); /*!< @note called by the DeviceBuffers */ + void deviceAllocated(DeviceBuffer *buffer); /*!< \brief Is the \c Coal::DeviceBuffer for \p buffer allocated ? */ + /** + * \brief Set a destructor callback for this memory object + * + * This callback is called when this memory object is deleted. It is + * currently called from the destructor, so the memory object is already + * invalid, but as OpenCL objects are immutable, the callback cannot + * use its \c memobj parameter except in a pointer comparison, and there + * is no problem. + * + * \param pfn_notify function to call when the memory object is deleted + * \param user_data user data to pass to this function + */ void setDestructorCallback(void (CL_CALLBACK *pfn_notify)(cl_mem memobj, void *user_data), void *user_data); + + /** + * \brief Get information about this memory object + * \copydetails Coal::DeviceInterface::info + */ cl_int info(cl_mem_info param_name, size_t param_value_size, void *param_value, @@ -88,80 +134,140 @@ class MemObject : public Object void *p_dtor_userdata; }; +/** + * \brief Simple buffer object + */ class Buffer : public MemObject { public: + /** + * \brief Constructor + * \param ctx parent \c Coal::Context + * \param size size of the buffer, in bytes + * \param host_ptr host pointer + * \param flags memory flags + * \param errcode_ret return code + */ Buffer(Context *ctx, size_t size, void *host_ptr, cl_mem_flags flags, cl_int *errcode_ret); - size_t size() const; - Type type() const; + size_t size() const; /*!< \brief Size of the buffer, in bytes */ + Type type() const; /*!< \brief Return that we are a \c Coal::MemObject::Buffer */ private: size_t p_size; }; +/** + * \brief Sub-buffer + */ class SubBuffer : public MemObject { public: + /** + * \brief Constructor + * \param parent parent \c Coal::Buffer + * \param offset offset in \p parent of the start of this sub-buffer + * \param size size of the sub-buffer + * \param flags memory flags (must be compatible with the \p parent's ones) + * \param errcode_ret return code + */ SubBuffer(class Buffer *parent, size_t offset, size_t size, cl_mem_flags flags, cl_int *errcode_ret); - size_t size() const; - Type type() const; - bool allocate(DeviceInterface *device); + size_t size() const; /*!< \brief Size */ + Type type() const; /*!< \brief Return that we are a \c Coal::MemObject::SubBuffer */ + bool allocate(DeviceInterface *device); /*!< \brief Allocate the \b parent \c Coal::Buffer */ - size_t offset() const; - class Buffer *parent() const; + size_t offset() const; /*!< \brief Offset in bytes */ + class Buffer *parent() const; /*!< \brief Parent \c Coal::Buffer */ private: size_t p_offset, p_size; class Buffer *p_parent; }; +/** + * \brief 2D image + */ class Image2D : public MemObject { public: + /** + * \brief Constructor + * \param ctx parent \c Coal::Context + * \param width width of the image + * \param height height of the image + * \param row_pitch number of bytes in a row of pixels. If 0, defaults to <tt>width * pixel_size()</tt> + * \param format image format + * \param host_ptr host pointer + * \param flags memory flags + * \param errcode_ret return code + */ Image2D(Context *ctx, size_t width, size_t height, size_t row_pitch, const cl_image_format *format, void *host_ptr, cl_mem_flags flags, cl_int *errcode_ret); - virtual size_t size() const; - virtual Type type() const; + virtual size_t size() const; /*!< \brief Size in bytes */ + virtual Type type() const; /*!< \brief Return that we are a \c Coal::MemObject::Image2D */ - size_t width() const; - size_t height() const; - size_t row_pitch() const; - virtual size_t slice_pitch() const; - const cl_image_format &format() const; + size_t width() const; /*!< \brief Width */ + size_t height() const; /*!< \brief Height */ + size_t row_pitch() const; /*!< \brief Size in bytes of a row of pixels */ + virtual size_t slice_pitch() const; /*!< \brief Size in bytes of the image */ + const cl_image_format &format() const; /*!< \brief Image format descriptor */ + /** + * \brief Information about this image object + * + * This function is also usable for \c Coal::Image3D objects as it does + * casting when necessary in order to give information when needed. + * + * \copydetails Coal::DeviceInterface::info + */ cl_int imageInfo(cl_image_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) const; - static size_t element_size(const cl_image_format &format); - static size_t pixel_size(const cl_image_format &format); - size_t pixel_size() const; + static size_t element_size(const cl_image_format &format); /*!< \brief Size in bytes of each channel of \p format */ + static size_t pixel_size(const cl_image_format &format); /*!< \brief Size in bytes of a pixel in \p format */ + size_t pixel_size() const; /*!< \brief Pixel size of this image */ private: size_t p_width, p_height, p_row_pitch; cl_image_format p_format; }; +/** + * \brief 3D image + */ class Image3D : public Image2D { public: + /** + * \brief Constructor + * \param ctx parent \c Coal::Context + * \param width width of the image + * \param height height of the image + * \param depth depth of the image + * \param row_pitch number of bytes in a row of pixels. If 0, defaults to <tt>width * pixel_size()</tt> + * \param slice_pitch number of bytes in a 2D slice. If 0, defaults to <tt>height * row_pitch()</tt> + * \param format image format + * \param host_ptr host pointer + * \param flags memory flags + * \param errcode_ret return code + */ Image3D(Context *ctx, size_t width, size_t height, size_t depth, size_t row_pitch, size_t slice_pitch, const cl_image_format *format, void *host_ptr, cl_mem_flags flags, cl_int *errcode_ret); - size_t size() const; - Type type() const; + size_t size() const; /*!< \brief Size in bytes of this image */ + Type type() const; /*!< \brief Return that we are a \c Coal::MemObject::Image3D */ - size_t depth() const; - size_t slice_pitch() const; + size_t depth() const; /*!< \brief Depth of the image */ + size_t slice_pitch() const; /*!< \brief Size in bytes of a 2D slice */ private: size_t p_depth, p_slice_pitch; |