JimR
JimR

Reputation: 16113

iostreams slow. Is there a way to speed them up?

I've been hacking at a problem on and off for several days now that lists filenames that exceed the Windows MAX_PATH limit. I'm using Visual Studio 2008 with all the patches I can find. The timing is done with QueryPerformanceCounter and company.

The latest issue occurs in the following code:

    start = getTime();
    for( vector<wstring>::iterator it = files.begin(); it != files.end(); ++it )
    {
#if USE_COUT
            wcout << setw( 6 ) << it->length() << L": " << *it << endl;  // 1
#else
            wstring x( *it );
            wprintf( L"%6.6d: %s\n", it->length(), x.c_str() );          // 2
#endif
    }
    stop = getTime();

The above loop runs over a vector with 6755 entries with an average string length of 256 characters.

The code that prints via wcout takes roughly 52 seconds to display the vector using the loop above. The code that uses wprintf prints in about 1.2 seconds.

If I minimize the console window the printf code runs in about 500 milliseconds while the wcout code still takes about 40 seconds.

I've really tried to like iostreams over the years, but... I keep butting my head on this speed issue. In 1993/1994 when using the Borland OS/2 compiler, we had a similar issue with a runtime that took 4 to 6 hours to complete using an strstream that ran in about 200 milliseconds with sprintf.

Any suggestions to get me to change my mind about iostreams?


Edit:
All this talk of flushing has me curious.
Isn't \n in a printf string functionally the same as std::endl in the sense that both cause a newline and flush to be emitted to the output?
IIRC, printf without a \n does not print on some OS's until a buffer is filled or the stream is flushed, including Windows in the past.
So, if wprintf( "%6.6d: %s\n", length, string ) is flushed by the \n, why isn't wprintf as slow as wcout?

Thanks for your feedback/opinions. I wish I had had SO 18 years ago when I started hacking at this stuff.

Upvotes: 3

Views: 1391

Answers (4)

CashCow
CashCow

Reputation: 31435

It is very likely to speed you up a lot by not flushing your stream every iteration (use '\n' rather than endl), although my guess is that you will still find printf to be faster.

You might move the setw outside of your loop too, by the way.

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941267

Optimizing code to make it less likely that a human can keep up with the blur of scrolling lines of text doesn't make a lot of sense. Rethink this approach. Output to a text file, use HTML perhaps to make it look decent, then start a program to display the result. Easier on your user's eyes. It's going to run a lot faster as well, no auto-flushing and no time spent scrolling the console. Only the disk I/O is your bottleneck now.

Upvotes: 1

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361292

  wcout << setw( 6 ) << it->length() << L": " << *it << endl;  // 1

One way to speed up is to use "\n" instead of endl in the loop, as endl is more than just a newline!

Upvotes: 2

Rudi
Rudi

Reputation: 19940

It is very likely that the std::endl line terminator is causing the performance bottleneck, since it flushes the stream after putting the newline. Exchange it with '\n' and a std::wcout << std::flush at the end of all output.

start = getTime();
for( vector<wstring>::iterator it = files.begin(); it != files.end(); ++it )
{
        wcout << setw( 6 ) << it->length() << L": " << *it << '\n';  // 1
}
std::wcout << std::flush;
stop = getTime();

Upvotes: 8

Related Questions