| // -*- C++ -*- |
| // Boost general library 'format' --------------------------- |
| // See http://www.boost.org for updates, documentation, and revision history. |
| |
| // Copyright (c) 2001 Samuel Krempp |
| // krempp@crans.ens-cachan.fr |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| // several suggestions from Jens Maurer |
| |
| // ------------------------------------------------------------------------------ |
| // bench_variants.cc : do the same task, with snprintf, stream, and format |
| // and compare their times. |
| |
| // This benchmark is provided purely for information. |
| // It might not even compile as-is, |
| // or not give any sensible results. |
| // (e.g., it expects sprintf to be POSIX compliant) |
| |
| // ------------------------------------------------------------------------------ |
| |
| |
| #include <iostream> |
| #include <iomanip> |
| #include <cstdio> // sprintf |
| #include <cstring> |
| #include <fstream> |
| #include <cmath> // floor |
| #include <boost/timer.hpp> |
| |
| #include <boost/format.hpp> |
| |
| //#define knelson |
| |
| #ifdef knelson |
| namespace KNelson { |
| #include "boost/format3.hpp" |
| } |
| #endif |
| |
| |
| |
| |
| // portable /dev/null stream equivalent, by James Kanze, http://www.gabi-soft.de |
| class NulStreambuf : public std::streambuf |
| { |
| public: |
| NulStreambuf() { |
| setp( dummyBuffer , dummyBuffer + 64 ) ; |
| } |
| virtual int overflow( int c ); |
| virtual int underflow(); |
| private: |
| char dummyBuffer[ 64 ] ; |
| } ; |
| |
| class NulStream : public std::basic_ostream<char, std::char_traits<char> > |
| { |
| public: |
| NulStream(); |
| virtual ~NulStream(); |
| NulStreambuf* rdbuf() { |
| return static_cast< NulStreambuf* >( |
| ((std::basic_ostream<char, std::char_traits<char> > *) this) -> rdbuf() ) ; |
| } |
| } ; |
| |
| |
| //------------------------------------------------------------------------------------- |
| // NulStream implementation |
| |
| NulStream::NulStream() : std::basic_ostream<char, std::char_traits<char> > (NULL) { |
| init( new NulStreambuf ) ; |
| } |
| |
| NulStream::~NulStream() { |
| delete rdbuf() ; |
| } |
| |
| int NulStreambuf::underflow(){ return std::ios::traits_type::eof(); |
| } |
| |
| int NulStreambuf::overflow( int c ){ |
| setp( dummyBuffer , dummyBuffer + 64 ) ; |
| return (c == std::ios::traits_type::eof()) ? '\0' : c ; |
| } |
| |
| |
| |
| // ------------------------------------------------------------------------------------- |
| |
| static int NTests = 300000; |
| |
| //static std::stringstream nullStream; |
| static NulStream nullStream; |
| static double tstream, tpf; |
| //static const std::string fstring="%3$#x %1$20.10E %2$g %3$d \n"; |
| static const std::string fstring="%3$0#6x %1$20.10E %2$g %3$0+5d \n"; |
| static const double arg1=45.23; |
| static const double arg2=12.34; |
| static const int arg3=23; |
| static const std::string res = |
| "0x0017 4.5230000000E+01 12.34 +0023 \n"; |
| //static const std::string res = "23.0000 4.5230000000E+01 12.34 23 \n"; |
| void test_snprintf(); |
| void test_nullstream(); |
| void test_opti_nullstream(); |
| void test_parsed_once_format(); |
| void test_reused_format(); |
| void test_format(); |
| void test_try1(); |
| void test_try2(); |
| |
| #ifdef knelson |
| void test_format3(); |
| #endif |
| |
| int main(int argc, char * argv[]) { |
| using namespace boost; |
| using namespace std; |
| const string::size_type npos = string::npos; |
| |
| string choices=""; |
| if(1<argc) { |
| choices = (argv[1]); // profiling is easier launching only one. |
| NTests = 1000*1000; // andmoreprecise with many iterations |
| cout << "choices (" << choices << ") \n"; |
| } |
| |
| if(choices=="" || choices.find('p') !=npos) |
| test_snprintf(); |
| if(choices=="" || choices.find('n') !=npos) |
| test_nullstream(); |
| if(choices=="" || choices.find('1') !=npos) |
| test_parsed_once_format(); |
| if(choices=="" || choices.find('r') !=npos) |
| test_reused_format(); |
| if(choices=="" || choices.find('f') !=npos) |
| test_format(); |
| if(choices.find('t') !=npos) |
| test_try1(); |
| if(choices.find('y') !=npos) |
| test_try2(); |
| if(choices.find('o') !=npos) |
| test_opti_nullstream(); |
| #ifdef knelson |
| if(choices=="" || choices.find('k') !=npos) |
| test_format3(); |
| #endif |
| return 0; |
| } |
| |
| |
| void test_snprintf() |
| { |
| using namespace std; |
| |
| // Check that snpintf is Unix98 compatible on the platform : |
| char * buf = new char[4000]; |
| sprintf(buf, fstring.c_str(), arg1, arg2, arg3); |
| if( strncmp( buf, res.c_str(), res.size()) != 0 ) { |
| cerr << endl << buf; |
| } |
| // time the loop : |
| boost::timer chrono; |
| for(int i=0; i<NTests; ++i) { |
| sprintf(buf, fstring.c_str(), arg1, arg2, arg3); |
| } |
| tpf=chrono.elapsed(); |
| cout << left << setw(20) <<"printf time"<< right <<":" << tpf << endl; |
| } |
| |
| void test_try1() |
| { |
| using namespace std; |
| boost::io::basic_oaltstringstream<char> oss; |
| oss << boost::format(fstring) % arg1 % arg2 % arg3; |
| boost::timer chrono; |
| int dummy=0; |
| for(int i=0; i<NTests; ++i) { |
| dummy += oss.cur_size(); |
| } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"try1 time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf " |
| << ", = " << t / tstream << " * nullStream \n"; |
| } |
| |
| void test_try2() |
| { |
| using namespace std; |
| boost::io::basic_oaltstringstream<char> oss; |
| oss << boost::format(fstring) % arg1 % arg2 % arg3; |
| oss << "blas 34567890GGGGGGGGGGGGGGGGGGGGGGGGGGGGggggggggggggggggggggggggggg " << endl; |
| string s = oss.cur_str(); |
| oss << s << s << s; |
| oss.clear_buffer(); |
| oss << s << s; |
| s = oss.cur_str(); |
| boost::timer chrono; |
| int dummy=0; |
| for(int i=0; i<NTests; ++i) { |
| dummy += oss.cur_size(); |
| } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"try2 time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf " |
| << ", = " << t / tstream << " * nullStream \n"; |
| } |
| |
| void do_stream(std::ostream& os) { |
| using namespace std; |
| std::ios_base::fmtflags f = os.flags(); |
| os << hex << showbase << internal << setfill('0') << setw(6) << arg3 |
| << dec << noshowbase << right << setfill(' ') |
| << " " |
| << scientific << setw(20) << setprecision(10) << uppercase << arg1 |
| << setprecision(6) << nouppercase ; |
| os.flags(f); |
| os << " " << arg2 << " " |
| << showpos << setw(5) << internal << setfill('0') << arg3 << " \n" ; |
| os.flags(f); |
| } |
| |
| void test_nullstream() |
| { |
| using namespace std; |
| boost::timer chrono; |
| boost::io::basic_oaltstringstream<char> oss; |
| |
| { |
| do_stream(oss); |
| if(oss.str() != res ) { |
| cerr << endl << oss.str() ; |
| } |
| } |
| |
| for(int i=0; i<NTests; ++i) { |
| do_stream(nullStream); |
| } |
| |
| // for(int i=0; i<NTests; ++i) { |
| // std::ios_base::fmtflags f0 = nullStream.flags(); |
| // nullStream << hex << showbase << arg3 |
| // << dec << noshowbase << " " |
| // << scientific << setw(20) << setprecision(10) << uppercase << arg1 |
| // << setprecision(0); |
| // nullStream.flags(f0); |
| // nullStream << " " << arg2 << " " << arg3 << " \n" ; |
| |
| // } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"ostream time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf \n"; |
| tstream = t; |
| } |
| |
| void test_opti_nullstream() |
| { |
| using namespace std; |
| boost::timer chrono; |
| boost::io::basic_oaltstringstream<char> oss; |
| //static const std::string fstring="%3$#x %1$20.10E %2$g %3$d \n"; |
| |
| std::ios_base::fmtflags f0 = oss.flags(), f1, f2; |
| streamsize p0 = oss.precision(); |
| { |
| oss << hex << showbase; |
| f1 = oss.flags(); |
| oss << arg3; |
| |
| oss.flags(f0); |
| oss << " " << scientific << setw(20) << setprecision(10) << uppercase; |
| f2 = oss.flags(); |
| oss << arg1; |
| |
| oss.flags(f0); oss.precision(p0); |
| oss << " " << arg2 << " " << arg3 << " \n" ; |
| |
| if(oss.str() != res ) { |
| cerr << endl << oss.str() ; |
| } |
| } |
| |
| for(int i=0; i<NTests; ++i) { |
| nullStream.flags(f1); |
| nullStream << arg3; |
| |
| nullStream << setw(20) << setprecision(10); |
| nullStream.flags(f2); |
| nullStream << arg1; |
| |
| nullStream.flags(f0); nullStream.precision(p0); |
| nullStream << " " << arg2 << " " << arg3 << " \n" ; |
| } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"opti-stream time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf \n"; |
| // tstream = t; |
| } |
| |
| void test_parsed_once_format() |
| { |
| using namespace std; |
| static const boost::format fmter(fstring); |
| |
| boost::io::basic_oaltstringstream<char> oss; |
| oss << boost::format(fmter) % arg1 % arg2 % arg3 ; |
| if( oss.str() != res ) { |
| cerr << endl << oss.str(); |
| } |
| |
| // not only is the format-string parsed once, |
| // but also the buffer of the internal stringstream is already allocated. |
| |
| boost::timer chrono; |
| for(int i=0; i<NTests; ++i) { |
| nullStream << boost::format(fmter) % arg1 % arg2 % arg3; |
| } |
| double t=chrono.elapsed(); |
| cout << left << setw(20) <<"parsed-once time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf " |
| << ", = " << t / tstream << " * nullStream \n"; |
| } |
| |
| void test_reused_format() |
| { |
| using namespace std; |
| boost::io::basic_oaltstringstream<char> oss; |
| oss << boost::format(fstring) % arg1 % arg2 % arg3; |
| if(oss.str() != res ) { |
| cerr << endl << oss.str(); |
| } |
| |
| boost::timer chrono; |
| boost::format fmter; |
| for(int i=0; i<NTests; ++i) { |
| nullStream << fmter.parse(fstring) % arg1 % arg2 % arg3; |
| } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"reused format time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf " |
| << ", = " << t / tstream << " * nullStream \n"; |
| } |
| |
| void test_format() |
| { |
| using namespace std; |
| boost::io::basic_oaltstringstream<char> oss; |
| oss << boost::format(fstring) % arg1 % arg2 % arg3; |
| if(oss.str() != res ) { |
| cerr << endl << oss.str(); |
| } |
| |
| boost::timer chrono; |
| for(int i=0; i<NTests; ++i) { |
| nullStream << boost::format(fstring) % arg1 % arg2 % arg3; |
| } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"format time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf " |
| << ", = " << t / tstream << " * nullStream \n"; |
| } |
| |
| |
| #ifdef knelson |
| void test_format3() |
| { |
| using namespace std; |
| boost::io::basic_oaltstringstream<char> oss; |
| oss << KNelson::boost::format(fstring.c_str(), arg1, arg2, arg3); |
| if(oss.str() != res ) { |
| cerr << endl << oss.str(); |
| } |
| |
| boost::timer chrono; |
| for(int i=0; i<NTests; ++i) { |
| nullStream << KNelson::boost::format(fstring.c_str(), arg1, arg2, arg3); |
| } |
| double t = chrono.elapsed(); |
| cout << left << setw(20) <<"format3 time"<< right <<":" << setw(5) << t |
| << ", = " << t / tpf << " * printf " |
| << ", = " << t / tstream << " * nullStream \n" ; |
| } |
| |
| #endif |