e4b101cd92
unit tests were failing on cygwin so I changed them to use lightweight test therefore Boost.Format no longer depends on Boost.Test
357 lines
10 KiB
C++
357 lines
10 KiB
C++
// -*- 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 sprintf, 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 <vector>
|
|
|
|
#include <boost/format.hpp>
|
|
|
|
// 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 ;
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
namespace benchmark {
|
|
|
|
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_sprintf();
|
|
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();
|
|
|
|
void test_sprintf()
|
|
{
|
|
using namespace std;
|
|
|
|
vector<char> bufr;
|
|
bufr.reserve(4000);
|
|
char *buf = &bufr[0];
|
|
|
|
// Check that sprintf is Unix98 compatible on the platform :
|
|
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;
|
|
size_t 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;
|
|
size_t 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";
|
|
}
|
|
|
|
} // benchmark
|
|
|
|
int main(int argc, char * argv[]) {
|
|
using namespace benchmark;
|
|
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_sprintf();
|
|
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();
|
|
return 0;
|
|
}
|
|
|