libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
unique_ptr_parallel.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2011 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/ave_deviation_meter.hpp"
27 #include "core/stats_output.hpp"
28 #include "core/thread_wrapper.hpp"
29 #include "core/unique_ptr.hpp"
30 
31 #include <boost/move/unique_ptr.hpp>
32 
33 #include <chrono>
34 
35 using namespace libjmmcg;
36 using namespace ppd;
37 
38 template<class Mdl>
39 struct obj {
40  using lock_traits=api_lock_traits<platform_api, Mdl>;
41  using element_type=int;
42  using deleter_t=default_delete<obj>;
43 
44  element_type const init;
45 
46  obj(element_type i) noexcept(true) : init(i) {}
47  ~obj() noexcept(true) {}
48 
49  void deleter() {
50  deleter_t().operator()(this);
51  }
52 };
53 
54 using ptr_types=boost::mpl::list<
55  std::unique_ptr<obj<heavyweight_threading>>,
56  boost::movelib::unique_ptr<obj<heavyweight_threading>>,
57  unique_ptr<obj<sequential_mode>, api_lock_traits<platform_api, sequential_mode>>,
58  unique_ptr<obj<heavyweight_threading>, api_lock_traits<platform_api, heavyweight_threading>>
59 >;
60 using timed_results_t=ave_deviation_meter<unsigned long long>;
61 
62 template<class Element>
63 struct cctor_thread final : public ppd::wrapper<ppd::platform_api, heavyweight_threading> {
65  typedef std::vector<Element> cont_t;
66  struct make {
68 
69  make() noexcept(true) : i() {}
70 
71  typename cont_t::value_type operator ()() {
72  return typename cont_t::value_type(new typename cont_t::value_type::element_type(++i));
73  }
74  };
75 
77 
78  explicit __stdcall cctor_thread(cont_t &c) noexcept(true)
79  : base_t(), cont(c) {
80  }
81 
82  bool __fastcall worker_fn(typename base_t::thread_context_t &) override {
83  while (!cont.empty()) {
84  const typename cont_t::value_type tmp(std::move(cont.back()));
85  cont.pop_back();
86  }
87  return true;
88  }
89 };
90 
91 template<class Element>
92 struct dtor_thread final : public ppd::wrapper<ppd::platform_api, heavyweight_threading> {
94  typedef std::vector<Element> cont_t;
95  struct make {
97 
98  make() noexcept(true) : i() {}
99 
100  typename cont_t::value_type operator ()() {
101  return typename cont_t::value_type(new typename cont_t::value_type::element_type(++i));
102  }
103  };
104 
106 
107  explicit __stdcall dtor_thread(cont_t &c) noexcept(true)
108  : base_t(), cont(c) {
109  }
110 
111  bool __fastcall worker_fn(typename base_t::thread_context_t &) override {
112  while (!cont.empty()) {
113  cont.back().reset();
114  cont.pop_back();
115  }
116  return true;
117  }
118 };
119 
120 BOOST_AUTO_TEST_SUITE(performance_cctor, *stats_to_csv::make_fixture("unique_ptr_parallel_cctor.csv"))
121 
122 BOOST_AUTO_TEST_SUITE(unique_ptr_parallel_tests)
123 
124 /**
125  \test <a href="./examples/unique_ptr_parallel_cctor.svg">Graph</a> of performance results for parallel unique_ptr cctors.
126  ==========================================================================================
127  Results for 100000000 items:
128 */
129 BOOST_AUTO_TEST_CASE_TEMPLATE(parallel_cctor, ptr_t, ptr_types) {
130  typedef cctor_thread<ptr_t> thread_t;
131 #ifdef JMMCG_PERFORMANCE_TESTS
132  const std::size_t num_items=100000000;
133 #else
134  const std::size_t num_items=100;
135 #endif
136  const unsigned short loops_for_conv=50;
137  const double perc_conv_estimate=5.0;
138 
139  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
140  perc_conv_estimate,
141  loops_for_conv,
142  []() {
143  typename thread_t::cont_t c;
144  std::generate_n(std::back_inserter(c), num_items, typename thread_t::make());
145  thread_t th1(c);
146  thread_t th2(c);
147  c.clear();
148  const auto t1=std::chrono::high_resolution_clock::now();
149  th1.create_running();
150  th2.create_running();
151  do {
152  api_threading_traits<platform_api, heavyweight_threading>::sleep(100);
153  } while (th1.is_running() || th2.is_running());
154  const auto t2=std::chrono::high_resolution_clock::now();
155  BOOST_CHECK(th1.cont.empty());
156  BOOST_CHECK(th2.cont.empty());
157  BOOST_CHECK(c.empty());
158  return timed_results_t::value_type(num_items/(static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count())/1000000));
159  }
160  ));
161  std::cout<<thread_t::thread_traits::demangle_name(typeid(ptr_t))<<" rate cctors/sec="<<timed_results.first<<std::endl;
162 #ifdef JMMCG_PERFORMANCE_TESTS
163  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
164  BOOST_CHECK(!timed_results.second);
165 #endif
166 }
167 
168 BOOST_AUTO_TEST_SUITE_END()
169 
170 BOOST_AUTO_TEST_SUITE(performance_cctor, *stats_to_csv::make_fixture("unique_ptr_parallel_dtor.csv"))
171 
172 /**
173  \test <a href="./examples/unique_ptr_parallel_dtor.svg">Graph</a> of performance results for parallel unique_ptr dtors.
174  ==========================================================================================
175  Results for 100000000 items:
176 */
177 BOOST_AUTO_TEST_CASE_TEMPLATE(parallel_deletes, ptr_t, ptr_types) {
178  typedef dtor_thread<ptr_t> thread_t;
179 #ifdef JMMCG_PERFORMANCE_TESTS
180  const std::size_t num_items=100000000;
181 #else
182  const std::size_t num_items=100;
183 #endif
184  const unsigned short loops_for_conv=50;
185  const double perc_conv_estimate=5.0;
186 
187  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
188  perc_conv_estimate,
189  loops_for_conv,
190  []() {
191  typename thread_t::cont_t c;
192  std::generate_n(std::back_inserter(c), num_items, typename thread_t::make());
193  thread_t th1(c);
194  thread_t th2(c);
195  c.clear();
196  const auto t1=std::chrono::high_resolution_clock::now();
197  th1.create_running();
198  th2.create_running();
199  do {
200  api_threading_traits<platform_api, heavyweight_threading>::sleep(100);
201  } while (th1.is_running() || th2.is_running());
202  const auto t2=std::chrono::high_resolution_clock::now();
203  BOOST_CHECK(th1.cont.empty());
204  BOOST_CHECK(th2.cont.empty());
205  BOOST_CHECK(c.empty());
206  return timed_results_t::value_type(num_items/(static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count())/1000000));
207  }
208  ));
209  std::cout<<thread_t::thread_traits::demangle_name(typeid(ptr_t))<<" rate dtors/sec="<<timed_results.first<<std::endl;
210 #ifdef JMMCG_PERFORMANCE_TESTS
211  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
212  BOOST_CHECK(!timed_results.second);
213 #endif
214 }
215 
216 BOOST_AUTO_TEST_SUITE_END()
217 
218 BOOST_AUTO_TEST_SUITE_END()