Home | History | Annotate | Download | only in soft
      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