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