libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
dataflow_full_statistics.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2012 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE libjmmcg_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include <boost/mpl/list.hpp>
25 
26 #include "core/thread_pool_sequential.hpp"
27 #include "core/thread_pool_master.hpp"
28 #include "core/thread_pool_workers.hpp"
29 
30 using namespace libjmmcg;
31 using namespace ppd;
32 
33 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, template<class> class CFG=no_control_flow_graph, unsigned int PoolSize=0, unsigned int GSSk=1>
34 struct fifo_queue_t {
35  typedef pool_aspects<
36  Jn,
38  Mdl,
40  std::less,
41  GSSk,
43  CFG
45 
46  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
47 
48  static const typename pool_type::pool_type::size_type pool_size=PoolSize;
49 };
50 
51 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, template<class> class CFG, unsigned int PoolSize, unsigned int GSSk>
52 const typename fifo_queue_t<Db, Sz, Jn, Mdl, CFG, PoolSize, GSSk>::pool_type::pool_type::size_type fifo_queue_t<Db, Sz, Jn, Mdl, CFG, PoolSize, GSSk>::pool_size;
53 
54 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, template<class> class CFG=no_control_flow_graph, unsigned int PoolSize=0, unsigned int GSSk=1>
55 struct lifo_queue_t {
56  typedef pool_aspects<
57  Jn,
59  Mdl,
61  std::less,
62  GSSk,
64  CFG
66 
67  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
68 
69  static const typename pool_type::pool_type::size_type pool_size=PoolSize;
70 };
71 
72 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, template<class> class CFG, unsigned int PoolSize, unsigned int GSSk>
73 const typename lifo_queue_t<Db, Sz, Jn, Mdl, CFG, PoolSize, GSSk>::pool_type::pool_type::size_type lifo_queue_t<Db, Sz, Jn, Mdl, CFG, PoolSize, GSSk>::pool_size;
74 
75 typedef boost::mpl::list<
76  fifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode>,
77  fifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode, control_flow_graph>,
78  fifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, no_control_flow_graph, 1>,
79  fifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, control_flow_graph, 1>,
80  fifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, no_control_flow_graph, 2>,
81  fifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, control_flow_graph, 2>,
82  lifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode>,
83  lifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode, control_flow_graph>,
84  lifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, no_control_flow_graph, 1>,
85  lifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, control_flow_graph, 1>,
86  lifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, no_control_flow_graph, 2>,
87  lifo_queue_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::pool_owns_queue>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, control_flow_graph, 2>
88 > finite_test_types;
89 
90 typedef boost::mpl::list<
91  fifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode>,
92  fifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode, control_flow_graph>,
93  fifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::infinite, generic_traits::return_data::joinable, heavyweight_threading>,
94  fifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::infinite, generic_traits::return_data::joinable, heavyweight_threading, control_flow_graph>,
95  lifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode>,
96  lifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::sequential, generic_traits::return_data::joinable, sequential_mode, control_flow_graph>,
97  lifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::infinite, generic_traits::return_data::joinable, heavyweight_threading>,
98  lifo_queue_t<pool_traits::work_distribution_mode_t::one_thread_distributes<>, pool_traits::size_mode_t::infinite, generic_traits::return_data::joinable, heavyweight_threading, control_flow_graph>
99 > infinite_test_types;
100 
101 // TODO Need to test: pool_traits::size_mode_t::tracks_to_max
102 
103 struct res_t {
104  long i;
105 };
106 
107 struct work_type {
109 
110  int i_;
111 
112  explicit work_type(const int i)
113  : i_(i) {
114  }
115  void __fastcall process(result_type &r) {
116  r.i=i_<<1;
117  }
118  void __fastcall mutate(result_type &r) {
119  process(r);
120  }
121 
122  bool __fastcall operator<(work_type const &i) const {
123  return i_<i.i_;
124  }
125 };
126 
127 struct work_type_simple {
128  int i_;
129 
130  work_type_simple(const int i)
131  : i_(i) {
132  }
133  void __fastcall process(res_t &r) {
134  r.i=i_<<1;
135  }
136 
137  bool __fastcall operator<(work_type_simple const &i) const {
138  return i_<i.i_;
139  }
140 };
141 
142 struct bool_work_type {
143  typedef bool result_type;
144 
145  int i_;
146 
147  explicit bool_work_type(const int i)
148  : i_(i) {
149  }
150  void __fastcall process(result_type &r) const {
151  r=static_cast<bool>(i_);
152  }
153  bool __fastcall operator<(bool_work_type const &) const {
154  return true;
155  }
156 };
157 
158 template<generic_traits::api_type API, typename Mdl>
159 struct horizontal_work_type {
160  typedef void result_type;
161 
162  bool &release;
163 
164  explicit horizontal_work_type(bool &r) noexcept(true)
165  : release(r) {
166  }
167 
168  void __fastcall process() noexcept(false) {
169  while (!release) {
170  api_threading_traits<API, Mdl>::sleep(10);
171  }
172  }
173  bool __fastcall operator<(horizontal_work_type const &) const {
174  return true;
175  }
176 };
177 template<generic_traits::api_type API>
178 struct horizontal_work_type<API, sequential_mode> {
179  typedef void result_type;
180 
181  bool &release;
182 
183  explicit horizontal_work_type(bool &r) noexcept(true)
184  : release(r) {
185  }
186 
187  void __fastcall process() noexcept(true) {
188  }
189  bool __fastcall operator<(horizontal_work_type const &) const {
190  return true;
191  }
192 };
193 
194 template<generic_traits::api_type API, typename Mdl>
196  typedef void result_type;
197 
198  bool &release;
199 
200  explicit horizontal_work_type_rel(bool &r) noexcept(true)
201  : release(r) {}
202 
203  void __fastcall process() noexcept(true) {
204  release=true;
205  }
206  bool __fastcall operator<(horizontal_work_type_rel const &) const {
207  return true;
208  }
209 };
210 
211 BOOST_AUTO_TEST_SUITE(thread_pool_tests)
212 
213 BOOST_AUTO_TEST_SUITE(joinable)
214 
215 BOOST_AUTO_TEST_SUITE(finite)
216 
217 BOOST_AUTO_TEST_SUITE(wait_dataflow)
218 
219 BOOST_AUTO_TEST_CASE_TEMPLATE(add_one_work, T, finite_test_types) {
220  typedef typename T::pool_type pool_type;
221  typedef typename pool_type::joinable joinable;
222 
223  pool_type pool(T::pool_size);
224  auto const &context=pool<<joinable()<<work_type_simple(1);
225  BOOST_CHECK_EQUAL(context->i, 2);
226  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 1);
227  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
228  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 1);
229  BOOST_CHECK_GE(pool.statistics().total_hrz_work().total(), 0);
230  BOOST_CHECK_LE(pool.statistics().total_hrz_work().total(), 1);
231  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
232  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
233  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
234  std::cout<<pool.statistics()<<std::endl;
235 }
236 
237 BOOST_AUTO_TEST_CASE_TEMPLATE(add_two_work, T, finite_test_types) {
238  typedef typename T::pool_type pool_type;
239  typedef typename pool_type::joinable joinable;
240 
241  pool_type pool(T::pool_size);
242  auto const &context=pool<<joinable()<<work_type_simple(1);
243  auto const &context2=pool<<joinable()<<work_type_simple(3);
244  BOOST_CHECK_EQUAL(context->i, 2);
245  BOOST_CHECK_EQUAL(context2->i, 6);
246  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 2);
247  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
248  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 2);
249  BOOST_CHECK_GE(pool.statistics().total_hrz_work().total(), 0);
250  BOOST_CHECK_LE(pool.statistics().total_hrz_work().total(), 2);
251  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
252  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
253  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
254  std::cout<<pool.statistics()<<std::endl;
255 }
256 
257 BOOST_AUTO_TEST_CASE_TEMPLATE(horizontal_threading, T, finite_test_types) {
258  typedef horizontal_work_type<T::thread_pool_traits::os_traits::thread_traits::api_params_type::api_type, typename T::thread_pool_traits::os_traits::thread_traits::model_type> hrz_wk_t;
259  typedef horizontal_work_type_rel<T::thread_pool_traits::os_traits::thread_traits::api_params_type::api_type, typename T::thread_pool_traits::os_traits::thread_traits::model_type> hrz_wk_rel_t;
260  typedef typename T::pool_type pool_type;
261  typedef typename pool_type::joinable joinable;
262 
263  pool_type pool(T::pool_size);
264  bool release=false;
265  hrz_wk_t hz(release);
266  hrz_wk_rel_t hz_rel(release);
267  auto const &context=pool<<joinable()<<hz;
268  auto const &context_rel=pool<<joinable()<<hz_rel;
269  *context;
270  *context_rel;
271  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 2);
272  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
273  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 2);
274  BOOST_CHECK_GE(pool.statistics().total_hrz_work().total(), 0);
275  BOOST_CHECK_LE(pool.statistics().total_hrz_work().total(), 2);
276  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
277  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
278  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
279  std::cout<<pool.statistics()<<std::endl;
280 }
281 
282 BOOST_AUTO_TEST_CASE_TEMPLATE(unary_fn, T, finite_test_types) {
283  typedef typename T::pool_type pool_type;
284 
285  pool_type pool(T::pool_size);
286  auto const &context=pool.unary_fun(bool_work_type(0), std::logical_not<bool_work_type::result_type>());
287  BOOST_CHECK_EQUAL(*context, true);
288  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 2);
289  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
290  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 2);
291  BOOST_CHECK_GE(pool.statistics().total_hrz_work().total(), 0);
292  BOOST_CHECK_LE(pool.statistics().total_hrz_work().total(), 2);
293  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
294  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
295  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
296  std::cout<<pool.statistics()<<std::endl;
297 }
298 
299 BOOST_AUTO_TEST_CASE_TEMPLATE(logical_and, T, finite_test_types) {
300  typedef typename T::pool_type pool_type;
301 
302  pool_type pool(T::pool_size);
303  BOOST_CHECK_EQUAL(pool.pool_size(), T::pool_size);
304  auto const &context=pool.logical_and(bool_work_type(1), bool_work_type(2));
305  BOOST_CHECK_EQUAL(*context, true);
306  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 3);
307  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
308  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 3);
309  BOOST_CHECK_GE(pool.statistics().total_hrz_work().total(), 0);
310  BOOST_CHECK_LE(pool.statistics().total_hrz_work().total(), 3);
311  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
312  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
313  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
314  std::cout<<pool.statistics()<<std::endl;
315 }
316 
317 BOOST_AUTO_TEST_SUITE_END()
318 
319 BOOST_AUTO_TEST_SUITE_END()
320 
321 BOOST_AUTO_TEST_SUITE(infinite)
322 
323 BOOST_AUTO_TEST_SUITE(wait_dataflow)
324 
325 BOOST_AUTO_TEST_CASE_TEMPLATE(add_one_work, T, infinite_test_types) {
326  typedef typename T::pool_type pool_type;
327  typedef typename pool_type::joinable joinable;
328 
329  pool_type pool;
330  auto const &context=pool<<joinable()<<work_type_simple(1);
331  BOOST_CHECK_EQUAL(context->i, 2);
332  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 1);
333  // TODO surely this should be accurate?
334  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
335  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 1);
336  BOOST_CHECK_EQUAL(pool.statistics().total_hrz_work().total(), 0);
337  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
338  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
339  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
340  std::cout<<pool.statistics()<<std::endl;
341 }
342 
343 BOOST_AUTO_TEST_CASE_TEMPLATE(add_two_work, T, infinite_test_types) {
344  typedef typename T::pool_type pool_type;
345  typedef typename pool_type::joinable joinable;
346 
347  pool_type pool;
348  auto const &context=pool<<joinable()<<work_type_simple(1);
349  auto const &context2=pool<<joinable()<<work_type_simple(3);
350  BOOST_CHECK_EQUAL(context->i, 2);
351  BOOST_CHECK_EQUAL(context2->i, 6);
352  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 2);
353  // TODO surely this should be accurate?
354  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
355  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 2);
356  BOOST_CHECK_EQUAL(pool.statistics().total_hrz_work().total(), 0);
357  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
358  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
359  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
360  std::cout<<pool.statistics()<<std::endl;
361 }
362 
363 BOOST_AUTO_TEST_CASE_TEMPLATE(unary_fn, T, infinite_test_types) {
364  typedef typename T::pool_type pool_type;
365 
366  pool_type pool;
367  auto const &context=pool.unary_fun(bool_work_type(1),std::logical_not<bool_work_type::result_type>());
368  BOOST_CHECK_EQUAL(*context, false);
369  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 2);
370  // TODO surely this should be accurate?
371  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
372  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 2);
373  BOOST_CHECK_EQUAL(pool.statistics().total_hrz_work().total(), 0);
374  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
375  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
376  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
377  std::cout<<pool.statistics()<<std::endl;
378 }
379 
380 BOOST_AUTO_TEST_CASE_TEMPLATE(logical_and, T, infinite_test_types) {
381  typedef typename T::pool_type pool_type;
382 
383  pool_type pool;
384  auto const &context=pool.logical_and(bool_work_type(1), bool_work_type(2));
385  BOOST_CHECK_EQUAL(*context, true);
386  BOOST_CHECK_EQUAL(pool.statistics().total_work_added(), 3);
387  // TODO surely this should be accurate?
388  BOOST_CHECK_GE(pool.statistics().total_vertical_work().total(), 0);
389  BOOST_CHECK_LE(pool.statistics().total_vertical_work().total(), 3);
390  BOOST_CHECK_EQUAL(pool.statistics().total_hrz_work().total(), 0);
391  BOOST_CHECK_GE(pool.statistics().total_work_added(), pool.statistics().total_vertical_work().total()+pool.statistics().total_hrz_work().total());
392  BOOST_CHECK_EQUAL(pool.min_time(context), 0U);
393  BOOST_CHECK_EQUAL(pool.min_processors(context), 0U);
394  std::cout<<pool.statistics()<<std::endl;
395 }
396 
397 BOOST_AUTO_TEST_SUITE_END()
398 
399 BOOST_AUTO_TEST_SUITE_END()
400 
401 BOOST_AUTO_TEST_SUITE_END()
402 
403 BOOST_AUTO_TEST_SUITE_END()