1 /* 2 * soft_worker.cpp - soft worker implementation 3 * 4 * Copyright (c) 2017 Intel Corporation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Wind Yuan <feng.yuan (at) intel.com> 19 */ 20 21 #include "soft_worker.h" 22 #include "thread_pool.h" 23 #include "xcam_mutex.h" 24 25 namespace XCam { 26 27 class ItemSynch { 28 private: 29 mutable std::atomic<uint32_t> _remain_items; 30 Mutex _mutex; 31 XCamReturn _error; 32 33 public: 34 ItemSynch (uint32_t items) 35 : _remain_items(items), _error (XCAM_RETURN_NO_ERROR) 36 {} 37 void update_error (XCamReturn err) { 38 SmartLock locker(_mutex); 39 _error = err; 40 } 41 XCamReturn get_error () { 42 SmartLock locker(_mutex); 43 return _error; 44 } 45 uint32_t dec() { 46 return --_remain_items; 47 } 48 49 private: 50 XCAM_DEAD_COPY (ItemSynch); 51 }; 52 53 class WorkItem 54 : public ThreadPool::UserData 55 { 56 public: 57 WorkItem ( 58 const SmartPtr<SoftWorker> &worker, 59 const SmartPtr<Worker::Arguments> &args, 60 const WorkSize &item, 61 SmartPtr<ItemSynch> &sync) 62 : _worker (worker) 63 , _args (args) 64 , _item (item) 65 , _sync (sync) 66 { 67 } 68 virtual XCamReturn run (); 69 virtual void done (XCamReturn err); 70 71 72 private: 73 SmartPtr<SoftWorker> _worker; 74 SmartPtr<Worker::Arguments> _args; 75 WorkSize _item; 76 SmartPtr<ItemSynch> _sync; 77 }; 78 79 XCamReturn 80 WorkItem::run () 81 { 82 XCamReturn ret = _sync->get_error(); 83 if (!xcam_ret_is_ok (ret)) 84 return ret; 85 86 ret = _worker->work_impl (_args, _item); 87 if (!xcam_ret_is_ok (ret)) 88 _sync->update_error (ret); 89 90 return ret; 91 } 92 93 void 94 WorkItem::done (XCamReturn err) 95 { 96 if (_sync->dec () == 0) { 97 XCamReturn ret = _sync->get_error (); 98 if (xcam_ret_is_ok (ret)) 99 ret = err; 100 _worker->all_items_done (_args, ret); 101 } 102 } 103 104 SoftWorker::SoftWorker (const char *name, const SmartPtr<Callback> &cb) 105 : Worker (name, cb) 106 , _global (1, 1, 1) 107 , _local (1, 1, 1) 108 , _work_unit (1, 1, 1) 109 { 110 } 111 112 SoftWorker::~SoftWorker () 113 { 114 } 115 116 bool 117 SoftWorker::set_work_uint (uint32_t x, uint32_t y, uint32_t z) 118 { 119 XCAM_FAIL_RETURN ( 120 ERROR, x && y && z, false, 121 "SoftWorker(%s) set work unit failed(x:%d, y:%d, z:%d)", 122 XCAM_STR (get_name ()), x, y, z); 123 _work_unit.value[0] = x; 124 _work_unit.value[1] = y; 125 _work_unit.value[2] = z; 126 return true; 127 } 128 129 bool 130 SoftWorker::set_threads (const SmartPtr<ThreadPool> &threads) 131 { 132 XCAM_FAIL_RETURN ( 133 ERROR, !_threads.ptr (), false, 134 "SoftWorker(%s) set threads failed, it's already set before.", XCAM_STR (get_name ())); 135 _threads = threads; 136 return true; 137 } 138 139 bool 140 SoftWorker::set_global_size (const WorkSize &size) 141 { 142 XCAM_FAIL_RETURN ( 143 ERROR, size.value[0] && size.value[1] && size.value[2], false, 144 "SoftWorker(%s) set global size(x:%d, y:%d, z:%d) failed.", 145 XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]); 146 147 _global = size; 148 return true; 149 } 150 151 bool 152 SoftWorker::set_local_size (const WorkSize &size) 153 { 154 XCAM_FAIL_RETURN ( 155 ERROR, size.value[0] && size.value[1] && size.value[2], false, 156 "SoftWorker(%s) set local size(x:%d, y:%d, z:%d) failed.", 157 XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]); 158 159 _local = size; 160 return true; 161 } 162 163 XCamReturn 164 SoftWorker::stop () 165 { 166 _threads->stop (); 167 return XCAM_RETURN_NO_ERROR; 168 } 169 170 XCamReturn 171 SoftWorker::work (const SmartPtr<Worker::Arguments> &args) 172 { 173 XCamReturn ret = XCAM_RETURN_NO_ERROR; 174 175 XCAM_ASSERT (_local.value[0] * _local.value[1] * _local.value[2]); 176 XCAM_ASSERT (_global.value[0] * _global.value[1] * _global.value[2]); 177 178 WorkSize items; 179 uint32_t max_items = 1; 180 181 for (uint32_t i = 0; i < SOFT_MAX_DIM; ++i) { 182 items.value[i] = xcam_ceil (_global.value[i], _local.value[i]) / _local.value[i]; 183 max_items *= items.value[i]; 184 } 185 186 XCAM_FAIL_RETURN ( 187 ERROR, max_items, XCAM_RETURN_ERROR_PARAM, 188 "SoftWorker(%s) max item is zero. work failed.", XCAM_STR (get_name ())); 189 190 if (max_items == 1) { 191 ret = work_impl (args, WorkSize(0, 0, 0)); 192 status_check (args, ret); 193 return ret; 194 } 195 196 if (!_threads.ptr ()) { 197 char thr_name [XCAM_MAX_STR_SIZE]; 198 snprintf (thr_name, XCAM_MAX_STR_SIZE, "%s-thrs", XCAM_STR(get_name ())); 199 _threads = new ThreadPool (thr_name); 200 XCAM_ASSERT (_threads.ptr ()); 201 _threads->set_threads (max_items, max_items + 1); //extra thread to process all_items_done 202 ret = _threads->start (); 203 XCAM_FAIL_RETURN ( 204 ERROR, xcam_ret_is_ok (ret), ret, 205 "SoftWorker(%s) work failed when starting threads", XCAM_STR(get_name())); 206 } 207 208 SmartPtr<ItemSynch> sync = new ItemSynch (max_items); 209 for (uint32_t z = 0; z < items.value[2]; ++z) 210 for (uint32_t y = 0; y < items.value[1]; ++y) 211 for (uint32_t x = 0; x < items.value[0]; ++x) 212 { 213 SmartPtr<WorkItem> item = new WorkItem (this, args, WorkSize(x, y, z), sync); 214 ret = _threads->queue (item); 215 if (!xcam_ret_is_ok (ret)) { 216 //consider half queued but half failed 217 sync->update_error (ret); 218 //status_check (args, ret); // need it here? 219 XCAM_LOG_ERROR ( 220 "SoftWorker(%s) queue work item(x:%d y: %d z:%d) failed", 221 XCAM_STR(get_name()), x, y, z); 222 return ret; 223 } 224 } 225 226 return XCAM_RETURN_NO_ERROR; 227 } 228 229 void 230 SoftWorker::all_items_done (const SmartPtr<Arguments> &args, XCamReturn error) 231 { 232 status_check (args, error); 233 } 234 235 WorkRange 236 SoftWorker::get_range (const WorkSize &item) 237 { 238 WorkRange range; 239 for (uint32_t i = 0; i < SOFT_MAX_DIM; ++i) { 240 range.pos[i] = item.value[i] * _local.value[i]; 241 XCAM_ASSERT (range.pos[i] < _global.value[i]); 242 if (range.pos[i] + _local.value[i] > _global.value[i]) 243 range.pos_len[i] = _global.value[i] - range.pos[i]; 244 else 245 range.pos_len[i] = _local.value[i]; 246 } 247 return range; 248 } 249 250 XCamReturn 251 SoftWorker::work_impl (const SmartPtr<Arguments> &args, const WorkSize &item) 252 { 253 WorkRange range = get_range (item); 254 return work_range (args, range); 255 } 256 257 XCamReturn 258 SoftWorker::work_range (const SmartPtr<Arguments> &args, const WorkRange &range) 259 { 260 XCamReturn ret = XCAM_RETURN_NO_ERROR; 261 WorkSize unit; 262 memcpy(unit.value, range.pos, sizeof (unit.value)); 263 264 for (unit.value[2] = range.pos[2]; unit.value[2] < range.pos[2] + range.pos_len[2]; ++unit.value[2]) 265 for (unit.value[1] = range.pos[1]; unit.value[1] < range.pos[1] + range.pos_len[1]; ++unit.value[1]) 266 for (unit.value[0] = range.pos[0]; unit.value[0] < range.pos[0] + range.pos_len[0]; ++unit.value[0]) { 267 ret = work_unit (args, unit); 268 XCAM_FAIL_RETURN ( 269 ERROR, xcam_ret_is_ok (ret), ret, 270 "SoftWorker(%s) work on pixel(x:%d y: %d z:%d) failed", 271 get_name (), unit.value[0], unit.value[1], unit.value[2]); 272 } 273 274 return ret; 275 } 276 277 XCamReturn 278 SoftWorker::work_unit (const SmartPtr<Arguments> &, const WorkSize &) 279 { 280 XCAM_LOG_ERROR ("SoftWorker(%s) work_pixel was not derived. check code"); 281 return XCAM_RETURN_ERROR_PARAM; 282 } 283 284 }; 285