performance_test.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // (C) Copyright Antony Polukhin, 2012-2019.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. // See http://www.boost.org/libs/config for most recent version.
  6. //
  7. // Testing lexical_cast<> performance
  8. //
  9. #define BOOST_ERROR_CODE_HEADER_ONLY
  10. #define BOOST_CHRONO_HEADER_ONLY
  11. #include <boost/lexical_cast.hpp>
  12. #include <boost/chrono.hpp>
  13. #include <fstream>
  14. #include <cstring>
  15. #include <boost/container/string.hpp>
  16. // File to output data
  17. std::fstream fout;
  18. namespace boost {
  19. inline std::istream& operator>> (std::istream& in, boost::array<char,50>& res) {
  20. in >> res.begin();
  21. return in;
  22. }
  23. }
  24. template <class OutT, class InT>
  25. static inline void test_lexical(const InT& in_val) {
  26. OutT out_val = boost::lexical_cast<OutT>(in_val);
  27. (void)out_val;
  28. }
  29. template <class OutT, class InT>
  30. static inline void test_ss_constr(const InT& in_val) {
  31. OutT out_val;
  32. std::stringstream ss;
  33. ss << in_val;
  34. if (ss.fail()) throw std::logic_error("descr");
  35. ss >> out_val;
  36. if (ss.fail()) throw std::logic_error("descr");
  37. }
  38. template <class OutT, class CharT, std::size_t N>
  39. static inline void test_ss_constr(const boost::array<CharT, N>& in_val) {
  40. OutT out_val;
  41. std::stringstream ss;
  42. ss << in_val.begin();
  43. if (ss.fail()) throw std::logic_error("descr");
  44. ss >> out_val;
  45. if (ss.fail()) throw std::logic_error("descr");
  46. }
  47. template <class OutT, class StringStreamT, class CharT, std::size_t N>
  48. static inline void test_ss_noconstr(StringStreamT& ss, const boost::array<CharT, N>& in_val) {
  49. OutT out_val;
  50. ss << in_val.begin(); // ss is an instance of std::stringstream
  51. if (ss.fail()) throw std::logic_error("descr");
  52. ss >> out_val;
  53. if (ss.fail()) throw std::logic_error("descr");
  54. /* reseting std::stringstream to use it again */
  55. ss.str(std::string());
  56. ss.clear();
  57. }
  58. template <class OutT, class StringStreamT, class InT>
  59. static inline void test_ss_noconstr(StringStreamT& ss, const InT& in_val) {
  60. OutT out_val;
  61. ss << in_val; // ss is an instance of std::stringstream
  62. if (ss.fail()) throw std::logic_error("descr");
  63. ss >> out_val;
  64. if (ss.fail()) throw std::logic_error("descr");
  65. /* reseting std::stringstream to use it again */
  66. ss.str(std::string());
  67. ss.clear();
  68. }
  69. struct structure_sprintf {
  70. template <class OutT, class BufferT, class InT>
  71. static inline void test(BufferT* buffer, const InT& in_val, const char* const conv) {
  72. sprintf(buffer, conv, in_val);
  73. OutT out_val(buffer);
  74. }
  75. template <class OutT, class BufferT>
  76. static inline void test(BufferT* buffer, const std::string& in_val, const char* const conv) {
  77. sprintf(buffer, conv, in_val.c_str());
  78. OutT out_val(buffer);
  79. }
  80. };
  81. struct structure_sscanf {
  82. template <class OutT, class BufferT, class CharT, std::size_t N>
  83. static inline void test(BufferT* /*buffer*/, const boost::array<CharT, N>& in_val, const char* const conv) {
  84. OutT out_val;
  85. sscanf(in_val.cbegin(), conv, &out_val);
  86. }
  87. template <class OutT, class BufferT, class InT>
  88. static inline void test(BufferT* /*buffer*/, const InT& in_val, const char* const conv) {
  89. OutT out_val;
  90. sscanf(reinterpret_cast<const char*>(in_val), conv, &out_val);
  91. }
  92. template <class OutT, class BufferT>
  93. static inline void test(BufferT* /*buffer*/, const std::string& in_val, const char* const conv) {
  94. OutT out_val;
  95. sscanf(in_val.c_str(), conv, &out_val);
  96. }
  97. template <class OutT, class BufferT>
  98. static inline void test(BufferT* /*buffer*/, const boost::iterator_range<const char*>& in_val, const char* const conv) {
  99. OutT out_val;
  100. sscanf(in_val.begin(), conv, &out_val);
  101. }
  102. };
  103. struct structure_fake {
  104. template <class OutT, class BufferT, class InT>
  105. static inline void test(BufferT* /*buffer*/, const InT& /*in_val*/, const char* const /*conv*/) {}
  106. };
  107. static const int fake_test_value = 9999;
  108. template <class T>
  109. static inline void min_fancy_output(T v1, T v2, T v3, T v4) {
  110. const char beg_mark[] = "!!! *";
  111. const char end_mark[] = "* !!!";
  112. const char no_mark[] = "";
  113. unsigned int res = 4;
  114. if (v1 < v2 && v1 < v3 && v1 < v4) res = 1;
  115. if (v2 < v1 && v2 < v3 && v2 < v4) res = 2;
  116. if (v3 < v1 && v3 < v2 && v3 < v4) res = 3;
  117. fout << "[ "
  118. << (res == 1 ? beg_mark : no_mark)
  119. ;
  120. if (v1) fout << v1;
  121. else fout << "<1";
  122. fout << (res == 1 ? end_mark : no_mark)
  123. << " ][ "
  124. << (res == 2 ? beg_mark : no_mark)
  125. ;
  126. if (v2) fout << v2;
  127. else fout << "<1";
  128. fout << (res == 2 ? end_mark : no_mark)
  129. << " ][ "
  130. << (res == 3 ? beg_mark : no_mark)
  131. ;
  132. if (v3) fout << v3;
  133. else fout << "<1";
  134. fout << (res == 3 ? end_mark : no_mark)
  135. << " ][ "
  136. << (res == 4 ? beg_mark : no_mark)
  137. ;
  138. if (!v4) fout << "<1";
  139. else if (v4 == fake_test_value) fout << "---";
  140. else fout << v4;
  141. fout
  142. << (res == 4 ? end_mark : no_mark)
  143. << " ]";
  144. }
  145. template <unsigned int IetartionsCountV, class ToT, class SprintfT, class FromT>
  146. static inline void perf_test_impl(const FromT& in_val, const char* const conv) {
  147. typedef boost::chrono::steady_clock test_clock;
  148. test_clock::time_point start;
  149. typedef boost::chrono::milliseconds duration_t;
  150. duration_t lexical_cast_time, ss_constr_time, ss_noconstr_time, printf_time;
  151. start = test_clock::now();
  152. for (unsigned int i = 0; i < IetartionsCountV; ++i) {
  153. test_lexical<ToT>(in_val);
  154. test_lexical<ToT>(in_val);
  155. test_lexical<ToT>(in_val);
  156. test_lexical<ToT>(in_val);
  157. }
  158. lexical_cast_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
  159. start = test_clock::now();
  160. for (unsigned int i = 0; i < IetartionsCountV; ++i) {
  161. test_ss_constr<ToT>(in_val);
  162. test_ss_constr<ToT>(in_val);
  163. test_ss_constr<ToT>(in_val);
  164. test_ss_constr<ToT>(in_val);
  165. }
  166. ss_constr_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
  167. std::stringstream ss;
  168. start = test_clock::now();
  169. for (unsigned int i = 0; i < IetartionsCountV; ++i) {
  170. test_ss_noconstr<ToT>(ss, in_val);
  171. test_ss_noconstr<ToT>(ss, in_val);
  172. test_ss_noconstr<ToT>(ss, in_val);
  173. test_ss_noconstr<ToT>(ss, in_val);
  174. }
  175. ss_noconstr_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
  176. char buffer[128];
  177. start = test_clock::now();
  178. for (unsigned int i = 0; i < IetartionsCountV; ++i) {
  179. SprintfT::template test<ToT>(buffer, in_val, conv);
  180. SprintfT::template test<ToT>(buffer, in_val, conv);
  181. SprintfT::template test<ToT>(buffer, in_val, conv);
  182. SprintfT::template test<ToT>(buffer, in_val, conv);
  183. }
  184. printf_time = boost::chrono::duration_cast<duration_t>(test_clock::now() - start);
  185. min_fancy_output(
  186. lexical_cast_time.count(),
  187. ss_constr_time.count(),
  188. ss_noconstr_time.count(),
  189. boost::is_same<SprintfT, structure_fake>::value ? fake_test_value : printf_time.count()
  190. );
  191. }
  192. template <class ToT, class SprintfT, class FromT>
  193. static inline void perf_test(const std::string& test_name, const FromT& in_val, const char* const conv) {
  194. const unsigned int ITERATIONSCOUNT = 100000;
  195. fout << " [[ " << test_name << " ]";
  196. perf_test_impl<ITERATIONSCOUNT/4, ToT, SprintfT>(in_val, conv);
  197. fout << "]\n";
  198. }
  199. template <class ConverterT>
  200. void string_like_test_set(const std::string& from) {
  201. typedef structure_sscanf ssc_t;
  202. ConverterT conv;
  203. perf_test<char, ssc_t>(from + "->char", conv("c"), "%c");
  204. perf_test<signed char, ssc_t>(from + "->signed char", conv("c"), "%hhd");
  205. perf_test<unsigned char, ssc_t>(from + "->unsigned char", conv("c"), "%hhu");
  206. perf_test<int, ssc_t>(from + "->int", conv("100"), "%d");
  207. perf_test<short, ssc_t>(from + "->short", conv("100"), "%hd");
  208. perf_test<long int, ssc_t>(from + "->long int", conv("100"), "%ld");
  209. perf_test<boost::long_long_type, ssc_t>(from + "->long long", conv("100"), "%lld");
  210. perf_test<unsigned int, ssc_t>(from + "->unsigned int", conv("100"), "%u");
  211. perf_test<unsigned short, ssc_t>(from + "->unsigned short", conv("100"), "%hu");
  212. perf_test<unsigned long int, ssc_t>(from + "->unsigned long int", conv("100"), "%lu");
  213. perf_test<boost::ulong_long_type, ssc_t>(from + "->unsigned long long", conv("100"), "%llu");
  214. // perf_test<bool, ssc_t>(from + "->bool", conv("1"), "%");
  215. perf_test<float, ssc_t>(from + "->float", conv("1.123"), "%f");
  216. perf_test<double, ssc_t>(from + "->double", conv("1.123"), "%lf");
  217. perf_test<long double, ssc_t>(from + "->long double", conv("1.123"), "%Lf");
  218. perf_test<boost::array<char, 50>, ssc_t>(from + "->array<char, 50>", conv("1.123"), "%s");
  219. perf_test<std::string, structure_fake>(from + "->string", conv("string"), "%Lf");
  220. perf_test<boost::container::string, structure_fake>(from + "->container::string"
  221. , conv("string"), "%Lf");
  222. }
  223. struct to_string_conv {
  224. std::string operator()(const char* const c) const {
  225. return c;
  226. }
  227. };
  228. struct to_char_conv {
  229. const char* operator()(const char* const c) const {
  230. return c;
  231. }
  232. };
  233. struct to_uchar_conv {
  234. const unsigned char* operator()(const char* const c) const {
  235. return reinterpret_cast<const unsigned char*>(c);
  236. }
  237. };
  238. struct to_schar_conv {
  239. const signed char* operator()(const char* const c) const {
  240. return reinterpret_cast<const signed char*>(c);
  241. }
  242. };
  243. struct to_iterator_range {
  244. boost::iterator_range<const char*> operator()(const char* const c) const {
  245. return boost::make_iterator_range(c, c + std::strlen(c));
  246. }
  247. };
  248. struct to_array_50 {
  249. boost::array<char, 50> operator()(const char* const c) const {
  250. boost::array<char, 50> ret;
  251. std::strcpy(ret.begin(), c);
  252. return ret;
  253. }
  254. };
  255. int main(int argc, char** argv) {
  256. BOOST_ASSERT(argc >= 2);
  257. std::string output_path(argv[1]);
  258. output_path += "/results.txt";
  259. fout.open(output_path.c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
  260. BOOST_ASSERT(fout);
  261. fout << "[section " << BOOST_COMPILER << "]\n"
  262. << "[table:id Performance Table ( "<< BOOST_COMPILER << ")\n"
  263. << "[[From->To] [lexical_cast] [std::stringstream with construction] "
  264. << "[std::stringstream without construction][scanf/printf]]\n";
  265. // From std::string to ...
  266. string_like_test_set<to_string_conv>("string");
  267. // From ... to std::string
  268. perf_test<std::string, structure_sprintf>("string->char", 'c', "%c");
  269. perf_test<std::string, structure_sprintf>("string->signed char", static_cast<signed char>('c'), "%hhd");
  270. perf_test<std::string, structure_sprintf>("string->unsigned char", static_cast<unsigned char>('c'), "%hhu");
  271. perf_test<std::string, structure_sprintf>("int->string", 100, "%d");
  272. perf_test<std::string, structure_sprintf>("short->string", static_cast<short>(100), "%hd");
  273. perf_test<std::string, structure_sprintf>("long int->string", 100l, "%ld");
  274. perf_test<std::string, structure_sprintf>("long long->string", 100ll, "%lld");
  275. perf_test<std::string, structure_sprintf>("unsigned int->string", static_cast<unsigned short>(100u), "%u");
  276. perf_test<std::string, structure_sprintf>("unsigned short->string", 100u, "%hu");
  277. perf_test<std::string, structure_sprintf>("unsigned long int->string", 100ul, "%lu");
  278. perf_test<std::string, structure_sprintf>("unsigned long long->string", static_cast<boost::ulong_long_type>(100), "%llu");
  279. // perf_test<bool, structure_sscanf>("bool->string", std::string("1"), "%");
  280. perf_test<std::string, structure_sprintf>("float->string", 1.123f, "%f");
  281. perf_test<std::string, structure_sprintf>("double->string", 1.123, "%lf");
  282. perf_test<std::string, structure_sprintf>("long double->string", 1.123L, "%Lf");
  283. string_like_test_set<to_char_conv>("char*");
  284. string_like_test_set<to_uchar_conv>("unsigned char*");
  285. string_like_test_set<to_schar_conv>("signed char*");
  286. string_like_test_set<to_iterator_range>("iterator_range<char*>");
  287. string_like_test_set<to_array_50>("array<char, 50>");
  288. perf_test<int, structure_fake>("int->int", 100, "");
  289. perf_test<double, structure_fake>("float->double", 100.0f, "");
  290. perf_test<signed char, structure_fake>("char->signed char", 'c', "");
  291. fout << "]\n"
  292. << "[endsect]\n\n";
  293. return 0;
  294. }