libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
dataflow_full_transfer_performance.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2002 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_workers.hpp"
28 
29 #include <boost/graph/graphviz.hpp>
30 
31 #include <chrono>
32 #include <random>
33 
34 using namespace libjmmcg;
35 using namespace ppd;
36 
37 using timed_results_t=ave_deviation_meter<unsigned long long>;
38 
39 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
40 struct erew_normal_fifo_t {
41  typedef api_lock_traits<platform_api, Mdl> lock_traits;
42  typedef safe_colln<
43  std::vector<long>,
46 
47  typedef pool_aspects<
48  Jn,
50  Mdl,
52  std::less,
53  GSSk/*,
54  basic_statistics,
55  control_flow_graph*/
57 
58  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
59 
60  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
61 };
62 
63 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
64 struct erew_normal_lifo_t {
65  typedef api_lock_traits<platform_api, Mdl> lock_traits;
66  typedef safe_colln<
67  std::vector<long>,
70 
71  typedef pool_aspects<
72  Jn,
74  Mdl,
76  std::less,
77  GSSk/*,
78  basic_statistics,
79  control_flow_graph*/
81 
82  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
83 
84  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
85 };
86 
87 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
88 struct erew_priority_queue_t {
89  typedef api_lock_traits<platform_api, Mdl> lock_traits;
90  typedef safe_colln<
91  std::vector<long>,
94 
95  typedef pool_aspects<
96  Jn,
98  Mdl,
100  std::less,
101  GSSk/*,
102  basic_statistics,
103  control_flow_graph*/
105 
106  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
107 
108  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
109 };
110 
111 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1UL>
112 struct crew_normal_fifo_t {
113  typedef api_lock_traits<platform_api, Mdl> lock_traits;
114  typedef safe_colln<
115  std::vector<long>,
116  typename lock::rw::locker<lock_traits>,
119 
120  typedef pool_aspects<
121  Jn,
122  platform_api,
123  Mdl,
125  std::less,
126  GSSk/*,
127  basic_statistics,
128  control_flow_graph*/
130 
131  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
132 
133  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
134 };
135 
136 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1UL>
137 struct crew_normal_lifo_t {
138  typedef api_lock_traits<platform_api, Mdl> lock_traits;
139  typedef safe_colln<
140  std::vector<long>,
141  typename lock::rw::locker<lock_traits>,
144 
145  typedef pool_aspects<
146  Jn,
147  platform_api,
148  Mdl,
150  std::less,
151  GSSk/*,
152  basic_statistics,
153  control_flow_graph*/
155 
156  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
157 
158  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
159 };
160 
161 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1UL>
163  typedef api_lock_traits<platform_api, Mdl> lock_traits;
164  typedef safe_colln<
165  std::vector<long>,
166  typename lock::rw::locker<lock_traits>,
169 
170  typedef pool_aspects<
171  Jn,
172  platform_api,
173  Mdl,
175  std::less,
176  GSSk/*,
177  basic_statistics,
178  control_flow_graph*/
180 
181  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
182 
183  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
184 };
185 
186 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
187 struct crew_priority_queue_t {
188  typedef api_lock_traits<platform_api, Mdl> lock_traits;
189  typedef safe_colln<
190  std::vector<long>,
191  typename lock::rw::locker<lock_traits>,
194 
195  typedef pool_aspects<
196  Jn,
197  platform_api,
198  Mdl,
200  std::less,
201  GSSk/*,
202  basic_statistics,
203  control_flow_graph*/
205 
206  typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
207 
208  static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
209 };
210 
211 typedef boost::mpl::list<
212  erew_normal_fifo_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, 1>,
213  erew_normal_lifo_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, 1>,
214  crew_normal_fifo_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, 1>,
215  crew_normal_lifo_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, 1>,
216  crew_normal_lifo_lockfree_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, 1>,
217  crew_normal_lifo_lockfree_t<pool_traits::work_distribution_mode_t::worker_threads_get_work<pool_traits::work_distribution_mode_t::queue_model_t::thread_owns_queue<pool_traits::work_distribution_mode_t::queue_model_t::stealing_mode_t::random>>, pool_traits::size_mode_t::fixed_size, generic_traits::return_data::joinable, heavyweight_threading, 1>
218 > dataflow_ps1_test_types;
219 
220 typedef boost::mpl::list<
221  erew_normal_fifo_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, 12>,
222  erew_normal_lifo_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, 12>,
223  crew_normal_fifo_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, 12>,
224  crew_normal_lifo_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, 12>/*,
225 TODO crew_normal_lifo_lockfree_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, 12>*/
226 > dataflow_ps12_test_types;
227 
228 struct trivial_work {
229  constexpr trivial_work() noexcept(true) {
230  }
231  void process() noexcept(true) {
232  }
233 
234  constexpr bool __fastcall operator<(trivial_work const &) const noexcept(true) {
235  return true;
236  }
237 };
238 
239 template<class PT>
241  typedef PT pool_type;
242  typedef typename pool_type::joinable joinable;
243 
244  const unsigned long depth;
246 
247  constexpr recusive_work(const unsigned long d, pool_type &p) noexcept(true)
248  : depth(d), pool(p) {
249  }
250  void process() noexcept(true) {
251  if (depth>0) {
252  auto const &context1=pool<<joinable()<<recusive_work(depth-1, pool);
253  auto const &context2=pool<<joinable()<<recusive_work(depth-1, pool);
254  *context1;
255  *context2;
256  }
257  }
258 
259  constexpr bool __fastcall operator<(recusive_work const &) const noexcept(true) {
260  return true;
261  }
262 };
263 
264 template<class PT>
266  typedef PT pool_type;
267  using joinable=typename pool_type::joinable;
268 
269  unsigned long num_xfers;
271 
272  constexpr pool_1ctx_work(const unsigned long x, pool_type &p) noexcept(true)
273  : num_xfers(x), pool(p) {
274  }
275  void process() noexcept(true) {
276  while (--num_xfers) {
277  auto const &context=pool<<joinable()<<trivial_work();
278  *context;
279  }
280  }
281 
282  constexpr bool __fastcall operator<(pool_1ctx_work const &) const noexcept(true) {
283  return true;
284  }
285 };
286 
287 // TODO Need to test: pool_traits::size_mode_t::tracks_to_max
288 
289 BOOST_AUTO_TEST_SUITE(thread_pool_tests)
290 
291 BOOST_AUTO_TEST_SUITE(joinable_dataflow)
292 
293 BOOST_AUTO_TEST_SUITE(finite)
294 
295 BOOST_AUTO_TEST_SUITE(n_elements)
296 
297 /**
298  \test Graphs of <a href="./examples/dataflow_full_transfer_performance.svg">vertical & horizontal</a> and <a href="./examples/dataflow_full_vertical_transfer_performance_pool_size_1.svg">vertical with different pool_types</a> dataflow (pool_size()=1) operations rate.
299  =========================================
300  This tests how long it takes to:
301  -# Create an execution_context on the stack.
302  -# Add the work to the queue.
303  -# Increment and decrement the number of active work items in the queue.
304  -# Have one vertical thread wake up and remove the work, i.e. the thread pool does not saturate as only the main thread produces work, and one thread in the pool consumes that work and a context-switch is involved.
305  -# Signal that the work has been completed.
306  -# It does not test the scalability of multiple threads contending to add work to, or remove work from, the queue.
307  -# Results:
308  -# Build 1405:
309  - Pool=1, vertical dataflow transfers per second: [14063, 36066 ~(+/-9%), 287956], samples=1001, total=36102451
310  i.e. @2.6GHz, [71microsec, 28microsec, 3.5microsec] per data transfer.
311  -# Build 1447:
312  - Pool=1, vertical dataflow transfers per second: [8438, 53961 ~(+/-29%), 260460], samples=1001, total=54015303
313  i.e. @2.6GHz, [119microsec, 19microsec, 3.8microsec] per data transfer.
314  -# Build 1561:
315  - Pool=1, time taken: [3023, 23473 ~(+/-174%), 130458], samples=2001, total=46971159 usec.
316  i.e. @2.6GHz, [130microsec, 23microsec, 3.0microsec] per data transfer.
317 */
318 BOOST_AUTO_TEST_CASE_TEMPLATE(single_vertical_dataflow_operations_rate, T, dataflow_ps1_test_types) {
319  typedef typename T::pool_type pool_type;
320 
321 #ifdef JMMCG_PERFORMANCE_TESTS
322  const unsigned long test_size=2<<9;
323  const unsigned long num_reps=20000;
324 #else
325  const unsigned long test_size=2<<3;
326  const unsigned long num_reps=2;
327 #endif
328  pool_type pool(T::pool_size);
329  BOOST_CHECK_EQUAL(pool.pool_size(), 1UL); // The pool_size() must be 1 for this test.
330  std::cout<<"Pool="<<pool.pool_size()<<std::flush;
331  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
332  1.0,
333  num_reps,
334  [&pool]() {
335  typedef typename pool_type::joinable joinable;
336 
337  const auto t1=std::chrono::high_resolution_clock::now();
338  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
339  auto const &context=pool<<joinable()<<trivial_work();
340  *context;
341  }
342  const auto t2=std::chrono::high_resolution_clock::now();
343  return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
344  }
345  ));
346  std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
347  const double rescale=1.0/(test_size*pool.pool_size());
348  std::cout<<"Vertical dataflow transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
349  std::cout<<pool.statistics()<<std::endl;
350 #ifdef JMMCG_PERFORMANCE_TESTS
351  BOOST_CHECK(!timed_results.second);
352 #endif
353 }
354 
355 /** TODO
356  \test <a href="./examples/dataflow_full_transfer_performance.svg">Graph</a> of vertical dataflow-transfers, avoiding a context switch, (pool_size()=1) operations rate.
357  =========================================
358  This tests how long it takes to:
359  -# Create an execution_context on the stack.
360  -# Add the work to the queue, and wait for it to complete.
361  -# The work task is to transfer a trivial work-item to the queue and wait for it to complete. This is performed repeatedly.
362  -# The concept is that the transferred work should be run by the same thread that transferred it, potentially avoiding any context switch.
363  -# Results:
364  -# Build 1671:
365  - Pool=1, vertical dataflow transfers per second: TODO
366  i.e. @2.6GHz, [71microsec, 28microsec, 3.5microsec] per data transfer.
367 */
368 /* TODO
369 BOOST_AUTO_TEST_CASE_TEMPLATE(vertical_dataflow_1ctx_operations_rate, T, dataflow_ps1_test_types) {
370  typedef typename T::pool_type pool_type;
371 
372 #ifdef JMMCG_PERFORMANCE_TESTS
373  const unsigned long test_size=2<<4;
374  const unsigned long num_reps=1000;
375 #else
376  const unsigned long test_size=2<<2;
377  const unsigned long num_reps=2;
378 #endif
379  pool_type pool(T::pool_size);
380  BOOST_CHECK_EQUAL(pool.pool_size(), 1UL); // The pool_size() must be 1 for this test.
381  std::cout<<"Pool="<<pool.pool_size()<<std::flush;
382  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
383  1.0,
384  num_reps,
385  [test_size, &pool]() {
386  typedef typename pool_type::joinable joinable;
387 
388  const auto t1=std::chrono::high_resolution_clock::now();
389  using work_type=pool_1ctx_work<pool_type>;
390  auto const &context=pool<<joinable()<<work_type(test_size, pool);
391  const auto t2=std::chrono::high_resolution_clock::now();
392  return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
393  }
394  ));
395  std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
396  const double rescale=1.0/(test_size*pool.pool_size());
397  std::cout<<"Vertical dataflow transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
398  std::cout<<pool.statistics()<<std::endl;
399 #ifdef JMMCG_PERFORMANCE_TESTS
400  BOOST_CHECK(!timed_results.second);
401 #endif
402 }
403 */
404 /**
405  \test Graphs of <a href="./examples/dataflow_full_transfer_performance.svg">vertical & horizontal</a> and <a href="./examples/dataflow_full_vertical_transfer_performance_pool_size_12.svg">vertical with different pool_types</a> dataflow (pool_size()=12) operations rate.
406  ==================================
407  This tests how long it takes to:
408  -# Creates twelve execution_contexts on the stack, enqueuing the work.
409  -# The pool of threads process the work, i.e. a context-switch is involved.
410  -# This rapidly creates work, which is processed, usually using only one of the threads in the pool. With twelve threads there is a lot of contention on the queue for the work. The vast majority is executed vertically.
411  -# Results:
412  -# Build 1405:
413  - Pool=12, vertical dataflow transfers per second: [681, 1223 ~(+/-0%), 1811], samples=64, total=78278
414  i.e. @2.6GHz, [122microsec, 68microsec, 46microsec] per data transfer.
415  -# Build 1415:
416  - Pool=12, vertical dataflow transfers per second: [3368, 3547 ~(+/-0%), 3855], samples=181, total=642030
417  i.e. @2.6GHz, [25microsec, 23microsec, 22microsec] per data transfer.
418  -# Build 1447:
419  - Pool=12, vertical dataflow transfers per second: [4242, 4622 ~(+/-0%), 5879], samples=757, total=3499459
420  i.e. @2.6GHz, [20microsec, 18microsec, 14microsec] per data transfer.
421 */
422 BOOST_AUTO_TEST_CASE_TEMPLATE(vertical_dataflow_operations_rate, T, dataflow_ps12_test_types) {
423  typedef typename T::pool_type pool_type;
424 
425 #ifdef JMMCG_PERFORMANCE_TESTS
426  const unsigned long test_size=2<<10;
427  const unsigned long num_reps=1000;
428 #else
429  const unsigned long test_size=2<<3;
430  const unsigned long num_reps=2;
431 #endif
432  // This parameter is heavily dependent upon the max_stack_size of the pool_threads in the thread_pool.
433  pool_type pool(T::pool_size);
434  BOOST_CHECK_EQUAL(pool.pool_size(), 12UL); // The pool_size() must be 12 for this test.
435  std::cout<<"Pool="<<pool.pool_size()<<std::flush;
436  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
437  10.0,
438  num_reps,
439  [&pool]() {
440  typedef typename pool_type::joinable joinable;
441 
442  const auto t1=std::chrono::high_resolution_clock::now();
443  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
444  auto const &context1=pool<<joinable()<<trivial_work();
445  auto const &context2=pool<<joinable()<<trivial_work();
446  auto const &context3=pool<<joinable()<<trivial_work();
447  auto const &context4=pool<<joinable()<<trivial_work();
448  auto const &context5=pool<<joinable()<<trivial_work();
449  auto const &context6=pool<<joinable()<<trivial_work();
450  auto const &context7=pool<<joinable()<<trivial_work();
451  auto const &context8=pool<<joinable()<<trivial_work();
452  auto const &context9=pool<<joinable()<<trivial_work();
453  auto const &context10=pool<<joinable()<<trivial_work();
454  auto const &context11=pool<<joinable()<<trivial_work();
455  auto const &context12=pool<<joinable()<<trivial_work();
456  *context1;
457  *context2;
458  *context3;
459  *context4;
460  *context5;
461  *context6;
462  *context7;
463  *context8;
464  *context9;
465  *context10;
466  *context11;
467  *context12;
468  }
469  const auto t2=std::chrono::high_resolution_clock::now();
470  return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
471  }
472  ));
473  std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
474  const double rescale=1.0/(test_size*pool.pool_size());
475  std::cout<<"Vertical dataflow transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
476  std::cout<<pool.statistics()<<std::endl;
477 #ifdef JMMCG_PERFORMANCE_TESTS
478  BOOST_CHECK(!timed_results.second);
479 #endif
480 }
481 
482 /**
483  \test <a href="./examples/dataflow_full_transfer_performance.svg">Graph</a> of tree-creation dataflow (pool_size()=12) transfers rate.
484  ===================================
485  This tests how long it takes to:
486  -# Recursively creates two execution_contexts on the stack, waiting for the tree to be created.
487  -# The leaf-nodes are processed & return, the tree reduces. Related sibling-nodes are executed by the same thread, others may involve a context-switch.
488  -# If the test_depth is small, e.g. 3, then eight leaf-nodes are created, for a total of 14 nodes . With a pool_size of 12, the work will be mutated vertically. A test-depth of 4 would produce 16 leaf-nodes, and a total of 30 nodes.
489  -# This can rapidly flood the pool full of work, if the depth generates many more leaf-nodes than pool_threads, in which case the vast majority would be executed horizontally.
490  -# The contention on the queue is extremely high from all of the spawned horizontal threads.
491  -# Results:
492  -# Build 1447:
493  - Pool=12, vertical dataflow transfers per second: [8438, 53961 ~(+/-29%), 260460], samples=1001, total=54015303
494  i.e. @2.6GHz, [119microsec, 19microsec, 3.8microsec] per data transfer.
495  -# Build 1561:
496  - Pool=12, time taken: [54029, 103259 ~(+/-19%), 478100], samples=2001, total=206621313 usec.
497  i.e. @2.6GHz, 0.53microsec per data transfer.
498 */
499 BOOST_AUTO_TEST_CASE_TEMPLATE(horizontal_dataflow_transfers_rate, T, dataflow_ps12_test_types) {
500  typedef typename T::pool_type pool_type;
501 
502  // This parameter is heavily dependent upon the max_stack_size of the pool_threads in the thread_pool.
503 #ifdef JMMCG_PERFORMANCE_TESTS
504  const unsigned long test_size=2<<13;
505  const unsigned long num_reps=20000;
506  const unsigned long test_depth=3;
507 #else
508  const unsigned long test_size=2<<3;
509  const unsigned long num_reps=2;
510  const unsigned long test_depth=1;
511 #endif
512  pool_type pool(T::pool_size);
513  std::cout<<"Pool="<<pool.pool_size()<<std::flush;
514  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
515  5.0,
516  num_reps,
517  [&pool]() {
518  typedef typename pool_type::joinable joinable;
519  typedef recusive_work<pool_type> work_type;
520 
521  const unsigned long test_size=1<<6;
522  const auto t1=std::chrono::high_resolution_clock::now();
523  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
524  auto const &context=pool<<joinable()<<work_type(test_depth, pool);
525  *context;
526  }
527  const auto t2=std::chrono::high_resolution_clock::now();
528  return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
529  }
530  ));
531  std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
532  const double rescale=1.0/(test_size*pool.pool_size());
533  std::cout<<"Tree-constructions transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
534  std::cout<<pool.statistics()<<std::endl;
535 #ifdef JMMCG_PERFORMANCE_TESTS
536  BOOST_CHECK(!timed_results.second);
537 #endif
538 }
539 
540 BOOST_AUTO_TEST_SUITE_END()
541 
542 BOOST_AUTO_TEST_SUITE_END()
543 
544 BOOST_AUTO_TEST_SUITE_END()
545 
546 BOOST_AUTO_TEST_SUITE_END()