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_finish(screen, NULL, _fence, 0)) 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, NULL, _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