diff options
Diffstat (limited to 'src/gallium/frontends/clover/core/event.cpp')
-rw-r--r-- | src/gallium/frontends/clover/core/event.cpp | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/src/gallium/frontends/clover/core/event.cpp b/src/gallium/frontends/clover/core/event.cpp new file mode 100644 index 00000000000..3d313ce8969 --- /dev/null +++ b/src/gallium/frontends/clover/core/event.cpp @@ -0,0 +1,267 @@ +// +// Copyright 2012 Francisco Jerez +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#include "core/event.hpp" +#include "pipe/p_screen.h" + +using namespace clover; + +event::event(clover::context &ctx, const ref_vector<event> &deps, + action action_ok, action action_fail) : + context(ctx), _wait_count(1), _status(0), + action_ok(action_ok), action_fail(action_fail) { + for (auto &ev : deps) + ev.chain(*this); +} + +event::~event() { +} + +std::vector<intrusive_ref<event>> +event::trigger_self() { + std::lock_guard<std::mutex> lock(mutex); + std::vector<intrusive_ref<event>> evs; + + if (_wait_count && !--_wait_count) + std::swap(_chain, evs); + + cv.notify_all(); + return evs; +} + +void +event::trigger() try { + if (wait_count() == 1) + action_ok(*this); + + for (event &ev : trigger_self()) + ev.trigger(); +} catch (error &e) { + abort(e.get()); +} + +std::vector<intrusive_ref<event>> +event::abort_self(cl_int status) { + std::lock_guard<std::mutex> lock(mutex); + std::vector<intrusive_ref<event>> evs; + + _status = status; + _wait_count = 0; + std::swap(_chain, evs); + + cv.notify_all(); + return evs; +} + +void +event::abort(cl_int status) { + action_fail(*this); + + for (event &ev : abort_self(status)) + ev.abort(status); +} + +unsigned +event::wait_count() const { + std::lock_guard<std::mutex> lock(mutex); + return _wait_count; +} + +bool +event::signalled() const { + return !wait_count(); +} + +cl_int +event::status() const { + std::lock_guard<std::mutex> lock(mutex); + return _status; +} + +void +event::chain(event &ev) { + std::unique_lock<std::mutex> lock(mutex, std::defer_lock); + std::unique_lock<std::mutex> lock_ev(ev.mutex, std::defer_lock); + std::lock(lock, lock_ev); + + if (_wait_count) { + ev._wait_count++; + _chain.push_back(ev); + } + ev.deps.push_back(*this); +} + +void +event::wait_signalled() const { + std::unique_lock<std::mutex> lock(mutex); + cv.wait(lock, [=]{ return !_wait_count; }); +} + +void +event::wait() const { + for (event &ev : deps) + ev.wait(); + + wait_signalled(); +} + +hard_event::hard_event(command_queue &q, cl_command_type command, + const ref_vector<event> &deps, action action) : + event(q.context(), deps, profile(q, action), [](event &ev){}), + _queue(q), _command(command), _fence(NULL) { + if (q.profiling_enabled()) + _time_queued = timestamp::current(q); + + q.sequence(*this); + trigger(); +} + +hard_event::~hard_event() { + pipe_screen *screen = queue()->device().pipe; + screen->fence_reference(screen, &_fence, NULL); +} + +cl_int +hard_event::status() const { + pipe_screen *screen = queue()->device().pipe; + + if (event::status() < 0) + return event::status(); + + else if (!_fence) + return CL_QUEUED; + + else if (!screen->fence_finish(screen, NULL, _fence, 0)) + return CL_SUBMITTED; + + else + return CL_COMPLETE; +} + +command_queue * +hard_event::queue() const { + return &_queue(); +} + +cl_command_type +hard_event::command() const { + return _command; +} + +void +hard_event::wait() const { + pipe_screen *screen = queue()->device().pipe; + + event::wait(); + + if (status() == CL_QUEUED) + queue()->flush(); + + if (!_fence || + !screen->fence_finish(screen, NULL, _fence, PIPE_TIMEOUT_INFINITE)) + throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST); +} + +const lazy<cl_ulong> & +hard_event::time_queued() const { + return _time_queued; +} + +const lazy<cl_ulong> & +hard_event::time_submit() const { + return _time_submit; +} + +const lazy<cl_ulong> & +hard_event::time_start() const { + return _time_start; +} + +const lazy<cl_ulong> & +hard_event::time_end() const { + return _time_end; +} + +void +hard_event::fence(pipe_fence_handle *fence) { + pipe_screen *screen = queue()->device().pipe; + screen->fence_reference(screen, &_fence, fence); +} + +event::action +hard_event::profile(command_queue &q, const action &action) const { + if (q.profiling_enabled()) { + return [&q, action] (event &ev) { + auto &hev = static_cast<hard_event &>(ev); + + hev._time_submit = timestamp::current(q); + hev._time_start = timestamp::query(q); + + action(ev); + + hev._time_end = timestamp::query(q); + }; + + } else { + return action; + } +} + +soft_event::soft_event(clover::context &ctx, const ref_vector<event> &deps, + bool _trigger, action action) : + event(ctx, deps, action, action) { + if (_trigger) + trigger(); +} + +cl_int +soft_event::status() const { + if (event::status() < 0) + return event::status(); + + else if (!signalled() || + any_of([](const event &ev) { + return ev.status() != CL_COMPLETE; + }, deps)) + return CL_SUBMITTED; + + else + return CL_COMPLETE; +} + +command_queue * +soft_event::queue() const { + return NULL; +} + +cl_command_type +soft_event::command() const { + return CL_COMMAND_USER; +} + +void +soft_event::wait() const { + event::wait(); + + if (status() != CL_COMPLETE) + throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST); +} |