bench_format.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // -*- C++ -*-
  2. // Boost general library 'format' ---------------------------
  3. // See http://www.boost.org for updates, documentation, and revision history.
  4. // Copyright (c) 2001 Samuel Krempp
  5. // krempp@crans.ens-cachan.fr
  6. // Distributed under the Boost Software License, Version 1.0. (See
  7. // accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. // several suggestions from Jens Maurer
  10. // ------------------------------------------------------------------------------
  11. // bench_variants.cc : do the same task, with sprintf, stream, and format
  12. // and compare their times.
  13. // This benchmark is provided purely for information.
  14. // It might not even compile as-is,
  15. // or not give any sensible results.
  16. // (e.g., it expects sprintf to be POSIX compliant)
  17. // ------------------------------------------------------------------------------
  18. #include <iostream>
  19. #include <iomanip>
  20. #include <cstdio> // sprintf
  21. #include <cstring>
  22. #include <fstream>
  23. #include <cmath> // floor
  24. #include <boost/timer.hpp>
  25. #include <vector>
  26. #include <boost/format.hpp>
  27. // portable /dev/null stream equivalent, by James Kanze, http://www.gabi-soft.de
  28. class NulStreambuf : public std::streambuf
  29. {
  30. public:
  31. NulStreambuf() {
  32. setp( dummyBuffer , dummyBuffer + 64 ) ;
  33. }
  34. virtual int overflow( int c );
  35. virtual int underflow();
  36. private:
  37. char dummyBuffer[ 64 ] ;
  38. } ;
  39. class NulStream : public std::basic_ostream<char, std::char_traits<char> >
  40. {
  41. public:
  42. NulStream();
  43. virtual ~NulStream();
  44. NulStreambuf* rdbuf() {
  45. return static_cast< NulStreambuf* >(
  46. ((std::basic_ostream<char, std::char_traits<char> > *) this) -> rdbuf() ) ;
  47. }
  48. } ;
  49. //-------------------------------------------------------------------------------------
  50. // NulStream implementation
  51. NulStream::NulStream() : std::basic_ostream<char, std::char_traits<char> > (NULL) {
  52. init( new NulStreambuf ) ;
  53. }
  54. NulStream::~NulStream() {
  55. delete rdbuf() ;
  56. }
  57. int NulStreambuf::underflow(){ return std::ios::traits_type::eof();
  58. }
  59. int NulStreambuf::overflow( int c ){
  60. setp( dummyBuffer , dummyBuffer + 64 ) ;
  61. return (c == std::ios::traits_type::eof()) ? '\0' : c ;
  62. }
  63. // -------------------------------------------------------------------------------------
  64. namespace benchmark {
  65. static int NTests = 300000;
  66. //static std::stringstream nullStream;
  67. static NulStream nullStream;
  68. static double tstream, tpf;
  69. //static const std::string fstring="%3$#x %1$20.10E %2$g %3$d \n";
  70. static const std::string fstring="%3$0#6x %1$20.10E %2$g %3$0+5d \n";
  71. static const double arg1=45.23;
  72. static const double arg2=12.34;
  73. static const int arg3=23;
  74. static const std::string res =
  75. "0x0017 4.5230000000E+01 12.34 +0023 \n";
  76. //static const std::string res = "23.0000 4.5230000000E+01 12.34 23 \n";
  77. void test_sprintf();
  78. void test_nullstream();
  79. void test_opti_nullstream();
  80. void test_parsed_once_format();
  81. void test_reused_format();
  82. void test_format();
  83. void test_try1();
  84. void test_try2();
  85. void test_sprintf()
  86. {
  87. using namespace std;
  88. vector<char> bufr;
  89. bufr.reserve(4000);
  90. char *buf = &bufr[0];
  91. // Check that sprintf is Unix98 compatible on the platform :
  92. sprintf(buf, fstring.c_str(), arg1, arg2, arg3);
  93. if( strncmp( buf, res.c_str(), res.size()) != 0 ) {
  94. cerr << endl << buf;
  95. }
  96. // time the loop :
  97. boost::timer chrono;
  98. for(int i=0; i<NTests; ++i) {
  99. sprintf(buf, fstring.c_str(), arg1, arg2, arg3);
  100. }
  101. tpf=chrono.elapsed();
  102. cout << left << setw(20) <<"printf time"<< right <<":" << tpf << endl;
  103. }
  104. void test_try1()
  105. {
  106. using namespace std;
  107. boost::io::basic_oaltstringstream<char> oss;
  108. oss << boost::format(fstring) % arg1 % arg2 % arg3;
  109. boost::timer chrono;
  110. size_t dummy=0;
  111. for(int i=0; i<NTests; ++i) {
  112. dummy += oss.cur_size();
  113. }
  114. double t = chrono.elapsed();
  115. cout << left << setw(20) <<"try1 time"<< right <<":" << setw(5) << t
  116. << ", = " << t / tpf << " * printf "
  117. << ", = " << t / tstream << " * nullStream \n";
  118. }
  119. void test_try2()
  120. {
  121. using namespace std;
  122. boost::io::basic_oaltstringstream<char> oss;
  123. oss << boost::format(fstring) % arg1 % arg2 % arg3;
  124. oss << "blas 34567890GGGGGGGGGGGGGGGGGGGGGGGGGGGGggggggggggggggggggggggggggg " << endl;
  125. string s = oss.cur_str();
  126. oss << s << s << s;
  127. oss.clear_buffer();
  128. oss << s << s;
  129. s = oss.cur_str();
  130. boost::timer chrono;
  131. size_t dummy=0;
  132. for(int i=0; i<NTests; ++i) {
  133. dummy += oss.cur_size();
  134. }
  135. double t = chrono.elapsed();
  136. cout << left << setw(20) <<"try2 time"<< right <<":" << setw(5) << t
  137. << ", = " << t / tpf << " * printf "
  138. << ", = " << t / tstream << " * nullStream \n";
  139. }
  140. void do_stream(std::ostream& os) {
  141. using namespace std;
  142. std::ios_base::fmtflags f = os.flags();
  143. os << hex << showbase << internal << setfill('0') << setw(6) << arg3
  144. << dec << noshowbase << right << setfill(' ')
  145. << " "
  146. << scientific << setw(20) << setprecision(10) << uppercase << arg1
  147. << setprecision(6) << nouppercase ;
  148. os.flags(f);
  149. os << " " << arg2 << " "
  150. << showpos << setw(5) << internal << setfill('0') << arg3 << " \n" ;
  151. os.flags(f);
  152. }
  153. void test_nullstream()
  154. {
  155. using namespace std;
  156. boost::timer chrono;
  157. boost::io::basic_oaltstringstream<char> oss;
  158. {
  159. do_stream(oss);
  160. if(oss.str() != res ) {
  161. cerr << endl << oss.str() ;
  162. }
  163. }
  164. for(int i=0; i<NTests; ++i) {
  165. do_stream(nullStream);
  166. }
  167. // for(int i=0; i<NTests; ++i) {
  168. // std::ios_base::fmtflags f0 = nullStream.flags();
  169. // nullStream << hex << showbase << arg3
  170. // << dec << noshowbase << " "
  171. // << scientific << setw(20) << setprecision(10) << uppercase << arg1
  172. // << setprecision(0);
  173. // nullStream.flags(f0);
  174. // nullStream << " " << arg2 << " " << arg3 << " \n" ;
  175. // }
  176. double t = chrono.elapsed();
  177. cout << left << setw(20) <<"ostream time"<< right <<":" << setw(5) << t
  178. << ", = " << t / tpf << " * printf \n";
  179. tstream = t;
  180. }
  181. void test_opti_nullstream()
  182. {
  183. using namespace std;
  184. boost::timer chrono;
  185. boost::io::basic_oaltstringstream<char> oss;
  186. //static const std::string fstring="%3$#x %1$20.10E %2$g %3$d \n";
  187. std::ios_base::fmtflags f0 = oss.flags(), f1, f2;
  188. streamsize p0 = oss.precision();
  189. {
  190. oss << hex << showbase;
  191. f1 = oss.flags();
  192. oss << arg3;
  193. oss.flags(f0);
  194. oss << " " << scientific << setw(20) << setprecision(10) << uppercase;
  195. f2 = oss.flags();
  196. oss << arg1;
  197. oss.flags(f0); oss.precision(p0);
  198. oss << " " << arg2 << " " << arg3 << " \n" ;
  199. if(oss.str() != res ) {
  200. cerr << endl << oss.str() ;
  201. }
  202. }
  203. for(int i=0; i<NTests; ++i) {
  204. nullStream.flags(f1);
  205. nullStream << arg3;
  206. nullStream << setw(20) << setprecision(10);
  207. nullStream.flags(f2);
  208. nullStream << arg1;
  209. nullStream.flags(f0); nullStream.precision(p0);
  210. nullStream << " " << arg2 << " " << arg3 << " \n" ;
  211. }
  212. double t = chrono.elapsed();
  213. cout << left << setw(20) <<"opti-stream time"<< right <<":" << setw(5) << t
  214. << ", = " << t / tpf << " * printf \n";
  215. // tstream = t;
  216. }
  217. void test_parsed_once_format()
  218. {
  219. using namespace std;
  220. static const boost::format fmter(fstring);
  221. boost::io::basic_oaltstringstream<char> oss;
  222. oss << boost::format(fmter) % arg1 % arg2 % arg3 ;
  223. if( oss.str() != res ) {
  224. cerr << endl << oss.str();
  225. }
  226. // not only is the format-string parsed once,
  227. // but also the buffer of the internal stringstream is already allocated.
  228. boost::timer chrono;
  229. for(int i=0; i<NTests; ++i) {
  230. nullStream << boost::format(fmter) % arg1 % arg2 % arg3;
  231. }
  232. double t=chrono.elapsed();
  233. cout << left << setw(20) <<"parsed-once time"<< right <<":" << setw(5) << t
  234. << ", = " << t / tpf << " * printf "
  235. << ", = " << t / tstream << " * nullStream \n";
  236. }
  237. void test_reused_format()
  238. {
  239. using namespace std;
  240. boost::io::basic_oaltstringstream<char> oss;
  241. oss << boost::format(fstring) % arg1 % arg2 % arg3;
  242. if(oss.str() != res ) {
  243. cerr << endl << oss.str();
  244. }
  245. boost::timer chrono;
  246. boost::format fmter;
  247. for(int i=0; i<NTests; ++i) {
  248. nullStream << fmter.parse(fstring) % arg1 % arg2 % arg3;
  249. }
  250. double t = chrono.elapsed();
  251. cout << left << setw(20) <<"reused format time"<< right <<":" << setw(5) << t
  252. << ", = " << t / tpf << " * printf "
  253. << ", = " << t / tstream << " * nullStream \n";
  254. }
  255. void test_format()
  256. {
  257. using namespace std;
  258. boost::io::basic_oaltstringstream<char> oss;
  259. oss << boost::format(fstring) % arg1 % arg2 % arg3;
  260. if(oss.str() != res ) {
  261. cerr << endl << oss.str();
  262. }
  263. boost::timer chrono;
  264. for(int i=0; i<NTests; ++i) {
  265. nullStream << boost::format(fstring) % arg1 % arg2 % arg3;
  266. }
  267. double t = chrono.elapsed();
  268. cout << left << setw(20) <<"format time"<< right <<":" << setw(5) << t
  269. << ", = " << t / tpf << " * printf "
  270. << ", = " << t / tstream << " * nullStream \n";
  271. }
  272. } // benchmark
  273. int main(int argc, char * argv[]) {
  274. using namespace benchmark;
  275. using namespace boost;
  276. using namespace std;
  277. const string::size_type npos = string::npos;
  278. string choices = "";
  279. if (1<argc) {
  280. choices = (argv[1]); // profiling is easier launching only one.
  281. NTests = 1000 * 1000; // andmoreprecise with many iterations
  282. cout << "choices (" << choices << ") \n";
  283. }
  284. if (choices == "" || choices.find('p') != npos)
  285. test_sprintf();
  286. if (choices == "" || choices.find('n') != npos)
  287. test_nullstream();
  288. if (choices == "" || choices.find('1') != npos)
  289. test_parsed_once_format();
  290. if (choices == "" || choices.find('r') != npos)
  291. test_reused_format();
  292. if (choices == "" || choices.find('f') != npos)
  293. test_format();
  294. if (choices.find('t') != npos)
  295. test_try1();
  296. if (choices.find('y') != npos)
  297. test_try2();
  298. if (choices.find('o') != npos)
  299. test_opti_nullstream();
  300. return 0;
  301. }