libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
string_conversions_performance.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2017 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/ttypes.hpp"
29 
30 #include <boost/lexical_cast.hpp>
31 
32 #include <charconv>
33 #include <chrono>
34 
35 using namespace libjmmcg;
36 
37 using timed_results_t=ave_deviation_meter<unsigned long long>;
38 
39 ALIGN_TO_L1_CACHE static constexpr char const * const numbers[]={
40  "572489496",
41  "45643348",
42  "51453335",
43  "9978974234",
44  "11447",
45  "16836812",
46  "15681223211",
47  "125",
48  "9845631699",
49  "4598888",
50  "0",
51  "1",
52  "1234567890123456789",
53  "4581123500063313800"
54 };
55 
56 struct std_atol {
57  static long result(char const * const s, std::size_t) noexcept(true) {
58  assert(s);
59  return std::atol(s);
60  }
61 };
62 
63 struct std_strtol {
64  static long result(char const * const s, std::size_t) noexcept(true) {
65  assert(s);
66  return std::strtol(s, nullptr, 10);
67  }
68 };
69 
71  static long result(char const * const s, std::size_t sz) noexcept(true) {
72  assert(s);
73  long res;
74  std::from_chars(s, s+sz, res, 10);
75  return res;
76  }
77 };
78 
79 struct std_to_chars {
80  static std::size_t result(long v, char * const s, std::size_t sz) noexcept(true) {
81  assert(s);
82  std::to_chars(s, s+sz, v, 10);
83  return 42;
84  }
85 };
86 
87 template<class V>
89  static V result(char const * const s, std::size_t sz) noexcept(true) __attribute__((pure)) {
90  assert(s);
91  return fromstring<V>(s, sz);
92  }
93 };
94 
96  static long result(char const * const s, std::size_t sz) noexcept(true) __attribute__((pure)) {
97  assert(s);
98  return folly_ascii_to_int(s, sz);
99  }
100 };
101 
102 template<class V>
104  static V result(const char * const s, std::size_t) noexcept(true) __attribute__((pure)) {
105  assert(s);
106  return boost::lexical_cast<V>(s);
107  }
108 };
109 
111  static std::size_t result(long v, char * const s, std::size_t sz) noexcept(true) __attribute__((pure)) {
112  assert(s);
113  return tostring(v, s, sz);
114  }
115 };
116 
117 using from_conversion_algorithms=boost::mpl::list<
118  test_folly_ascii_to_int,
119  test_from_string_baseline<unsigned long long>,
120  test_from_string_baseline<double>,
121  std_atol,
122  boost_lexical_cast_from<long>,
123  boost_lexical_cast_from<double>,
124  std_strtol,
125  std_from_chars
126 >;
127 
128 using to_conversion_algorithms=boost::mpl::list<
129  folly_uint64ToBufferUnsafe,
130  std_to_chars
131 >;
132 
133 BOOST_AUTO_TEST_SUITE(conversions_tests)
134 
135 BOOST_AUTO_TEST_SUITE(performance, *stats_to_csv::make_fixture("string_conversions_performance.csv"))
136 
137 /**
138  \test <a href="./examples/string_conversions_performance.svg">Graph</a> of performance results for string-to-long conversion algorithms.
139  ==========================================================================================
140  Test the performance of various string-to-long conversion algorithms.
141 */
142 BOOST_AUTO_TEST_CASE_TEMPLATE(from_string, algorithm, from_conversion_algorithms) {
143 #ifdef JMMCG_PERFORMANCE_TESTS
144  const unsigned long test_size=2<<25;
145  const unsigned short loops_for_conv=4000;
146 #else
147  const unsigned long test_size=2<<2;
148  const unsigned short loops_for_conv=1;
149 #endif
150  const double perc_conv_estimate=2.0;
151 
152  unsigned long res=0;
153 
154  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
155  perc_conv_estimate,
156  loops_for_conv,
157  [&res]() {
158  char const * const number=numbers[res%(sizeof(numbers)/sizeof(numbers[0]))];
159  const std::size_t sz=std::strlen(number);
160  const auto t1=std::chrono::high_resolution_clock::now();
161  for (unsigned long i=0; i<test_size; ++i) {
162  res+=algorithm::result(number, sz);
163  }
164  const auto t2=std::chrono::high_resolution_clock::now();
165  return timed_results_t::value_type(static_cast<double>(test_size)*1000000/std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
166  }
167  ));
168  BOOST_CHECK_GT(res, 0);
169  std::cout<<typeid(algorithm).name()<<" conversions/sec="<<timed_results.first<<std::endl;
170 #ifdef JMMCG_PERFORMANCE_TESTS
171  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
172  BOOST_CHECK(!timed_results.second);
173 #endif
174 }
175 
176 /**
177  \test <a href="./examples/string_conversions_performance.svg">Graph</a> of performance results for long-to-string conversion algorithms.
178  ==========================================================================================
179  Test the performance of various long-to-string conversion algorithms.
180 */
181 BOOST_AUTO_TEST_CASE_TEMPLATE(to_string, algorithm, to_conversion_algorithms) {
182 #ifdef JMMCG_PERFORMANCE_TESTS
183  const unsigned long test_size=2<<25;
184  const unsigned short loops_for_conv=4000;
185 #else
186  const unsigned long test_size=2<<2;
187  const unsigned short loops_for_conv=1;
188 #endif
189  const double perc_conv_estimate=5.0;
190 
191  std::size_t res=0;
192 
193  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
194  perc_conv_estimate,
195  loops_for_conv,
196  [&res]() {
197  ALIGN_TO_L1_CACHE std::array<char, 512> buff={};
198  const auto t1=std::chrono::high_resolution_clock::now();
199  for (unsigned long i=0; i<test_size; ++i) {
200  res+=algorithm::result(i, buff.begin(), buff.max_size());
201  }
202  const auto t2=std::chrono::high_resolution_clock::now();
203  return timed_results_t::value_type(static_cast<double>(test_size)*1000000/std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count());
204  }
205  ));
206  BOOST_CHECK_GT(res, 0);
207  std::cout<<typeid(algorithm).name()<<" conversions/sec="<<timed_results.first<<std::endl;
208 #ifdef JMMCG_PERFORMANCE_TESTS
209  stats_to_csv::handle->stats<<timed_results.first.to_csv()<<std::flush;
210  BOOST_CHECK(!timed_results.second);
211 #endif
212 }
213 
214 BOOST_AUTO_TEST_SUITE_END()
215 
216 BOOST_AUTO_TEST_SUITE_END()