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@intel.com> 19 */ 20 21#include "soft_worker.h" 22#include "thread_pool.h" 23#include "xcam_mutex.h" 24 25namespace XCam { 26 27class ItemSynch { 28private: 29 mutable std::atomic<uint32_t> _remain_items; 30 Mutex _mutex; 31 XCamReturn _error; 32 33public: 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 49private: 50 XCAM_DEAD_COPY (ItemSynch); 51}; 52 53class WorkItem 54 : public ThreadPool::UserData 55{ 56public: 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 72private: 73 SmartPtr<SoftWorker> _worker; 74 SmartPtr<Worker::Arguments> _args; 75 WorkSize _item; 76 SmartPtr<ItemSynch> _sync; 77}; 78 79XCamReturn 80WorkItem::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 93void 94WorkItem::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 104SoftWorker::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 112SoftWorker::~SoftWorker () 113{ 114} 115 116bool 117SoftWorker::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 129bool 130SoftWorker::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 139bool 140SoftWorker::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 151bool 152SoftWorker::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 163XCamReturn 164SoftWorker::stop () 165{ 166 _threads->stop (); 167 return XCAM_RETURN_NO_ERROR; 168} 169 170XCamReturn 171SoftWorker::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 229void 230SoftWorker::all_items_done (const SmartPtr<Arguments> &args, XCamReturn error) 231{ 232 status_check (args, error); 233} 234 235WorkRange 236SoftWorker::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 250XCamReturn 251SoftWorker::work_impl (const SmartPtr<Arguments> &args, const WorkSize &item) 252{ 253 WorkRange range = get_range (item); 254 return work_range (args, range); 255} 256 257XCamReturn 258SoftWorker::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 277XCamReturn 278SoftWorker::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