root/examples/dataflow_full_transfer_performance.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. BOOST_AUTO_TEST_SUITE
  2. BOOST_AUTO_TEST_CASE_TEMPLATE
  3. BOOST_AUTO_TEST_CASE_TEMPLATE

   1 /******************************************************************************

   2 ** $Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/examples/dataflow_full_transfer_performance.cpp 2185 2017-10-13 10:14:17Z jmmcg $

   3 **

   4 ** Copyright © 2002 by J.M.McGuiness, coder@hussar.me.uk

   5 **

   6 ** This library is free software; you can redistribute it and/or

   7 ** modify it under the terms of the GNU Lesser General Public

   8 ** License as published by the Free Software Foundation; either

   9 ** version 2.1 of the License, or (at your option) any later version.

  10 **

  11 ** This library is distributed in the hope that it will be useful,

  12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of

  13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

  14 ** Lesser General Public License for more details.

  15 **

  16 ** You should have received a copy of the GNU Lesser General Public

  17 ** License along with this library; if not, write to the Free Software

  18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

  19 */
  20 
  21 #include "stdafx.h"
  22 
  23 #define BOOST_TEST_MODULE libjmmcg_tests
  24 #include <boost/test/included/unit_test.hpp>
  25 
  26 #include <boost/test/test_case_template.hpp>
  27 #include <boost/mpl/list.hpp>
  28 
  29 #include "core/thread_pool_sequential.hpp"
  30 #include "core/thread_pool_workers.hpp"
  31 
  32 #include <boost/graph/graphviz.hpp>
  33 
  34 #include <chrono>
  35 #include <random>
  36 
  37 using namespace jmmcg;
  38 using namespace jmmcg::ppd;
  39 
  40 using timed_results_t=ave_deviation_meter<unsigned long long>;
  41 
  42 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
  43 struct erew_normal_fifo_t {
  44         typedef api_lock_traits<platform_api, Mdl> lock_traits;
  45         typedef safe_colln<
  46                 std::vector<long>,
  47                 typename lock_traits::nonrecursive_anon_mutex_type
  48         > vtr_colln_t;
  49 
  50         typedef pool_aspects<
  51                 Jn,
  52                 platform_api,
  53                 Mdl,
  54                 pool_traits::normal_fifo,
  55                 std::less,
  56                 GSSk/*,

  57                 basic_statistics,

  58                 control_flow_graph*/
  59         > thread_pool_traits;
  60 
  61         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
  62 
  63         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
  64 };
  65 
  66 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
  67 struct erew_normal_lifo_t {
  68         typedef api_lock_traits<platform_api, Mdl> lock_traits;
  69         typedef safe_colln<
  70                 std::vector<long>,
  71                 typename lock_traits::nonrecursive_anon_mutex_type
  72         > vtr_colln_t;
  73 
  74         typedef pool_aspects<
  75                 Jn,
  76                 platform_api,
  77                 Mdl,
  78                 pool_traits::normal_lifo,
  79                 std::less,
  80                 GSSk/*,

  81                 basic_statistics,

  82                 control_flow_graph*/
  83         > thread_pool_traits;
  84 
  85         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
  86 
  87         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
  88 };
  89 
  90 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
  91 struct erew_priority_queue_t {
  92         typedef api_lock_traits<platform_api, Mdl> lock_traits;
  93         typedef safe_colln<
  94                 std::vector<long>,
  95                 typename lock_traits::nonrecursive_anon_mutex_type
  96         > vtr_colln_t;
  97 
  98         typedef pool_aspects<
  99                 Jn,
 100                 platform_api,
 101                 Mdl,
 102                 pool_traits::prioritised_queue,
 103                 std::less,
 104                 GSSk/*,

 105                 basic_statistics,

 106                 control_flow_graph*/
 107         > thread_pool_traits;
 108 
 109         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
 110 
 111         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
 112 };
 113 
 114 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1UL>
 115 struct crew_normal_fifo_t {
 116         typedef api_lock_traits<platform_api, Mdl> lock_traits;
 117         typedef safe_colln<
 118                 std::vector<long>,
 119                 typename lock::rw::locker<lock_traits>,
 120                 typename lock::rw::locker<lock_traits>::decaying_write_lock_type
 121         > vtr_colln_t;
 122 
 123         typedef pool_aspects<
 124                 Jn,
 125                 platform_api,
 126                 Mdl,
 127                 pool_traits::normal_fifo,
 128                 std::less,
 129                 GSSk/*,

 130                 basic_statistics,

 131                 control_flow_graph*/
 132         > thread_pool_traits;
 133 
 134         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
 135 
 136         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
 137 };
 138 
 139 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1UL>
 140 struct crew_normal_lifo_t {
 141         typedef api_lock_traits<platform_api, Mdl> lock_traits;
 142         typedef safe_colln<
 143                 std::vector<long>,
 144                 typename lock::rw::locker<lock_traits>,
 145                 typename lock::rw::locker<lock_traits>::decaying_write_lock_type
 146         > vtr_colln_t;
 147 
 148         typedef pool_aspects<
 149                 Jn,
 150                 platform_api,
 151                 Mdl,
 152                 pool_traits::normal_lifo,
 153                 std::less,
 154                 GSSk/*,

 155                 basic_statistics,

 156                 control_flow_graph*/
 157         > thread_pool_traits;
 158 
 159         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
 160 
 161         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
 162 };
 163 
 164 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1UL>
 165 struct crew_normal_lifo_lockfree_t {
 166         typedef api_lock_traits<platform_api, Mdl> lock_traits;
 167         typedef safe_colln<
 168                 std::vector<long>,
 169                 typename lock::rw::locker<lock_traits>,
 170                 typename lock::rw::locker<lock_traits>::decaying_write_lock_type
 171         > vtr_colln_t;
 172 
 173         typedef pool_aspects<
 174                 Jn,
 175                 platform_api,
 176                 Mdl,
 177                 pool_traits::normal_lifo_lockfree,
 178                 std::less,
 179                 GSSk/*,

 180                 basic_statistics,

 181                 control_flow_graph*/
 182         > thread_pool_traits;
 183 
 184         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
 185 
 186         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
 187 };
 188 
 189 template<class Db, pool_traits::size_mode_t Sz, generic_traits::return_data Jn, class Mdl, unsigned int PoolSize=0, unsigned long GSSk=1>
 190 struct crew_priority_queue_t {
 191         typedef api_lock_traits<platform_api, Mdl> lock_traits;
 192         typedef safe_colln<
 193                 std::vector<long>,
 194                 typename lock::rw::locker<lock_traits>,
 195                 typename lock::rw::locker<lock_traits>::decaying_write_lock_type
 196         > vtr_colln_t;
 197 
 198         typedef pool_aspects<
 199                 Jn,
 200                 platform_api,
 201                 Mdl,
 202                 pool_traits::prioritised_queue,
 203                 std::less,
 204                 GSSk/*,

 205                 basic_statistics,

 206                 control_flow_graph*/
 207         > thread_pool_traits;
 208 
 209         typedef thread_pool<Db, Sz, thread_pool_traits> pool_type;
 210 
 211         static constexpr typename pool_type::pool_type::size_type pool_size=PoolSize;
 212 };
 213 
 214 typedef boost::mpl::list<
 215         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>,
 216         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>,
 217         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>,
 218         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>,
 219         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>,
 220         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>
 221 > dataflow_ps1_test_types;
 222 
 223 typedef boost::mpl::list<
 224         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>,
 225         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>,
 226         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>,
 227         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>/*,

 228 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>*/
 229 > dataflow_ps12_test_types;
 230 
 231 struct trivial_work {
 232         constexpr trivial_work() noexcept(true) {
 233         }
 234         void process() noexcept(true) {
 235         }
 236 
 237         constexpr bool __fastcall operator<(trivial_work const &) const noexcept(true) {
 238                 return true;
 239         }
 240 };
 241 
 242 template<class PT>
 243 struct recusive_work {
 244         typedef PT pool_type;
 245         typedef typename pool_type::joinable joinable;
 246 
 247         const unsigned long depth;
 248         pool_type &pool;
 249 
 250         constexpr recusive_work(const unsigned long d, pool_type &p) noexcept(true)
 251         : depth(d), pool(p) {
 252         }
 253         void process() noexcept(true) {
 254                 if (depth>0) {
 255                         auto const &context1=pool<<joinable()<<recusive_work(depth-1, pool);
 256                         auto const &context2=pool<<joinable()<<recusive_work(depth-1, pool);
 257                         *context1;
 258                         *context2;
 259                 }
 260         }
 261 
 262         constexpr bool __fastcall operator<(recusive_work const &) const noexcept(true) {
 263                 return true;
 264         }
 265 };
 266 
 267 template<class PT>
 268 struct pool_1ctx_work {
 269         typedef PT pool_type;
 270         using joinable=typename pool_type::joinable;
 271 
 272         unsigned long num_xfers;
 273         pool_type &pool;
 274 
 275         constexpr pool_1ctx_work(const unsigned long x, pool_type &p) noexcept(true)
 276         : num_xfers(x), pool(p) {
 277         }
 278         void process() noexcept(true) {
 279                 while (--num_xfers) {
 280                         auto const &context=pool<<joinable()<<trivial_work();
 281                         *context;
 282                 }
 283         }
 284 
 285         constexpr bool __fastcall operator<(pool_1ctx_work const &) const noexcept(true) {
 286                 return true;
 287         }
 288 };
 289 
 290 // TODO Need to test: pool_traits::size_mode_t::tracks_to_max

 291 
 292 BOOST_AUTO_TEST_SUITE(thread_pool_tests)
 293 
 294 BOOST_AUTO_TEST_SUITE(joinable_dataflow)
 295 
 296 BOOST_AUTO_TEST_SUITE(finite)
 297 
 298 BOOST_AUTO_TEST_SUITE(n_elements)
 299 
 300 /**

 301         \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.

 302                         =========================================

 303         This tests how long it takes to:

 304         -# Create an execution_context on the stack.

 305         -# Add the work to the queue.

 306         -# Increment and decrement the number of active work items in the queue.

 307         -# 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.

 308         -# Signal that the work has been completed.

 309         -# It does not test the scalability of multiple threads contending to add work to, or remove work from, the queue.

 310         -# Results:

 311                 -#      Build 1405:

 312                         -       Pool=1, vertical dataflow transfers per second: [14063, 36066 ~(+/-9%), 287956], samples=1001, total=36102451

 313                                 i.e. @2.6GHz, [71microsec, 28microsec, 3.5microsec] per data transfer.

 314                 -#      Build 1447:

 315                         -       Pool=1, vertical dataflow transfers per second: [8438, 53961 ~(+/-29%), 260460], samples=1001, total=54015303

 316                                 i.e. @2.6GHz, [119microsec, 19microsec, 3.8microsec] per data transfer.

 317                 -#      Build 1561:

 318                         -       Pool=1, time taken: [3023, 23473 ~(+/-174%), 130458], samples=2001, total=46971159 usec.

 319                                 i.e. @2.6GHz, [130microsec, 23microsec, 3.0microsec] per data transfer.

 320 */
 321 BOOST_AUTO_TEST_CASE_TEMPLATE(single_vertical_dataflow_operations_rate, T, dataflow_ps1_test_types) {
 322         typedef typename T::pool_type pool_type;
 323 
 324 #ifdef JMMCG_PERFORMANCE_TESTS
 325         const unsigned long test_size=2<<9;
 326         const unsigned long num_reps=20000;
 327 #else
 328         const unsigned long test_size=2<<3;
 329         const unsigned long num_reps=2;
 330 #endif
 331         pool_type pool(T::pool_size);
 332         BOOST_CHECK_EQUAL(pool.pool_size(), 1UL);       // The pool_size() must be 1 for this test.

 333         std::cout<<"Pool="<<pool.pool_size()<<std::flush;
 334         const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
 335                 1.0,
 336                 num_reps,
 337                 [test_size, &pool]() {
 338                         typedef typename pool_type::joinable joinable;
 339 
 340                         const auto t1=std::chrono::high_resolution_clock::now();
 341                         for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
 342                                 auto const &context=pool<<joinable()<<trivial_work();
 343                                 *context;
 344                         }
 345                         const auto t2=std::chrono::high_resolution_clock::now();
 346                         return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
 347                 }
 348         ));
 349         std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
 350         const double rescale=1.0d/(test_size*pool.pool_size());
 351         std::cout<<"Vertical dataflow transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
 352         std::cout<<pool.statistics()<<std::endl;
 353 #ifdef JMMCG_PERFORMANCE_TESTS
 354         BOOST_CHECK(!timed_results.second);
 355 #endif
 356 }
 357 
 358 /** TODO

 359         \test <a href="./examples/dataflow_full_transfer_performance.svg">Graph</a> of vertical dataflow-transfers, avoiding a context switch, (pool_size()=1) operations rate.

 360                         =========================================

 361         This tests how long it takes to:

 362         -# Create an execution_context on the stack.

 363         -# Add the work to the queue, and wait for it to complete.

 364         -# The work task is to transfer a trivial work-item to the queue and wait for it to complete. This is performed repeatedly.

 365         -# The concept is that the transferred work should be run by the same thread that transferred it, potentially avoiding any context switch.

 366         -# Results:

 367                 -#      Build 1671:

 368                         -       Pool=1, vertical dataflow transfers per second: TODO

 369                                 i.e. @2.6GHz, [71microsec, 28microsec, 3.5microsec] per data transfer.

 370 */
 371 /* TODO

 372 BOOST_AUTO_TEST_CASE_TEMPLATE(vertical_dataflow_1ctx_operations_rate, T, dataflow_ps1_test_types) {

 373         typedef typename T::pool_type pool_type;

 374 

 375 #ifdef JMMCG_PERFORMANCE_TESTS

 376         const unsigned long test_size=2<<4;

 377         const unsigned long num_reps=1000;

 378 #else

 379         const unsigned long test_size=2<<2;

 380         const unsigned long num_reps=2;

 381 #endif

 382         pool_type pool(T::pool_size);

 383         BOOST_CHECK_EQUAL(pool.pool_size(), 1UL);       // The pool_size() must be 1 for this test.

 384         std::cout<<"Pool="<<pool.pool_size()<<std::flush;

 385         const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(

 386                 1.0,

 387                 num_reps,

 388                 [test_size, &pool]() {

 389                         typedef typename pool_type::joinable joinable;

 390 

 391                         const auto t1=std::chrono::high_resolution_clock::now();

 392                         using work_type=pool_1ctx_work<pool_type>;

 393                         auto const &context=pool<<joinable()<<work_type(test_size, pool);

 394                         const auto t2=std::chrono::high_resolution_clock::now();

 395                         return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());

 396                 }

 397         ));

 398         std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;

 399         const double rescale=1.0d/(test_size*pool.pool_size());

 400         std::cout<<"Vertical dataflow transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;

 401         std::cout<<pool.statistics()<<std::endl;

 402 #ifdef JMMCG_PERFORMANCE_TESTS

 403         BOOST_CHECK(!timed_results.second);

 404 #endif

 405 }

 406 */
 407 /**

 408         \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.

 409                         ==================================

 410         This tests how long it takes to:

 411         -# Creates twelve execution_contexts on the stack, enqueuing the work.

 412         -# The pool of threads process the work, i.e. a context-switch is involved.

 413         -# 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.

 414         -# Results:

 415                 -#      Build 1405:

 416                         -       Pool=12, vertical dataflow transfers per second: [681, 1223 ~(+/-0%), 1811], samples=64, total=78278

 417                                 i.e. @2.6GHz, [122microsec, 68microsec, 46microsec] per data transfer.

 418                 -#      Build 1415:

 419                         -       Pool=12, vertical dataflow transfers per second: [3368, 3547 ~(+/-0%), 3855], samples=181, total=642030

 420                                 i.e. @2.6GHz, [25microsec, 23microsec, 22microsec] per data transfer.

 421                 -#      Build 1447:

 422                         -       Pool=12, vertical dataflow transfers per second: [4242, 4622 ~(+/-0%), 5879], samples=757, total=3499459

 423                                 i.e. @2.6GHz, [20microsec, 18microsec, 14microsec] per data transfer.

 424 */
 425 BOOST_AUTO_TEST_CASE_TEMPLATE(vertical_dataflow_operations_rate, T, dataflow_ps12_test_types) {
 426         typedef typename T::pool_type pool_type;
 427 
 428 #ifdef JMMCG_PERFORMANCE_TESTS
 429         const unsigned long test_size=2<<10;
 430         const unsigned long num_reps=1000;
 431 #else
 432         const unsigned long test_size=2<<3;
 433         const unsigned long num_reps=2;
 434 #endif
 435         // This parameter is heavily dependent upon the max_stack_size of the pool_threads in the thread_pool.

 436         pool_type pool(T::pool_size);
 437         BOOST_CHECK_EQUAL(pool.pool_size(), 12UL);      // The pool_size() must be 12 for this test.

 438         std::cout<<"Pool="<<pool.pool_size()<<std::flush;
 439         const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
 440                 10.0,
 441                 num_reps,
 442                 [&pool]() {
 443                         typedef typename pool_type::joinable joinable;
 444 
 445                         const auto t1=std::chrono::high_resolution_clock::now();
 446                         for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
 447                                 auto const &context1=pool<<joinable()<<trivial_work();
 448                                 auto const &context2=pool<<joinable()<<trivial_work();
 449                                 auto const &context3=pool<<joinable()<<trivial_work();
 450                                 auto const &context4=pool<<joinable()<<trivial_work();
 451                                 auto const &context5=pool<<joinable()<<trivial_work();
 452                                 auto const &context6=pool<<joinable()<<trivial_work();
 453                                 auto const &context7=pool<<joinable()<<trivial_work();
 454                                 auto const &context8=pool<<joinable()<<trivial_work();
 455                                 auto const &context9=pool<<joinable()<<trivial_work();
 456                                 auto const &context10=pool<<joinable()<<trivial_work();
 457                                 auto const &context11=pool<<joinable()<<trivial_work();
 458                                 auto const &context12=pool<<joinable()<<trivial_work();
 459                                 *context1;
 460                                 *context2;
 461                                 *context3;
 462                                 *context4;
 463                                 *context5;
 464                                 *context6;
 465                                 *context7;
 466                                 *context8;
 467                                 *context9;
 468                                 *context10;
 469                                 *context11;
 470                                 *context12;
 471                         }
 472                         const auto t2=std::chrono::high_resolution_clock::now();
 473                         return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
 474                 }
 475         ));
 476         std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
 477         const double rescale=1.0d/(test_size*pool.pool_size());
 478         std::cout<<"Vertical dataflow transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
 479         std::cout<<pool.statistics()<<std::endl;
 480 #ifdef JMMCG_PERFORMANCE_TESTS
 481         BOOST_CHECK(!timed_results.second);
 482 #endif
 483 }
 484 
 485 /**

 486         \test <a href="./examples/dataflow_full_transfer_performance.svg">Graph</a> of tree-creation dataflow (pool_size()=12) transfers rate.

 487                         ===================================

 488         This tests how long it takes to:

 489         -# Recursively creates two execution_contexts on the stack, waiting for the tree to be created.

 490         -# The leaf-nodes are processed & return, the tree reduces. Related sibling-nodes are executed by the same thread, others may involve a context-switch.

 491         -# 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.

 492         -# 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.

 493         -# The contention on the queue is extremely high from all of the spawned horizontal threads.

 494         -# Results:

 495                 -#      Build 1447:

 496                         -       Pool=12, vertical dataflow transfers per second: [8438, 53961 ~(+/-29%), 260460], samples=1001, total=54015303

 497                                 i.e. @2.6GHz, [119microsec, 19microsec, 3.8microsec] per data transfer.

 498                 -#      Build 1561:

 499                         -       Pool=12, time taken: [54029, 103259 ~(+/-19%), 478100], samples=2001, total=206621313 usec.

 500                                 i.e. @2.6GHz, 0.53microsec per data transfer.

 501 */
 502 BOOST_AUTO_TEST_CASE_TEMPLATE(horizontal_dataflow_transfers_rate, T, dataflow_ps12_test_types) {
 503         typedef typename T::pool_type pool_type;
 504 
 505         // This parameter is heavily dependent upon the max_stack_size of the pool_threads in the thread_pool.

 506 #ifdef JMMCG_PERFORMANCE_TESTS
 507         const unsigned long test_size=2<<13;
 508         const unsigned long num_reps=20000;
 509         const unsigned long test_depth=3;
 510 #else
 511         const unsigned long test_size=2<<3;
 512         const unsigned long num_reps=2;
 513         const unsigned long test_depth=1;
 514 #endif
 515         pool_type pool(T::pool_size);
 516         std::cout<<"Pool="<<pool.pool_size()<<std::flush;
 517         const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
 518                 5.0,
 519                 num_reps,
 520                 [test_depth, test_size, &pool]() {
 521                         typedef typename pool_type::joinable joinable;
 522                         typedef recusive_work<pool_type> work_type;
 523 
 524                         const unsigned long test_size=1<<6;
 525                         const auto t1=std::chrono::high_resolution_clock::now();
 526                         for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
 527                                 auto const &context=pool<<joinable()<<work_type(test_depth, pool);
 528                                 *context;
 529                         }
 530                         const auto t2=std::chrono::high_resolution_clock::now();
 531                         return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
 532                 }
 533         ));
 534         std::cout<<", time taken: "<<timed_results.first<<" usec."<<std::endl;
 535         const double rescale=1.0d/(test_size*pool.pool_size());
 536         std::cout<<"Tree-constructions transfer took (usec): "<<rescale*timed_results.first.arithmetic_mean()<<std::endl;
 537         std::cout<<pool.statistics()<<std::endl;
 538 #ifdef JMMCG_PERFORMANCE_TESTS
 539         BOOST_CHECK(!timed_results.second);
 540 #endif
 541 }
 542 
 543 BOOST_AUTO_TEST_SUITE_END()
 544 
 545 BOOST_AUTO_TEST_SUITE_END()
 546 
 547 BOOST_AUTO_TEST_SUITE_END()
 548 
 549 BOOST_AUTO_TEST_SUITE_END()

/* [<][>][^][v][top][bottom][index][help] */