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