• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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:
ItemSynch(uint32_t items)34     ItemSynch (uint32_t items)
35         : _remain_items(items), _error (XCAM_RETURN_NO_ERROR)
36     {}
update_error(XCamReturn err)37     void update_error (XCamReturn err) {
38         SmartLock locker(_mutex);
39         _error = err;
40     }
get_error()41     XCamReturn get_error () {
42         SmartLock locker(_mutex);
43         return _error;
44     }
dec()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:
WorkItem(const SmartPtr<SoftWorker> & worker,const SmartPtr<Worker::Arguments> & args,const WorkSize & item,SmartPtr<ItemSynch> & sync)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
run()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
done(XCamReturn err)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 
SoftWorker(const char * name,const SmartPtr<Callback> & cb)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 
~SoftWorker()112 SoftWorker::~SoftWorker ()
113 {
114 }
115 
116 bool
set_work_uint(uint32_t x,uint32_t y,uint32_t z)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
set_threads(const SmartPtr<ThreadPool> & threads)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
set_global_size(const WorkSize & size)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
set_local_size(const WorkSize & size)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
stop()164 SoftWorker::stop ()
165 {
166     _threads->stop ();
167     return XCAM_RETURN_NO_ERROR;
168 }
169 
170 XCamReturn
work(const SmartPtr<Worker::Arguments> & args)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
all_items_done(const SmartPtr<Arguments> & args,XCamReturn error)230 SoftWorker::all_items_done (const SmartPtr<Arguments> &args, XCamReturn error)
231 {
232     status_check (args, error);
233 }
234 
235 WorkRange
get_range(const WorkSize & item)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
work_impl(const SmartPtr<Arguments> & args,const WorkSize & item)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
work_range(const SmartPtr<Arguments> & args,const WorkRange & range)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
work_unit(const SmartPtr<Arguments> &,const WorkSize &)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