How can I improve streams performance?

Discussion in 'C++' started by Roy Smith, Jul 16, 2003.

  1. Roy Smith

    Roy Smith Guest

    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.
    Roy Smith, Jul 16, 2003
    #1
    1. Advertising

  2. Roy Smith

    Ron Natalie Guest

    "Roy Smith" <> wrote in message news:bf41hq$rst$...

    > 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...
    Ron Natalie, Jul 16, 2003
    #2
    1. Advertising

  3. Roy Smith

    Raoul Gough Guest

    "Ron Natalie" <> writes:

    > "Roy Smith" <> wrote in message
    > news:bf41hq$rst$...
    >
    >> 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...


    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);
    // ...
    }

    --
    Raoul Gough
    "Let there be one measure for wine throughout our kingdom, and one
    measure for ale, and one measure for corn" - Magna Carta
    Raoul Gough, Jul 16, 2003
    #3
  4. Roy Smith

    Raoul Gough Guest

    Raoul Gough <> writes:

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


    Correction - that should be:

    std::cout.sync_with_stdio(false);

    The thread I referred to (performance of printf(...) vs. cout << ...)
    is at http://groups.google.com/groups?th=d75093a01bedc2f0

    --
    Raoul Gough
    "Let there be one measure for wine throughout our kingdom, and one
    measure for ale, and one measure for corn" - Magna Carta
    Raoul Gough, Jul 16, 2003
    #4
  5. Roy Smith

    Roy Smith Guest

    Raoul Gough <> wrote:
    > 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.
    Roy Smith, Jul 16, 2003
    #5
  6. Roy Smith

    Raoul Gough Guest

    (Roy Smith) writes:

    > Raoul Gough <> wrote:
    >> 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.


    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);

    --
    Raoul Gough
    "Let there be one measure for wine throughout our kingdom, and one
    measure for ale, and one measure for corn" - Magna Carta
    Raoul Gough, Jul 16, 2003
    #6
  7. Roy Smith

    Alex Vinokur Guest

    "Roy Smith" <> wrote in message news:bf41hq$rst$...
    > 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:
    http://sourceforge.net/users/alexvn
    http://www.simtel.net/search.php?action=search&authorName=Alex Vinokur
    ==========================================
    Alex Vinokur, Jul 16, 2003
    #7
  8. Roy Smith wrote:

    > 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
    Thomas Matthews, Jul 16, 2003
    #8
  9. Thomas Matthews <> wrote in message news:<M5iRa.10457$>...

    > 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,
    --
    Michiel Salters
    Michiel Salters, Jul 18, 2003
    #9
  10. Roy Smith

    Mike Wahler Guest

    "Krzysztof Rzymkowski" <> wrote in message
    news:bptvca$1fia$...
    > 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
    Mike Wahler, Nov 24, 2003
    #10
  11. 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.
    Krzysztof Rzymkowski, Nov 24, 2003
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. hb
    Replies:
    2
    Views:
    474
  2. Marc Twain
    Replies:
    5
    Views:
    4,740
    Andrew Thompson
    Jan 15, 2004
  3. Nishi Bhonsle
    Replies:
    1
    Views:
    888
    Thomas Weidenfeller
    Jul 20, 2004
  4. Replies:
    3
    Views:
    291
  5. =?Utf-8?B?U3dhbWk=?=

    Improve performance using masterpages and base classes?

    =?Utf-8?B?U3dhbWk=?=, Oct 4, 2006, in forum: ASP .Net
    Replies:
    0
    Views:
    298
    =?Utf-8?B?U3dhbWk=?=
    Oct 4, 2006
Loading...

Share This Page