libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
stack_string_performance.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2013 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/stack_string.hpp"
27 
28 #include "core/ave_deviation_meter.hpp"
29 #include "core/stats_output.hpp"
30 
31 #include <chrono>
32 #include <iostream>
33 #include <string>
34 #include <ext/vstring.h>
35 
36 using namespace libjmmcg;
37 
38 using timed_results_t=ave_deviation_meter<unsigned long long>;
39 
40 typedef boost::mpl::list<
41  basic_stack_string<12, char>,
42  std::string,
45 
46 const unsigned short loops_for_conv=50;
47 const double perc_conv_estimate=5.0;
48 #ifdef JMMCG_PERFORMANCE_TESTS
49  const unsigned long test_size=100000000U;
50 #else
51  const unsigned long test_size=100U;
52 #endif
53 
54 /**
55  \test <a href="./examples/stack_string_performance_ctor_dtor.svg">Graph of ctor & dtor</a>, <a href="./examples/stack_string_performance_assignment.svg">Graph of ctor, dtor & assignment</a> and <a href="./examples/stack_string_performance_replace.svg">Graph of ctor, dtor & replace</a> performance comparison of stack_string vs std::string and __gnucxx::__vstring'
56  ==============================================================================
57  Results for 100000000 repetitions.
58  On my dual, 6-core AMD Opteron 4180s at 2.6GHz box with 16Gb RAM (not quiescent), I measured the following statistics for a release build:
59  -# Build 1414:
60  - stack_string small string (ctors+dtors)/sec=[135662569, 136631149 ~(+/-4%), 136727642], samples=21, total=2869254133
61  - std::string small string (ctors+dtors)/sec=[14223043, 14258612 ~(+/-4%), 14268891], samples=21, total=299430869
62  - __gnucxx::__vstring small string (ctors+dtors)/sec=[86412573, 86559127 ~(+/-4%), 86598005], samples=21, total=1817741679
63  - stack_string big string (ctors+dtors)/sec=[17663500, 17665794 ~(+/-4%), 17668187], samples=21, total=370981680
64  - std::string big string (ctors+dtors)/sec=[13455498, 13810127 ~(+/-4%), 14190757], samples=24, total=331443053
65  - __gnucxx::__vstring big string (ctors+dtors)/sec=[17905987, 17909566 ~(+/-4%), 17911321], samples=21, total=376100905
66  - stack_string small string (ctors+dtors+assignment)/sec=[55224728, 55254120 ~(+/-4%), 55267397], samples=21, total=1160336527
67  - std::string small string (ctors+dtors+assignment)/sec=[10093766, 10138325 ~(+/-4%), 10177015], samples=21, total=212904843
68  - __gnucxx::__vstring small string (ctors+dtors+assignment)/sec=[37145984, 39441839 ~(+/-4%), 42999101], samples=41, total=1617115404
69  - stack_string big string (ctors+dtors+assignment)/sec=[8446274, 8726725 ~(+/-4%), 8744792], samples=20, total=174534506
70  - std::string big string (ctors+dtors+assignment)/sec=[9887807, 10000563 ~(+/-4%), 10065898], samples=21, total=210011827
71  - __gnucxx::__vstring big string (ctors+dtors+assignment)/sec=[9993189, 10073089 ~(+/-4%), 10130002], samples=20, total=201461782
72  - stack_string small string (ctors+dtors+replace)/sec=[30779326, 31247464 ~(+/-4%), 31286947], samples=21, total=656196758
73  - std::string small string (ctors+dtors+replace)/sec=[3554754, 3569919 ~(+/-4%), 3580345], samples=21, total=74968318
74  - __gnucxx::__vstring small string (ctors+dtors+replace)/sec=[24622578, 25761126 ~(+/-4%), 25973223], samples=20, total=515222525
75  - stack_string big string (ctors+dtors+replace)/sec=[5175213, 5381860 ~(+/-4%), 5412671], samples=20, total=107637218
76  - std::string big string (ctors+dtors+replace)/sec=[3548994, 3575052 ~(+/-4%), 3605774], samples=21, total=75076100
77  - __gnucxx::__vstring big string (ctors+dtors+replace)/sec=[5421178, 5540581 ~(+/-4%), 5548517], samples=20, total=110811631
78  -# Build 1627:
79  - stack_string small string (ctors+dtors)/sec=[77688729, 78157207 ~(+/-4%), 78233671], samples=21, total=1641301351
80  - std::string small string (ctors+dtors)/sec=[15288084, 15429237 ~(+/-4%), 15484286], samples=20, total=308584744
81  - __gnucxx::__vstring small string (ctors+dtors)/sec=[39799648, 41135410 ~(+/-4%), 41391482], samples=20, total=822708201
82  - stack_string big string (ctors+dtors)/sec=[14184497, 14435743 ~(+/-4%), 14460011], samples=21, total=303150620
83  - std::string big string (ctors+dtors)/sec=[14697476, 14779399 ~(+/-4%), 14815372], samples=21, total=310367382
84  - __gnucxx::__vstring big string (ctors+dtors)/sec=[12887788, 13119301 ~(+/-5%), 13231750], samples=21, total=275505323
85  - stack_string small string (ctors+dtors+assignment)/sec=[66254782, 67709907 ~(+/-5%), 67908163], samples=21, total=1421908066
86  - std::string small string (ctors+dtors+assignment)/sec=[10831330, 10883866 ~(+/-4%), 10897227], samples=21, total=228561205
87  - __gnucxx::__vstring small string (ctors+dtors+assignment)/sec=[23789008, 24003363 ~(+/-5%), 24265407], samples=21, total=504070629
88  - stack_string big string (ctors+dtors+assignment)/sec=[7340829, 7656490 ~(+/-6%), 7802339], samples=21, total=160786309
89  - std::string big string (ctors+dtors+assignment)/sec=[10271093, 10534818 ~(+/-5%), 10578410], samples=21, total=221231184
90  - __gnucxx::__vstring big string (ctors+dtors+assignment)/sec=[7732222, 7846254 ~(+/-5%), 7857272], samples=21, total=164771350
91  - stack_string small string (ctors+dtors+replace)/sec=[16342456, 16412117 ~(+/-4%), 16427649], samples=21, total=344654458
92  - std::string small string (ctors+dtors+replace)/sec=[4232467, 4267956 ~(+/-4%), 4281863], samples=21, total=89627089
93  - __gnucxx::__vstring small string (ctors+dtors+replace)/sec=[15143025, 15316453 ~(+/-4%), 15364299], samples=21, total=321645514
94  - stack_string big string (ctors+dtors+replace)/sec=[4185507, 4281924 ~(+/-5%), 4298870], samples=21, total=89920404
95  - std::string big string (ctors+dtors+replace)/sec=[4425767, 4452773 ~(+/-4%), 4463363], samples=20, total=89055461
96  - __gnucxx::__vstring big string (ctors+dtors+replace)/sec=[4680365, 4695952 ~(+/-4%), 4719313], samples=21, total=98615000
97  -# Build 1643:
98  - stack_string small string (ctors+dtors)/sec=[77731544, 78352331 ~(+/-4%), 78418333], samples=20, total=1567046620
99  - std::string small string (ctors+dtors)/sec=[15381950, 15471575 ~(+/-4%), 15510609], samples=21, total=324903095
100  - __gnucxx::__vstring small string (ctors+dtors)/sec=[40882288, 42053251 ~(+/-4%), 42234812], samples=20, total=841065030
101  - stack_string big string (ctors+dtors)/sec=[14472412, 14509867 ~(+/-4%), 14522212], samples=21, total=304707207
102  - std::string big string (ctors+dtors)/sec=[14733592, 14750590 ~(+/-4%), 14759905], samples=21, total=309762398
103  - __gnucxx::__vstring big string (ctors+dtors)/sec=[12806720, 13027029 ~(+/-4%), 13219483], samples=35, total=455946018
104  - stack_string small string (ctors+dtors+assignment)/sec=[64906657, 64933195 ~(+/-4%), 64948307], samples=21, total=1363597097
105  - std::string small string (ctors+dtors+assignment)/sec=[9965722, 10753837 ~(+/-4%), 10893439], samples=25, total=268845934
106  - __gnucxx::__vstring small string (ctors+dtors+assignment)/sec=[25880419, 26471226 ~(+/-4%), 26642595], samples=23, total=608838203
107  - stack_string big string (ctors+dtors+assignment)/sec=[7380573, 7479894 ~(+/-4%), 7582891], samples=26, total=194477260
108  - std::string big string (ctors+dtors+assignment)/sec=[10530196, 10532715 ~(+/-4%), 10535628], samples=21, total=221187030
109  - __gnucxx::__vstring big string (ctors+dtors+assignment)/sec=[7574794, 7824633 ~(+/-4%), 7860065], samples=22, total=172141946
110  - stack_string small string (ctors+dtors+replace)/sec=[15697091, 15820997 ~(+/-4%), 15966704], samples=22, total=348061936
111  - std::string small string (ctors+dtors+replace)/sec=[4502732, 4529391 ~(+/-4%), 4540575], samples=21, total=95117212
112  - __gnucxx::__vstring small string (ctors+dtors+replace)/sec=[14205080, 14691759 ~(+/-4%), 15367257], samples=32, total=470136317
113  - stack_string big string (ctors+dtors+replace)/sec=[4185298, 4235308 ~(+/-4%), 4247537], samples=20, total=84706170
114  - std::string big string (ctors+dtors+replace)/sec=[4468726, 4474550 ~(+/-4%), 4475729], samples=21, total=93965557
115  - __gnucxx::__vstring big string (ctors+dtors+replace)/sec=[4673622, 4688568 ~(+/-4%), 4691540], samples=21, total=98459947
116  \todo In gcc 5.10 std::string uses small-string optimisation - needs testing.
117 */
118 
119 BOOST_AUTO_TEST_SUITE(string_tests)
120 
121 BOOST_AUTO_TEST_SUITE(performance_ctor_dtor, *stats_to_csv::make_fixture("stack_string_performance_ctor_dtor.csv"))
122 
123 BOOST_AUTO_TEST_CASE_TEMPLATE(small_ctor, T, string_types)
124 {
125  typedef T string_t;
126 
127  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
128  perc_conv_estimate,
129  loops_for_conv,
130  []() {
131  char const src[]="small";
132  const auto t1=std::chrono::high_resolution_clock::now();
133  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
134  string_t s(src);
135  }
136  const auto t2=std::chrono::high_resolution_clock::now();
137  return timed_results_t::value_type(test_size/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/1000000000));
138  }
139  ));
140  std::cout<<typeid(string_t).name()<<" small string (ctors+dtors)/sec="<<timed_results.first<<std::endl;
141 #ifdef JMMCG_PERFORMANCE_TESTS
142  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
143  BOOST_CHECK(!timed_results.second);
144 #endif
145 }
146 
147 BOOST_AUTO_TEST_CASE_TEMPLATE(big_ctor, T, string_types)
148 {
149  typedef T string_t;
150 
151  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
152  perc_conv_estimate,
153  loops_for_conv,
154  []() {
155  char const src[]="a very very big string";
156  const auto t1=std::chrono::high_resolution_clock::now();
157  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
158  string_t s(src);
159  }
160  const auto t2=std::chrono::high_resolution_clock::now();
161  return timed_results_t::value_type(test_size/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/1000000000));
162  }
163  ));
164  std::cout<<typeid(string_t).name()<<" big string (ctors+dtors)/sec="<<timed_results.first<<std::endl;
165 #ifdef JMMCG_PERFORMANCE_TESTS
166  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
167  BOOST_CHECK(!timed_results.second);
168 #endif
169 }
170 
171 BOOST_AUTO_TEST_SUITE_END()
172 
173 BOOST_AUTO_TEST_SUITE(performance_assignment, *stats_to_csv::make_fixture("stack_string_performance_assignment.csv"))
174 
175 BOOST_AUTO_TEST_CASE_TEMPLATE(small_assignment, T, string_types)
176 {
177  typedef T string_t;
178 
179  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
180  perc_conv_estimate,
181  loops_for_conv,
182  []() {
183  char const src[]="small";
184  const auto t1=std::chrono::high_resolution_clock::now();
185  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
186  string_t s1(src);
187  string_t s2;
188  s2=s1;
189  }
190  const auto t2=std::chrono::high_resolution_clock::now();
191  return timed_results_t::value_type(test_size/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/1000000000));
192  }
193  ));
194  std::cout<<typeid(string_t).name()<<" small string (ctors+dtors+assignment)/sec="<<timed_results.first<<std::endl;
195 #ifdef JMMCG_PERFORMANCE_TESTS
196  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
197  BOOST_CHECK(!timed_results.second);
198 #endif
199 }
200 
201 BOOST_AUTO_TEST_CASE_TEMPLATE(big_assignment, T, string_types)
202 {
203  typedef T string_t;
204 
205  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
206  perc_conv_estimate,
207  loops_for_conv,
208  []() {
209  char const src[]="a very very big string";
210  const auto t1=std::chrono::high_resolution_clock::now();
211  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
212  string_t s1(src);
213  string_t s2;
214  s2=s1;
215  }
216  const auto t2=std::chrono::high_resolution_clock::now();
217  return timed_results_t::value_type(test_size/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/1000000000));
218  }
219  ));
220  std::cout<<typeid(string_t).name()<<" big string (ctors+dtors+assignment)/sec="<<timed_results.first<<std::endl;
221 #ifdef JMMCG_PERFORMANCE_TESTS
222  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
223  BOOST_CHECK(!timed_results.second);
224 #endif
225 }
226 
227 BOOST_AUTO_TEST_SUITE_END()
228 
229 BOOST_AUTO_TEST_SUITE(performance_replace, *stats_to_csv::make_fixture("stack_string_performance_replace.csv"))
230 
231 BOOST_AUTO_TEST_CASE_TEMPLATE(small_replace, T, string_types)
232 {
233  typedef T string_t;
234 
235  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
236  perc_conv_estimate,
237  loops_for_conv,
238  []() {
239  char const src[]="small";
240  const auto t1=std::chrono::high_resolution_clock::now();
241  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
242  string_t s1(src);
243  string_t s2(src);
244  s2.replace(std::next(s2.begin()), std::prev(s2.end()), s1.begin(), s1.end());
245  }
246  const auto t2=std::chrono::high_resolution_clock::now();
247  return timed_results_t::value_type(test_size/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/1000000000));
248  }
249  ));
250  std::cout<<typeid(string_t).name()<<" small string (ctors+dtors+replace)/sec="<<timed_results.first<<std::endl;
251 #ifdef JMMCG_PERFORMANCE_TESTS
252  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
253  BOOST_CHECK(!timed_results.second);
254 #endif
255 }
256 
257 BOOST_AUTO_TEST_CASE_TEMPLATE(big_replace, T, string_types)
258 {
259  typedef T string_t;
260 
261  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
262  perc_conv_estimate,
263  loops_for_conv,
264  []() {
265  char const src[]="a very very big string";
266  const auto t1=std::chrono::high_resolution_clock::now();
267  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
268  string_t s1(src);
269  {
270  string_t s2(src);
271  {
272  s2.replace(std::next(s2.begin()), std::prev(s2.end()), s1.begin(), s1.end());
273  }
274  }
275  }
276  const auto t2=std::chrono::high_resolution_clock::now();
277  return timed_results_t::value_type(test_size/(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/1000000000));
278  }
279  ));
280  std::cout<<typeid(string_t).name()<<" big string (ctors+dtors+replace)/sec="<<timed_results.first<<std::endl;
281 #ifdef JMMCG_PERFORMANCE_TESTS
282  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
283  BOOST_CHECK(!timed_results.second);
284 #endif
285 }
286 
287 BOOST_AUTO_TEST_SUITE_END()
288 
289 BOOST_AUTO_TEST_SUITE_END()