Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. #include "core/event.hpp"
  24. #include "pipe/p_screen.h"
  25.  
  26. using namespace clover;
  27.  
  28. event::event(clover::context &ctx, const ref_vector<event> &deps,
  29.              action action_ok, action action_fail) :
  30.    context(ctx), wait_count(1), _status(0),
  31.    action_ok(action_ok), action_fail(action_fail) {
  32.    for (auto &ev : deps)
  33.       ev.chain(*this);
  34. }
  35.  
  36. event::~event() {
  37. }
  38.  
  39. std::vector<intrusive_ref<event>>
  40. event::trigger_self() {
  41.    std::lock_guard<std::mutex> lock(mutex);
  42.    std::vector<intrusive_ref<event>> evs;
  43.  
  44.    if (!--wait_count)
  45.       std::swap(_chain, evs);
  46.  
  47.    return evs;
  48. }
  49.  
  50. void
  51. event::trigger() {
  52.    auto evs = trigger_self();
  53.  
  54.    if (signalled()) {
  55.       action_ok(*this);
  56.       cv.notify_all();
  57.    }
  58.  
  59.    for (event &ev : evs)
  60.       ev.trigger();
  61. }
  62.  
  63. std::vector<intrusive_ref<event>>
  64. event::abort_self(cl_int status) {
  65.    std::lock_guard<std::mutex> lock(mutex);
  66.    std::vector<intrusive_ref<event>> evs;
  67.  
  68.    _status = status;
  69.    std::swap(_chain, evs);
  70.  
  71.    return evs;
  72. }
  73.  
  74. void
  75. event::abort(cl_int status) {
  76.    auto evs = abort_self(status);
  77.  
  78.    action_fail(*this);
  79.  
  80.    for (event &ev : evs)
  81.       ev.abort(status);
  82. }
  83.  
  84. bool
  85. event::signalled() const {
  86.    std::lock_guard<std::mutex> lock(mutex);
  87.    return !wait_count;
  88. }
  89.  
  90. cl_int
  91. event::status() const {
  92.    std::lock_guard<std::mutex> lock(mutex);
  93.    return _status;
  94. }
  95.  
  96. void
  97. event::chain(event &ev) {
  98.    std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
  99.    std::unique_lock<std::mutex> lock_ev(ev.mutex, std::defer_lock);
  100.    std::lock(lock, lock_ev);
  101.  
  102.    if (wait_count) {
  103.       ev.wait_count++;
  104.       _chain.push_back(ev);
  105.    }
  106.    ev.deps.push_back(*this);
  107. }
  108.  
  109. void
  110. event::wait() const {
  111.    for (event &ev : deps)
  112.       ev.wait();
  113.  
  114.    std::unique_lock<std::mutex> lock(mutex);
  115.    cv.wait(lock, [=]{ return !wait_count; });
  116. }
  117.  
  118. hard_event::hard_event(command_queue &q, cl_command_type command,
  119.                        const ref_vector<event> &deps, action action) :
  120.    event(q.context(), deps, profile(q, action), [](event &ev){}),
  121.    _queue(q), _command(command), _fence(NULL) {
  122.    if (q.profiling_enabled())
  123.       _time_queued = timestamp::current(q);
  124.  
  125.    q.sequence(*this);
  126.    trigger();
  127. }
  128.  
  129. hard_event::~hard_event() {
  130.    pipe_screen *screen = queue()->device().pipe;
  131.    screen->fence_reference(screen, &_fence, NULL);
  132. }
  133.  
  134. cl_int
  135. hard_event::status() const {
  136.    pipe_screen *screen = queue()->device().pipe;
  137.  
  138.    if (event::status() < 0)
  139.       return event::status();
  140.  
  141.    else if (!_fence)
  142.       return CL_QUEUED;
  143.  
  144.    else if (!screen->fence_signalled(screen, _fence))
  145.       return CL_SUBMITTED;
  146.  
  147.    else
  148.       return CL_COMPLETE;
  149. }
  150.  
  151. command_queue *
  152. hard_event::queue() const {
  153.    return &_queue();
  154. }
  155.  
  156. cl_command_type
  157. hard_event::command() const {
  158.    return _command;
  159. }
  160.  
  161. void
  162. hard_event::wait() const {
  163.    pipe_screen *screen = queue()->device().pipe;
  164.  
  165.    event::wait();
  166.  
  167.    if (status() == CL_QUEUED)
  168.       queue()->flush();
  169.  
  170.    if (!_fence ||
  171.        !screen->fence_finish(screen, _fence, PIPE_TIMEOUT_INFINITE))
  172.       throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
  173. }
  174.  
  175. const lazy<cl_ulong> &
  176. hard_event::time_queued() const {
  177.    return _time_queued;
  178. }
  179.  
  180. const lazy<cl_ulong> &
  181. hard_event::time_submit() const {
  182.    return _time_submit;
  183. }
  184.  
  185. const lazy<cl_ulong> &
  186. hard_event::time_start() const {
  187.    return _time_start;
  188. }
  189.  
  190. const lazy<cl_ulong> &
  191. hard_event::time_end() const {
  192.    return _time_end;
  193. }
  194.  
  195. void
  196. hard_event::fence(pipe_fence_handle *fence) {
  197.    pipe_screen *screen = queue()->device().pipe;
  198.    screen->fence_reference(screen, &_fence, fence);
  199. }
  200.  
  201. event::action
  202. hard_event::profile(command_queue &q, const action &action) const {
  203.    if (q.profiling_enabled()) {
  204.       return [&q, action] (event &ev) {
  205.          auto &hev = static_cast<hard_event &>(ev);
  206.  
  207.          hev._time_submit = timestamp::current(q);
  208.          hev._time_start = timestamp::query(q);
  209.  
  210.          action(ev);
  211.  
  212.          hev._time_end = timestamp::query(q);
  213.       };
  214.  
  215.    } else {
  216.       return action;
  217.    }
  218. }
  219.  
  220. soft_event::soft_event(clover::context &ctx, const ref_vector<event> &deps,
  221.                        bool _trigger, action action) :
  222.    event(ctx, deps, action, action) {
  223.    if (_trigger)
  224.       trigger();
  225. }
  226.  
  227. cl_int
  228. soft_event::status() const {
  229.    if (event::status() < 0)
  230.       return event::status();
  231.  
  232.    else if (!signalled() ||
  233.             any_of([](const event &ev) {
  234.                   return ev.status() != CL_COMPLETE;
  235.                }, deps))
  236.       return CL_SUBMITTED;
  237.  
  238.    else
  239.       return CL_COMPLETE;
  240. }
  241.  
  242. command_queue *
  243. soft_event::queue() const {
  244.    return NULL;
  245. }
  246.  
  247. cl_command_type
  248. soft_event::command() const {
  249.    return CL_COMMAND_USER;
  250. }
  251.  
  252. void
  253. soft_event::wait() const {
  254.    event::wait();
  255.  
  256.    if (status() != CL_COMPLETE)
  257.       throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
  258. }
  259.