performance.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Boost.Convert test and usage example
  2. // Copyright (c) 2009-2016 Vladimir Batov.
  3. // Use, modification and distribution are subject to the Boost Software License,
  4. // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
  5. #include "./test.hpp"
  6. #if defined(BOOST_CONVERT_IS_NOT_SUPPORTED)
  7. int main(int, char const* []) { return 0; }
  8. #else
  9. #include "./prepare.hpp"
  10. #include <boost/convert.hpp>
  11. #include <boost/convert/stream.hpp>
  12. #include <boost/convert/printf.hpp>
  13. #include <boost/convert/strtol.hpp>
  14. #include <boost/convert/spirit.hpp>
  15. #include <boost/convert/lexical_cast.hpp>
  16. #include <boost/detail/lightweight_test.hpp>
  17. #include <boost/timer/timer.hpp>
  18. #include <boost/array.hpp>
  19. #include <boost/random/mersenne_twister.hpp>
  20. #include <boost/random/uniform_int_distribution.hpp>
  21. #include <cstdlib>
  22. #include <cstdio>
  23. using std::string;
  24. using boost::convert;
  25. namespace cnv = boost::cnv;
  26. namespace arg = boost::cnv::parameter;
  27. namespace { namespace local
  28. {
  29. template<typename Type>
  30. struct array
  31. {
  32. typedef boost::array<Type, 20> type;
  33. };
  34. template<typename T> static typename array<T>::type const& get();
  35. static int const num_cycles = 1000000;
  36. int sum = 0;
  37. struct timer : public boost::timer::cpu_timer
  38. {
  39. typedef timer this_type;
  40. typedef boost::timer::cpu_timer base_type;
  41. double value() const
  42. {
  43. boost::timer::cpu_times times = base_type::elapsed();
  44. int const use_sum = (sum % 2) ? 0 : (sum % 2); BOOST_TEST(use_sum == 0);
  45. return double(times.user + times.system) / 1000000000 + use_sum;
  46. }
  47. };
  48. template< typename Type, typename Cnv> static double str_to (Cnv const&);
  49. template<typename S, typename Type, typename Cnv> static double to_str (Cnv const&);
  50. template<>
  51. local::array<int>::type const&
  52. get<int>()
  53. {
  54. static array<int>::type ints;
  55. static bool filled;
  56. if (!filled)
  57. {
  58. boost::random::mt19937 gen (::time(0));
  59. boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2,147,483,647
  60. for (size_t k = 0; k < ints.size(); ++k)
  61. ints[k] = dist(gen);
  62. filled = true;
  63. }
  64. return ints;
  65. }
  66. template<>
  67. array<long int>::type const&
  68. get<long int>()
  69. {
  70. static array<long int>::type ints;
  71. static bool filled;
  72. if (!filled)
  73. {
  74. boost::random::mt19937 gen (::time(0));
  75. boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2147483647
  76. for (size_t k = 0; k < ints.size(); ++k)
  77. ints[k] = dist(gen);
  78. filled = true;
  79. }
  80. return ints;
  81. }
  82. template<>
  83. array<double>::type const&
  84. get<double>()
  85. {
  86. static array<double>::type dbls;
  87. static bool filled;
  88. if (!filled)
  89. {
  90. boost::random::mt19937 gen (::time(0));
  91. boost::random::uniform_int_distribution<> dist (INT_MIN, INT_MAX); // INT_MAX(32) = 2147483647
  92. for (size_t k = 0; k < dbls.size(); ++k)
  93. dbls[k] = double(dist(gen)) + 0.7654321;
  94. filled = true;
  95. }
  96. return dbls;
  97. }
  98. }}
  99. struct raw_str_to_int_spirit
  100. {
  101. int operator()(char const* str) const
  102. {
  103. char const* beg = str;
  104. char const* end = beg + strlen(str);
  105. int result;
  106. if (boost::spirit::qi::parse(beg, end, boost::spirit::int_, result))
  107. if (beg == end) // ensure the whole string was parsed
  108. return result;
  109. return (BOOST_ASSERT(0), result);
  110. }
  111. };
  112. struct raw_str_to_int_lxcast
  113. {
  114. int operator()(char const* str) const
  115. {
  116. return boost::lexical_cast<int>(str);
  117. }
  118. };
  119. template<typename Type, typename Converter>
  120. double
  121. raw_str_to(Converter const& cnv)
  122. {
  123. local::strings strings = local::get_strs(); // Create strings on the stack
  124. int const size = strings.size();
  125. local::timer timer;
  126. for (int t = 0; t < local::num_cycles; ++t)
  127. for (int k = 0; k < size; ++k)
  128. local::sum += cnv(strings[k].c_str());
  129. return timer.value();
  130. }
  131. template<typename Type, typename Converter>
  132. double
  133. local::str_to(Converter const& try_converter)
  134. {
  135. local::strings strings = local::get_strs(); // Create strings on the stack
  136. int const size = strings.size();
  137. local::timer timer;
  138. for (int t = 0; t < local::num_cycles; ++t)
  139. for (int k = 0; k < size; ++k)
  140. local::sum += boost::convert<Type>(strings[k].c_str(), try_converter).value();
  141. return timer.value();
  142. }
  143. template<typename string_type, typename Type, typename Converter>
  144. double
  145. local::to_str(Converter const& try_converter)
  146. {
  147. typedef typename local::array<Type>::type collection;
  148. collection values = local::get<Type>();
  149. int const size = values.size();
  150. local::timer timer;
  151. for (int t = 0; t < local::num_cycles; ++t)
  152. for (int k = 0; k < size; ++k)
  153. local::sum += *boost::convert<string_type>(Type(values[k]), try_converter).value().begin();
  154. return timer.value();
  155. }
  156. template<typename Converter>
  157. double
  158. performance_str_to_type(Converter const& try_converter)
  159. {
  160. char const* input[] = { "no", "up", "dn" };
  161. local::timer timer;
  162. for (int k = 0; k < local::num_cycles; ++k)
  163. {
  164. change chg = boost::convert<change>(input[k % 3], try_converter).value();
  165. int res = chg.value();
  166. BOOST_TEST(res == k % 3);
  167. local::sum += res; // Make sure chg is not optimized out
  168. }
  169. return timer.value();
  170. }
  171. template<typename Converter>
  172. double
  173. performance_type_to_str(Converter const& try_converter)
  174. {
  175. boost::array<change, 3> input = {{ change::no, change::up, change::dn }};
  176. boost::array<string, 3> results = {{ "no", "up", "dn" }};
  177. local::timer timer;
  178. for (int k = 0; k < local::num_cycles; ++k)
  179. {
  180. string res = boost::convert<string>(input[k % 3], try_converter).value();
  181. BOOST_TEST(res == results[k % 3]);
  182. local::sum += res[0]; // Make sure res is not optimized out
  183. }
  184. return timer.value();
  185. }
  186. template<typename Raw, typename Cnv>
  187. void
  188. performance_comparative(Raw const& raw, Cnv const& cnv, char const* txt)
  189. {
  190. int const num_tries = 5;
  191. double cnv_time = 0;
  192. double raw_time = 0;
  193. for (int k = 0; k < num_tries; ++k) cnv_time += local::str_to<int>(cnv);
  194. for (int k = 0; k < num_tries; ++k) raw_time += raw_str_to<int>(raw);
  195. cnv_time /= num_tries;
  196. raw_time /= num_tries;
  197. double change = 100 * (1 - cnv_time / raw_time);
  198. printf("str-to-int: %s raw/cnv=%.2f/%.2f seconds (%.2f%%).\n", txt, raw_time, cnv_time, change);
  199. }
  200. int
  201. main(int, char const* [])
  202. {
  203. printf("Started performance tests...\n");
  204. printf("str-to-int: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
  205. local::str_to<int>(boost::cnv::spirit()),
  206. local::str_to<int>(boost::cnv::strtol()),
  207. local::str_to<int>(boost::cnv::lexical_cast()),
  208. local::str_to<int>(boost::cnv::printf()),
  209. local::str_to<int>(boost::cnv::cstream()));
  210. printf("str-to-lng: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
  211. local::str_to<long int>(boost::cnv::spirit()),
  212. local::str_to<long int>(boost::cnv::strtol()),
  213. local::str_to<long int>(boost::cnv::lexical_cast()),
  214. local::str_to<long int>(boost::cnv::printf()),
  215. local::str_to<long int>(boost::cnv::cstream()));
  216. printf("str-to-dbl: spirit/strtol/lcast/scanf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
  217. local::str_to<double>(boost::cnv::spirit()),
  218. local::str_to<double>(boost::cnv::strtol()),
  219. local::str_to<double>(boost::cnv::lexical_cast()),
  220. local::str_to<double>(boost::cnv::printf()),
  221. local::str_to<double>(boost::cnv::cstream()));
  222. printf("int-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
  223. local::to_str<std::string, int>(boost::cnv::spirit()),
  224. local::to_str<std::string, int>(boost::cnv::strtol()),
  225. local::to_str<std::string, int>(boost::cnv::lexical_cast()),
  226. local::to_str<std::string, int>(boost::cnv::printf()),
  227. local::to_str<std::string, int>(boost::cnv::cstream()));
  228. printf("lng-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
  229. local::to_str<std::string, long int>(boost::cnv::spirit()),
  230. local::to_str<std::string, long int>(boost::cnv::strtol()),
  231. local::to_str<std::string, long int>(boost::cnv::lexical_cast()),
  232. local::to_str<std::string, long int>(boost::cnv::printf()),
  233. local::to_str<std::string, long int>(boost::cnv::cstream()));
  234. printf("dbl-to-str: spirit/strtol/lcast/prntf/stream=%7.2f/%7.2f/%7.2f/%7.2f/%7.2f seconds.\n",
  235. local::to_str<std::string, double>(boost::cnv::spirit()),
  236. local::to_str<std::string, double>(boost::cnv::strtol()(arg::precision = 6)),
  237. local::to_str<std::string, double>(boost::cnv::lexical_cast()),
  238. local::to_str<std::string, double>(boost::cnv::printf()(arg::precision = 6)),
  239. local::to_str<std::string, double>(boost::cnv::cstream()(arg::precision = 6)));
  240. printf("str-to-user-type: lcast/stream/strtol=%.2f/%.2f/%.2f seconds.\n",
  241. performance_str_to_type(boost::cnv::lexical_cast()),
  242. performance_str_to_type(boost::cnv::cstream()),
  243. performance_str_to_type(boost::cnv::strtol()));
  244. printf("user-type-to-str: lcast/stream/strtol=%.2f/%.2f/%.2f seconds.\n",
  245. performance_type_to_str(boost::cnv::lexical_cast()),
  246. performance_type_to_str(boost::cnv::cstream()),
  247. performance_type_to_str(boost::cnv::strtol()));
  248. //[small_string_results
  249. printf("strtol int-to std::string/small-string: %.2f/%.2f seconds.\n",
  250. local::to_str<std::string, int>(boost::cnv::strtol()),
  251. local::to_str< my_string, int>(boost::cnv::strtol()));
  252. printf("spirit int-to std::string/small-string: %.2f/%.2f seconds.\n",
  253. local::to_str<std::string, int>(boost::cnv::spirit()),
  254. local::to_str< my_string, int>(boost::cnv::spirit()));
  255. printf("stream int-to std::string/small-string: %.2f/%.2f seconds.\n",
  256. local::to_str<std::string, int>(boost::cnv::cstream()),
  257. local::to_str< my_string, int>(boost::cnv::cstream()));
  258. //]
  259. performance_comparative(raw_str_to_int_spirit(), boost::cnv::spirit(), "spirit");
  260. performance_comparative(raw_str_to_int_lxcast(), boost::cnv::lexical_cast(), "lxcast");
  261. return boost::report_errors();
  262. }
  263. #endif