Home | History | Annotate | Download | only in core
      1 //
      2 // Copyright 2012 Francisco Jerez
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a
      5 // copy of this software and associated documentation files (the "Software"),
      6 // to deal in the Software without restriction, including without limitation
      7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 // and/or sell copies of the Software, and to permit persons to whom the
      9 // Software is furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 // OTHER DEALINGS IN THE SOFTWARE.
     21 //
     22 
     23 #ifndef CLOVER_CORE_EVENT_HPP
     24 #define CLOVER_CORE_EVENT_HPP
     25 
     26 #include <condition_variable>
     27 #include <functional>
     28 
     29 #include "core/object.hpp"
     30 #include "core/queue.hpp"
     31 #include "core/timestamp.hpp"
     32 #include "util/lazy.hpp"
     33 
     34 namespace clover {
     35    ///
     36    /// Class that represents a task that might be executed
     37    /// asynchronously at some point in the future.
     38    ///
     39    /// An event consists of a list of dependencies, a boolean
     40    /// signalled() flag, and an associated task.  An event is
     41    /// considered signalled as soon as all its dependencies (if any)
     42    /// are signalled as well, and the trigger() method is called; at
     43    /// that point the associated task will be started through the
     44    /// specified \a action_ok.  If the abort() method is called
     45    /// instead, the specified \a action_fail is executed and the
     46    /// associated task will never be started.  Dependent events will
     47    /// be aborted recursively.
     48    ///
     49    /// The execution status of the associated task can be queried
     50    /// using the status() method, and it can be waited for completion
     51    /// using the wait() method.
     52    ///
     53    class event : public ref_counter, public _cl_event {
     54    public:
     55       typedef std::function<void (event &)> action;
     56 
     57       event(clover::context &ctx, const ref_vector<event> &deps,
     58             action action_ok, action action_fail);
     59       virtual ~event();
     60 
     61       event(const event &ev) = delete;
     62       event &
     63       operator=(const event &ev) = delete;
     64 
     65       void trigger();
     66       void abort(cl_int status);
     67       bool signalled() const;
     68 
     69       virtual cl_int status() const;
     70       virtual command_queue *queue() const = 0;
     71       virtual cl_command_type command() const = 0;
     72       void wait_signalled() const;
     73       virtual void wait() const;
     74 
     75       virtual struct pipe_fence_handle *fence() const {
     76          return NULL;
     77       }
     78 
     79       const intrusive_ref<clover::context> context;
     80 
     81    protected:
     82       void chain(event &ev);
     83 
     84       std::vector<intrusive_ref<event>> deps;
     85 
     86    private:
     87       std::vector<intrusive_ref<event>> trigger_self();
     88       std::vector<intrusive_ref<event>> abort_self(cl_int status);
     89       unsigned wait_count() const;
     90 
     91       unsigned _wait_count;
     92       cl_int _status;
     93       action action_ok;
     94       action action_fail;
     95       std::vector<intrusive_ref<event>> _chain;
     96       mutable std::condition_variable cv;
     97       mutable std::mutex mutex;
     98    };
     99 
    100    ///
    101    /// Class that represents a task executed by a command queue.
    102    ///
    103    /// Similar to a normal clover::event.  In addition it's associated
    104    /// with a given command queue \a q and a given OpenCL \a command.
    105    /// hard_event instances created for the same queue are implicitly
    106    /// ordered with respect to each other, and they are implicitly
    107    /// triggered on construction.
    108    ///
    109    /// A hard_event is considered complete when the associated
    110    /// hardware task finishes execution.
    111    ///
    112    class hard_event : public event {
    113    public:
    114       hard_event(command_queue &q, cl_command_type command,
    115                  const ref_vector<event> &deps,
    116                  action action = [](event &){});
    117       ~hard_event();
    118 
    119       virtual cl_int status() const;
    120       virtual command_queue *queue() const;
    121       virtual cl_command_type command() const;
    122       virtual void wait() const;
    123 
    124       const lazy<cl_ulong> &time_queued() const;
    125       const lazy<cl_ulong> &time_submit() const;
    126       const lazy<cl_ulong> &time_start() const;
    127       const lazy<cl_ulong> &time_end() const;
    128 
    129       friend class command_queue;
    130 
    131       virtual struct pipe_fence_handle *fence() const {
    132          return _fence;
    133       }
    134 
    135    private:
    136       virtual void fence(pipe_fence_handle *fence);
    137       action profile(command_queue &q, const action &action) const;
    138 
    139       const intrusive_ref<command_queue> _queue;
    140       cl_command_type _command;
    141       pipe_fence_handle *_fence;
    142       lazy<cl_ulong> _time_queued, _time_submit, _time_start, _time_end;
    143    };
    144 
    145    ///
    146    /// Class that represents a software event.
    147    ///
    148    /// A soft_event is not associated with any specific hardware task
    149    /// or command queue.  It's considered complete as soon as all its
    150    /// dependencies finish execution.
    151    ///
    152    class soft_event : public event {
    153    public:
    154       soft_event(clover::context &ctx, const ref_vector<event> &deps,
    155                  bool trigger, action action = [](event &){});
    156 
    157       virtual cl_int status() const;
    158       virtual command_queue *queue() const;
    159       virtual cl_command_type command() const;
    160       virtual void wait() const;
    161    };
    162 }
    163 
    164 #endif
    165