How can I improve streams performance?

R

Roy Smith

I've been running some benchmarks to compare streams and stdio
performance. I've always suspected stdio was faster, but was
astonished to discover how much faster. I timed the following running
into /dev/null, as well as the same loop using printf().

int main ()
{
for (int i = 0; i < 1000 * 1000; ++i) {
cout << "i = " << i << '\n';
}
}

I did two variations of the streams version (with '\n' and with endl),
and also two variations with printf, the difference being ading a call
to fflush() after each call to printf(). Here's the results using the
Sun Workshop compiler on a Sun E-250:

printf.noflush 2.80 user 0.01 system (2.81 total)
printf.flush 6.02 user 3.28 system (9.30 total)
stream.newline 33.02 user 18.29 system (51.31 total)
stream.endl 36.33 user 19.81 system (56.14 total)

Stdio looks like it's 5-20 times faster than streams. I got similar
ratios using gcc on a 800 MHz Pentium running Linux. Using gcc on a
400 MHz Macintosh G4 running OS-X, stdio was closer to 100 times
faster!

Are these ratios typical? Is there something I can do to make streams
faster? I like the type safety and extensibility, but 5-20 (or maybe
even 100) times slower is a big price to pay for applications which do
any significant amount of i/o.
 
R

Ron Natalie

Roy Smith said:
Stdio looks like it's 5-20 times faster than streams. I got similar
ratios using gcc on a 800 MHz Pentium running Linux. Using gcc on a
400 MHz Macintosh G4 running OS-X, stdio was closer to 100 times
faster!

Are you sure you turned on the optimizer? The standard library relies heavily
on inline functions in most implementations. I only get a 3x difference on g++
here (printf is still faster). Of course, try feeding some class type to printf...
 
R

Raoul Gough

Ron Natalie said:
Are you sure you turned on the optimizer? The standard library
relies heavily on inline functions in most implementations. I only
get a 3x difference on g++ here (printf is still faster). Of
course, try feeding some class type to printf...

Another important point is to cancel sync_with_stdio. Dietmar Kuehl
pointed this out a while back in a clc++m thread on a similar
topic. ISTR it making iostreams twice as fast as printf (using STLport
with gcc on Windows, anyway). In theory, iostreams formatting should
be faster, since it doesn't have to parse a format string first.

// ...
int main () {
std::sync_with_stdio (false);
// ...
}
 
R

Roy Smith

Raoul Gough said:
Another important point is to cancel sync_with_stdio.

Hmmm. The Sun Workshop compiler doesn't seem to know about that.
When I added:

std::sync_with_stdio (false);

I got:

"stream.cc", line 5: Error: sync_with_stdio is not a member of std.
 
R

Raoul Gough

Hmmm. The Sun Workshop compiler doesn't seem to know about that.
When I added:

std::sync_with_stdio (false);

I got:

"stream.cc", line 5: Error: sync_with_stdio is not a member of std.

No wait, I'll get it right eventually :) sync_with_stdio is a static
member function of std::ios_base, so you should be using

std::ios_base::sync_with_stdio (false);
 
A

Alex Vinokur

Roy Smith said:
I've been running some benchmarks to compare streams and stdio
performance. I've always suspected stdio was faster, but was
astonished to discover how much faster. I timed the following running
into /dev/null, as well as the same loop using printf().
[snip]


C/C++ Performance Tests
=======================
Using C/C++ Program Perfometer
http://sourceforge.net/projects/cpp-perfometer
http://alexvn.freeservers.com/s1/perfometer.html


Environment
-----------
Windows 2000 Professional
CYGWIN_NT-5.0 1.3.22(0.78/3/2)
Intel(R) Celeron(R) CPU 1.70 GHz
GNU gcc/g++ version 3.2 20020927 (prerelease)
Compilation : No optimization


Summary test results
--------------------

#==================================================
# stdout, stderr,
# cout, cerr, clog, ostringstream,
# cout-to-file, cerr-to-file, clog-to-file
# - - - - - - - - - - - - - - - - - - - - -
# endl vs. "\n/" and '\n'
#--------------------------------------------------
# Resource Name : user time used (via rusage)
# Resource Cost Unit : milliseconds (unsigned long long)
# Resource State Unit : timeval
#==================================================
: -----------------------------------
: stdout "\n" -> 71
: stdout '\n' -> 81
: cout endl -> 420
: cout "\n" -> 90
: cout '\n' -> 79
: stderr "\n" -> 432
: stderr '\n' -> 421
: cerr endl -> 746
: cerr "\n" -> 764
: cerr '\n' -> 718
: clog endl -> 756
: clog "\n" -> 737
: clog '\n' -> 739
: ostringstream endl -> 30
: ostringstream "\n" -> 46
: ostringstream '\n' -> 33
: cout-to-file endl -> 400
: cout-to-file "\n" -> 52
: cout-to-file '\n' -> 41
: cerr-to-file endl -> 445
: cerr-to-file "\n" -> 53
: cerr-to-file '\n' -> 43
: clog-to-file endl -> 489
: clog-to-file "\n" -> 61
: clog-to-file '\n' -> 48
: -----------------------------------


==========================================
Alex Vinokur
mailto:[email protected]
http://sourceforge.net/users/alexvn
http://www.simtel.net/search.php?action=search&authorName=Alex+Vinokur
==========================================
 
T

Thomas Matthews

Roy said:
I've been running some benchmarks to compare streams and stdio
performance. I've always suspected stdio was faster, but was
astonished to discover how much faster. I timed the following running
into /dev/null, as well as the same loop using printf().

int main ()
{
for (int i = 0; i < 1000 * 1000; ++i) {
cout << "i = " << i << '\n';
}
}

I did two variations of the streams version (with '\n' and with endl),
and also two variations with printf, the difference being ading a call
to fflush() after each call to printf(). Here's the results using the
Sun Workshop compiler on a Sun E-250:

printf.noflush 2.80 user 0.01 system (2.81 total)
printf.flush 6.02 user 3.28 system (9.30 total)
stream.newline 33.02 user 18.29 system (51.31 total)
stream.endl 36.33 user 19.81 system (56.14 total)

Stdio looks like it's 5-20 times faster than streams. I got similar
ratios using gcc on a 800 MHz Pentium running Linux. Using gcc on a
400 MHz Macintosh G4 running OS-X, stdio was closer to 100 times
faster!

Are these ratios typical? Is there something I can do to make streams
faster? I like the type safety and extensibility, but 5-20 (or maybe
even 100) times slower is a big price to pay for applications which do
any significant amount of i/o.

Applications which perform any significant amount of I/O will first
format to a buffer, then output the buffer as one chunk. IOW, use
stringstream, then ostream::write(). In C, this translates to
ssprintf, then fwrite().

These applications would also either queue up the I/O requests or
reduce the number of requests. For example:
cout << "Menu choices:\n";
cout << "0) Exit\n";
cout << "1) Nothing\n";
cout << "2) Sleep\n";
cout << "3) Party\n";
could be reduced to:
const char Menu[] = "Menu choices:\n"
"0) Exit\n"
"1) Nothing\n"
"2) Sleep\n"
"3) Party\n";
cout << Menu;
or
cout.write(Menu, sizeof Menu);
Even a mixture of using write() for the constant text and the
formatted operator << for the variant part would still be
faster than using the stream insertion operator for everything.

If the application is truly I/O dependent, it would use some
assembly language to maximise the usage of platform I/O.
Another technique is to use double or more of buffers and
a thread for processing the buffers.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
M

Michiel Salters

Thomas Matthews said:
Applications which perform any significant amount of I/O will first
format to a buffer, then output the buffer as one chunk. IOW, use
stringstream, then ostream::write().

The technique is correct, but the implementation youy suggest is not.
Te format to buffer should be done by ostream, the chunked output by
ostreambuf. Luckily, that's what happens already. Buffering twice
will often decrease performance.

Regards,
 
M

Mike Wahler

Krzysztof Rzymkowski said:
Thomas Matthews wrote:
[snip]
Applications which perform any significant amount of I/O will first
format to a buffer, then output the buffer as one chunk. IOW, use
stringstream, then ostream::write(). In C, this translates to
ssprintf, then fwrite().

I don't suppose this would give any better results since buffering is
done internaly by iostream classes. That's what std::streambuf is for.
These applications would also either queue up the I/O requests or
reduce the number of requests. For example:
cout << "Menu choices:\n";
cout << "0) Exit\n";
cout << "1) Nothing\n";
cout << "2) Sleep\n";
cout << "3) Party\n";
could be reduced to:
const char Menu[] = "Menu choices:\n"
"0) Exit\n"
"1) Nothing\n"
"2) Sleep\n"
"3) Party\n";
cout << Menu;
or
cout.write(Menu, sizeof Menu);
Even a mixture of using write() for the constant text and the
formatted operator << for the variant part would still be
faster

You can't always say that one way is 'faster' than another.
That's an implementation detail. The only way to know is
to measure (and the results can and will vary among implementations.)
than using the stream insertion operator for everything.

You just gain less function calls here. But if you write

cout <<
"Menu choices:\n";
"0) Exit\n";
"1) Nothing\n";
"2) Sleep\n";
"3) Party\n";

you get just one function call.


Only optimize if performance is proven to be unacceptable.
Then only optimize after a profiler shows where any 'bottlenecks'
are.

E.g. a sequence of 'cout << [string]' statements might be already
be combined into one by an optimizing compiler.

First make it work, then make it fast (but only if really necessary).
In either case, always try to make it *clear* to a reader of the
source code. (Yes, the above is just as 'clear' as several 'cout'
statements, my advice is more general, motivated by seeing too much
obscure code written in the interest of (often not gained anyway)
'efficiency'.

$.02,
-Mike
 
K

Krzysztof Rzymkowski

Thomas Matthews wrote:
[snip]
Applications which perform any significant amount of I/O will first
format to a buffer, then output the buffer as one chunk. IOW, use
stringstream, then ostream::write(). In C, this translates to
ssprintf, then fwrite().

I don't suppose this would give any better results since buffering is
done internaly by iostream classes. That's what std::streambuf is for.
These applications would also either queue up the I/O requests or
reduce the number of requests. For example:
cout << "Menu choices:\n";
cout << "0) Exit\n";
cout << "1) Nothing\n";
cout << "2) Sleep\n";
cout << "3) Party\n";
could be reduced to:
const char Menu[] = "Menu choices:\n"
"0) Exit\n"
"1) Nothing\n"
"2) Sleep\n"
"3) Party\n";
cout << Menu;
or
cout.write(Menu, sizeof Menu);
Even a mixture of using write() for the constant text and the
formatted operator << for the variant part would still be
faster than using the stream insertion operator for everything.

You just gain less function calls here. But if you write

cout <<
"Menu choices:\n";
"0) Exit\n";
"1) Nothing\n";
"2) Sleep\n";
"3) Party\n";

you get just one function call.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top