1. iostream output is spanned across several commands and hence it is slower.
2.boost.spirit is real quick. |
When I said that boost.spirit is the fastest (for input speed, which was the title of the thread), I meant the code that has to do with converting the input (sequence of characters) to data (ints, doubles, structs, etc), which is where the significant differences between C++ and C streams are. The steps from an external device into a program-accessible sequence of characters are the same or can be made the same with simple steps (sync_with_stdio(false), setbuf, memory mapping, etc).
I felt like giving it a test: my input is a string holding 10,000,000 random doubles in -10.0 .. 10.0 range, separated by varying amounts of whitespace (1..10 spaces), as generated by this code:
1 2 3 4 5 6 7 8 9
|
const unsigned MAX = 10000000;
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_real_distribution<> value_d(-10.0, 10.0);
std::uniform_int_distribution<> space_d(1, 10);
for(unsigned n = 0; n < MAX; ++n)
data += std::string(space_d(mt), ' ')
+ std::to_string(value_d(mt));
|
The size of the string was 139,993,617 bytes
Each of the following functions received a pre-allocated vector<double>
Boost.spirit (personal favorite)
1 2 3 4
|
void use_boost_spirit(const std::string& data, std::vector<double>& result)
{
qi::phrase_parse(data.begin(), data.end(), *qi::double_, ascii::space, result);
}
|
C stdio (crowd favorite)
1 2 3 4 5 6 7 8 9 10 11
|
void use_stdio(const std::string& data, std::vector<double>& result)
{
const char* p = data.c_str();
char* p2;
double val;
while( val = std::strtod(p, &p2), p != p2 )
{
result.push_back(val);
p = p2;
};
}
|
C++ streams: run-of-the-mill stringstream
1 2 3 4 5 6
|
void use_stringstream(const std::string& data, std::vector<double>& result)
{
std::istringstream buf(data);
result.assign( std::istream_iterator<double>(buf),
std::istream_iterator<double>() );
}
|
C++ streams: istrstream (old-timer's delight)
1 2 3 4 5 6
|
void use_strstream(const std::string& data, std::vector<double>& result)
{
std::istrstream buf(data.c_str());
result.assign( std::istream_iterator<double>(buf),
std::istream_iterator<double>() );
}
|
C++ streams: boost replacement for istrstream
1 2 3 4 5 6 7
|
void use_boost_stream(const std::string& data, std::vector<double>& result)
{
io::stream_buffer<io::array_source> boost_buf(data.c_str(), data.size());
std::istream buf(&boost_buf);
result.assign( std::istream_iterator<double>(buf),
std::istream_iterator<double>() );
}
|
Complete program:
http://liveworkspace.org/code/30FxYn (also shows the output metrics on whatever system LWS uses)
Results: time in seconds, average over 10 runs:
spirit strtod boost::iostream strstream stringstream
on intel,
intel-13.0.1 -Ofast -xHost 0.901 1.765 4.765 4.551 4.981
gcc-4.7.2 -O3 -march=native 1.423 1.817 4.808 4.853 5.048
clang-3.1 -O3 -march=native 1.492 1.814 6.790 6.830 7.039
on ibm,
gcc-4.7.2 -O3 -mcpu=power6 0.651 1.396 >1 min
xlC-11.1 -O3 -qarch=pwr6 0.882 6.290 6.341 6.330
on sun,
CC-5.10 -fast -library=stlport4 0.306 11.650 11.760 12.070
|