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       virtual void wait() const;
     73 
     74       virtual struct pipe_fence_handle *fence() const {
     75          return NULL;
     76       }
     77 
     78       const intrusive_ref<clover::context> context;
     79 
     80    protected:
     81       void chain(event &ev);
     82 
     83       std::vector<intrusive_ref<event>> deps;
     84 
     85    private:
     86       std::vector<intrusive_ref<event>> trigger_self();
     87       std::vector<intrusive_ref<event>> abort_self(cl_int status);
     88 
     89       unsigned wait_count;
     90       cl_int _status;
     91       action action_ok;
     92       action action_fail;
     93       std::vector<intrusive_ref<event>> _chain;
     94       mutable std::condition_variable cv;
     95       mutable std::mutex mutex;
     96    };
     97 
     98    ///
     99    /// Class that represents a task executed by a command queue.
    100    ///
    101    /// Similar to a normal clover::event.  In addition it's associated
    102    /// with a given command queue \a q and a given OpenCL \a command.
    103    /// hard_event instances created for the same queue are implicitly
    104    /// ordered with respect to each other, and they are implicitly
    105    /// triggered on construction.
    106    ///
    107    /// A hard_event is considered complete when the associated
    108    /// hardware task finishes execution.
    109    ///
    110    class hard_event : public event {
    111    public:
    112       hard_event(command_queue &q, cl_command_type command,
    113                  const ref_vector<event> &deps,
    114                  action action = [](event &){});
    115       ~hard_event();
    116 
    117       virtual cl_int status() const;
    118       virtual command_queue *queue() const;
    119       virtual cl_command_type command() const;
    120       virtual void wait() const;
    121 
    122       const lazy<cl_ulong> &time_queued() const;
    123       const lazy<cl_ulong> &time_submit() const;
    124       const lazy<cl_ulong> &time_start() const;
    125       const lazy<cl_ulong> &time_end() const;
    126 
    127       friend class command_queue;
    128 
    129       virtual struct pipe_fence_handle *fence() const {
    130          return _fence;
    131       }
    132 
    133    private:
    134       virtual void fence(pipe_fence_handle *fence);
    135       action profile(command_queue &q, const action &action) const;
    136 
    137       const intrusive_ref<command_queue> _queue;
    138       cl_command_type _command;
    139       pipe_fence_handle *_fence;
    140       lazy<cl_ulong> _time_queued, _time_submit, _time_start, _time_end;
    141    };
    142 
    143    ///
    144    /// Class that represents a software event.
    145    ///
    146    /// A soft_event is not associated with any specific hardware task
    147    /// or command queue.  It's considered complete as soon as all its
    148    /// dependencies finish execution.
    149    ///
    150    class soft_event : public event {
    151    public:
    152       soft_event(clover::context &ctx, const ref_vector<event> &deps,
    153                  bool trigger, action action = [](event &){});
    154 
    155       virtual cl_int status() const;
    156       virtual command_queue *queue() const;
    157       virtual cl_command_type command() const;
    158       virtual void wait() const;
    159    };
    160 }
    161 
    162 #endif
    163